From 3ad09041293ccddb57f88f0b22c15bb57ffa0747 Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 27 Nov 2018 13:32:31 +0100 Subject: [PATCH 01/54] Some benchmarking --- .../CtorInvokeBenchmarks.cs | 32 +++++++++++++++++-- .../Umbraco.Tests.Benchmarks.csproj | 4 +-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Tests.Benchmarks/CtorInvokeBenchmarks.cs b/src/Umbraco.Tests.Benchmarks/CtorInvokeBenchmarks.cs index 5588e13d12..ccd9b01969 100644 --- a/src/Umbraco.Tests.Benchmarks/CtorInvokeBenchmarks.cs +++ b/src/Umbraco.Tests.Benchmarks/CtorInvokeBenchmarks.cs @@ -11,7 +11,13 @@ using Umbraco.Core; namespace Umbraco.Tests.Benchmarks { - [Config(typeof(Config))] + // some conclusions + // - ActivatorCreateInstance is slow + // - it's faster to get+invoke the ctor + // - emitting the ctor is unless if invoked only 1 + + //[Config(typeof(Config))] + [MemoryDiagnoser] public class CtorInvokeBenchmarks { private class Config : ManualConfig @@ -25,7 +31,7 @@ namespace Umbraco.Tests.Benchmarks // see benchmarkdotnet FAQ Add(Job.Default .WithLaunchCount(1) // benchmark process will be launched only once - .WithIterationTime(TimeInterval.FromMilliseconds(400)) + .WithIterationTime(TimeInterval.FromMilliseconds(400)) .WithWarmupCount(3) .WithIterationCount(6)); } @@ -158,6 +164,28 @@ namespace Umbraco.Tests.Benchmarks var foo = new Foo(_foo); } + [Benchmark] + public void EmitCtor() + { + var ctor = ReflectionUtilities.EmitConstuctor>(); + var foo = ctor(_foo); + } + + [Benchmark] + public void ActivatorCreateInstance() + { + var foo = Activator.CreateInstance(typeof(Foo), _foo); + } + + [Benchmark] + public void GetAndInvokeCtor() + { + var ctorArgTypes = new[] { typeof(IFoo) }; + var type = typeof(Foo); + var ctorInfo = type.GetConstructor(ctorArgTypes); + var foo = ctorInfo.Invoke(new object[] { _foo }); + } + [Benchmark] public void InvokeCtor() { diff --git a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj index 99bb768842..6fe3655bc9 100644 --- a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj +++ b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj @@ -87,8 +87,8 @@ - 0.11.2 + 0.11.3 - + \ No newline at end of file From 18c382d888ed51341f3b8fe2b94381711d2e178c Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 20 Nov 2018 13:24:06 +0100 Subject: [PATCH 02/54] in progress tags --- .../Migrations/Upgrade/UmbracoPlan.cs | 1 + .../Upgrade/V_8_0_0/MakeTagsVariant.cs | 16 + .../Models/ContentTagsExtensions.cs | 12 +- src/Umbraco.Core/Models/ITag.cs | 6 + .../Models/PropertyTagsExtensions.cs | 65 +- src/Umbraco.Core/Models/Tag.cs | 12 +- src/Umbraco.Core/Models/TaggedEntity.cs | 15 +- src/Umbraco.Core/Models/TaggedProperty.cs | 15 +- src/Umbraco.Core/Persistence/Dtos/TagDto.cs | 12 +- .../Persistence/Factories/TagFactory.cs | 3 +- .../Persistence/Mappers/TagMapper.cs | 1 + .../Persistence/NPocoSqlExtensions.cs | 75 ++- .../Repositories/ITagRepository.cs | 57 +- .../Implement/ContentRepositoryBase.cs | 32 +- .../Implement/LanguageRepository.cs | 3 +- .../Repositories/Implement/TagRepository.cs | 364 +++++------ .../PropertyEditorTagsExtensions.cs | 2 +- src/Umbraco.Core/Services/ITagService.cs | 123 ++-- .../Services/Implement/TagService.cs | 203 ++----- src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../Composing/TypeLoaderTests.cs | 7 + .../Services/ContentServiceTagsTests.cs | 545 +++++++++++++++++ .../Services/ContentServiceTests.cs | 563 ------------------ src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + .../valpropertyvalidator.directive.js | 5 +- .../propertyeditors/tags/tags.controller.js | 11 +- .../Editors/BackOfficeServerVariables.cs | 2 +- src/Umbraco.Web/Editors/ContentController.cs | 3 +- .../Editors/ContentControllerBase.cs | 15 +- src/Umbraco.Web/Editors/MediaController.cs | 5 +- src/Umbraco.Web/Editors/MemberController.cs | 5 +- src/Umbraco.Web/ITagQuery.cs | 64 +- .../PropertyEditors/TagsDataController.cs | 5 +- src/Umbraco.Web/TagQuery.cs | 171 ++---- src/Umbraco.Web/UmbracoHelper.cs | 2 +- 35 files changed, 1146 insertions(+), 1276 deletions(-) create mode 100644 src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/MakeTagsVariant.cs create mode 100644 src/Umbraco.Tests/Services/ContentServiceTagsTests.cs diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index ec49544976..570b923514 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -144,6 +144,7 @@ namespace Umbraco.Core.Migrations.Upgrade Chain("{EE429F1B-9B26-43CA-89F8-A86017C809A3}"); Chain("{08919C4B-B431-449C-90EC-2B8445B5C6B1}"); Chain("{7EB0254C-CB8B-4C75-B15B-D48C55B449EB}"); + Chain("{C39BF2A7-1454-4047-BBFE-89E40F66ED63}"); //FINAL diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/MakeTagsVariant.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/MakeTagsVariant.cs new file mode 100644 index 0000000000..c898187884 --- /dev/null +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/MakeTagsVariant.cs @@ -0,0 +1,16 @@ +using Umbraco.Core.Persistence.Dtos; + +namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 +{ + public class MakeTagsVariant : MigrationBase + { + public MakeTagsVariant(IMigrationContext context) + : base(context) + { } + + public override void Migrate() + { + AddColumn("languageId"); + } + } +} diff --git a/src/Umbraco.Core/Models/ContentTagsExtensions.cs b/src/Umbraco.Core/Models/ContentTagsExtensions.cs index 8aceaac762..dd7a716520 100644 --- a/src/Umbraco.Core/Models/ContentTagsExtensions.cs +++ b/src/Umbraco.Core/Models/ContentTagsExtensions.cs @@ -15,10 +15,10 @@ namespace Umbraco.Core.Models /// The property alias. /// The tags. /// A value indicating whether to merge the tags with existing tags instead of replacing them. - /// Tags do not support variants. - public static void AssignTags(this IContentBase content, string propertyTypeAlias, IEnumerable tags, bool merge = false) + /// A culture, for multi-lingual properties. + public static void AssignTags(this IContentBase content, string propertyTypeAlias, IEnumerable tags, bool merge = false, string culture = null) { - content.GetTagProperty(propertyTypeAlias).AssignTags(tags, merge); + content.GetTagProperty(propertyTypeAlias).AssignTags(tags, merge, culture); } /// @@ -27,10 +27,10 @@ namespace Umbraco.Core.Models /// The content item. /// The property alias. /// The tags. - /// Tags do not support variants. - public static void RemoveTags(this IContentBase content, string propertyTypeAlias, IEnumerable tags) + /// A culture, for multi-lingual properties. + public static void RemoveTags(this IContentBase content, string propertyTypeAlias, IEnumerable tags, string culture = null) { - content.GetTagProperty(propertyTypeAlias).RemoveTags(tags); + content.GetTagProperty(propertyTypeAlias).RemoveTags(tags, culture); } // gets and validates the property diff --git a/src/Umbraco.Core/Models/ITag.cs b/src/Umbraco.Core/Models/ITag.cs index 6f492a2d78..f2c30b2644 100644 --- a/src/Umbraco.Core/Models/ITag.cs +++ b/src/Umbraco.Core/Models/ITag.cs @@ -20,6 +20,12 @@ namespace Umbraco.Core.Models [DataMember] string Text { get; set; } + /// + /// Gets or sets the tag language. + /// + [DataMember] + int? LanguageId { get; set; } + /// /// Gets the number of nodes tagged with this tag. /// diff --git a/src/Umbraco.Core/Models/PropertyTagsExtensions.cs b/src/Umbraco.Core/Models/PropertyTagsExtensions.cs index 26779161a1..39172fff34 100644 --- a/src/Umbraco.Core/Models/PropertyTagsExtensions.cs +++ b/src/Umbraco.Core/Models/PropertyTagsExtensions.cs @@ -38,13 +38,13 @@ namespace Umbraco.Core.Models } /// - /// Assign default tags. + /// Assign tags. /// /// The property. /// The tags. /// A value indicating whether to merge the tags with existing tags instead of replacing them. - /// Tags do not support variants. - public static void AssignTags(this Property property, IEnumerable tags, bool merge = false) + /// A culture, for multi-lingual properties. + public static void AssignTags(this Property property, IEnumerable tags, bool merge = false, string culture = null) { if (property == null) throw new ArgumentNullException(nameof(property)); @@ -52,11 +52,11 @@ namespace Umbraco.Core.Models if (configuration == null) throw new NotSupportedException($"Property with alias \"{property.Alias}\" does not support tags."); - property.AssignTags(tags, merge, configuration.StorageType, configuration.Delimiter); + property.AssignTags(tags, merge, configuration.StorageType, configuration.Delimiter, culture); } // assumes that parameters are consistent with the datatype configuration - internal static void AssignTags(this Property property, IEnumerable tags, bool merge, TagsStorageType storageType, char delimiter) + private static void AssignTags(this Property property, IEnumerable tags, bool merge, TagsStorageType storageType, char delimiter, string culture) { // set the property value var trimmedTags = tags.Select(x => x.Trim()).ToArray(); @@ -68,11 +68,11 @@ namespace Umbraco.Core.Models switch (storageType) { case TagsStorageType.Csv: - property.SetValue(string.Join(delimiter.ToString(), currentTags.Union(trimmedTags))); // csv string + property.SetValue(string.Join(delimiter.ToString(), currentTags.Union(trimmedTags)), culture); // csv string break; case TagsStorageType.Json: - property.SetValue(JsonConvert.SerializeObject(currentTags.Union(trimmedTags).ToArray())); // json array + property.SetValue(JsonConvert.SerializeObject(currentTags.Union(trimmedTags).ToArray()), culture); // json array break; } } @@ -81,23 +81,23 @@ namespace Umbraco.Core.Models switch (storageType) { case TagsStorageType.Csv: - property.SetValue(string.Join(delimiter.ToString(), trimmedTags)); // csv string + property.SetValue(string.Join(delimiter.ToString(), trimmedTags), culture); // csv string break; case TagsStorageType.Json: - property.SetValue(JsonConvert.SerializeObject(trimmedTags)); // json array + property.SetValue(JsonConvert.SerializeObject(trimmedTags), culture); // json array break; } } } /// - /// Removes default tags. + /// Removes tags. /// /// The property. /// The tags. - /// Tags do not support variants. - public static void RemoveTags(this Property property, IEnumerable tags) + /// A culture, for multi-lingual properties. + public static void RemoveTags(this Property property, IEnumerable tags, string culture = null) { if (property == null) throw new ArgumentNullException(nameof(property)); @@ -105,33 +105,33 @@ namespace Umbraco.Core.Models if (configuration == null) throw new NotSupportedException($"Property with alias \"{property.Alias}\" does not support tags."); - property.RemoveTags(tags, configuration.StorageType, configuration.Delimiter); + property.RemoveTags(tags, configuration.StorageType, configuration.Delimiter, culture); } // assumes that parameters are consistent with the datatype configuration - private static void RemoveTags(this Property property, IEnumerable tags, TagsStorageType storageType, char delimiter) + private static void RemoveTags(this Property property, IEnumerable tags, TagsStorageType storageType, char delimiter, string culture) { // already empty = nothing to do - //fixme doesn't take into account variants - var value = property.GetValue()?.ToString(); + var value = property.GetValue(culture)?.ToString(); if (string.IsNullOrWhiteSpace(value)) return; // set the property value var trimmedTags = tags.Select(x => x.Trim()).ToArray(); - var currentTags = property.GetTagsValue(storageType, delimiter); + var currentTags = property.GetTagsValue(storageType, delimiter, culture); switch (storageType) { case TagsStorageType.Csv: - property.SetValue(string.Join(delimiter.ToString(), currentTags.Except(trimmedTags))); // csv string + property.SetValue(string.Join(delimiter.ToString(), currentTags.Except(trimmedTags)), culture); // csv string break; case TagsStorageType.Json: - property.SetValue(JsonConvert.SerializeObject(currentTags.Except(trimmedTags).ToArray())); // json array + property.SetValue(JsonConvert.SerializeObject(currentTags.Except(trimmedTags).ToArray()), culture); // json array break; } } - internal static IEnumerable GetTagsValue(this Property property) + // used by ContentRepositoryBase + internal static IEnumerable GetTagsValue(this Property property, string culture = null) { if (property == null) throw new ArgumentNullException(nameof(property)); @@ -139,15 +139,14 @@ namespace Umbraco.Core.Models if (configuration == null) throw new NotSupportedException($"Property with alias \"{property.Alias}\" does not support tags."); - return property.GetTagsValue(configuration.StorageType, configuration.Delimiter); + return property.GetTagsValue(configuration.StorageType, configuration.Delimiter, culture); } - internal static IEnumerable GetTagsValue(this Property property, TagsStorageType storageType, char delimiter) + private static IEnumerable GetTagsValue(this Property property, TagsStorageType storageType, char delimiter, string culture = null) { if (property == null) throw new ArgumentNullException(nameof(property)); - //fixme doesn't take into account variants - var value = property.GetValue()?.ToString(); + var value = property.GetValue(culture)?.ToString(); if (string.IsNullOrWhiteSpace(value)) return Enumerable.Empty(); switch (storageType) @@ -158,7 +157,6 @@ namespace Umbraco.Core.Models case TagsStorageType.Json: try { - //fixme doesn't take into account variants return JsonConvert.DeserializeObject(value).Select(x => x.ToString().Trim()); } catch (JsonException) @@ -178,34 +176,33 @@ namespace Umbraco.Core.Models /// The property. /// The property value. /// The datatype configuration. - /// + /// A culture, for multi-lingual properties. + /// /// The value is either a string (delimited string) or an enumeration of strings (tag list). /// This is used both by the content repositories to initialize a property with some tag values, and by the /// content controllers to update a property with values received from the property editor. /// - internal static void SetTagsValue(this Property property, object value, TagConfiguration tagConfiguration) + internal static void SetTagsValue(this Property property, object value, TagConfiguration tagConfiguration, string culture) { if (property == null) throw new ArgumentNullException(nameof(property)); if (tagConfiguration == null) throw new ArgumentNullException(nameof(tagConfiguration)); - var merge = false; // fixme always! var storageType = tagConfiguration.StorageType; var delimiter = tagConfiguration.Delimiter; - SetTagsValue(property, value, merge, storageType, delimiter); + SetTagsValue(property, value, storageType, delimiter, culture); } // assumes that parameters are consistent with the datatype configuration // value can be an enumeration of string, or a serialized value using storageType format - // fixme merge always false here?! - private static void SetTagsValue(Property property, object value, bool merge, TagsStorageType storageType, char delimiter) + private static void SetTagsValue(Property property, object value, TagsStorageType storageType, char delimiter, string culture) { if (value == null) value = Enumerable.Empty(); // if value is already an enumeration of strings, just use it if (value is IEnumerable tags1) { - property.AssignTags(tags1, merge, storageType, delimiter); + property.AssignTags(tags1, false, storageType, delimiter, culture); return; } @@ -214,14 +211,14 @@ namespace Umbraco.Core.Models { case TagsStorageType.Csv: var tags2 = value.ToString().Split(new[] { delimiter }, StringSplitOptions.RemoveEmptyEntries); - property.AssignTags(tags2, merge, storageType, delimiter); + property.AssignTags(tags2, false, storageType, delimiter, culture); break; case TagsStorageType.Json: try { var tags3 = JsonConvert.DeserializeObject>(value.ToString()); - property.AssignTags(tags3 ?? Enumerable.Empty(), merge, storageType, delimiter); + property.AssignTags(tags3 ?? Enumerable.Empty(), false, storageType, delimiter, culture); } catch (Exception ex) { diff --git a/src/Umbraco.Core/Models/Tag.cs b/src/Umbraco.Core/Models/Tag.cs index 867d43c257..e9707e587d 100644 --- a/src/Umbraco.Core/Models/Tag.cs +++ b/src/Umbraco.Core/Models/Tag.cs @@ -16,6 +16,7 @@ namespace Umbraco.Core.Models private string _group; private string _text; + private int? _languageId; /// /// Initializes a new instance of the class. @@ -26,11 +27,12 @@ namespace Umbraco.Core.Models /// /// Initializes a new instance of the class. /// - public Tag(int id, string group, string text) + public Tag(int id, string group, string text, int? languageId = null) { Id = id; Text = text; Group = group; + LanguageId = languageId; } private static PropertySelectors Selectors => _selectors ?? (_selectors = new PropertySelectors()); @@ -39,6 +41,7 @@ namespace Umbraco.Core.Models { public readonly PropertyInfo Group = ExpressionHelper.GetPropertyInfo(x => x.Group); public readonly PropertyInfo Text = ExpressionHelper.GetPropertyInfo(x => x.Text); + public readonly PropertyInfo LanguageId = ExpressionHelper.GetPropertyInfo(x => x.LanguageId); } /// @@ -55,6 +58,13 @@ namespace Umbraco.Core.Models set => SetPropertyValueAndDetectChanges(value, ref _text, Selectors.Text); } + /// + public int? LanguageId + { + get => _languageId; + set => SetPropertyValueAndDetectChanges(value, ref _languageId, Selectors.LanguageId); + } + /// public int NodeCount { get; internal set; } } diff --git a/src/Umbraco.Core/Models/TaggedEntity.cs b/src/Umbraco.Core/Models/TaggedEntity.cs index ac194c15cd..8c4695555d 100644 --- a/src/Umbraco.Core/Models/TaggedEntity.cs +++ b/src/Umbraco.Core/Models/TaggedEntity.cs @@ -5,10 +5,13 @@ namespace Umbraco.Core.Models /// /// Represents a tagged entity. /// - /// Note that it is the properties of an entity (like Content, Media, Members, etc.) that is tagged, - /// which is why this class is composed of a list of tagged properties and an Id reference to the actual entity. + /// Note that it is the properties of an entity (like Content, Media, Members, etc.) that are tagged, + /// which is why this class is composed of a list of tagged properties and the identifier the actual entity. public class TaggedEntity { + /// + /// Initializes a new instance of the class. + /// public TaggedEntity(int entityId, IEnumerable taggedProperties) { EntityId = entityId; @@ -16,13 +19,13 @@ namespace Umbraco.Core.Models } /// - /// Id of the entity, which is tagged + /// Gets the identifier of the entity. /// - public int EntityId { get; private set; } + public int EntityId { get; } /// - /// An enumerable list of tagged properties + /// Gets the tagged properties. /// - public IEnumerable TaggedProperties { get; private set; } + public IEnumerable TaggedProperties { get; } } } diff --git a/src/Umbraco.Core/Models/TaggedProperty.cs b/src/Umbraco.Core/Models/TaggedProperty.cs index 2b9650b432..2d9fda9a4f 100644 --- a/src/Umbraco.Core/Models/TaggedProperty.cs +++ b/src/Umbraco.Core/Models/TaggedProperty.cs @@ -7,6 +7,9 @@ namespace Umbraco.Core.Models /// public class TaggedProperty { + /// + /// Initializes a new instance of the class. + /// public TaggedProperty(int propertyTypeId, string propertyTypeAlias, IEnumerable tags) { PropertyTypeId = propertyTypeId; @@ -15,18 +18,18 @@ namespace Umbraco.Core.Models } /// - /// Id of the PropertyType, which this tagged property is based on + /// Gets the identifier of the property type. /// - public int PropertyTypeId { get; private set; } + public int PropertyTypeId { get; } /// - /// Alias of the PropertyType, which this tagged property is based on + /// Gets the alias of the property type. /// - public string PropertyTypeAlias { get; private set; } + public string PropertyTypeAlias { get; } /// - /// An enumerable list of Tags for the property + /// Gets the tags. /// - public IEnumerable Tags { get; private set; } + public IEnumerable Tags { get; } } } diff --git a/src/Umbraco.Core/Persistence/Dtos/TagDto.cs b/src/Umbraco.Core/Persistence/Dtos/TagDto.cs index 15c309d9e5..f6296e4bd0 100644 --- a/src/Umbraco.Core/Persistence/Dtos/TagDto.cs +++ b/src/Umbraco.Core/Persistence/Dtos/TagDto.cs @@ -3,11 +3,13 @@ using Umbraco.Core.Persistence.DatabaseAnnotations; namespace Umbraco.Core.Persistence.Dtos { - [TableName(Constants.DatabaseSchema.Tables.Tag)] + [TableName(TableName)] [PrimaryKey("id")] [ExplicitColumns] internal class TagDto { + public const string TableName = Constants.DatabaseSchema.Tables.Tag; + [Column("id")] [PrimaryKeyColumn] public int Id { get; set; } @@ -16,9 +18,15 @@ namespace Umbraco.Core.Persistence.Dtos [Length(100)] public string Group { get; set; } + [Column("languageId")] + [ForeignKey(typeof(LanguageDto))] + [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_LanguageId")] + [NullSetting(NullSetting = NullSettings.Null)] + public int? LanguageId { get;set; } + [Column("tag")] [Length(200)] - [Index(IndexTypes.UniqueNonClustered, ForColumns = "group,tag", Name = "IX_cmsTags")] + [Index(IndexTypes.UniqueNonClustered, ForColumns = "group,tag,languageId", Name = "IX_cmsTags")] public string Text { get; set; } //[Column("key")] diff --git a/src/Umbraco.Core/Persistence/Factories/TagFactory.cs b/src/Umbraco.Core/Persistence/Factories/TagFactory.cs index 867e6b0ae3..10441707ec 100644 --- a/src/Umbraco.Core/Persistence/Factories/TagFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/TagFactory.cs @@ -7,7 +7,7 @@ namespace Umbraco.Core.Persistence.Factories { public static ITag BuildEntity(TagDto dto) { - var entity = new Tag(dto.Id, dto.Group, dto.Text) { NodeCount = dto.NodeCount }; + var entity = new Tag(dto.Id, dto.Group, dto.Text, dto.LanguageId) { NodeCount = dto.NodeCount }; // reset dirty initial properties (U4-1946) entity.ResetDirtyProperties(false); return entity; @@ -20,6 +20,7 @@ namespace Umbraco.Core.Persistence.Factories Id = entity.Id, Group = entity.Group, Text = entity.Text, + LanguageId = entity.LanguageId //Key = entity.Group + "/" + entity.Text // de-normalize }; } diff --git a/src/Umbraco.Core/Persistence/Mappers/TagMapper.cs b/src/Umbraco.Core/Persistence/Mappers/TagMapper.cs index 8cd2ab27d7..63f73d060a 100644 --- a/src/Umbraco.Core/Persistence/Mappers/TagMapper.cs +++ b/src/Umbraco.Core/Persistence/Mappers/TagMapper.cs @@ -23,6 +23,7 @@ namespace Umbraco.Core.Persistence.Mappers CacheMap(src => src.Id, dto => dto.Id); CacheMap(src => src.Text, dto => dto.Text); CacheMap(src => src.Group, dto => dto.Group); + CacheMap(src => src.LanguageId, dto => dto.LanguageId); } } } diff --git a/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs b/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs index a5ab62d25f..86839cdaee 100644 --- a/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs +++ b/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs @@ -589,11 +589,14 @@ namespace Umbraco.Core.Persistence /// Creates a SELECT COUNT(*) Sql statement. /// /// The origin sql. + /// An optional alias. /// The Sql statement. - public static Sql SelectCount(this Sql sql) + public static Sql SelectCount(this Sql sql, string alias = null) { if (sql == null) throw new ArgumentNullException(nameof(sql)); - return sql.Select("COUNT(*)"); + var text = "COUNT(*)"; + if (alias != null) text += " AS " + sql.SqlContext.SqlSyntax.GetQuotedColumnName(alias); + return sql.Select(text); } /// @@ -607,13 +610,29 @@ namespace Umbraco.Core.Persistence /// If is empty, all columns are counted. /// public static Sql SelectCount(this Sql sql, params Expression>[] fields) + => sql.SelectCount(null, fields); + + /// + /// Creates a SELECT COUNT Sql statement. + /// + /// The type of the DTO to count. + /// The origin sql. + /// An alias. + /// Expressions indicating the columns to count. + /// The Sql statement. + /// + /// If is empty, all columns are counted. + /// + public static Sql SelectCount(this Sql sql, string alias, params Expression>[] fields) { if (sql == null) throw new ArgumentNullException(nameof(sql)); var sqlSyntax = sql.SqlContext.SqlSyntax; var columns = fields.Length == 0 ? sql.GetColumns(withAlias: false) : fields.Select(x => sqlSyntax.GetFieldName(x)).ToArray(); - return sql.Select("COUNT (" + string.Join(", ", columns) + ")"); + var text = "COUNT (" + string.Join(", ", columns) + ")"; + if (alias != null) text += " AS " + sql.SqlContext.SqlSyntax.GetQuotedColumnName(alias); + return sql.Select(text); } /// @@ -705,6 +724,56 @@ namespace Umbraco.Core.Persistence return sql.Append(", " + string.Join(", ", sql.GetColumns(tableAlias: tableAlias, columnExpressions: fields))); } + /// + /// Adds a COUNT(*) to a SELECT Sql statement. + /// + /// The origin sql. + /// An optional alias. + /// The Sql statement. + public static Sql AndSelectCount(this Sql sql, string alias = null) + { + if (sql == null) throw new ArgumentNullException(nameof(sql)); + var text = ", COUNT(*)"; + if (alias != null) text += " AS " + sql.SqlContext.SqlSyntax.GetQuotedColumnName(alias); + return sql.Append(text); + } + + /// + /// Adds a COUNT to a SELECT Sql statement. + /// + /// The type of the DTO to count. + /// The origin sql. + /// Expressions indicating the columns to count. + /// The Sql statement. + /// + /// If is empty, all columns are counted. + /// + public static Sql AndSelectCount(this Sql sql, params Expression>[] fields) + => sql.AndSelectCount(null, fields); + + /// + /// Adds a COUNT to a SELECT Sql statement. + /// + /// The type of the DTO to count. + /// The origin sql. + /// An alias. + /// Expressions indicating the columns to count. + /// The Sql statement. + /// + /// If is empty, all columns are counted. + /// + public static Sql AndSelectCount(this Sql sql, string alias = null, params Expression>[] fields) + { + if (sql == null) throw new ArgumentNullException(nameof(sql)); + var sqlSyntax = sql.SqlContext.SqlSyntax; + var columns = fields.Length == 0 + ? sql.GetColumns(withAlias: false) + : fields.Select(x => sqlSyntax.GetFieldName(x)).ToArray(); + var text = ", COUNT (" + string.Join(", ", columns) + ")"; + if (alias != null) text += " AS " + sql.SqlContext.SqlSyntax.GetQuotedColumnName(alias); + return sql.Append(text); + } + /// /// Creates a SELECT Sql statement with a referenced Dto. /// diff --git a/src/Umbraco.Core/Persistence/Repositories/ITagRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ITagRepository.cs index 782f3f1b89..c3e6dc028b 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ITagRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ITagRepository.cs @@ -19,7 +19,8 @@ namespace Umbraco.Core.Persistence.Repositories /// When is false, the tags specified in are added to those already assigned. /// When is empty and is true, all assigned tags are removed. /// - void Assign(int contentId, int propertyTypeId, IEnumerable tags, bool replaceTags); + // TODO: replaceTags is used as 'false' in tests exclusively - should get rid of it + void Assign(int contentId, int propertyTypeId, IEnumerable tags, bool replaceTags = true); /// /// Removes assigned tags from a content property. @@ -46,54 +47,48 @@ namespace Umbraco.Core.Persistence.Repositories #region Queries + /// + /// Gets a tagged entity. + /// TaggedEntity GetTaggedEntityByKey(Guid key); + + /// + /// Gets a tagged entity. + /// TaggedEntity GetTaggedEntityById(int id); - IEnumerable GetTaggedEntitiesByTagGroup(TaggableObjectTypes objectType, string tagGroup); - - IEnumerable GetTaggedEntitiesByTag(TaggableObjectTypes objectType, string tag, string tagGroup = null); + /// Gets all entities of a type, tagged with any tag in the specified group. + IEnumerable GetTaggedEntitiesByTagGroup(TaggableObjectTypes objectType, string group, string culture = null); /// - /// Returns all tags for an entity type (content/media/member) + /// Gets all entities of a type, tagged with the specified tag. /// - /// Entity type - /// Optional group - /// - IEnumerable GetTagsForEntityType(TaggableObjectTypes objectType, string group = null); + IEnumerable GetTaggedEntitiesByTag(TaggableObjectTypes objectType, string tag, string group = null, string culture = null); /// - /// Returns all tags that exist on the content item - Content/Media/Member + /// Gets all tags for an entity type. /// - /// The content item id to get tags for - /// Optional group - /// - IEnumerable GetTagsForEntity(int contentId, string group = null); + IEnumerable GetTagsForEntityType(TaggableObjectTypes objectType, string group = null, string culture = null); /// - /// Returns all tags that exist on the content item - Content/Media/Member + /// Gets all tags attached to an entity. /// - /// The content item id to get tags for - /// Optional group - /// - IEnumerable GetTagsForEntity(Guid contentId, string group = null); + IEnumerable GetTagsForEntity(int contentId, string group = null, string culture = null); /// - /// Returns all tags that exist on the content item for the property specified - Content/Media/Member + /// Gets all tags attached to an entity. /// - /// The content item id to get tags for - /// The property alias to get tags for - /// Optional group - /// - IEnumerable GetTagsForProperty(int contentId, string propertyTypeAlias, string group = null); + IEnumerable GetTagsForEntity(Guid contentId, string group = null, string culture = null); /// - /// Returns all tags that exist on the content item for the property specified - Content/Media/Member + /// Gets all tags attached to an entity via a property. /// - /// The content item id to get tags for - /// The property alias to get tags for - /// Optional group - /// - IEnumerable GetTagsForProperty(Guid contentId, string propertyTypeAlias, string group = null); + IEnumerable GetTagsForProperty(int contentId, string propertyTypeAlias, string group = null, string culture = null); + + /// + /// Gets all tags attached to an entity via a property. + /// + IEnumerable GetTagsForProperty(Guid contentId, string propertyTypeAlias, string group = null, string culture = null); #endregion } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs index 58f58c3d84..bd7943ff1d 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs @@ -217,8 +217,26 @@ namespace Umbraco.Core.Persistence.Repositories.Implement foreach (var property in entity.Properties) { var tagConfiguration = property.GetTagConfiguration(); - if (tagConfiguration == null) continue; - tagRepo.Assign(entity.Id, property.PropertyTypeId, property.GetTagsValue().Select(x => new Tag { Group = tagConfiguration.Group, Text = x }), true); + if (tagConfiguration == null) continue; // not a tags property + + if (property.PropertyType.VariesByCulture()) + { + var tags = new List(); + foreach (var pvalue in property.Values) + { + var tagsValue = property.GetTagsValue(pvalue.Culture); + var languageId = LanguageRepository.GetIdByIsoCode(pvalue.Culture); + var cultureTags = tagsValue.Select(x => new Tag { Group = tagConfiguration.Group, Text = x, LanguageId = languageId }); + tags.AddRange(cultureTags); + } + tagRepo.Assign(entity.Id, property.PropertyTypeId, tags); + } + else + { + var tagsValue = property.GetTagsValue(); // strings + var tags = tagsValue.Select(x => new Tag { Group = tagConfiguration.Group, Text = x }); + tagRepo.Assign(entity.Id, property.PropertyTypeId, tags); + } } } @@ -541,16 +559,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement propertyDataDtos.AddRange(propertyDataDtos2); var properties = PropertyFactory.BuildEntities(compositionProperties, propertyDataDtos, temp.PublishedVersionId, LanguageRepository).ToList(); - // deal with tags - foreach (var property in properties) - { - if (!tagConfigurations.TryGetValue(property.PropertyType.PropertyEditorAlias, out var tagConfiguration)) - continue; - - //fixme doesn't take into account variants - property.SetTagsValue(property.GetValue(), tagConfiguration); - } - if (result.ContainsKey(temp.VersionId)) { if (ContentRepositoryBase.ThrowOnWarning) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs index 09fb664ffe..e236670e74 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs @@ -111,7 +111,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement "DELETE FROM umbracoPropertyData WHERE languageId = @id", "DELETE FROM umbracoContentVersionCultureVariation WHERE languageId = @id", "DELETE FROM umbracoDocumentCultureVariation WHERE languageId = @id", - "DELETE FROM umbracoLanguage WHERE id = @id" + "DELETE FROM umbracoLanguage WHERE id = @id", + "DELETE FROM " + Constants.DatabaseSchema.Tables.Tag + " WHERE languageId = @id" }; return list; } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/TagRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/TagRepository.cs index 418e3d8ac3..77e474be08 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/TagRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/TagRepository.cs @@ -11,6 +11,7 @@ using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Factories; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Scoping; +using static Umbraco.Core.Persistence.NPocoSqlExtensions.Statics; namespace Umbraco.Core.Persistence.Repositories.Implement { @@ -109,74 +110,65 @@ namespace Umbraco.Core.Persistence.Repositories.Implement #region Assign and Remove Tags /// - public void Assign(int contentId, int propertyTypeId, IEnumerable tags, bool replaceTags) + // only invoked from ContentRepositoryBase with all cultures + replaceTags being true + public void Assign(int contentId, int propertyTypeId, IEnumerable tags, bool replaceTags = true) { // to no-duplicates array var tagsA = tags.Distinct(new TagComparer()).ToArray(); - // no tags? - if (tagsA.Length == 0) + // replacing = clear all + if (replaceTags) { - // replacing = clear all - if (replaceTags) - { - var sql0 = Sql().Delete().Where(x => x.NodeId == contentId && x.PropertyTypeId == propertyTypeId); - Database.Execute(sql0); - } - - // nothing else to do - return; + var sql0 = Sql().Delete().Where(x => x.NodeId == contentId && x.PropertyTypeId == propertyTypeId); + Database.Execute(sql0); } + // no tags? nothing else to do + if (tagsA.Length == 0) + return; + // tags // using some clever logic (?) to insert tags that don't exist in 1 query + // must coalesce languageId because equality of NULLs does not exist var tagSetSql = GetTagSet(tagsA); var group = SqlSyntax.GetQuotedColumnName("group"); // insert tags - var sql1 = $@"INSERT INTO cmsTags (tag, {group}) -SELECT tagSet.tag, tagSet.{group} + var sql1 = $@"INSERT INTO cmsTags (tag, {group}, languageId) +SELECT tagSet.tag, tagSet.{group}, tagSet.languageId FROM {tagSetSql} -LEFT OUTER JOIN cmsTags ON (tagSet.tag = cmsTags.tag AND tagSet.{group} = cmsTags.{group}) +LEFT OUTER JOIN cmsTags ON (tagSet.tag = cmsTags.tag AND tagSet.{group} = cmsTags.{group} AND COALESCE(tagSet.languageId, -1) = COALESCE(cmsTags.languageId, -1)) WHERE cmsTags.id IS NULL"; Database.Execute(sql1); - // if replacing, remove everything first - if (replaceTags) - { - var sql2 = Sql().Delete().Where(x => x.NodeId == contentId && x.PropertyTypeId == propertyTypeId); - Database.Execute(sql2); - } - // insert relations - var sql3 = $@"INSERT INTO cmsTagRelationship (nodeId, propertyTypeId, tagId) + var sql2 = $@"INSERT INTO cmsTagRelationship (nodeId, propertyTypeId, tagId) SELECT {contentId}, {propertyTypeId}, tagSet2.Id FROM ( SELECT t.Id FROM {tagSetSql} - INNER JOIN cmsTags as t ON (tagSet.tag = t.tag AND tagSet.{group} = t.{group}) + INNER JOIN cmsTags as t ON (tagSet.tag = t.tag AND tagSet.{group} = t.{group} AND COALESCE(tagSet.languageId, -1) = COALESCE(t.languageId, -1)) ) AS tagSet2 LEFT OUTER JOIN cmsTagRelationship r ON (tagSet2.id = r.tagId AND r.nodeId = {contentId} AND r.propertyTypeID = {propertyTypeId}) WHERE r.tagId IS NULL"; - Database.Execute(sql3); + Database.Execute(sql2); } /// + // only invoked from tests public void Remove(int contentId, int propertyTypeId, IEnumerable tags) { var tagSetSql = GetTagSet(tags); + var group = SqlSyntax.GetQuotedColumnName("group"); - var deleteSql = string.Concat("DELETE FROM cmsTagRelationship WHERE nodeId = ", - contentId, - " AND propertyTypeId = ", - propertyTypeId, - " AND tagId IN ", - "(SELECT id FROM cmsTags INNER JOIN ", - tagSetSql, - " ON (TagSet.Tag = cmsTags.Tag and TagSet." + SqlSyntax.GetQuotedColumnName("group") + @" = cmsTags." + SqlSyntax.GetQuotedColumnName("group") + @"))"); + var deleteSql = $@"DELETE FROM cmsTagRelationship WHERE nodeId = {contentId} AND propertyTypeId = {propertyTypeId} AND tagId IN ( + SELECT id FROM cmsTags INNER JOIN {tagSetSql} ON ( + tagSet.tag = cmsTags.tag AND tagSet.{group} = cmsTags.{group} AND COALESCE(tagSet.languageId, -1) = COALESCE(cmsTags.languageId, -1) + ) + )"; Database.Execute(deleteSql); } @@ -207,13 +199,6 @@ WHERE r.tagId IS NULL"; // private string GetTagSet(IEnumerable tags) { - string EscapeSqlString(string s) - { - // why were we escaping @ symbols? - //return NPocoDatabaseExtensions.EscapeAtSymbols(s.Replace("'", "''")); - return s.Replace("'", "''"); - } - var sql = new StringBuilder(); var group = SqlSyntax.GetQuotedColumnName("group"); var first = true; @@ -226,11 +211,17 @@ WHERE r.tagId IS NULL"; else sql.Append(" UNION "); sql.Append("SELECT N'"); - sql.Append(EscapeSqlString(tag.Text)); + sql.Append(SqlSyntax.EscapeString(tag.Text)); sql.Append("' AS tag, '"); - sql.Append(EscapeSqlString(tag.Group)); + sql.Append(SqlSyntax.EscapeString(tag.Group)); sql.Append("' AS "); sql.Append(group); + sql.Append(" , "); + if (tag.LanguageId.HasValue) + sql.Append(tag.LanguageId); + else + sql.Append("NULL"); + sql.Append(" AS languageId"); } sql.Append(") AS tagSet"); @@ -244,14 +235,17 @@ WHERE r.tagId IS NULL"; public bool Equals(ITag x, ITag y) { return ReferenceEquals(x, y) // takes care of both being null - || x != null && y != null && x.Text == y.Text && x.Group == y.Group; + || x != null && y != null && x.Text == y.Text && x.Group == y.Group && x.LanguageId == y.LanguageId; } public int GetHashCode(ITag obj) { unchecked { - return (obj.Text.GetHashCode() * 397) ^ obj.Group.GetHashCode(); + var h = obj.Text.GetHashCode(); + h = h * 397 ^ obj.Group.GetHashCode(); + h = h * 397 ^ (obj.LanguageId?.GetHashCode() ?? 0); + return h; } } } @@ -264,118 +258,126 @@ WHERE r.tagId IS NULL"; // consider caching implications // add lookups for parentId or path (ie get content in tag group, that are descendants of x) + // ReSharper disable once ClassNeverInstantiated.Local + // ReSharper disable UnusedAutoPropertyAccessor.Local + private class TaggedEntityDto + { + public int NodeId { get; set; } + public string PropertyTypeAlias { get; set; } + public int PropertyTypeId { get; set; } + public int TagId { get; set; } + public string TagText { get; set; } + public string TagGroup { get; set; } + public int? TagLanguage { get; set; } + } + // ReSharper restore UnusedAutoPropertyAccessor.Local + + /// public TaggedEntity GetTaggedEntityByKey(Guid key) { - var sql = Sql() - .Select("cmsTagRelationship.nodeId, cmsPropertyType.Alias, cmsPropertyType.id as propertyTypeId, cmsTags.tag, cmsTags.id as tagId, cmsTags." + SqlSyntax.GetQuotedColumnName("group")) - .From() - .InnerJoin() - .On(left => left.TagId, right => right.Id) - .InnerJoin() - .On(left => left.NodeId, right => right.NodeId) - .InnerJoin() - .On(left => left.Id, right => right.PropertyTypeId) - .InnerJoin() - .On(left => left.NodeId, right => right.NodeId) + var sql = GetTaggedEntitiesSql(TaggableObjectTypes.All, "*"); + + sql = sql .Where(dto => dto.UniqueId == key); - return CreateTaggedEntityCollection(Database.Fetch(sql)).FirstOrDefault(); + return Map(Database.Fetch(sql)).FirstOrDefault(); } + /// public TaggedEntity GetTaggedEntityById(int id) { - var sql = Sql() - .Select("cmsTagRelationship.nodeId, cmsPropertyType.Alias, cmsPropertyType.id as propertyTypeId, cmsTags.tag, cmsTags.id as tagId, cmsTags." + SqlSyntax.GetQuotedColumnName("group")) - .From() - .InnerJoin() - .On(left => left.TagId, right => right.Id) - .InnerJoin() - .On(left => left.NodeId, right => right.NodeId) - .InnerJoin() - .On(left => left.Id, right => right.PropertyTypeId) - .InnerJoin() - .On(left => left.NodeId, right => right.NodeId) + var sql = GetTaggedEntitiesSql(TaggableObjectTypes.All, "*"); + + sql = sql .Where(dto => dto.NodeId == id); - return CreateTaggedEntityCollection(Database.Fetch(sql)).FirstOrDefault(); + return Map(Database.Fetch(sql)).FirstOrDefault(); } - public IEnumerable GetTaggedEntitiesByTagGroup(TaggableObjectTypes objectType, string tagGroup) + /// + public IEnumerable GetTaggedEntitiesByTagGroup(TaggableObjectTypes objectType, string group, string culture = null) { - var sql = Sql() - .Select("cmsTagRelationship.nodeId, cmsPropertyType.Alias, cmsPropertyType.id as propertyTypeId, cmsTags.tag, cmsTags.id as tagId, cmsTags." + SqlSyntax.GetQuotedColumnName("group")) - .From() - .InnerJoin() - .On(left => left.TagId, right => right.Id) - .InnerJoin() - .On(left => left.NodeId, right => right.NodeId) - .InnerJoin() - .On(left => left.Id, right => right.PropertyTypeId) - .InnerJoin() - .On(left => left.NodeId, right => right.NodeId) - .Where(dto => dto.Group == tagGroup); + var sql = GetTaggedEntitiesSql(objectType, culture); - if (objectType != TaggableObjectTypes.All) - { - var nodeObjectType = GetNodeObjectType(objectType); - sql = sql - .Where(dto => dto.NodeObjectType == nodeObjectType); - } + sql = sql + .Where(x => x.Group == group); - return CreateTaggedEntityCollection( - Database.Fetch(sql)); + return Map(Database.Fetch(sql)); } - public IEnumerable GetTaggedEntitiesByTag(TaggableObjectTypes objectType, string tag, string tagGroup = null) + /// + public IEnumerable GetTaggedEntitiesByTag(TaggableObjectTypes objectType, string tag, string group = null, string culture = null) { - var sql = Sql() - .Select("cmsTagRelationship.nodeId, cmsPropertyType.Alias, cmsPropertyType.id as propertyTypeId, cmsTags.tag, cmsTags.id as tagId, cmsTags." + SqlSyntax.GetQuotedColumnName("group")) - .From() - .InnerJoin() - .On(left => left.TagId, right => right.Id) - .InnerJoin() - .On(left => left.NodeId, right => right.NodeId) - .InnerJoin() - .On(left => left.Id, right => right.PropertyTypeId) - .InnerJoin() - .On(left => left.NodeId, right => right.NodeId) + var sql = GetTaggedEntitiesSql(objectType, culture); + + sql = sql .Where(dto => dto.Text == tag); + if (group.IsNullOrWhiteSpace() == false) + sql = sql + .Where(dto => dto.Group == group); + + return Map(Database.Fetch(sql)); + } + + private Sql GetTaggedEntitiesSql(TaggableObjectTypes objectType, string culture) + { + var sql = Sql() + .Select(x => Alias(x.NodeId, "NodeId")) + .AndSelect(x => Alias(x.Alias, "PropertyTypeAlias"), x => Alias(x.Id, "PropertyTypeId")) + .AndSelect(x => Alias(x.Id, "TagId"), x => Alias(x.Text, "TagText"), x => Alias(x.Group, "TagGroup"), x => Alias(x.LanguageId, "TagLanguage")) + .From() + .InnerJoin().On((tag, rel) => tag.Id == rel.TagId) + .InnerJoin().On((rel, content) => rel.NodeId == content.NodeId) + .InnerJoin().On((rel, prop) => rel.PropertyTypeId == prop.Id) + .InnerJoin().On((content, node) => content.NodeId == node.NodeId); + + if (culture == null) + { + sql = sql + .Where(dto => dto.LanguageId == null); + } + else if (culture != "*") + { + sql = sql + .InnerJoin().On((tag, lang) => tag.LanguageId == lang.Id) + .Where(x => x.IsoCode == culture); + } + if (objectType != TaggableObjectTypes.All) { var nodeObjectType = GetNodeObjectType(objectType); - sql = sql - .Where(dto => dto.NodeObjectType == nodeObjectType); + sql = sql.Where(dto => dto.NodeObjectType == nodeObjectType); } - if (tagGroup.IsNullOrWhiteSpace() == false) - { - sql = sql.Where(dto => dto.Group == tagGroup); - } - - return CreateTaggedEntityCollection( - Database.Fetch(sql)); + return sql; } - private IEnumerable CreateTaggedEntityCollection(IEnumerable dbResult) + private static IEnumerable Map(IEnumerable dtos) { - foreach (var node in dbResult.GroupBy(x => (int)x.nodeId)) + return dtos.GroupBy(x => x.NodeId).Select(dtosForNode => { - var properties = new List(); - foreach (var propertyType in node.GroupBy(x => new { id = (int)x.propertyTypeId, alias = (string)x.Alias })) + var taggedProperties = dtosForNode.GroupBy(x => x.PropertyTypeId).Select(dtosForProperty => { - var tags = propertyType.Select(x => new Tag((int)x.tagId, (string)x.group, (string)x.tag)); - properties.Add(new TaggedProperty(propertyType.Key.id, propertyType.Key.alias, tags)); - } - yield return new TaggedEntity(node.Key, properties); - } + string propertyTypeAlias = null; + var tags = dtosForProperty.Select(dto => + { + propertyTypeAlias = dto.PropertyTypeAlias; + return new Tag(dto.TagId, dto.TagGroup, dto.TagText, dto.TagLanguage); + }).ToList(); + return new TaggedProperty(dtosForProperty.Key, propertyTypeAlias, tags); + }).ToList(); + + return new TaggedEntity(dtosForNode.Key, taggedProperties); + }).ToList(); } - public IEnumerable GetTagsForEntityType(TaggableObjectTypes objectType, string group = null) + /// + public IEnumerable GetTagsForEntityType(TaggableObjectTypes objectType, string group = null, string culture = null) { - var sql = GetTagsQuerySelect(true); + var sql = GetTagsSql(culture, true); - sql = ApplyRelationshipJoinToTagsQuery(sql); + AddTagsSqlWhere(sql, culture); if (objectType != TaggableObjectTypes.All) { @@ -384,116 +386,126 @@ WHERE r.tagId IS NULL"; .Where(dto => dto.NodeObjectType == nodeObjectType); } - sql = ApplyGroupFilterToTagsQuery(sql, group); + if (group.IsNullOrWhiteSpace() == false) + sql = sql + .Where(dto => dto.Group == group); - sql = ApplyGroupByToTagsQuery(sql); + sql = sql + .GroupBy(x => x.Id, x => x.Text, x => x.Group, x => x.LanguageId); return ExecuteTagsQuery(sql); } - public IEnumerable GetTagsForEntity(int contentId, string group = null) + /// + public IEnumerable GetTagsForEntity(int contentId, string group = null, string culture = null) { - var sql = GetTagsQuerySelect(); + var sql = GetTagsSql(culture); - sql = ApplyRelationshipJoinToTagsQuery(sql); + AddTagsSqlWhere(sql, culture); sql = sql .Where(dto => dto.NodeId == contentId); - sql = ApplyGroupFilterToTagsQuery(sql, group); + if (group.IsNullOrWhiteSpace() == false) + sql = sql + .Where(dto => dto.Group == group); return ExecuteTagsQuery(sql); } - public IEnumerable GetTagsForEntity(Guid contentId, string group = null) + /// + public IEnumerable GetTagsForEntity(Guid contentId, string group = null, string culture = null) { - var sql = GetTagsQuerySelect(); + var sql = GetTagsSql(culture); - sql = ApplyRelationshipJoinToTagsQuery(sql); + AddTagsSqlWhere(sql, culture); sql = sql .Where(dto => dto.UniqueId == contentId); - sql = ApplyGroupFilterToTagsQuery(sql, group); + if (group.IsNullOrWhiteSpace() == false) + sql = sql + .Where(dto => dto.Group == group); return ExecuteTagsQuery(sql); } - public IEnumerable GetTagsForProperty(int contentId, string propertyTypeAlias, string group = null) + /// + public IEnumerable GetTagsForProperty(int contentId, string propertyTypeAlias, string group = null, string culture = null) { - var sql = GetTagsQuerySelect(); - - sql = ApplyRelationshipJoinToTagsQuery(sql); + var sql = GetTagsSql(culture); sql = sql - .InnerJoin() - .On(left => left.Id, right => right.PropertyTypeId) - .Where(dto => dto.NodeId == contentId) - .Where(dto => dto.Alias == propertyTypeAlias); + .InnerJoin().On((prop, rel) => prop.Id == rel.PropertyTypeId) + .Where(x => x.NodeId == contentId) + .Where(x => x.Alias == propertyTypeAlias); - sql = ApplyGroupFilterToTagsQuery(sql, group); + AddTagsSqlWhere(sql, culture); + + if (group.IsNullOrWhiteSpace() == false) + sql = sql + .Where(dto => dto.Group == group); return ExecuteTagsQuery(sql); } - public IEnumerable GetTagsForProperty(Guid contentId, string propertyTypeAlias, string group = null) + /// + public IEnumerable GetTagsForProperty(Guid contentId, string propertyTypeAlias, string group = null, string culture = null) { - var sql = GetTagsQuerySelect(); - - sql = ApplyRelationshipJoinToTagsQuery(sql); + var sql = GetTagsSql(culture); sql = sql - .InnerJoin() - .On(left => left.Id, right => right.PropertyTypeId) + .InnerJoin().On((prop, rel) => prop.Id == rel.PropertyTypeId) .Where(dto => dto.UniqueId == contentId) .Where(dto => dto.Alias == propertyTypeAlias); - sql = ApplyGroupFilterToTagsQuery(sql, group); + AddTagsSqlWhere(sql, culture); + + if (group.IsNullOrWhiteSpace() == false) + sql = sql + .Where(dto => dto.Group == group); return ExecuteTagsQuery(sql); } - private Sql GetTagsQuerySelect(bool withGrouping = false) + private Sql GetTagsSql(string culture, bool withGrouping = false) { - var sql = Sql(); + var sql = Sql() + .Select(); if (withGrouping) - { - sql = sql.Select("cmsTags.id, cmsTags.tag, cmsTags." + SqlSyntax.GetQuotedColumnName("group") + @", Count(*) NodeCount"); - } - else - { - sql = sql.Select("DISTINCT cmsTags.*"); - } + sql = sql + .AndSelectCount("NodeCount"); - return sql; - } - - private Sql ApplyRelationshipJoinToTagsQuery(Sql sql) - { - return sql + sql = sql .From() - .InnerJoin() - .On(left => left.TagId, right => right.Id) - .InnerJoin() - .On(left => left.NodeId, right => right.NodeId) - .InnerJoin() - .On(left => left.NodeId, right => right.NodeId); - } + .InnerJoin().On((rel, tag) => tag.Id == rel.TagId) + .InnerJoin().On((content, rel) => content.NodeId == rel.NodeId) + .InnerJoin().On((node, content) => node.NodeId == content.NodeId); - private Sql ApplyGroupFilterToTagsQuery(Sql sql, string group) - { - if (group.IsNullOrWhiteSpace() == false) + if (culture != null && culture != "*") { - sql = sql.Where(dto => dto.Group == group); + sql = sql + .InnerJoin().On((tag, lang) => tag.LanguageId == lang.Id); } return sql; } - private Sql ApplyGroupByToTagsQuery(Sql sql) + private Sql AddTagsSqlWhere(Sql sql, string culture) { - return sql.GroupBy("cmsTags.id", "cmsTags.tag", "cmsTags." + SqlSyntax.GetQuotedColumnName("group") + @""); + if (culture == null) + { + sql = sql + .Where(dto => dto.LanguageId == null); + } + else if (culture != "*") + { + sql = sql + .Where(x => x.IsoCode == culture); + } + + return sql; } private IEnumerable ExecuteTagsQuery(Sql sql) diff --git a/src/Umbraco.Core/PropertyEditors/PropertyEditorTagsExtensions.cs b/src/Umbraco.Core/PropertyEditors/PropertyEditorTagsExtensions.cs index 8f01bcab5a..3b2a9dd4e2 100644 --- a/src/Umbraco.Core/PropertyEditors/PropertyEditorTagsExtensions.cs +++ b/src/Umbraco.Core/PropertyEditors/PropertyEditorTagsExtensions.cs @@ -9,7 +9,7 @@ /// Determines whether an editor supports tags. /// public static bool IsTagsEditor(this IDataEditor editor) - => editor?.GetType().GetCustomAttribute(false) != null; + => editor.GetTagAttribute() != null; /// /// Gets the tags configuration attribute of an editor. diff --git a/src/Umbraco.Core/Services/ITagService.cs b/src/Umbraco.Core/Services/ITagService.cs index 63b7ce31a7..6be18624cb 100644 --- a/src/Umbraco.Core/Services/ITagService.cs +++ b/src/Umbraco.Core/Services/ITagService.cs @@ -5,7 +5,7 @@ using Umbraco.Core.Models; namespace Umbraco.Core.Services { /// - /// Tag service to query for tags in the tags db table. The tags returned are only relavent for published content & saved media or members + /// Tag service to query for tags in the tags db table. The tags returned are only relevant for published content & saved media or members /// /// /// If there is unpublished content with tags, those tags will not be contained. @@ -15,135 +15,84 @@ namespace Umbraco.Core.Services /// public interface ITagService : IService { - + /// + /// Gets a tagged entity. + /// TaggedEntity GetTaggedEntityById(int id); + + /// + /// Gets a tagged entity. + /// TaggedEntity GetTaggedEntityByKey(Guid key); /// - /// Gets tagged Content by a specific 'Tag Group'. + /// Gets all documents tagged with any tag in the specified group. /// - /// The contains the Id and Tags of the Content, not the actual Content item. - /// Name of the 'Tag Group' - /// An enumerable list of - IEnumerable GetTaggedContentByTagGroup(string tagGroup); + IEnumerable GetTaggedContentByTagGroup(string group, string culture = null); /// - /// Gets tagged Content by a specific 'Tag' and optional 'Tag Group'. + /// Gets all documents tagged with the specified tag. /// - /// The contains the Id and Tags of the Content, not the actual Content item. - /// Tag - /// Optional name of the 'Tag Group' - /// An enumerable list of - IEnumerable GetTaggedContentByTag(string tag, string tagGroup = null); + IEnumerable GetTaggedContentByTag(string tag, string group = null, string culture = null); /// - /// Gets tagged Media by a specific 'Tag Group'. + /// Gets all media tagged with any tag in the specified group. /// - /// The contains the Id and Tags of the Media, not the actual Media item. - /// Name of the 'Tag Group' - /// An enumerable list of - IEnumerable GetTaggedMediaByTagGroup(string tagGroup); + IEnumerable GetTaggedMediaByTagGroup(string group, string culture = null); /// - /// Gets tagged Media by a specific 'Tag' and optional 'Tag Group'. + /// Gets all media tagged with the specified tag. /// - /// The contains the Id and Tags of the Media, not the actual Media item. - /// Tag - /// Optional name of the 'Tag Group' - /// An enumerable list of - IEnumerable GetTaggedMediaByTag(string tag, string tagGroup = null); + IEnumerable GetTaggedMediaByTag(string tag, string group = null, string culture = null); /// - /// Gets tagged Members by a specific 'Tag Group'. + /// Gets all members tagged with any tag in the specified group. /// - /// The contains the Id and Tags of the Member, not the actual Member item. - /// Name of the 'Tag Group' - /// An enumerable list of - IEnumerable GetTaggedMembersByTagGroup(string tagGroup); + IEnumerable GetTaggedMembersByTagGroup(string group, string culture = null); /// - /// Gets tagged Members by a specific 'Tag' and optional 'Tag Group'. + /// Gets all members tagged with the specified tag. /// - /// The contains the Id and Tags of the Member, not the actual Member item. - /// Tag - /// Optional name of the 'Tag Group' - /// An enumerable list of - IEnumerable GetTaggedMembersByTag(string tag, string tagGroup = null); + IEnumerable GetTaggedMembersByTag(string tag, string group = null, string culture = null); /// - /// Gets every tag stored in the database + /// Gets all tags. /// - /// Optional name of the 'Tag Group' - /// An enumerable list of - IEnumerable GetAllTags(string tagGroup = null); + IEnumerable GetAllTags(string group = null, string culture = null); /// - /// Gets all tags for content items + /// Gets all document tags. /// - /// Use the optional tagGroup parameter to limit the - /// result to a specific 'Tag Group'. - /// Optional name of the 'Tag Group' - /// An enumerable list of - IEnumerable GetAllContentTags(string tagGroup = null); + IEnumerable GetAllContentTags(string group = null, string culture = null); /// - /// Gets all tags for media items + /// Gets all media tags. /// - /// Use the optional tagGroup parameter to limit the - /// result to a specific 'Tag Group'. - /// Optional name of the 'Tag Group' - /// An enumerable list of - IEnumerable GetAllMediaTags(string tagGroup = null); + IEnumerable GetAllMediaTags(string group = null, string culture = null); /// - /// Gets all tags for member items + /// Gets all member tags. /// - /// Use the optional tagGroup parameter to limit the - /// result to a specific 'Tag Group'. - /// Optional name of the 'Tag Group' - /// An enumerable list of - IEnumerable GetAllMemberTags(string tagGroup = null); + IEnumerable GetAllMemberTags(string group = null, string culture = null); /// - /// Gets all tags attached to a property by entity id + /// Gets all tags attached to an entity via a property. /// - /// Use the optional tagGroup parameter to limit the - /// result to a specific 'Tag Group'. - /// The content item id to get tags for - /// Property type alias - /// Optional name of the 'Tag Group' - /// An enumerable list of - IEnumerable GetTagsForProperty(int contentId, string propertyTypeAlias, string tagGroup = null); + IEnumerable GetTagsForProperty(int contentId, string propertyTypeAlias, string group = null, string culture = null); /// - /// Gets all tags attached to an entity (content, media or member) by entity id + /// Gets all tags attached to an entity. /// - /// Use the optional tagGroup parameter to limit the - /// result to a specific 'Tag Group'. - /// The content item id to get tags for - /// Optional name of the 'Tag Group' - /// An enumerable list of - IEnumerable GetTagsForEntity(int contentId, string tagGroup = null); + IEnumerable GetTagsForEntity(int contentId, string group = null, string culture = null); /// - /// Gets all tags attached to a property by entity id + /// Gets all tags attached to an entity via a property. /// - /// Use the optional tagGroup parameter to limit the - /// result to a specific 'Tag Group'. - /// The content item id to get tags for - /// Property type alias - /// Optional name of the 'Tag Group' - /// An enumerable list of - IEnumerable GetTagsForProperty(Guid contentId, string propertyTypeAlias, string tagGroup = null); + IEnumerable GetTagsForProperty(Guid contentId, string propertyTypeAlias, string group = null, string culture = null); /// - /// Gets all tags attached to an entity (content, media or member) by entity id + /// Gets all tags attached to an entity. /// - /// Use the optional tagGroup parameter to limit the - /// result to a specific 'Tag Group'. - /// The content item id to get tags for - /// Optional name of the 'Tag Group' - /// An enumerable list of - IEnumerable GetTagsForEntity(Guid contentId, string tagGroup = null); + IEnumerable GetTagsForEntity(Guid contentId, string group = null, string culture = null); } } diff --git a/src/Umbraco.Core/Services/Implement/TagService.cs b/src/Umbraco.Core/Services/Implement/TagService.cs index b2395502dc..e888258067 100644 --- a/src/Umbraco.Core/Services/Implement/TagService.cs +++ b/src/Umbraco.Core/Services/Implement/TagService.cs @@ -25,230 +25,147 @@ namespace Umbraco.Core.Services.Implement _tagRepository = tagRepository; } + /// public TaggedEntity GetTaggedEntityById(int id) { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) + using (ScopeProvider.CreateScope(autoComplete: true)) { return _tagRepository.GetTaggedEntityById(id); } } + /// public TaggedEntity GetTaggedEntityByKey(Guid key) { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) + using (ScopeProvider.CreateScope(autoComplete: true)) { return _tagRepository.GetTaggedEntityByKey(key); } } - /// - /// Gets tagged Content by a specific 'Tag Group'. - /// - /// The contains the Id and Tags of the Content, not the actual Content item. - /// Name of the 'Tag Group' - /// An enumerable list of - public IEnumerable GetTaggedContentByTagGroup(string tagGroup) + /// + public IEnumerable GetTaggedContentByTagGroup(string group, string culture = null) { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) + using (ScopeProvider.CreateScope(autoComplete: true)) { - return _tagRepository.GetTaggedEntitiesByTagGroup(TaggableObjectTypes.Content, tagGroup); + return _tagRepository.GetTaggedEntitiesByTagGroup(TaggableObjectTypes.Content, group, culture); } } - /// - /// Gets tagged Content by a specific 'Tag' and optional 'Tag Group'. - /// - /// The contains the Id and Tags of the Content, not the actual Content item. - /// Tag - /// Optional name of the 'Tag Group' - /// An enumerable list of - public IEnumerable GetTaggedContentByTag(string tag, string tagGroup = null) + /// + public IEnumerable GetTaggedContentByTag(string tag, string group = null, string culture = null) { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) + using (ScopeProvider.CreateScope(autoComplete: true)) { - return _tagRepository.GetTaggedEntitiesByTag(TaggableObjectTypes.Content, tag, tagGroup); + return _tagRepository.GetTaggedEntitiesByTag(TaggableObjectTypes.Content, tag, group, culture); } } - /// - /// Gets tagged Media by a specific 'Tag Group'. - /// - /// The contains the Id and Tags of the Media, not the actual Media item. - /// Name of the 'Tag Group' - /// An enumerable list of - public IEnumerable GetTaggedMediaByTagGroup(string tagGroup) + /// + public IEnumerable GetTaggedMediaByTagGroup(string group, string culture = null) { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) + using (ScopeProvider.CreateScope(autoComplete: true)) { - return _tagRepository.GetTaggedEntitiesByTagGroup(TaggableObjectTypes.Media, tagGroup); + return _tagRepository.GetTaggedEntitiesByTagGroup(TaggableObjectTypes.Media, group, culture); } } - /// - /// Gets tagged Media by a specific 'Tag' and optional 'Tag Group'. - /// - /// The contains the Id and Tags of the Media, not the actual Media item. - /// Tag - /// Optional name of the 'Tag Group' - /// An enumerable list of - public IEnumerable GetTaggedMediaByTag(string tag, string tagGroup = null) + /// + public IEnumerable GetTaggedMediaByTag(string tag, string group = null, string culture = null) { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) + using (ScopeProvider.CreateScope(autoComplete: true)) { - return _tagRepository.GetTaggedEntitiesByTag(TaggableObjectTypes.Media, tag, tagGroup); + return _tagRepository.GetTaggedEntitiesByTag(TaggableObjectTypes.Media, tag, group, culture); } } - /// - /// Gets tagged Members by a specific 'Tag Group'. - /// - /// The contains the Id and Tags of the Member, not the actual Member item. - /// Name of the 'Tag Group' - /// An enumerable list of - public IEnumerable GetTaggedMembersByTagGroup(string tagGroup) + /// + public IEnumerable GetTaggedMembersByTagGroup(string group, string culture = null) { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) + using (ScopeProvider.CreateScope(autoComplete: true)) { - return _tagRepository.GetTaggedEntitiesByTagGroup(TaggableObjectTypes.Member, tagGroup); + return _tagRepository.GetTaggedEntitiesByTagGroup(TaggableObjectTypes.Member, group, culture); } } - /// - /// Gets tagged Members by a specific 'Tag' and optional 'Tag Group'. - /// - /// The contains the Id and Tags of the Member, not the actual Member item. - /// Tag - /// Optional name of the 'Tag Group' - /// An enumerable list of - public IEnumerable GetTaggedMembersByTag(string tag, string tagGroup = null) + /// + public IEnumerable GetTaggedMembersByTag(string tag, string group = null, string culture = null) { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) + using (ScopeProvider.CreateScope(autoComplete: true)) { - return _tagRepository.GetTaggedEntitiesByTag(TaggableObjectTypes.Member, tag, tagGroup); + return _tagRepository.GetTaggedEntitiesByTag(TaggableObjectTypes.Member, tag, group, culture); } } - /// - /// Gets every tag stored in the database - /// - /// Optional name of the 'Tag Group' - /// An enumerable list of - public IEnumerable GetAllTags(string tagGroup = null) + /// + public IEnumerable GetAllTags(string group = null, string culture = null) { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) + using (ScopeProvider.CreateScope(autoComplete: true)) { - return _tagRepository.GetTagsForEntityType(TaggableObjectTypes.All, tagGroup); + return _tagRepository.GetTagsForEntityType(TaggableObjectTypes.All, group, culture); } } - /// - /// Gets all tags for content items - /// - /// Use the optional tagGroup parameter to limit the - /// result to a specific 'Tag Group'. - /// Optional name of the 'Tag Group' - /// An enumerable list of - public IEnumerable GetAllContentTags(string tagGroup = null) + /// + public IEnumerable GetAllContentTags(string group = null, string culture = null) { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) + using (ScopeProvider.CreateScope(autoComplete: true)) { - return _tagRepository.GetTagsForEntityType(TaggableObjectTypes.Content, tagGroup); + return _tagRepository.GetTagsForEntityType(TaggableObjectTypes.Content, group, culture); } } - /// - /// Gets all tags for media items - /// - /// Use the optional tagGroup parameter to limit the - /// result to a specific 'Tag Group'. - /// Optional name of the 'Tag Group' - /// An enumerable list of - public IEnumerable GetAllMediaTags(string tagGroup = null) + /// + public IEnumerable GetAllMediaTags(string group = null, string culture = null) { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) + using (ScopeProvider.CreateScope(autoComplete: true)) { - return _tagRepository.GetTagsForEntityType(TaggableObjectTypes.Media, tagGroup); + return _tagRepository.GetTagsForEntityType(TaggableObjectTypes.Media, group, culture); } } - /// - /// Gets all tags for member items - /// - /// Use the optional tagGroup parameter to limit the - /// result to a specific 'Tag Group'. - /// Optional name of the 'Tag Group' - /// An enumerable list of - public IEnumerable GetAllMemberTags(string tagGroup = null) + /// + public IEnumerable GetAllMemberTags(string group = null, string culture = null) { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) + using (ScopeProvider.CreateScope(autoComplete: true)) { - return _tagRepository.GetTagsForEntityType(TaggableObjectTypes.Member, tagGroup); + return _tagRepository.GetTagsForEntityType(TaggableObjectTypes.Member, group, culture); } } - /// - /// Gets all tags attached to a property by entity id - /// - /// Use the optional tagGroup parameter to limit the - /// result to a specific 'Tag Group'. - /// The content item id to get tags for - /// Property type alias - /// Optional name of the 'Tag Group' - /// An enumerable list of - public IEnumerable GetTagsForProperty(int contentId, string propertyTypeAlias, string tagGroup = null) + /// + public IEnumerable GetTagsForProperty(int contentId, string propertyTypeAlias, string group = null, string culture = null) { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) + using (ScopeProvider.CreateScope(autoComplete: true)) { - return _tagRepository.GetTagsForProperty(contentId, propertyTypeAlias, tagGroup); + return _tagRepository.GetTagsForProperty(contentId, propertyTypeAlias, group, culture); } } - /// - /// Gets all tags attached to an entity (content, media or member) by entity id - /// - /// Use the optional tagGroup parameter to limit the - /// result to a specific 'Tag Group'. - /// The content item id to get tags for - /// Optional name of the 'Tag Group' - /// An enumerable list of - public IEnumerable GetTagsForEntity(int contentId, string tagGroup = null) + /// + public IEnumerable GetTagsForEntity(int contentId, string group = null, string culture = null) { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) + using (ScopeProvider.CreateScope(autoComplete: true)) { - return _tagRepository.GetTagsForEntity(contentId, tagGroup); + return _tagRepository.GetTagsForEntity(contentId, group, culture); } } - /// - /// Gets all tags attached to a property by entity id - /// - /// Use the optional tagGroup parameter to limit the - /// result to a specific 'Tag Group'. - /// The content item id to get tags for - /// Property type alias - /// Optional name of the 'Tag Group' - /// An enumerable list of - public IEnumerable GetTagsForProperty(Guid contentId, string propertyTypeAlias, string tagGroup = null) + /// + public IEnumerable GetTagsForProperty(Guid contentId, string propertyTypeAlias, string group = null, string culture = null) { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) + using (ScopeProvider.CreateScope(autoComplete: true)) { - return _tagRepository.GetTagsForProperty(contentId, propertyTypeAlias, tagGroup); + return _tagRepository.GetTagsForProperty(contentId, propertyTypeAlias, group, culture); } } - /// - /// Gets all tags attached to an entity (content, media or member) by entity id - /// - /// Use the optional tagGroup parameter to limit the - /// result to a specific 'Tag Group'. - /// The content item id to get tags for - /// Optional name of the 'Tag Group' - /// An enumerable list of - public IEnumerable GetTagsForEntity(Guid contentId, string tagGroup = null) + /// + public IEnumerable GetTagsForEntity(Guid contentId, string group = null, string culture = null) { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) + using (ScopeProvider.CreateScope(autoComplete: true)) { - return _tagRepository.GetTagsForEntity(contentId, tagGroup); + return _tagRepository.GetTagsForEntity(contentId, group, culture); } } } diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index e46fca3c99..31014753af 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -363,6 +363,7 @@ + diff --git a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs index 07625db9bf..7b2f9766f9 100644 --- a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs +++ b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs @@ -22,6 +22,7 @@ namespace Umbraco.Tests.Composing public class TypeLoaderTests { private TypeLoader _typeLoader; + [SetUp] public void Initialize() { @@ -53,6 +54,12 @@ namespace Umbraco.Tests.Composing public void TearDown() { _typeLoader = null; + + + // cleanup + var assDir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory; + foreach (var d in Directory.GetDirectories(Path.Combine(assDir.FullName, "TypeLoader"))) + Directory.Delete(d, true); } private DirectoryInfo PrepareFolder() diff --git a/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs b/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs new file mode 100644 index 0000000000..c05bde4c7c --- /dev/null +++ b/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs @@ -0,0 +1,545 @@ +using System; +using System.Linq; +using LightInject; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Models; +using Umbraco.Core.Persistence.Repositories.Implement; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Services; +using Umbraco.Tests.TestHelpers.Entities; +using Umbraco.Tests.Testing; + +namespace Umbraco.Tests.Services +{ + [TestFixture] + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, + PublishedRepositoryEvents = true, + WithApplication = true, + Logger = UmbracoTestOptions.Logger.Console)] + public class ContentServiceTagsTests : TestWithSomeContentBase + { + public override void SetUp() + { + base.SetUp(); + ContentRepositoryBase.ThrowOnWarning = true; + } + + public override void TearDown() + { + ContentRepositoryBase.ThrowOnWarning = false; + base.TearDown(); + } + + protected override void Compose() + { + base.Compose(); + + // fixme - do it differently + Container.Register(factory => factory.GetInstance().TextService); + } + + [Test] + public void TagsCanBeInvariant() + { + var contentService = ServiceContext.ContentService; + var contentTypeService = ServiceContext.ContentTypeService; + var tagService = ServiceContext.TagService; + var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); + contentType.PropertyGroups.First().PropertyTypes.Add( + new PropertyType("test", ValueStorageType.Ntext, "tags") + { + DataTypeId = 1041 + }); + contentTypeService.Save(contentType); + + IContent content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + content1.AssignTags("tags", new[] { "hello", "world", "another", "one" }); + contentService.SaveAndPublish(content1); + + content1 = contentService.GetById(content1.Id); + + var enTags = content1.Properties["tags"].GetTagsValue().ToArray(); + Assert.AreEqual(4, enTags.Length); + Assert.Contains("one", enTags); + Assert.AreEqual(-1, enTags.IndexOf("plus")); + + var tagGroups = tagService.GetAllTags().GroupBy(x => x.LanguageId); + foreach (var tag in tagService.GetAllTags()) + Console.WriteLine($"{tag.Group}:{tag.Text} {tag.LanguageId}"); + Assert.AreEqual(1, tagGroups.Count()); + var enTagGroup = tagGroups.FirstOrDefault(x => x.Key == null); + Assert.IsNotNull(enTagGroup); + Assert.AreEqual(4, enTagGroup.Count()); + Assert.IsTrue(enTagGroup.Any(x => x.Text == "one")); + Assert.IsFalse(enTagGroup.Any(x => x.Text == "plus")); + } + + [Test] + public void TagsCanBeVariant() + { + var languageService = ServiceContext.LocalizationService; + languageService.Save(new Language("fr-FR")); // en-US is already there + + var contentService = ServiceContext.ContentService; + var contentTypeService = ServiceContext.ContentTypeService; + var tagService = ServiceContext.TagService; + var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); + contentType.PropertyGroups.First().PropertyTypes.Add( + new PropertyType("test", ValueStorageType.Ntext, "tags") + { + DataTypeId = 1041, + Variations = ContentVariation.Culture + }); + contentType.Variations = ContentVariation.Culture; + contentTypeService.Save(contentType); + + IContent content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + content1.SetCultureName("name-fr", "fr-FR"); + content1.SetCultureName("name-en", "en-US"); + content1.AssignTags("tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); + content1.AssignTags("tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); + contentService.SaveAndPublish(content1); + + content1 = contentService.GetById(content1.Id); + + var frTags = content1.Properties["tags"].GetTagsValue("fr-FR").ToArray(); + Assert.AreEqual(5, frTags.Length); + Assert.Contains("plus", frTags); + Assert.AreEqual(-1, frTags.IndexOf("one")); + + var enTags = content1.Properties["tags"].GetTagsValue("en-US").ToArray(); + Assert.AreEqual(4, enTags.Length); + Assert.Contains("one", enTags); + Assert.AreEqual(-1, enTags.IndexOf("plus")); + + var tagGroups = tagService.GetAllTags(culture:"*").GroupBy(x => x.LanguageId); + foreach (var tag in tagService.GetAllTags()) + Console.WriteLine($"{tag.Group}:{tag.Text} {tag.LanguageId}"); + Assert.AreEqual(2, tagGroups.Count()); + var frTagGroup = tagGroups.FirstOrDefault(x => x.Key == 2); + Assert.IsNotNull(frTagGroup); + Assert.AreEqual(5, frTagGroup.Count()); + Assert.IsTrue(frTagGroup.Any(x => x.Text == "plus")); + Assert.IsFalse(frTagGroup.Any(x => x.Text == "one")); + var enTagGroup = tagGroups.FirstOrDefault(x => x.Key == 1); + Assert.IsNotNull(enTagGroup); + Assert.AreEqual(4, enTagGroup.Count()); + Assert.IsTrue(enTagGroup.Any(x => x.Text == "one")); + Assert.IsFalse(enTagGroup.Any(x => x.Text == "plus")); + } + + [Test] + public void TagsAreUpdatedWhenContentIsTrashedAndUnTrashed_One() + { + var contentService = ServiceContext.ContentService; + var contentTypeService = ServiceContext.ContentTypeService; + var tagService = ServiceContext.TagService; + var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); + contentType.PropertyGroups.First().PropertyTypes.Add( + new PropertyType("test", ValueStorageType.Ntext, "tags") + { + DataTypeId = 1041 + }); + contentTypeService.Save(contentType); + + var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + content1.AssignTags("tags", new[] { "hello", "world", "some", "tags", "plus" }); + contentService.SaveAndPublish(content1); + + var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", -1); + content2.AssignTags("tags", new[] { "hello", "world", "some", "tags" }); + contentService.SaveAndPublish(content2); + + // verify + var tags = tagService.GetTagsForEntity(content1.Id); + Assert.AreEqual(5, tags.Count()); + var allTags = tagService.GetAllContentTags(); + Assert.AreEqual(5, allTags.Count()); + + contentService.MoveToRecycleBin(content1); + } + + [Test] + public void TagsAreUpdatedWhenContentIsTrashedAndUnTrashed_All() + { + var contentService = ServiceContext.ContentService; + var contentTypeService = ServiceContext.ContentTypeService; + var tagService = ServiceContext.TagService; + var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); + contentType.PropertyGroups.First().PropertyTypes.Add( + new PropertyType("test", ValueStorageType.Ntext, "tags") + { + DataTypeId = 1041 + }); + contentTypeService.Save(contentType); + + var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + content1.AssignTags("tags", new[] { "hello", "world", "some", "tags", "bam" }); + contentService.SaveAndPublish(content1); + + var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", -1); + content2.AssignTags("tags", new[] { "hello", "world", "some", "tags" }); + contentService.SaveAndPublish(content2); + + // verify + var tags = tagService.GetTagsForEntity(content1.Id); + Assert.AreEqual(5, tags.Count()); + var allTags = tagService.GetAllContentTags(); + Assert.AreEqual(5, allTags.Count()); + + contentService.Unpublish(content1); + contentService.Unpublish(content2); + } + + [Test] + [Ignore("U4-8442, will need to be fixed eventually.")] + public void TagsAreUpdatedWhenContentIsTrashedAndUnTrashed_Tree() + { + var contentService = ServiceContext.ContentService; + var contentTypeService = ServiceContext.ContentTypeService; + var tagService = ServiceContext.TagService; + var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); + contentType.PropertyGroups.First().PropertyTypes.Add( + new PropertyType("test", ValueStorageType.Ntext, "tags") + { + DataTypeId = 1041 + }); + contentTypeService.Save(contentType); + + var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + content1.AssignTags("tags", new[] { "hello", "world", "some", "tags", "plus" }); + content1.PublishCulture(); + contentService.SaveAndPublish(content1); + + var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", content1.Id); + content2.AssignTags("tags", new[] { "hello", "world", "some", "tags" }); + content2.PublishCulture(); + contentService.SaveAndPublish(content2); + + // verify + var tags = tagService.GetTagsForEntity(content1.Id); + Assert.AreEqual(5, tags.Count()); + var allTags = tagService.GetAllContentTags(); + Assert.AreEqual(5, allTags.Count()); + + contentService.MoveToRecycleBin(content1); + + // no more tags + tags = tagService.GetTagsForEntity(content1.Id); + Assert.AreEqual(0, tags.Count()); + tags = tagService.GetTagsForEntity(content2.Id); + Assert.AreEqual(0, tags.Count()); + + // no more tags + allTags = tagService.GetAllContentTags(); + Assert.AreEqual(0, allTags.Count()); + + contentService.Move(content1, -1); + + Assert.IsFalse(content1.Published); + + // no more tags + tags = tagService.GetTagsForEntity(content1.Id); + Assert.AreEqual(0, tags.Count()); + tags = tagService.GetTagsForEntity(content2.Id); + Assert.AreEqual(0, tags.Count()); + + // no more tags + allTags = tagService.GetAllContentTags(); + Assert.AreEqual(0, allTags.Count()); + + content1.PublishCulture(); + contentService.SaveAndPublish(content1); + + Assert.IsTrue(content1.Published); + + // tags are back + tags = tagService.GetTagsForEntity(content1.Id); + Assert.AreEqual(5, tags.Count()); + + // fixme tag & tree issue + // when we publish, we 'just' publish the top one and not the ones below = fails + // what we should do is... NOT clear tags when unpublishing or trashing or... + // and just update the tag service to NOT return anything related to trashed or + // unpublished entities (since trashed is set on ALL entities in the trashed branch) + tags = tagService.GetTagsForEntity(content2.Id); // including that one! + Assert.AreEqual(4, tags.Count()); + + // tags are back + allTags = tagService.GetAllContentTags(); + Assert.AreEqual(5, allTags.Count()); + } + + [Test] + public void TagsAreUpdatedWhenContentIsUnpublishedAndRePublished() + { + var contentService = ServiceContext.ContentService; + var contentTypeService = ServiceContext.ContentTypeService; + var tagService = ServiceContext.TagService; + var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); + contentType.PropertyGroups.First().PropertyTypes.Add( + new PropertyType("test", ValueStorageType.Ntext, "tags") + { + DataTypeId = 1041 + }); + contentTypeService.Save(contentType); + + var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + content1.AssignTags("tags", new[] { "hello", "world", "some", "tags", "bam" }); + contentService.SaveAndPublish(content1); + + var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", -1); + content2.AssignTags("tags", new[] { "hello", "world", "some", "tags" }); + contentService.SaveAndPublish(content2); + + contentService.Unpublish(content1); + contentService.Unpublish(content2); + } + + [Test] + [Ignore("U4-8442, will need to be fixed eventually.")] + public void TagsAreUpdatedWhenContentIsUnpublishedAndRePublished_Tree() + { + var contentService = ServiceContext.ContentService; + var contentTypeService = ServiceContext.ContentTypeService; + var tagService = ServiceContext.TagService; + var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); + contentType.PropertyGroups.First().PropertyTypes.Add( + new PropertyType("test", ValueStorageType.Ntext, "tags") + { + DataTypeId = 1041 + }); + contentTypeService.Save(contentType); + + var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + content1.AssignTags("tags", new[] { "hello", "world", "some", "tags", "bam" }); + content1.PublishCulture(); + contentService.SaveAndPublish(content1); + + var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", content1); + content2.AssignTags("tags", new[] { "hello", "world", "some", "tags" }); + content2.PublishCulture(); + contentService.SaveAndPublish(content2); + + contentService.Unpublish(content1); + + var tags = tagService.GetTagsForEntity(content1.Id); + Assert.AreEqual(0, tags.Count()); + + // fixme tag & tree issue + // when we (un)publish, we 'just' publish the top one and not the ones below = fails + // see similar note above + tags = tagService.GetTagsForEntity(content2.Id); + Assert.AreEqual(0, tags.Count()); + var allTags = tagService.GetAllContentTags(); + Assert.AreEqual(0, allTags.Count()); + + content1.PublishCulture(); + contentService.SaveAndPublish(content1); + + tags = tagService.GetTagsForEntity(content2.Id); + Assert.AreEqual(4, tags.Count()); + allTags = tagService.GetAllContentTags(); + Assert.AreEqual(5, allTags.Count()); + } + + [Test] + public void Create_Tag_Data_Bulk_Publish_Operation() + { + //Arrange + var contentService = ServiceContext.ContentService; + var contentTypeService = ServiceContext.ContentTypeService; + var dataTypeService = ServiceContext.DataTypeService; + + //set configuration + var dataType = dataTypeService.GetDataType(1041); + dataType.Configuration = new TagConfiguration + { + Group = "test", + StorageType = TagsStorageType.Csv + }; + + var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); + contentType.PropertyGroups.First().PropertyTypes.Add( + new PropertyType("test", ValueStorageType.Ntext, "tags") + { + DataTypeId = 1041 + }); + contentTypeService.Save(contentType); + contentType.AllowedContentTypes = new[] { new ContentTypeSort(new Lazy(() => contentType.Id), 0, contentType.Alias) }; + + var content = MockedContent.CreateSimpleContent(contentType, "Tagged content", -1); + content.AssignTags("tags", new[] { "hello", "world", "some", "tags" }); + contentService.Save(content); + + var child1 = MockedContent.CreateSimpleContent(contentType, "child 1 content", content.Id); + child1.AssignTags("tags", new[] { "hello1", "world1", "some1" }); + contentService.Save(child1); + + var child2 = MockedContent.CreateSimpleContent(contentType, "child 2 content", content.Id); + child2.AssignTags("tags", new[] { "hello2", "world2" }); + contentService.Save(child2); + + // Act + contentService.SaveAndPublishBranch(content, true); + + // Assert + var propertyTypeId = contentType.PropertyTypes.Single(x => x.Alias == "tags").Id; + + using (var scope = ScopeProvider.CreateScope()) + { + Assert.AreEqual(4, scope.Database.ExecuteScalar( + "SELECT COUNT(*) FROM cmsTagRelationship WHERE nodeId=@nodeId AND propertyTypeId=@propTypeId", + new { nodeId = content.Id, propTypeId = propertyTypeId })); + + Assert.AreEqual(3, scope.Database.ExecuteScalar( + "SELECT COUNT(*) FROM cmsTagRelationship WHERE nodeId=@nodeId AND propertyTypeId=@propTypeId", + new { nodeId = child1.Id, propTypeId = propertyTypeId })); + + Assert.AreEqual(2, scope.Database.ExecuteScalar( + "SELECT COUNT(*) FROM cmsTagRelationship WHERE nodeId=@nodeId AND propertyTypeId=@propTypeId", + new { nodeId = child2.Id, propTypeId = propertyTypeId })); + + scope.Complete(); + } + } + + [Test] + public void Does_Not_Create_Tag_Data_For_Non_Published_Version() + { + var contentService = ServiceContext.ContentService; + var contentTypeService = ServiceContext.ContentTypeService; + + // create content type with a tag property + var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); + contentType.PropertyGroups.First().PropertyTypes.Add(new PropertyType("test", ValueStorageType.Ntext, "tags") { DataTypeId = 1041 }); + contentTypeService.Save(contentType); + + // create a content with tags and publish + var content = MockedContent.CreateSimpleContent(contentType, "Tagged content", -1); + content.AssignTags("tags", new[] { "hello", "world", "some", "tags" }); + contentService.SaveAndPublish(content); + + // edit tags and save + content.AssignTags("tags", new[] { "another", "world" }, merge: true); + contentService.Save(content); + + // the (edit) property does contain all tags + Assert.AreEqual(5, content.Properties["tags"].GetValue().ToString().Split(',').Distinct().Count()); + + // but the database still contains the initial two tags + var propertyTypeId = contentType.PropertyTypes.Single(x => x.Alias == "tags").Id; + using (var scope = ScopeProvider.CreateScope()) + { + Assert.AreEqual(4, scope.Database.ExecuteScalar( + "SELECT COUNT(*) FROM cmsTagRelationship WHERE nodeId=@nodeId AND propertyTypeId=@propTypeId", + new { nodeId = content.Id, propTypeId = propertyTypeId })); + scope.Complete(); + } + } + + [Test] + public void Can_Replace_Tag_Data_To_Published_Content() + { + //Arrange + var contentService = ServiceContext.ContentService; + var contentTypeService = ServiceContext.ContentTypeService; + var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); + contentType.PropertyGroups.First().PropertyTypes.Add( + new PropertyType("test", ValueStorageType.Ntext, "tags") + { + DataTypeId = 1041 + }); + contentTypeService.Save(contentType); + + var content = MockedContent.CreateSimpleContent(contentType, "Tagged content", -1); + + + // Act + content.AssignTags("tags", new[] { "hello", "world", "some", "tags" }); + contentService.SaveAndPublish(content); + + // Assert + Assert.AreEqual(4, content.Properties["tags"].GetValue().ToString().Split(',').Distinct().Count()); + var propertyTypeId = contentType.PropertyTypes.Single(x => x.Alias == "tags").Id; + using (var scope = ScopeProvider.CreateScope()) + { + Assert.AreEqual(4, scope.Database.ExecuteScalar( + "SELECT COUNT(*) FROM cmsTagRelationship WHERE nodeId=@nodeId AND propertyTypeId=@propTypeId", + new { nodeId = content.Id, propTypeId = propertyTypeId })); + + scope.Complete(); + } + } + + [Test] + public void Can_Append_Tag_Data_To_Published_Content() + { + //Arrange + var contentService = ServiceContext.ContentService; + var contentTypeService = ServiceContext.ContentTypeService; + var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); + contentType.PropertyGroups.First().PropertyTypes.Add( + new PropertyType("test", ValueStorageType.Ntext, "tags") + { + DataTypeId = 1041 + }); + contentTypeService.Save(contentType); + var content = MockedContent.CreateSimpleContent(contentType, "Tagged content", -1); + content.AssignTags("tags", new[] { "hello", "world", "some", "tags" }); + contentService.SaveAndPublish(content); + + // Act + content.AssignTags("tags", new[] { "another", "world" }, merge: true); + contentService.SaveAndPublish(content); + + // Assert + Assert.AreEqual(5, content.Properties["tags"].GetValue().ToString().Split(',').Distinct().Count()); + var propertyTypeId = contentType.PropertyTypes.Single(x => x.Alias == "tags").Id; + using (var scope = ScopeProvider.CreateScope()) + { + Assert.AreEqual(5, scope.Database.ExecuteScalar( + "SELECT COUNT(*) FROM cmsTagRelationship WHERE nodeId=@nodeId AND propertyTypeId=@propTypeId", + new { nodeId = content.Id, propTypeId = propertyTypeId })); + + scope.Complete(); + } + } + + [Test] + public void Can_Remove_Tag_Data_To_Published_Content() + { + //Arrange + var contentService = ServiceContext.ContentService; + var contentTypeService = ServiceContext.ContentTypeService; + var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); + contentType.PropertyGroups.First().PropertyTypes.Add( + new PropertyType("test", ValueStorageType.Ntext, "tags") + { + DataTypeId = 1041 + }); + contentTypeService.Save(contentType); + var content = MockedContent.CreateSimpleContent(contentType, "Tagged content", -1); + content.AssignTags("tags", new[] { "hello", "world", "some", "tags" }); + contentService.SaveAndPublish(content); + + // Act + content.RemoveTags("tags", new[] { "some", "world" }); + contentService.SaveAndPublish(content); + + // Assert + Assert.AreEqual(2, content.Properties["tags"].GetValue().ToString().Split(',').Distinct().Count()); + var propertyTypeId = contentType.PropertyTypes.Single(x => x.Alias == "tags").Id; + using (var scope = ScopeProvider.CreateScope()) + { + Assert.AreEqual(2, scope.Database.ExecuteScalar( + "SELECT COUNT(*) FROM cmsTagRelationship WHERE nodeId=@nodeId AND propertyTypeId=@propTypeId", + new { nodeId = content.Id, propTypeId = propertyTypeId })); + + scope.Complete(); + } + } + + } +} diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs index 2c90ce90c5..494d12dbe1 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs @@ -193,63 +193,6 @@ namespace Umbraco.Tests.Services Assert.AreEqual(5, found.Length); } - /// - /// Ensures that we don't unpublish all nodes when a node is deleted that has an invalid path of -1 - /// Note: it is actually the MoveToRecycleBin happening on the initial deletion of a node through the UI - /// that causes the issue. - /// Regression test: http://issues.umbraco.org/issue/U4-9336 - /// - [Test] - [Ignore("not applicable to v8")] - - // fixme - this test was imported from 7.6 BUT it makes no sense for v8 - // we should trust the PATH, full stop - - public void Moving_Node_To_Recycle_Bin_With_Invalid_Path() - { - var contentService = ServiceContext.ContentService; - var root = ServiceContext.ContentService.GetById(NodeDto.NodeIdSeed + 1); - root.PublishCulture(); - Assert.IsTrue(contentService.SaveAndPublish(root).Success); - var content = contentService.CreateAndSave("Test", -1, "umbTextpage", Constants.Security.SuperUserId); - content.PublishCulture(); - Assert.IsTrue(contentService.SaveAndPublish(content).Success); - var hierarchy = CreateContentHierarchy().OrderBy(x => x.Level).ToArray(); - contentService.Save(hierarchy, Constants.Security.SuperUserId); - foreach (var c in hierarchy) - { - c.PublishCulture(); - Assert.IsTrue(contentService.SaveAndPublish(c).Success); - } - - //now make the data corrupted :/ - using (var scope = ScopeProvider.CreateScope()) - { - scope.Database.Execute("UPDATE umbracoNode SET path = '-1' WHERE id = @id", new { id = content.Id }); - scope.Complete(); - } - - //re-get with the corrupt path - content = contentService.GetById(content.Id); - - // here we get all descendants by the path of the node being moved to bin, and unpublish all of them. - // since the path is invalid, there's logic in here to fix that if it's possible and re-persist the entity. - var moveResult = ServiceContext.ContentService.MoveToRecycleBin(content); - - Assert.IsTrue(moveResult.Success); - - //re-get with the fixed/moved path - content = contentService.GetById(content.Id); - - Assert.AreEqual("-1,-20," + content.Id, content.Path); - - //re-get - hierarchy = contentService.GetByIds(hierarchy.Select(x => x.Id).ToArray()).OrderBy(x => x.Level).ToArray(); - - Assert.That(hierarchy.All(c => c.Trashed == false), Is.True); - Assert.That(hierarchy.All(c => c.Path.StartsWith("-1,-20") == false), Is.True); - } - [Test] public void Perform_Scheduled_Publishing() { @@ -501,511 +444,6 @@ namespace Umbraco.Tests.Services Assert.IsEmpty(res); } - [Test] - public void TagsAreUpdatedWhenContentIsTrashedAndUnTrashed_One() - { - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var tagService = ServiceContext.TagService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType("test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041 - }); - contentTypeService.Save(contentType); - - var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); - content1.AssignTags("tags", new[] { "hello", "world", "some", "tags", "plus" }); - contentService.SaveAndPublish(content1); - - var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", -1); - content2.AssignTags("tags", new[] { "hello", "world", "some", "tags" }); - contentService.SaveAndPublish(content2); - - // verify - var tags = tagService.GetTagsForEntity(content1.Id); - Assert.AreEqual(5, tags.Count()); - var allTags = tagService.GetAllContentTags(); - Assert.AreEqual(5, allTags.Count()); - - contentService.MoveToRecycleBin(content1); - - // fixme - killing the rest of this test - // this is not working consistently even in 7 when unpublishing a branch - // in 8, tags never go away - one has to check that the entity is published and not trashed - return; - - // no more tags for this entity - tags = tagService.GetTagsForEntity(content1.Id); - Assert.AreEqual(0, tags.Count()); - - // tags still assigned to content2 are still there - allTags = tagService.GetAllContentTags(); - Assert.AreEqual(4, allTags.Count()); - - contentService.Move(content1, -1); - - Assert.IsFalse(content1.Published); - - // no more tags for this entity - tags = tagService.GetTagsForEntity(content1.Id); - Assert.AreEqual(0, tags.Count()); - - // tags still assigned to content2 are still there - allTags = tagService.GetAllContentTags(); - Assert.AreEqual(4, allTags.Count()); - - content1.PublishCulture(); - contentService.SaveAndPublish(content1); - - Assert.IsTrue(content1.Published); - - // tags are back - tags = tagService.GetTagsForEntity(content1.Id); - Assert.AreEqual(5, tags.Count()); - - // tags are back - allTags = tagService.GetAllContentTags(); - Assert.AreEqual(5, allTags.Count()); - } - - [Test] - public void TagsAreUpdatedWhenContentIsTrashedAndUnTrashed_All() - { - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var tagService = ServiceContext.TagService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType("test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041 - }); - contentTypeService.Save(contentType); - - var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); - content1.AssignTags("tags", new[] { "hello", "world", "some", "tags", "bam" }); - contentService.SaveAndPublish(content1); - - var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", -1); - content2.AssignTags("tags", new[] { "hello", "world", "some", "tags" }); - contentService.SaveAndPublish(content2); - - // verify - var tags = tagService.GetTagsForEntity(content1.Id); - Assert.AreEqual(5, tags.Count()); - var allTags = tagService.GetAllContentTags(); - Assert.AreEqual(5, allTags.Count()); - - contentService.Unpublish(content1); - contentService.Unpublish(content2); - - // fixme - killing the rest of this test - // this is not working consistently even in 7 when unpublishing a branch - // in 8, tags never go away - one has to check that the entity is published and not trashed - return; - - // no more tags - tags = tagService.GetTagsForEntity(content1.Id); - Assert.AreEqual(0, tags.Count()); - - // no more tags - allTags = tagService.GetAllContentTags(); - Assert.AreEqual(0, allTags.Count()); - - contentService.Move(content1, -1); - contentService.Move(content2, -1); - - // no more tags - tags = tagService.GetTagsForEntity(content1.Id); - Assert.AreEqual(0, tags.Count()); - - // no more tags - allTags = tagService.GetAllContentTags(); - Assert.AreEqual(0, allTags.Count()); - - content1.PublishCulture(); - contentService.SaveAndPublish(content1); - content2.PublishCulture(); - contentService.SaveAndPublish(content2); - - // tags are back - tags = tagService.GetTagsForEntity(content1.Id); - Assert.AreEqual(5, tags.Count()); - - // tags are back - allTags = tagService.GetAllContentTags(); - Assert.AreEqual(5, allTags.Count()); - } - - [Test] - [Ignore("U4-8442, will need to be fixed eventually.")] - public void TagsAreUpdatedWhenContentIsTrashedAndUnTrashed_Tree() - { - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var tagService = ServiceContext.TagService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType("test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041 - }); - contentTypeService.Save(contentType); - - var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); - content1.AssignTags("tags", new[] { "hello", "world", "some", "tags", "plus" }); - content1.PublishCulture(); - contentService.SaveAndPublish(content1); - - var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", content1.Id); - content2.AssignTags("tags", new[] { "hello", "world", "some", "tags" }); - content2.PublishCulture(); - contentService.SaveAndPublish(content2); - - // verify - var tags = tagService.GetTagsForEntity(content1.Id); - Assert.AreEqual(5, tags.Count()); - var allTags = tagService.GetAllContentTags(); - Assert.AreEqual(5, allTags.Count()); - - contentService.MoveToRecycleBin(content1); - - // no more tags - tags = tagService.GetTagsForEntity(content1.Id); - Assert.AreEqual(0, tags.Count()); - tags = tagService.GetTagsForEntity(content2.Id); - Assert.AreEqual(0, tags.Count()); - - // no more tags - allTags = tagService.GetAllContentTags(); - Assert.AreEqual(0, allTags.Count()); - - contentService.Move(content1, -1); - - Assert.IsFalse(content1.Published); - - // no more tags - tags = tagService.GetTagsForEntity(content1.Id); - Assert.AreEqual(0, tags.Count()); - tags = tagService.GetTagsForEntity(content2.Id); - Assert.AreEqual(0, tags.Count()); - - // no more tags - allTags = tagService.GetAllContentTags(); - Assert.AreEqual(0, allTags.Count()); - - content1.PublishCulture(); - contentService.SaveAndPublish(content1); - - Assert.IsTrue(content1.Published); - - // tags are back - tags = tagService.GetTagsForEntity(content1.Id); - Assert.AreEqual(5, tags.Count()); - - // fixme tag & tree issue - // when we publish, we 'just' publish the top one and not the ones below = fails - // what we should do is... NOT clear tags when unpublishing or trashing or... - // and just update the tag service to NOT return anything related to trashed or - // unpublished entities (since trashed is set on ALL entities in the trashed branch) - tags = tagService.GetTagsForEntity(content2.Id); // including that one! - Assert.AreEqual(4, tags.Count()); - - // tags are back - allTags = tagService.GetAllContentTags(); - Assert.AreEqual(5, allTags.Count()); - } - - [Test] - public void TagsAreUpdatedWhenContentIsUnpublishedAndRePublished() - { - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var tagService = ServiceContext.TagService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType("test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041 - }); - contentTypeService.Save(contentType); - - var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); - content1.AssignTags("tags", new[] { "hello", "world", "some", "tags", "bam" }); - contentService.SaveAndPublish(content1); - - var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", -1); - content2.AssignTags("tags", new[] { "hello", "world", "some", "tags" }); - contentService.SaveAndPublish(content2); - - contentService.Unpublish(content1); - contentService.Unpublish(content2); - - // fixme - killing the rest of this test - // this is not working consistently even in 7 when unpublishing a branch - // in 8, tags never go away - one has to check that the entity is published and not trashed - return; - - var tags = tagService.GetTagsForEntity(content1.Id); - Assert.AreEqual(0, tags.Count()); - var allTags = tagService.GetAllContentTags(); - Assert.AreEqual(0, allTags.Count()); - - content2.PublishCulture(); - contentService.SaveAndPublish(content2); - - tags = tagService.GetTagsForEntity(content2.Id); - Assert.AreEqual(4, tags.Count()); - allTags = tagService.GetAllContentTags(); - Assert.AreEqual(4, allTags.Count()); - } - - [Test] - [Ignore("U4-8442, will need to be fixed eventually.")] - public void TagsAreUpdatedWhenContentIsUnpublishedAndRePublished_Tree() - { - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var tagService = ServiceContext.TagService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType("test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041 - }); - contentTypeService.Save(contentType); - - var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); - content1.AssignTags("tags", new[] { "hello", "world", "some", "tags", "bam" }); - content1.PublishCulture(); - contentService.SaveAndPublish(content1); - - var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", content1); - content2.AssignTags("tags", new[] { "hello", "world", "some", "tags" }); - content2.PublishCulture(); - contentService.SaveAndPublish(content2); - - contentService.Unpublish(content1); - - var tags = tagService.GetTagsForEntity(content1.Id); - Assert.AreEqual(0, tags.Count()); - - // fixme tag & tree issue - // when we (un)publish, we 'just' publish the top one and not the ones below = fails - // see similar note above - tags = tagService.GetTagsForEntity(content2.Id); - Assert.AreEqual(0, tags.Count()); - var allTags = tagService.GetAllContentTags(); - Assert.AreEqual(0, allTags.Count()); - - content1.PublishCulture(); - contentService.SaveAndPublish(content1); - - tags = tagService.GetTagsForEntity(content2.Id); - Assert.AreEqual(4, tags.Count()); - allTags = tagService.GetAllContentTags(); - Assert.AreEqual(5, allTags.Count()); - } - - [Test] - public void Create_Tag_Data_Bulk_Publish_Operation() - { - //Arrange - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var dataTypeService = ServiceContext.DataTypeService; - - //set configuration - var dataType = dataTypeService.GetDataType(1041); - dataType.Configuration = new TagConfiguration - { - Group = "test", - StorageType = TagsStorageType.Csv - }; - - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType("test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041 - }); - contentTypeService.Save(contentType); - contentType.AllowedContentTypes = new[] { new ContentTypeSort(new Lazy(() => contentType.Id), 0, contentType.Alias) }; - - var content = MockedContent.CreateSimpleContent(contentType, "Tagged content", -1); - content.AssignTags("tags", new[] { "hello", "world", "some", "tags" }); - contentService.Save(content); - - var child1 = MockedContent.CreateSimpleContent(contentType, "child 1 content", content.Id); - child1.AssignTags("tags", new[] { "hello1", "world1", "some1" }); - contentService.Save(child1); - - var child2 = MockedContent.CreateSimpleContent(contentType, "child 2 content", content.Id); - child2.AssignTags("tags", new[] { "hello2", "world2" }); - contentService.Save(child2); - - // Act - contentService.SaveAndPublishBranch(content, true); - - // Assert - var propertyTypeId = contentType.PropertyTypes.Single(x => x.Alias == "tags").Id; - - using (var scope = ScopeProvider.CreateScope()) - { - Assert.AreEqual(4, scope.Database.ExecuteScalar( - "SELECT COUNT(*) FROM cmsTagRelationship WHERE nodeId=@nodeId AND propertyTypeId=@propTypeId", - new { nodeId = content.Id, propTypeId = propertyTypeId })); - - Assert.AreEqual(3, scope.Database.ExecuteScalar( - "SELECT COUNT(*) FROM cmsTagRelationship WHERE nodeId=@nodeId AND propertyTypeId=@propTypeId", - new { nodeId = child1.Id, propTypeId = propertyTypeId })); - - Assert.AreEqual(2, scope.Database.ExecuteScalar( - "SELECT COUNT(*) FROM cmsTagRelationship WHERE nodeId=@nodeId AND propertyTypeId=@propTypeId", - new { nodeId = child2.Id, propTypeId = propertyTypeId })); - - scope.Complete(); - } - } - - [Test] - public void Does_Not_Create_Tag_Data_For_Non_Published_Version() - { - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - - // create content type with a tag property - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add(new PropertyType("test", ValueStorageType.Ntext, "tags") { DataTypeId = 1041 }); - contentTypeService.Save(contentType); - - // create a content with tags and publish - var content = MockedContent.CreateSimpleContent(contentType, "Tagged content", -1); - content.AssignTags("tags", new[] { "hello", "world", "some", "tags" }); - contentService.SaveAndPublish(content); - - // edit tags and save - content.AssignTags("tags", new[] { "another", "world" }, merge: true); - contentService.Save(content); - - // the (edit) property does contain all tags - Assert.AreEqual(5, content.Properties["tags"].GetValue().ToString().Split(',').Distinct().Count()); - - // but the database still contains the initial two tags - var propertyTypeId = contentType.PropertyTypes.Single(x => x.Alias == "tags").Id; - using (var scope = ScopeProvider.CreateScope()) - { - Assert.AreEqual(4, scope.Database.ExecuteScalar( - "SELECT COUNT(*) FROM cmsTagRelationship WHERE nodeId=@nodeId AND propertyTypeId=@propTypeId", - new { nodeId = content.Id, propTypeId = propertyTypeId })); - scope.Complete(); - } - } - - [Test] - public void Can_Replace_Tag_Data_To_Published_Content() - { - //Arrange - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType("test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041 - }); - contentTypeService.Save(contentType); - - var content = MockedContent.CreateSimpleContent(contentType, "Tagged content", -1); - - - // Act - content.AssignTags("tags", new[] { "hello", "world", "some", "tags" }); - contentService.SaveAndPublish(content); - - // Assert - Assert.AreEqual(4, content.Properties["tags"].GetValue().ToString().Split(',').Distinct().Count()); - var propertyTypeId = contentType.PropertyTypes.Single(x => x.Alias == "tags").Id; - using (var scope = ScopeProvider.CreateScope()) - { - Assert.AreEqual(4, scope.Database.ExecuteScalar( - "SELECT COUNT(*) FROM cmsTagRelationship WHERE nodeId=@nodeId AND propertyTypeId=@propTypeId", - new { nodeId = content.Id, propTypeId = propertyTypeId })); - - scope.Complete(); - } - } - - [Test] - public void Can_Append_Tag_Data_To_Published_Content() - { - //Arrange - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType("test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041 - }); - contentTypeService.Save(contentType); - var content = MockedContent.CreateSimpleContent(contentType, "Tagged content", -1); - content.AssignTags("tags", new[] { "hello", "world", "some", "tags" }); - contentService.SaveAndPublish(content); - - // Act - content.AssignTags("tags", new[] { "another", "world" }, merge: true); - contentService.SaveAndPublish(content); - - // Assert - Assert.AreEqual(5, content.Properties["tags"].GetValue().ToString().Split(',').Distinct().Count()); - var propertyTypeId = contentType.PropertyTypes.Single(x => x.Alias == "tags").Id; - using (var scope = ScopeProvider.CreateScope()) - { - Assert.AreEqual(5, scope.Database.ExecuteScalar( - "SELECT COUNT(*) FROM cmsTagRelationship WHERE nodeId=@nodeId AND propertyTypeId=@propTypeId", - new { nodeId = content.Id, propTypeId = propertyTypeId })); - - scope.Complete(); - } - } - - [Test] - public void Can_Remove_Tag_Data_To_Published_Content() - { - //Arrange - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType("test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041 - }); - contentTypeService.Save(contentType); - var content = MockedContent.CreateSimpleContent(contentType, "Tagged content", -1); - content.AssignTags("tags", new[] { "hello", "world", "some", "tags" }); - contentService.SaveAndPublish(content); - - // Act - content.RemoveTags("tags", new[] { "some", "world" }); - contentService.SaveAndPublish(content); - - // Assert - Assert.AreEqual(2, content.Properties["tags"].GetValue().ToString().Split(',').Distinct().Count()); - var propertyTypeId = contentType.PropertyTypes.Single(x => x.Alias == "tags").Id; - using (var scope = ScopeProvider.CreateScope()) - { - Assert.AreEqual(2, scope.Database.ExecuteScalar( - "SELECT COUNT(*) FROM cmsTagRelationship WHERE nodeId=@nodeId AND propertyTypeId=@propTypeId", - new { nodeId = content.Id, propTypeId = propertyTypeId })); - - scope.Complete(); - } - } - [Test] public void Can_Remove_Property_Type() { @@ -1134,7 +572,6 @@ namespace Umbraco.Tests.Services Assert.That(contents.Count(), Is.GreaterThanOrEqualTo(2)); } - [Test] public void Can_Get_All_Versions_Of_Content() { diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 322be82ca7..e901f3689e 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -131,6 +131,7 @@ + diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valpropertyvalidator.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valpropertyvalidator.directive.js index c1a2999017..37303d22ad 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valpropertyvalidator.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valpropertyvalidator.directive.js @@ -36,7 +36,7 @@ function valPropertyValidator(serverValidationManager) { // Validation method function validate (viewValue) { - // Calls the validition method + // Calls the validation method var result = scope.valPropertyValidator(); if (!result.errorKey || result.isValid === undefined || !result.errorMsg) { throw "The result object from valPropertyValidator does not contain required properties: isValid, errorKey, errorMsg"; @@ -55,6 +55,9 @@ function valPropertyValidator(serverValidationManager) { propCtrl.setPropertyError(result.errorMsg); } } + + // parsers are expected to return a value + return (result.isValid) ? viewValue : undefined; }; // Parsers are called as soon as the value in the form input is modified diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js index bcf27294f3..01a188c847 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js @@ -142,6 +142,13 @@ angular.module("umbraco") }); } + function currentCulture(scope) { + while (scope && !scope.activeVariant) + scope = scope.$parent; + if (!scope || !scope.activeVariant) return null; + return scope.activeVariant.language.culture; + } + var tagsHound = new Bloodhound({ datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'), queryTokenizer: Bloodhound.tokenizers.whitespace, @@ -150,14 +157,14 @@ angular.module("umbraco") }, //pre-fetch the tags for this category prefetch: { - url: umbRequestHelper.getApiUrl("tagsDataBaseUrl", "GetTags", [{ tagGroup: $scope.model.config.group }]), + url: umbRequestHelper.getApiUrl("tagsDataBaseUrl", "GetTags", { tagGroup: $scope.model.config.group, culture: currentCulture($scope) }), //TTL = 5 minutes ttl: 300000, filter: dataTransform }, //dynamically get the tags for this category (they may have changed on the server) remote: { - url: umbRequestHelper.getApiUrl("tagsDataBaseUrl", "GetTags", [{ tagGroup: $scope.model.config.group }]), + url: umbRequestHelper.getApiUrl("tagsDataBaseUrl", "GetTags", { tagGroup: $scope.model.config.group, culture: currentCulture($scope) }), filter: dataTransform } }); diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs index 23d8e2cc4e..a3c2bf494a 100644 --- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs @@ -254,7 +254,7 @@ namespace Umbraco.Web.Editors }, { "tagsDataBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( - controller => controller.GetTags("")) + controller => controller.GetTags("", "")) }, { "examineMgmtBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index 53ecddd015..5f33a31872 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -1778,7 +1778,8 @@ namespace Umbraco.Web.Editors contentSave, propertyCollection, (save, property) => Varies(property) ? property.GetValue(variant.Culture) : property.GetValue(), //get prop val - (save, property, v) => { if (Varies(property)) property.SetValue(v, variant.Culture); else property.SetValue(v); }); //set prop val + (save, property, v) => { if (Varies(property)) property.SetValue(v, variant.Culture); else property.SetValue(v); }, //set prop val + variant.Culture); variantIndex++; } diff --git a/src/Umbraco.Web/Editors/ContentControllerBase.cs b/src/Umbraco.Web/Editors/ContentControllerBase.cs index 0f174b6bbd..09d91a6436 100644 --- a/src/Umbraco.Web/Editors/ContentControllerBase.cs +++ b/src/Umbraco.Web/Editors/ContentControllerBase.cs @@ -39,17 +39,12 @@ namespace Umbraco.Web.Editors /// /// Maps the dto property values to the persisted model /// - /// - /// - /// - /// - /// - /// internal void MapPropertyValuesForPersistence( TSaved contentItem, ContentPropertyCollectionDto dto, Func getPropertyValue, - Action savePropertyValue) + Action savePropertyValue, + string culture) where TPersisted : IContentBase where TSaved : IContentSave { @@ -70,7 +65,7 @@ namespace Umbraco.Web.Editors // get the property var property = contentItem.PersistedContent.Properties[propertyDto.Alias]; - + // prepare files, if any matching property and culture var files = contentItem.UploadedFiles .Where(x => x.PropertyAlias == propertyDto.Alias && x.Culture == propertyDto.Culture) @@ -96,8 +91,8 @@ namespace Umbraco.Web.Editors { var tagConfiguration = ConfigurationEditor.ConfigurationAs(propertyDto.DataType.Configuration); if (tagConfiguration.Delimiter == default) tagConfiguration.Delimiter = tagAttribute.Delimiter; - //fixme how is this supposed to work with variants? - property.SetTagsValue(value, tagConfiguration); + var tagCulture = property.PropertyType.VariesByCulture() ? culture : null; + property.SetTagsValue(value, tagConfiguration, tagCulture); } else savePropertyValue(contentItem, property, value); diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index 9aebc11dc6..4f4c37910e 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -483,8 +483,9 @@ namespace Umbraco.Web.Editors MapPropertyValuesForPersistence( contentItem, contentItem.PropertyCollectionDto, - (save, property) => property.GetValue(), //get prop val - (save, property, v) => property.SetValue(v)); //set prop val + (save, property) => property.GetValue(), //get prop val + (save, property, v) => property.SetValue(v), //set prop val + null); // media are all invariant //We need to manually check the validation results here because: // * We still need to save the entity even if there are validation value errors diff --git a/src/Umbraco.Web/Editors/MemberController.cs b/src/Umbraco.Web/Editors/MemberController.cs index 6117db8857..e287006992 100644 --- a/src/Umbraco.Web/Editors/MemberController.cs +++ b/src/Umbraco.Web/Editors/MemberController.cs @@ -400,8 +400,9 @@ namespace Umbraco.Web.Editors base.MapPropertyValuesForPersistence( contentItem, contentItem.PropertyCollectionDto, - (save, property) => property.GetValue(), //get prop val - (save, property, v) => property.SetValue(v)); //set prop val + (save, property) => property.GetValue(), //get prop val + (save, property, v) => property.SetValue(v), //set prop val + null); // member are all invariant } /// diff --git a/src/Umbraco.Web/ITagQuery.cs b/src/Umbraco.Web/ITagQuery.cs index 3d0757a695..031061ad01 100644 --- a/src/Umbraco.Web/ITagQuery.cs +++ b/src/Umbraco.Web/ITagQuery.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Web.Models; @@ -8,76 +7,53 @@ namespace Umbraco.Web public interface ITagQuery { /// - /// Returns all content that is tagged with the specified tag value and optional tag group + /// Gets all documents tagged with the specified tag. /// - /// - /// - /// - IEnumerable GetContentByTag(string tag, string tagGroup = null); + IEnumerable GetContentByTag(string tag, string group = null, string culture = null); /// - /// Returns all content that has been tagged with any tag in the specified group + /// Gets all documents tagged with any tag in the specified group. /// - /// - /// - IEnumerable GetContentByTagGroup(string tagGroup); + IEnumerable GetContentByTagGroup(string group, string culture = null); /// - /// Returns all Media that is tagged with the specified tag value and optional tag group + /// Gets all media tagged with the specified tag. /// - /// - /// - /// - IEnumerable GetMediaByTag(string tag, string tagGroup = null); + IEnumerable GetMediaByTag(string tag, string group = null, string culture = null); /// - /// Returns all Media that has been tagged with any tag in the specified group + /// Gets all media tagged with any tag in the specified group. /// - /// - /// - IEnumerable GetMediaByTagGroup(string tagGroup); + IEnumerable GetMediaByTagGroup(string group, string culture); /// - /// Get every tag stored in the database (with optional group) + /// Gets all tags. /// - IEnumerable GetAllTags(string group = null); + IEnumerable GetAllTags(string group = null, string culture = null); /// - /// Get all tags for content items (with optional group) + /// Gets all document tags. /// - /// - /// - IEnumerable GetAllContentTags(string group = null); + IEnumerable GetAllContentTags(string group = null, string culture = null); /// - /// Get all tags for media items (with optional group) + /// Gets all media tags. /// - /// - /// - IEnumerable GetAllMediaTags(string group = null); + IEnumerable GetAllMediaTags(string group = null, string culture = null); /// - /// Get all tags for member items (with optional group) + /// Gets all member tags. /// - /// - /// - IEnumerable GetAllMemberTags(string group = null); + IEnumerable GetAllMemberTags(string group = null, string culture = null); /// - /// Returns all tags attached to a property by entity id + /// Gets all tags attached to an entity via a property. /// - /// - /// - /// - /// - IEnumerable GetTagsForProperty(int contentId, string propertyTypeAlias, string tagGroup = null); + IEnumerable GetTagsForProperty(int contentId, string propertyTypeAlias, string group = null, string culture = null); /// - /// Returns all tags attached to an entity (content, media or member) by entity id + /// Gets all tags attached to an entity. /// - /// - /// - /// - IEnumerable GetTagsForEntity(int contentId, string tagGroup = null); + IEnumerable GetTagsForEntity(int contentId, string group = null, string culture = null); } } diff --git a/src/Umbraco.Web/PropertyEditors/TagsDataController.cs b/src/Umbraco.Web/PropertyEditors/TagsDataController.cs index dc0a0787dd..bc0c281f98 100644 --- a/src/Umbraco.Web/PropertyEditors/TagsDataController.cs +++ b/src/Umbraco.Web/PropertyEditors/TagsDataController.cs @@ -15,9 +15,10 @@ namespace Umbraco.Web.PropertyEditors [PluginController("UmbracoApi")] public class TagsDataController : UmbracoAuthorizedApiController { - public IEnumerable GetTags(string tagGroup) + public IEnumerable GetTags(string tagGroup, string culture) { - return Umbraco.TagQuery.GetAllTags(tagGroup); + if (culture == string.Empty) culture = null; + return Umbraco.TagQuery.GetAllTags(tagGroup, culture); } } } diff --git a/src/Umbraco.Web/TagQuery.cs b/src/Umbraco.Web/TagQuery.cs index 9527e72453..e79640bb4d 100644 --- a/src/Umbraco.Web/TagQuery.cs +++ b/src/Umbraco.Web/TagQuery.cs @@ -9,195 +9,92 @@ using Umbraco.Web.Models; namespace Umbraco.Web { /// - /// A class that exposes methods used to query tag data in views + /// Implements . /// public class TagQuery : ITagQuery { - - //TODO: This class also acts as a wrapper for ITagQuery due to breaking changes, need to fix in - // version 8: http://issues.umbraco.org/issue/U4-6899 - private readonly ITagQuery _wrappedQuery; - private readonly ITagService _tagService; private readonly IPublishedContentQuery _contentQuery; - /// - /// Constructor for wrapping ITagQuery, see http://issues.umbraco.org/issue/U4-6899 + /// Initializes a new instance of the class. /// - /// - internal TagQuery(ITagQuery wrappedQuery) - { - if (wrappedQuery == null) throw new ArgumentNullException("wrappedQuery"); - _wrappedQuery = wrappedQuery; - } - - /// - /// Constructor - /// - /// - /// public TagQuery(ITagService tagService, IPublishedContentQuery contentQuery) { - if (tagService == null) throw new ArgumentNullException("tagService"); - if (contentQuery == null) throw new ArgumentNullException("contentQuery"); - _tagService = tagService; - _contentQuery = contentQuery; + _tagService = tagService ?? throw new ArgumentNullException(nameof(tagService)); + _contentQuery = contentQuery ?? throw new ArgumentNullException(nameof(contentQuery)); } - /// - /// Returns all content that is tagged with the specified tag value and optional tag group - /// - /// - /// - /// - public IEnumerable GetContentByTag(string tag, string tagGroup = null) + /// + public IEnumerable GetContentByTag(string tag, string group = null, string culture = null) { - //TODO: http://issues.umbraco.org/issue/U4-6899 - if (_wrappedQuery != null) return _wrappedQuery.GetContentByTag(tag, tagGroup); - - var ids = _tagService.GetTaggedContentByTag(tag, tagGroup) + var ids = _tagService.GetTaggedContentByTag(tag, group, culture) .Select(x => x.EntityId); return _contentQuery.Content(ids) .Where(x => x != null); } - /// - /// Returns all content that has been tagged with any tag in the specified group - /// - /// - /// - public IEnumerable GetContentByTagGroup(string tagGroup) + /// + public IEnumerable GetContentByTagGroup(string group, string culture = null) { - //TODO: http://issues.umbraco.org/issue/U4-6899 - if (_wrappedQuery != null) return _wrappedQuery.GetContentByTagGroup(tagGroup); - - var ids = _tagService.GetTaggedContentByTagGroup(tagGroup) + var ids = _tagService.GetTaggedContentByTagGroup(group, culture) .Select(x => x.EntityId); return _contentQuery.Content(ids) .Where(x => x != null); } - /// - /// Returns all Media that is tagged with the specified tag value and optional tag group - /// - /// - /// - /// - public IEnumerable GetMediaByTag(string tag, string tagGroup = null) + /// + public IEnumerable GetMediaByTag(string tag, string group = null, string culture = null) { - //TODO: http://issues.umbraco.org/issue/U4-6899 - if (_wrappedQuery != null) return _wrappedQuery.GetMediaByTag(tag, tagGroup); - - var ids = _tagService.GetTaggedMediaByTag(tag, tagGroup) + var ids = _tagService.GetTaggedMediaByTag(tag, group, culture) .Select(x => x.EntityId); return _contentQuery.Media(ids) .Where(x => x != null); } - /// - /// Returns all Media that has been tagged with any tag in the specified group - /// - /// - /// - public IEnumerable GetMediaByTagGroup(string tagGroup) + /// + public IEnumerable GetMediaByTagGroup(string group, string culture = null) { - //TODO: http://issues.umbraco.org/issue/U4-6899 - if (_wrappedQuery != null) return _wrappedQuery.GetMediaByTagGroup(tagGroup); - - var ids = _tagService.GetTaggedMediaByTagGroup(tagGroup) + var ids = _tagService.GetTaggedMediaByTagGroup(group, culture) .Select(x => x.EntityId); return _contentQuery.Media(ids) .Where(x => x != null); } - //TODO: Should prob implement these, requires a bit of work on the member service to do this, - // also not sure if its necessary ? - //public IEnumerable GetMembersByTag(string tag, string tagGroup = null) - //{ - //} - - //public IEnumerable GetMembersByTagGroup(string tagGroup) - //{ - //} - - /// - /// Get every tag stored in the database (with optional group) - /// - public IEnumerable GetAllTags(string group = null) + /// + public IEnumerable GetAllTags(string group = null, string culture = null) { - //TODO: http://issues.umbraco.org/issue/U4-6899 - if (_wrappedQuery != null) return _wrappedQuery.GetAllTags(group); - - return Mapper.Map>(_tagService.GetAllTags(group)); + return Mapper.Map>(_tagService.GetAllTags(group, culture)); } - /// - /// Get all tags for content items (with optional group) - /// - /// - /// - public IEnumerable GetAllContentTags(string group = null) + /// + public IEnumerable GetAllContentTags(string group = null, string culture = null) { - //TODO: http://issues.umbraco.org/issue/U4-6899 - if (_wrappedQuery != null) return _wrappedQuery.GetAllContentTags(group); - - return Mapper.Map>(_tagService.GetAllContentTags(group)); + return Mapper.Map>(_tagService.GetAllContentTags(group, culture)); } - /// - /// Get all tags for media items (with optional group) - /// - /// - /// - public IEnumerable GetAllMediaTags(string group = null) + /// + public IEnumerable GetAllMediaTags(string group = null, string culture = null) { - //TODO: http://issues.umbraco.org/issue/U4-6899 - if (_wrappedQuery != null) return _wrappedQuery.GetAllMediaTags(group); - - return Mapper.Map>(_tagService.GetAllMediaTags(group)); + return Mapper.Map>(_tagService.GetAllMediaTags(group, culture)); } - /// - /// Get all tags for member items (with optional group) - /// - /// - /// - public IEnumerable GetAllMemberTags(string group = null) + /// + public IEnumerable GetAllMemberTags(string group = null, string culture = null) { - //TODO: http://issues.umbraco.org/issue/U4-6899 - if (_wrappedQuery != null) return _wrappedQuery.GetAllMemberTags(group); - - return Mapper.Map>(_tagService.GetAllMemberTags(group)); + return Mapper.Map>(_tagService.GetAllMemberTags(group, culture)); } - /// - /// Returns all tags attached to a property by entity id - /// - /// - /// - /// - /// - public IEnumerable GetTagsForProperty(int contentId, string propertyTypeAlias, string tagGroup = null) + /// + public IEnumerable GetTagsForProperty(int contentId, string propertyTypeAlias, string group = null, string culture = null) { - //TODO: http://issues.umbraco.org/issue/U4-6899 - if (_wrappedQuery != null) return _wrappedQuery.GetTagsForProperty(contentId, propertyTypeAlias, tagGroup); - - return Mapper.Map>(_tagService.GetTagsForProperty(contentId, propertyTypeAlias, tagGroup)); + return Mapper.Map>(_tagService.GetTagsForProperty(contentId, propertyTypeAlias, group, culture)); } - /// - /// Returns all tags attached to an entity (content, media or member) by entity id - /// - /// - /// - /// - public IEnumerable GetTagsForEntity(int contentId, string tagGroup = null) + /// + public IEnumerable GetTagsForEntity(int contentId, string group = null, string culture = null) { - //TODO: http://issues.umbraco.org/issue/U4-6899 - if (_wrappedQuery != null) return _wrappedQuery.GetTagsForEntity(contentId, tagGroup); - - return Mapper.Map>(_tagService.GetTagsForEntity(contentId, tagGroup)); + return Mapper.Map>(_tagService.GetTagsForEntity(contentId, group, culture)); } } } diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs index aa30fff0ec..1ce7e51a7f 100644 --- a/src/Umbraco.Web/UmbracoHelper.cs +++ b/src/Umbraco.Web/UmbracoHelper.cs @@ -67,7 +67,7 @@ namespace Umbraco.Web if (appCache == null) throw new ArgumentNullException(nameof(appCache)); _umbracoContext = umbracoContext; - _tag = new TagQuery(tagQuery); + _tag = tagQuery; _dataTypeService = dataTypeService; _cultureDictionary = cultureDictionary; _componentRenderer = componentRenderer; From 5c140762c40dee8f4157c4dd25ef0079e75a2d27 Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 4 Dec 2018 08:23:18 +0100 Subject: [PATCH 03/54] Handle tags when variations change --- src/Umbraco.Core/ObjectExtensions.cs | 16 +- .../Persistence/Dtos/TagRelationshipDto.cs | 4 +- .../Querying/ExpressionVisitorBase.cs | 17 ++ .../Implement/ContentTypeRepositoryBase.cs | 147 ++++++++++++++++-- .../Persistence/UmbracoDatabase.cs | 22 ++- .../NPocoTests/NPocoSqlExtensionsTests.cs | 75 +++++++++ .../Services/ContentServiceTagsTests.cs | 135 +++++++++++++++- 7 files changed, 393 insertions(+), 23 deletions(-) diff --git a/src/Umbraco.Core/ObjectExtensions.cs b/src/Umbraco.Core/ObjectExtensions.cs index 44e5968a9f..1cbb4a6ea1 100644 --- a/src/Umbraco.Core/ObjectExtensions.cs +++ b/src/Umbraco.Core/ObjectExtensions.cs @@ -595,7 +595,6 @@ namespace Umbraco.Core return null; } - /// /// Attempts to serialize the value to an XmlString using ToXmlString /// @@ -788,5 +787,20 @@ namespace Umbraco.Core return BoolConvertCache[type] = false; } + + /// + /// Indicates whether two nullable values are equal, substituting a fallback value for nulls. + /// + /// The nullable type. + /// The value to compare. + /// The value to compare to. + /// The value to use when any value is null. + /// Do not use outside of Sql expressions. + // see usage in ExpressionVisitorBase + public static bool NEquals(this T? value, T? other, T fallbackValue) + where T : struct + { + return (value ?? fallbackValue).Equals(other ?? fallbackValue); + } } } diff --git a/src/Umbraco.Core/Persistence/Dtos/TagRelationshipDto.cs b/src/Umbraco.Core/Persistence/Dtos/TagRelationshipDto.cs index 4a07b16a07..cbe4cf0cd4 100644 --- a/src/Umbraco.Core/Persistence/Dtos/TagRelationshipDto.cs +++ b/src/Umbraco.Core/Persistence/Dtos/TagRelationshipDto.cs @@ -3,11 +3,13 @@ using Umbraco.Core.Persistence.DatabaseAnnotations; namespace Umbraco.Core.Persistence.Dtos { - [TableName(Constants.DatabaseSchema.Tables.TagRelationship)] + [TableName(TableName)] [PrimaryKey("nodeId", AutoIncrement = false)] [ExplicitColumns] internal class TagRelationshipDto { + public const string TableName = Constants.DatabaseSchema.Tables.TagRelationship; + [Column("nodeId")] [PrimaryKeyColumn(AutoIncrement = false, Name = "PK_cmsTagRelationship", OnColumns = "nodeId, propertyTypeId, tagId")] [ForeignKey(typeof(ContentDto), Name = "FK_cmsTagRelationship_cmsContent", Column = "nodeId")] diff --git a/src/Umbraco.Core/Persistence/Querying/ExpressionVisitorBase.cs b/src/Umbraco.Core/Persistence/Querying/ExpressionVisitorBase.cs index d313d27bbc..493bbcacc7 100644 --- a/src/Umbraco.Core/Persistence/Querying/ExpressionVisitorBase.cs +++ b/src/Umbraco.Core/Persistence/Querying/ExpressionVisitorBase.cs @@ -653,6 +653,23 @@ namespace Umbraco.Core.Persistence.Querying else throw new NotSupportedException("Expression is not a proper lambda."); + // c# 'x == null' becomes sql 'x IS NULL' which is fine + // c# 'x == y' becomes sql 'x = @0' which is fine - unless they are nullable types, + // because sql 'x = NULL' is always false and the 'IS NULL' syntax is required, + // so for comparing nullable types, we use x.NEquals(y, fb) where fb is a fallback + // value which will be used when values are null - turning the comparison into + // sql 'COALESCE(x,fb) = COALESCE(y,fb)' - of course, fb must be a value outside + // of x and y range - and if that is not possible, then a manual comparison need + // to be written + //TODO support NEquals with 0 parameters, using the full syntax below + case "NEquals": + var compareTo = Visit(m.Arguments[1]); + var fallback = Visit(m.Arguments[2]); + // that would work without a fallback value but is more cumbersome + //return Visited ? string.Empty : $"((({compareTo} is null) AND ({visitedMethodObject} is null)) OR (({compareTo} is not null) AND ({visitedMethodObject} = {compareTo})))"; + // use a fallback value + return Visited ? string.Empty : $"(COALESCE({visitedMethodObject},{fallback}) = COALESCE({compareTo},{fallback}))"; + default: throw new ArgumentOutOfRangeException("No logic supported for " + m.Method.Name); diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index 3184c69dfe..7e720ba08a 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -190,8 +190,8 @@ AND umbracoNode.nodeObjectType = @objectType", SortOrder = allowedContentType.SortOrder }); } - - + + //Insert Tabs foreach (var propertyGroup in entity.PropertyGroups) { @@ -620,7 +620,7 @@ AND umbracoNode.id <> @id", var sqlDelete = Sql() .Delete() .WhereIn((System.Linq.Expressions.Expression>)(x => x.ContentKey), sqlSelect); - + Database.Execute(sqlDelete); } @@ -663,9 +663,11 @@ AND umbracoNode.id <> @id", { case ContentVariation.Culture: CopyPropertyData(null, defaultLanguageId, propertyTypeIds, impactedL); + CopyTagData(null, defaultLanguageId, propertyTypeIds, impactedL); break; case ContentVariation.Nothing: CopyPropertyData(defaultLanguageId, null, propertyTypeIds, impactedL); + CopyTagData(defaultLanguageId, null, propertyTypeIds, impactedL); break; case ContentVariation.CultureAndSegment: case ContentVariation.Segment: @@ -690,7 +692,7 @@ AND umbracoNode.id <> @id", //first clear out any existing names that might already exists under the default lang //there's 2x tables to update - //clear out the versionCultureVariation table + //clear out the versionCultureVariation table var sqlSelect = Sql().Select(x => x.Id) .From() .InnerJoin().On(x => x.Id, x => x.VersionId) @@ -757,6 +759,129 @@ AND umbracoNode.id <> @id", } } + /// + private void CopyTagData(int? sourceLanguageId, int? targetLanguageId, IReadOnlyCollection propertyTypeIds, IReadOnlyCollection contentTypeIds = null) + { + // note: important to use NEquals for nullable types, cannot directly compare language identifiers + + // fixme - should we batch then? + var whereInArgsCount = propertyTypeIds.Count + (contentTypeIds?.Count ?? 0); + if (whereInArgsCount > 2000) + throw new NotSupportedException("Too many property/content types."); + + // delete existing relations (for target language) + // do *not* delete existing tags + + var sqlTagToDelete = Sql() + .Select(x => x.Id) + .From() + .InnerJoin().On((tag, rel) => tag.Id == rel.TagId); + + if (contentTypeIds != null) + sqlTagToDelete + .InnerJoin().On((rel, content) => rel.NodeId == content.NodeId) + .WhereIn(x => x.ContentTypeId, contentTypeIds); + + sqlTagToDelete + .WhereIn(x => x.PropertyTypeId, propertyTypeIds) + .Where(x => x.LanguageId.NEquals(targetLanguageId, -1)); + + var sqlDeleteRel = Sql() + .Delete() + .WhereIn(x => x.TagId, sqlTagToDelete); + + sqlDeleteRel.WriteToConsole(); + Database.Execute(sqlDeleteRel); + + // do *not* delete the tags - they could be used by other content types / property types + /* + var sqlDeleteTag = Sql() + .Delete() + .WhereIn(x => x.Id, sqlTagToDelete); + Database.Execute(sqlDeleteTag); + */ + + // copy tags from source language to target language + + var targetLanguageIdS = targetLanguageId.HasValue ? targetLanguageId.ToString() : "NULL"; + var sqlSelect = Sql() + .Select(x => x.Text, x => x.Group) + .Append(", " + targetLanguageIdS) + .From(); + + sqlSelect + .InnerJoin().On((tag, rel) => tag.Id == rel.TagId) + .LeftJoin("xtags").On((tag, xtag) => tag.Text == xtag.Text && tag.Group == xtag.Group && tag.LanguageId.NEquals(targetLanguageId, -1), aliasRight: "xtags"); + + if (contentTypeIds != null) + sqlSelect + .InnerJoin().On((rel, content) => rel.NodeId == content.NodeId); + + sqlSelect + .WhereIn(x => x.PropertyTypeId, propertyTypeIds) + .WhereNull(x => x.Id, "xtags"); // ie, not exists + + if (contentTypeIds != null) + sqlSelect + .WhereIn(x => x.ContentTypeId, contentTypeIds); + + sqlSelect.Where(x => x.LanguageId.NEquals(sourceLanguageId, -1)); + + var cols = Sql().Columns(x => x.Text, x => x.Group, x => x.LanguageId); + var sqlInsertTag = Sql($"INSERT INTO {TagDto.TableName} ({cols})").Append(sqlSelect); + + sqlInsertTag.WriteToConsole(); + Database.Execute(sqlInsertTag); + + // create relations to new tags + + var sqlFoo = Sql() + .Select(x => x.NodeId, x => x.PropertyTypeId) + .AndSelect("otag", x => x.Id) + .From() + .InnerJoin().On((rel, tag) => rel.TagId == tag.Id) + .InnerJoin("otag").On((tag, otag) => tag.Text == otag.Text && tag.Group == otag.Group && otag.LanguageId.NEquals(targetLanguageId, -1), aliasRight: "otag") + .Where(x => x.LanguageId.NEquals(sourceLanguageId, -1)); + + var cols2 = Sql().Columns(x => x.NodeId, x => x.PropertyTypeId, x => x.TagId); + var sqlInsertRel = Sql($"INSERT INTO {TagRelationshipDto.TableName} ({cols2})").Append(sqlFoo); + + sqlInsertRel.WriteToConsole(); + Database.Execute(sqlInsertRel); + + // delete original relations - *not* the tags - all of them + // cannot really "go back" with relations, would have to do it with property values + + sqlTagToDelete = Sql() + .Select(x => x.Id) + .From() + .InnerJoin().On((tag, rel) => tag.Id == rel.TagId); + + if (contentTypeIds != null) + sqlTagToDelete + .InnerJoin().On((rel, content) => rel.NodeId == content.NodeId) + .WhereIn(x => x.ContentTypeId, contentTypeIds); + + sqlTagToDelete + .WhereIn(x => x.PropertyTypeId, propertyTypeIds) + .Where(x => !x.LanguageId.NEquals(targetLanguageId, -1)); + + sqlDeleteRel = Sql() + .Delete() + .WhereIn(x => x.TagId, sqlTagToDelete); + + sqlDeleteRel.WriteToConsole(); + Database.Execute(sqlDeleteRel); + + // no + /* + var sqlDeleteTag = Sql() + .Delete() + .WhereIn(x => x.Id, sqlTagToDelete); + Database.Execute(sqlDeleteTag); + */ + } + /// /// Copies property data from one language to another. /// @@ -766,6 +891,8 @@ AND umbracoNode.id <> @id", /// The content type identifiers. private void CopyPropertyData(int? sourceLanguageId, int? targetLanguageId, IReadOnlyCollection propertyTypeIds, IReadOnlyCollection contentTypeIds = null) { + // note: important to use NEquals for nullable types, cannot directly compare language identifiers + // // fixme - should we batch then? var whereInArgsCount = propertyTypeIds.Count + (contentTypeIds?.Count ?? 0); if (whereInArgsCount > 2000) @@ -793,11 +920,7 @@ AND umbracoNode.id <> @id", sqlDelete.WhereIn(x => x.VersionId, inSql); } - // NPoco cannot turn the clause into IS NULL with a nullable parameter - deal with it - if (targetLanguageId == null) - sqlDelete.Where(x => x.LanguageId == null); - else - sqlDelete.Where(x => x.LanguageId == targetLanguageId); + sqlDelete.Where(x => x.LanguageId.NEquals(targetLanguageId, -1)); sqlDelete .WhereIn(x => x.PropertyTypeId, propertyTypeIds); @@ -821,11 +944,7 @@ AND umbracoNode.id <> @id", .InnerJoin().On((pdata, cversion) => pdata.VersionId == cversion.Id) .InnerJoin().On((cversion, c) => cversion.NodeId == c.NodeId); - // NPoco cannot turn the clause into IS NULL with a nullable parameter - deal with it - if (sourceLanguageId == null) - sqlSelectData.Where(x => x.LanguageId == null); - else - sqlSelectData.Where(x => x.LanguageId == sourceLanguageId); + sqlSelectData.Where(x => x.LanguageId.NEquals(sourceLanguageId, -1)); sqlSelectData .WhereIn(x => x.PropertyTypeId, propertyTypeIds); diff --git a/src/Umbraco.Core/Persistence/UmbracoDatabase.cs b/src/Umbraco.Core/Persistence/UmbracoDatabase.cs index 64e4c0adca..2c07dff63c 100644 --- a/src/Umbraco.Core/Persistence/UmbracoDatabase.cs +++ b/src/Umbraco.Core/Persistence/UmbracoDatabase.cs @@ -67,6 +67,24 @@ namespace Umbraco.Core.Persistence /// public ISqlContext SqlContext { get; } + #region Temp + + // work around NPoco issue https://github.com/schotime/NPoco/issues/517 while we wait for the fix + public override DbCommand CreateCommand(DbConnection connection, CommandType commandType, string sql, params object[] args) + { + var command = base.CreateCommand(connection, commandType, sql, args); + + if (!DatabaseType.IsSqlCe()) return command; + + foreach (DbParameter parameter in command.Parameters) + if (parameter.Value == DBNull.Value) + parameter.DbType = DbType.String; + + return command; + } + + #endregion + #region Testing, Debugging and Troubleshooting private bool _enableCount; @@ -242,7 +260,9 @@ namespace Umbraco.Core.Persistence sb.Append(" @"); sb.Append(i++); sb.Append(":"); - sb.Append(arg); + if (arg == DBNull.Value) sb.Append(""); + else if (arg == null) sb.Append(""); + else sb.Append(arg); } return sb.ToString(); diff --git a/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlExtensionsTests.cs b/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlExtensionsTests.cs index 458479b293..9fbba01e94 100644 --- a/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlExtensionsTests.cs +++ b/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlExtensionsTests.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using NPoco; using NUnit.Framework; +using Umbraco.Core; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; using Umbraco.Tests.TestHelpers; @@ -11,6 +12,80 @@ namespace Umbraco.Tests.Persistence.NPocoTests [TestFixture] public class NPocoSqlExtensionsTests : BaseUsingSqlCeSyntax { + [Test] + public void WhereTest() + { + var sql = new Sql(SqlContext) + .Select("*") + .From() + .Where(x => x.LanguageId == null); + Assert.AreEqual("SELECT *\nFROM [umbracoPropertyData]\nWHERE (([umbracoPropertyData].[languageId] is null))", sql.SQL, sql.SQL); + + sql = new Sql(SqlContext) + .Select("*") + .From() + .Where(x => x.LanguageId == 123); + Assert.AreEqual("SELECT *\nFROM [umbracoPropertyData]\nWHERE (([umbracoPropertyData].[languageId] = @0))", sql.SQL, sql.SQL); + + var id = 123; + + sql = new Sql(SqlContext) + .Select("*") + .From() + .Where(x => x.LanguageId == id); + Assert.AreEqual("SELECT *\nFROM [umbracoPropertyData]\nWHERE (([umbracoPropertyData].[languageId] = @0))", sql.SQL, sql.SQL); + + int? nid = 123; + + sql = new Sql(SqlContext) + .Select("*") + .From() + .Where(x => x.LanguageId == nid); + Assert.AreEqual("SELECT *\nFROM [umbracoPropertyData]\nWHERE (([umbracoPropertyData].[languageId] = @0))", sql.SQL, sql.SQL); + + // but the above comparison fails if @0 is null + // what we want is something similar to: + + sql = new Sql(SqlContext) + .Select("*") + .From() + .Where(x => (nid == null && x.LanguageId == null) || (nid != null && x.LanguageId == nid)); + Assert.AreEqual("SELECT *\nFROM [umbracoPropertyData]\nWHERE ((((@0 is null) AND ([umbracoPropertyData].[languageId] is null)) OR ((@1 is not null) AND ([umbracoPropertyData].[languageId] = @2))))", sql.SQL, sql.SQL); + + // new NEquals method does it automatically + // 'course it would be nicer if '==' could do it + // see note in ExpressionVisitorBase for NEquals + + //sql = new Sql(SqlContext) + // .Select("*") + // .From() + // .Where(x => x.LanguageId.NEquals(nid)); + //Assert.AreEqual("SELECT *\nFROM [umbracoPropertyData]\nWHERE ((((@0 is null) AND ([umbracoPropertyData].[languageId] is null)) OR ((@0 is not null) AND ([umbracoPropertyData].[languageId] = @0))))", sql.SQL, sql.SQL); + + // but, the expression above fails with SQL CE, 'specified argument for the function is not valid' in 'isnull' function + // so... compare with fallback values + + sql = new Sql(SqlContext) + .Select("*") + .From() + .Where(x => x.LanguageId.NEquals(nid, -1)); + Assert.AreEqual("SELECT *\nFROM [umbracoPropertyData]\nWHERE ((COALESCE([umbracoPropertyData].[languageId],@0) = COALESCE(@1,@0)))", sql.SQL, sql.SQL); + } + + [Test] + public void NEqualsTest() + { + int? a, b; + a = b = null; + Assert.IsTrue(a.NEquals(b, -1)); + b = 2; + Assert.IsFalse(a.NEquals(b, -1)); + a = 2; + Assert.IsTrue(a.NEquals(b, -1)); + b = null; + Assert.IsFalse(a.NEquals(b, -1)); + } + [Test] public void WhereInValueFieldTest() { diff --git a/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs b/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs index c05bde4c7c..071fa99264 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs @@ -129,6 +129,133 @@ namespace Umbraco.Tests.Services Assert.IsFalse(enTagGroup.Any(x => x.Text == "plus")); } + [Test] + public void TagsCanBecomeVariant() + { + var enId = ServiceContext.LocalizationService.GetLanguageIdByIsoCode("en-US").Value; + + var contentService = ServiceContext.ContentService; + var contentTypeService = ServiceContext.ContentTypeService; + var tagService = ServiceContext.TagService; + var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); + PropertyType propertyType; + contentType.PropertyGroups.First().PropertyTypes.Add( + propertyType = new PropertyType("test", ValueStorageType.Ntext, "tags") + { + DataTypeId = 1041 + }); + contentTypeService.Save(contentType); + + IContent content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + content1.AssignTags("tags", new[] { "hello", "world", "another", "one" }); + contentService.SaveAndPublish(content1); + + contentType.Variations = ContentVariation.Culture; + contentTypeService.Save(contentType); + + // no changes + content1 = contentService.GetById(content1.Id); + + var tags = content1.Properties["tags"].GetTagsValue().ToArray(); + Assert.AreEqual(4, tags.Length); + Assert.Contains("one", tags); + Assert.AreEqual(-1, tags.IndexOf("plus")); + + var tagGroups = tagService.GetAllTags().GroupBy(x => x.LanguageId); + foreach (var tag in tagService.GetAllTags()) + Console.WriteLine($"{tag.Group}:{tag.Text} {tag.LanguageId}"); + Assert.AreEqual(1, tagGroups.Count()); + var enTagGroup = tagGroups.FirstOrDefault(x => x.Key == null); + Assert.IsNotNull(enTagGroup); + Assert.AreEqual(4, enTagGroup.Count()); + Assert.IsTrue(enTagGroup.Any(x => x.Text == "one")); + Assert.IsFalse(enTagGroup.Any(x => x.Text == "plus")); + + propertyType.Variations = ContentVariation.Culture; + contentTypeService.Save(contentType); + + // changes + content1 = contentService.GetById(content1.Id); + + // property value has been moved from invariant to en-US + tags = content1.Properties["tags"].GetTagsValue().ToArray(); + Assert.IsEmpty(tags); + + tags = content1.Properties["tags"].GetTagsValue("en-US").ToArray(); + Assert.AreEqual(4, tags.Length); + Assert.Contains("one", tags); + Assert.AreEqual(-1, tags.IndexOf("plus")); + + // tags have been copied from invariant to en-US + tagGroups = tagService.GetAllTags(culture: "*").GroupBy(x => x.LanguageId); + foreach (var tag in tagService.GetAllTags("*")) + Console.WriteLine($"{tag.Group}:{tag.Text} {tag.LanguageId}"); + Assert.AreEqual(1, tagGroups.Count()); + + enTagGroup = tagGroups.FirstOrDefault(x => x.Key == enId); + Assert.IsNotNull(enTagGroup); + Assert.AreEqual(4, enTagGroup.Count()); + Assert.IsTrue(enTagGroup.Any(x => x.Text == "one")); + Assert.IsFalse(enTagGroup.Any(x => x.Text == "plus")); + } + + [Test] + public void TagsCanBecomeInvariant() + { + var languageService = ServiceContext.LocalizationService; + languageService.Save(new Language("fr-FR")); // en-US is already there + + var enId = ServiceContext.LocalizationService.GetLanguageIdByIsoCode("en-US").Value; + + var contentService = ServiceContext.ContentService; + var contentTypeService = ServiceContext.ContentTypeService; + var tagService = ServiceContext.TagService; + var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); + PropertyType propertyType; + contentType.PropertyGroups.First().PropertyTypes.Add( + propertyType = new PropertyType("test", ValueStorageType.Ntext, "tags") + { + DataTypeId = 1041, + Variations = ContentVariation.Culture + }); + contentType.Variations = ContentVariation.Culture; + contentTypeService.Save(contentType); + + IContent content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + content1.SetCultureName("name-fr", "fr-FR"); + content1.SetCultureName("name-en", "en-US"); + content1.AssignTags("tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); + content1.AssignTags("tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); + contentService.SaveAndPublish(content1); + + contentType.Variations = ContentVariation.Nothing; + contentTypeService.Save(contentType); + + // changes + content1 = contentService.GetById(content1.Id); + + // property value has been moved from en-US to invariant, fr-FR tags are gone + Assert.IsEmpty(content1.Properties["tags"].GetTagsValue("fr-FR")); + Assert.IsEmpty(content1.Properties["tags"].GetTagsValue("en-US")); + + var tags = content1.Properties["tags"].GetTagsValue().ToArray(); + Assert.AreEqual(4, tags.Length); + Assert.Contains("one", tags); + Assert.AreEqual(-1, tags.IndexOf("plus")); + + // tags have been copied from en-US to invariant, fr-FR tags are gone + var tagGroups = tagService.GetAllTags(culture: "*").GroupBy(x => x.LanguageId); + foreach (var tag in tagService.GetAllTags("*")) + Console.WriteLine($"{tag.Group}:{tag.Text} {tag.LanguageId}"); + Assert.AreEqual(1, tagGroups.Count()); + + var enTagGroup = tagGroups.FirstOrDefault(x => x.Key == null); + Assert.IsNotNull(enTagGroup); + Assert.AreEqual(4, enTagGroup.Count()); + Assert.IsTrue(enTagGroup.Any(x => x.Text == "one")); + Assert.IsFalse(enTagGroup.Any(x => x.Text == "plus")); + } + [Test] public void TagsAreUpdatedWhenContentIsTrashedAndUnTrashed_One() { @@ -193,7 +320,7 @@ namespace Umbraco.Tests.Services } [Test] - [Ignore("U4-8442, will need to be fixed eventually.")] + //[Ignore("U4-8442, will need to be fixed eventually.")] public void TagsAreUpdatedWhenContentIsTrashedAndUnTrashed_Tree() { var contentService = ServiceContext.ContentService; @@ -209,12 +336,10 @@ namespace Umbraco.Tests.Services var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); content1.AssignTags("tags", new[] { "hello", "world", "some", "tags", "plus" }); - content1.PublishCulture(); contentService.SaveAndPublish(content1); var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", content1.Id); content2.AssignTags("tags", new[] { "hello", "world", "some", "tags" }); - content2.PublishCulture(); contentService.SaveAndPublish(content2); // verify @@ -298,7 +423,7 @@ namespace Umbraco.Tests.Services } [Test] - [Ignore("U4-8442, will need to be fixed eventually.")] + //[Ignore("U4-8442, will need to be fixed eventually.")] public void TagsAreUpdatedWhenContentIsUnpublishedAndRePublished_Tree() { var contentService = ServiceContext.ContentService; @@ -314,12 +439,10 @@ namespace Umbraco.Tests.Services var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); content1.AssignTags("tags", new[] { "hello", "world", "some", "tags", "bam" }); - content1.PublishCulture(); contentService.SaveAndPublish(content1); var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", content1); content2.AssignTags("tags", new[] { "hello", "world", "some", "tags" }); - content2.PublishCulture(); contentService.SaveAndPublish(content2); contentService.Unpublish(content1); From b8b040439303f01c16a8a80654bd7c984af51cc7 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 5 Dec 2018 20:51:30 +1100 Subject: [PATCH 04/54] adds notes and ignores failing tests (to be fixed later) --- src/Umbraco.Tests/Services/ContentServiceTagsTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs b/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs index 071fa99264..8bb61fc186 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs @@ -320,7 +320,7 @@ namespace Umbraco.Tests.Services } [Test] - //[Ignore("U4-8442, will need to be fixed eventually.")] + [Ignore("https://github.com/umbraco/Umbraco-CMS/issues/3821 (U4-8442), will need to be fixed.")] public void TagsAreUpdatedWhenContentIsTrashedAndUnTrashed_Tree() { var contentService = ServiceContext.ContentService; @@ -423,7 +423,7 @@ namespace Umbraco.Tests.Services } [Test] - //[Ignore("U4-8442, will need to be fixed eventually.")] + [Ignore("https://github.com/umbraco/Umbraco-CMS/issues/3821 (U4-8442), will need to be fixed.")] public void TagsAreUpdatedWhenContentIsUnpublishedAndRePublished_Tree() { var contentService = ServiceContext.ContentService; From 0dda7c81a07b7caf328a0e3067e79c0d1d05e4de Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 5 Dec 2018 12:18:07 +0100 Subject: [PATCH 05/54] Rename NEquals --- src/Umbraco.Core/ObjectExtensions.cs | 2 +- .../Querying/ExpressionVisitorBase.cs | 6 +++--- .../Implement/ContentTypeRepositoryBase.cs | 20 +++++++++---------- .../NPocoTests/NPocoSqlExtensionsTests.cs | 18 ++++++++--------- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/Umbraco.Core/ObjectExtensions.cs b/src/Umbraco.Core/ObjectExtensions.cs index 1cbb4a6ea1..cfd1eedb5a 100644 --- a/src/Umbraco.Core/ObjectExtensions.cs +++ b/src/Umbraco.Core/ObjectExtensions.cs @@ -797,7 +797,7 @@ namespace Umbraco.Core /// The value to use when any value is null. /// Do not use outside of Sql expressions. // see usage in ExpressionVisitorBase - public static bool NEquals(this T? value, T? other, T fallbackValue) + public static bool SqlNullableEquals(this T? value, T? other, T fallbackValue) where T : struct { return (value ?? fallbackValue).Equals(other ?? fallbackValue); diff --git a/src/Umbraco.Core/Persistence/Querying/ExpressionVisitorBase.cs b/src/Umbraco.Core/Persistence/Querying/ExpressionVisitorBase.cs index 493bbcacc7..16bfc9b164 100644 --- a/src/Umbraco.Core/Persistence/Querying/ExpressionVisitorBase.cs +++ b/src/Umbraco.Core/Persistence/Querying/ExpressionVisitorBase.cs @@ -656,13 +656,13 @@ namespace Umbraco.Core.Persistence.Querying // c# 'x == null' becomes sql 'x IS NULL' which is fine // c# 'x == y' becomes sql 'x = @0' which is fine - unless they are nullable types, // because sql 'x = NULL' is always false and the 'IS NULL' syntax is required, - // so for comparing nullable types, we use x.NEquals(y, fb) where fb is a fallback + // so for comparing nullable types, we use x.SqlNullableEquals(y, fb) where fb is a fallback // value which will be used when values are null - turning the comparison into // sql 'COALESCE(x,fb) = COALESCE(y,fb)' - of course, fb must be a value outside // of x and y range - and if that is not possible, then a manual comparison need // to be written - //TODO support NEquals with 0 parameters, using the full syntax below - case "NEquals": + //TODO support SqlNullableEquals with 0 parameters, using the full syntax below + case "SqlNullableEquals": var compareTo = Visit(m.Arguments[1]); var fallback = Visit(m.Arguments[2]); // that would work without a fallback value but is more cumbersome diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index 7e720ba08a..cd9681fbda 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -762,7 +762,7 @@ AND umbracoNode.id <> @id", /// private void CopyTagData(int? sourceLanguageId, int? targetLanguageId, IReadOnlyCollection propertyTypeIds, IReadOnlyCollection contentTypeIds = null) { - // note: important to use NEquals for nullable types, cannot directly compare language identifiers + // note: important to use SqlNullableEquals for nullable types, cannot directly compare language identifiers // fixme - should we batch then? var whereInArgsCount = propertyTypeIds.Count + (contentTypeIds?.Count ?? 0); @@ -784,7 +784,7 @@ AND umbracoNode.id <> @id", sqlTagToDelete .WhereIn(x => x.PropertyTypeId, propertyTypeIds) - .Where(x => x.LanguageId.NEquals(targetLanguageId, -1)); + .Where(x => x.LanguageId.SqlNullableEquals(targetLanguageId, -1)); var sqlDeleteRel = Sql() .Delete() @@ -811,7 +811,7 @@ AND umbracoNode.id <> @id", sqlSelect .InnerJoin().On((tag, rel) => tag.Id == rel.TagId) - .LeftJoin("xtags").On((tag, xtag) => tag.Text == xtag.Text && tag.Group == xtag.Group && tag.LanguageId.NEquals(targetLanguageId, -1), aliasRight: "xtags"); + .LeftJoin("xtags").On((tag, xtag) => tag.Text == xtag.Text && tag.Group == xtag.Group && tag.LanguageId.SqlNullableEquals(targetLanguageId, -1), aliasRight: "xtags"); if (contentTypeIds != null) sqlSelect @@ -825,7 +825,7 @@ AND umbracoNode.id <> @id", sqlSelect .WhereIn(x => x.ContentTypeId, contentTypeIds); - sqlSelect.Where(x => x.LanguageId.NEquals(sourceLanguageId, -1)); + sqlSelect.Where(x => x.LanguageId.SqlNullableEquals(sourceLanguageId, -1)); var cols = Sql().Columns(x => x.Text, x => x.Group, x => x.LanguageId); var sqlInsertTag = Sql($"INSERT INTO {TagDto.TableName} ({cols})").Append(sqlSelect); @@ -840,8 +840,8 @@ AND umbracoNode.id <> @id", .AndSelect("otag", x => x.Id) .From() .InnerJoin().On((rel, tag) => rel.TagId == tag.Id) - .InnerJoin("otag").On((tag, otag) => tag.Text == otag.Text && tag.Group == otag.Group && otag.LanguageId.NEquals(targetLanguageId, -1), aliasRight: "otag") - .Where(x => x.LanguageId.NEquals(sourceLanguageId, -1)); + .InnerJoin("otag").On((tag, otag) => tag.Text == otag.Text && tag.Group == otag.Group && otag.LanguageId.SqlNullableEquals(targetLanguageId, -1), aliasRight: "otag") + .Where(x => x.LanguageId.SqlNullableEquals(sourceLanguageId, -1)); var cols2 = Sql().Columns(x => x.NodeId, x => x.PropertyTypeId, x => x.TagId); var sqlInsertRel = Sql($"INSERT INTO {TagRelationshipDto.TableName} ({cols2})").Append(sqlFoo); @@ -864,7 +864,7 @@ AND umbracoNode.id <> @id", sqlTagToDelete .WhereIn(x => x.PropertyTypeId, propertyTypeIds) - .Where(x => !x.LanguageId.NEquals(targetLanguageId, -1)); + .Where(x => !x.LanguageId.SqlNullableEquals(targetLanguageId, -1)); sqlDeleteRel = Sql() .Delete() @@ -891,7 +891,7 @@ AND umbracoNode.id <> @id", /// The content type identifiers. private void CopyPropertyData(int? sourceLanguageId, int? targetLanguageId, IReadOnlyCollection propertyTypeIds, IReadOnlyCollection contentTypeIds = null) { - // note: important to use NEquals for nullable types, cannot directly compare language identifiers + // note: important to use SqlNullableEquals for nullable types, cannot directly compare language identifiers // // fixme - should we batch then? var whereInArgsCount = propertyTypeIds.Count + (contentTypeIds?.Count ?? 0); @@ -920,7 +920,7 @@ AND umbracoNode.id <> @id", sqlDelete.WhereIn(x => x.VersionId, inSql); } - sqlDelete.Where(x => x.LanguageId.NEquals(targetLanguageId, -1)); + sqlDelete.Where(x => x.LanguageId.SqlNullableEquals(targetLanguageId, -1)); sqlDelete .WhereIn(x => x.PropertyTypeId, propertyTypeIds); @@ -944,7 +944,7 @@ AND umbracoNode.id <> @id", .InnerJoin().On((pdata, cversion) => pdata.VersionId == cversion.Id) .InnerJoin().On((cversion, c) => cversion.NodeId == c.NodeId); - sqlSelectData.Where(x => x.LanguageId.NEquals(sourceLanguageId, -1)); + sqlSelectData.Where(x => x.LanguageId.SqlNullableEquals(sourceLanguageId, -1)); sqlSelectData .WhereIn(x => x.PropertyTypeId, propertyTypeIds); diff --git a/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlExtensionsTests.cs b/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlExtensionsTests.cs index 9fbba01e94..de1e3ad5ad 100644 --- a/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlExtensionsTests.cs +++ b/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlExtensionsTests.cs @@ -52,14 +52,14 @@ namespace Umbraco.Tests.Persistence.NPocoTests .Where(x => (nid == null && x.LanguageId == null) || (nid != null && x.LanguageId == nid)); Assert.AreEqual("SELECT *\nFROM [umbracoPropertyData]\nWHERE ((((@0 is null) AND ([umbracoPropertyData].[languageId] is null)) OR ((@1 is not null) AND ([umbracoPropertyData].[languageId] = @2))))", sql.SQL, sql.SQL); - // new NEquals method does it automatically + // new SqlNullableEquals method does it automatically // 'course it would be nicer if '==' could do it - // see note in ExpressionVisitorBase for NEquals + // see note in ExpressionVisitorBase for SqlNullableEquals //sql = new Sql(SqlContext) // .Select("*") // .From() - // .Where(x => x.LanguageId.NEquals(nid)); + // .Where(x => x.LanguageId.SqlNullableEquals(nid)); //Assert.AreEqual("SELECT *\nFROM [umbracoPropertyData]\nWHERE ((((@0 is null) AND ([umbracoPropertyData].[languageId] is null)) OR ((@0 is not null) AND ([umbracoPropertyData].[languageId] = @0))))", sql.SQL, sql.SQL); // but, the expression above fails with SQL CE, 'specified argument for the function is not valid' in 'isnull' function @@ -68,22 +68,22 @@ namespace Umbraco.Tests.Persistence.NPocoTests sql = new Sql(SqlContext) .Select("*") .From() - .Where(x => x.LanguageId.NEquals(nid, -1)); + .Where(x => x.LanguageId.SqlNullableEquals(nid, -1)); Assert.AreEqual("SELECT *\nFROM [umbracoPropertyData]\nWHERE ((COALESCE([umbracoPropertyData].[languageId],@0) = COALESCE(@1,@0)))", sql.SQL, sql.SQL); } [Test] - public void NEqualsTest() + public void SqlNullableEqualsTest() { int? a, b; a = b = null; - Assert.IsTrue(a.NEquals(b, -1)); + Assert.IsTrue(a.SqlNullableEquals(b, -1)); b = 2; - Assert.IsFalse(a.NEquals(b, -1)); + Assert.IsFalse(a.SqlNullableEquals(b, -1)); a = 2; - Assert.IsTrue(a.NEquals(b, -1)); + Assert.IsTrue(a.SqlNullableEquals(b, -1)); b = null; - Assert.IsFalse(a.NEquals(b, -1)); + Assert.IsFalse(a.SqlNullableEquals(b, -1)); } [Test] From dd2c43485d19a9fb0f5107fd80ceecf9f27a0b12 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 6 Dec 2018 01:10:53 +1100 Subject: [PATCH 06/54] Moves tag editor to a component, fixes issue with typeahead and invariant properties, fixes migration to update the IX_cmsTags index correctly --- .../Upgrade/V_8_0_0/MakeTagsVariant.cs | 11 + .../content/umbtabbedcontent.directive.js | 5 +- .../tags/umbtagseditor.directive.js | 273 ++++++++++++++++++ .../components/tags/umb-tags-editor.html | 34 +++ .../propertyeditors/tags/tags.controller.js | 221 +------------- .../src/views/propertyeditors/tags/tags.html | 37 +-- 6 files changed, 331 insertions(+), 250 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/components/tags/umb-tags-editor.html diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/MakeTagsVariant.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/MakeTagsVariant.cs index c898187884..9ccd6d5e76 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/MakeTagsVariant.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/MakeTagsVariant.cs @@ -11,6 +11,17 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 public override void Migrate() { AddColumn("languageId"); + + Delete.Index($"IX_{Constants.DatabaseSchema.Tables.Tag}").OnTable(Constants.DatabaseSchema.Tables.Tag).Do(); + Create.Index($"IX_{Constants.DatabaseSchema.Tables.Tag}").OnTable(Constants.DatabaseSchema.Tables.Tag) + .OnColumn("group") + .Ascending() + .OnColumn("tag") + .Ascending() + .OnColumn("languageId") + .Ascending() + .WithOptions().Unique() + .Do(); } } } diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js index f83f441d66..5ebb40fac6 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js @@ -12,11 +12,12 @@ //expose the property/methods for other directives to use this.content = $scope.content; - - $scope.activeVariant = _.find(this.content.variants, variant => { + this.activeVariant = _.find(this.content.variants, variant => { return variant.active; }); + $scope.activeVariant = this.activeVariant; + $scope.defaultVariant = _.find(this.content.variants, variant => { return variant.language.isDefault; }); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js new file mode 100644 index 0000000000..eed23b4de2 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js @@ -0,0 +1,273 @@ +/** +@ngdoc directive +@name umbraco.directives.directive:umbTagsEditor +**/ + +(function () { + 'use strict'; + + angular + .module('umbraco.directives') + .component('umbTagsEditor', { + transclude: true, + templateUrl: 'views/components/tags/umb-tags-editor.html', + controller: umbTagsEditorController, + controllerAs: 'vm', + bindings: { + value: "<", + config: "<", + validation: "<", + culture: " 0) { + if (vm.config.storageType === "Json") { + //json storage + vm.viewModel = JSON.parse(vm.value); + updateModelValue(vm.viewModel); + } + else { + //csv storage + + // split the csv string, and remove any duplicate values + let tempArray = vm.value.split(',').map(function (v) { + return v.trim(); + }); + + vm.viewModel = tempArray.filter(function (v, i, self) { + return self.indexOf(v) === i; + }); + + updateModelValue(vm.viewModel); + } + } + } + } + + function updateModelValue(val) { + if (val) { + vm.onValueChanged({ value: val }); + } + else { + vm.onValueChanged({ value: [] }); + } + } + + /** + * Method required by the valPropertyValidator directive (returns true if the property editor has at least one tag selected) + */ + function validateMandatory() { + return { + isValid: !vm.validation.mandatory || (vm.viewModel != null && vm.viewModel.length > 0), + errorMsg: "Value cannot be empty", + errorKey: "required" + }; + } + + function addTagInternal(tagToAdd) { + if (tagToAdd != null && tagToAdd.length > 0) { + if (vm.viewModel.indexOf(tagToAdd) < 0) { + vm.viewModel.push(tagToAdd); + updateModelValue(vm.viewModel); + } + } + } + + function addTagOnEnter(e) { + var code = e.keyCode || e.which; + if (code == 13) { //Enter keycode + if ($element.find('.tags-' + vm.htmlId).parent().find(".tt-dropdown-menu .tt-cursor").length === 0) { + //this is required, otherwise the html form will attempt to submit. + e.preventDefault(); + addTag(); + } + } + } + + function addTag() { + //ensure that we're not pressing the enter key whilst selecting a typeahead value from the drop down + //we need to use jquery because typeahead duplicates the text box + addTagInternal(vm.tagToAdd); + vm.tagToAdd = ""; + //this clears the value stored in typeahead so it doesn't try to add the text again + // https://issues.umbraco.org/issue/U4-4947 + typeahead.typeahead('val', ''); + } + + function removeTag(tag) { + var i = vm.viewModel.indexOf(tag); + + if (i >= 0) { + // Make sure to hide the prompt so it does not stay open because another item gets a new number in the array index + vm.promptIsVisible = "-1"; + + // Remove the tag from the index + vm.viewModel.splice(i, 1); + + updateModelValue(vm.viewModel); + } + } + + function showPrompt(idx, tag) { + + var i = vm.viewModel.indexOf(tag); + + // Make the prompt visible for the clicked tag only + if (i === idx) { + vm.promptIsVisible = i; + } + } + + function hidePrompt() { + vm.promptIsVisible = "-1"; + } + + //helper method to format the data for bloodhound + function dataTransform(list) { + //transform the result to what bloodhound wants + var tagList = _.map(list, function (i) { + return { value: i.text }; + }); + // remove current tags from the list + return $.grep(tagList, function (tag) { + return ($.inArray(tag.value, vm.viewModel) === -1); + }); + } + + // helper method to remove current tags + function removeCurrentTagsFromSuggestions(suggestions) { + return $.grep(suggestions, function (suggestion) { + return ($.inArray(suggestion.value, vm.viewModel) === -1); + }); + } + + + } + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/components/tags/umb-tags-editor.html b/src/Umbraco.Web.UI.Client/src/views/components/tags/umb-tags-editor.html new file mode 100644 index 0000000000..4f83e05c17 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/components/tags/umb-tags-editor.html @@ -0,0 +1,34 @@ +
+ +
+ Loading... +
+ +
+ + + + + + + + + + + + + + +
+
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js index 01a188c847..688ac7693f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js @@ -1,223 +1,10 @@ angular.module("umbraco") .controller("Umbraco.PropertyEditors.TagsController", - function ($rootScope, $scope, $log, assetsService, umbRequestHelper, angularHelper, $timeout, $element) { + function ($scope) { - var $typeahead; - - $scope.isLoading = true; - $scope.tagToAdd = ""; - - function setModelValue(val) { - - $scope.model.value = val || $scope.model.value; - if ($scope.model.value) { - if (!$scope.model.config.storageType || $scope.model.config.storageType !== "Json") { - //it is csv - if (!$scope.model.value) { - $scope.model.value = []; - } - else { - if($scope.model.value.length > 0) { - // split the csv string, and remove any duplicate values - var tempArray = $scope.model.value.split(',').map(function(v) { - return v.trim(); - }); - - $scope.model.value = tempArray.filter(function(v, i, self) { - return self.indexOf(v) === i; - }); - } - } - } - } - else { - $scope.model.value = []; - } - } - - assetsService.loadJs("lib/typeahead.js/typeahead.bundle.min.js", $scope).then(function () { - - $scope.isLoading = false; - - //load current value - setModelValue(); - - // Method required by the valPropertyValidator directive (returns true if the property editor has at least one tag selected) - $scope.validateMandatory = function () { - return { - isValid: !$scope.model.validation.mandatory || ($scope.model.value != null && $scope.model.value.length > 0), - errorMsg: "Value cannot be empty", - errorKey: "required" - }; - } - - //Helper method to add a tag on enter or on typeahead select - function addTag(tagToAdd) { - if (tagToAdd != null && tagToAdd.length > 0) { - if ($scope.model.value.indexOf(tagToAdd) < 0) { - $scope.model.value.push(tagToAdd); - //this is required to re-validate - $scope.propertyForm.tagCount.$setViewValue($scope.model.value.length); - } - } - } - - $scope.addTagOnEnter = function (e) { - var code = e.keyCode || e.which; - if (code == 13) { //Enter keycode - if ($element.find('.tags-' + $scope.model.alias).parent().find(".tt-dropdown-menu .tt-cursor").length === 0) { - //this is required, otherwise the html form will attempt to submit. - e.preventDefault(); - $scope.addTag(); - } - } - }; - - $scope.addTag = function () { - //ensure that we're not pressing the enter key whilst selecting a typeahead value from the drop down - //we need to use jquery because typeahead duplicates the text box - addTag($scope.tagToAdd); - $scope.tagToAdd = ""; - //this clears the value stored in typeahead so it doesn't try to add the text again - // https://issues.umbraco.org/issue/U4-4947 - $typeahead.typeahead('val', ''); - }; - - // Set the visible prompt to -1 to ensure it will not be visible - $scope.promptIsVisible = "-1"; - - $scope.removeTag = function (tag) { - var i = $scope.model.value.indexOf(tag); - - if (i >= 0) { - // Make sure to hide the prompt so it does not stay open because another item gets a new number in the array index - $scope.promptIsVisible = "-1"; - - // Remove the tag from the index - $scope.model.value.splice(i, 1); - - //this is required to re-validate - $scope.propertyForm.tagCount.$setViewValue($scope.model.value.length); - } - }; - - $scope.showPrompt = function (idx, tag){ - - var i = $scope.model.value.indexOf(tag); - - // Make the prompt visible for the clicked tag only - if (i === idx) { - $scope.promptIsVisible = i; - } - } - - $scope.hidePrompt = function(){ - $scope.promptIsVisible = "-1"; - } - - //vice versa - $scope.model.onValueChanged = function (newVal, oldVal) { - //update the display val again if it has changed from the server - setModelValue(newVal); - }; - - //configure the tags data source - - //helper method to format the data for bloodhound - function dataTransform(list) { - //transform the result to what bloodhound wants - var tagList = _.map(list, function (i) { - return { value: i.text }; - }); - // remove current tags from the list - return $.grep(tagList, function (tag) { - return ($.inArray(tag.value, $scope.model.value) === -1); - }); - } - - // helper method to remove current tags - function removeCurrentTagsFromSuggestions(suggestions) { - return $.grep(suggestions, function (suggestion) { - return ($.inArray(suggestion.value, $scope.model.value) === -1); - }); - } - - function currentCulture(scope) { - while (scope && !scope.activeVariant) - scope = scope.$parent; - if (!scope || !scope.activeVariant) return null; - return scope.activeVariant.language.culture; - } - - var tagsHound = new Bloodhound({ - datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'), - queryTokenizer: Bloodhound.tokenizers.whitespace, - dupDetector : function(remoteMatch, localMatch) { - return (remoteMatch["value"] == localMatch["value"]); - }, - //pre-fetch the tags for this category - prefetch: { - url: umbRequestHelper.getApiUrl("tagsDataBaseUrl", "GetTags", { tagGroup: $scope.model.config.group, culture: currentCulture($scope) }), - //TTL = 5 minutes - ttl: 300000, - filter: dataTransform - }, - //dynamically get the tags for this category (they may have changed on the server) - remote: { - url: umbRequestHelper.getApiUrl("tagsDataBaseUrl", "GetTags", { tagGroup: $scope.model.config.group, culture: currentCulture($scope) }), - filter: dataTransform - } - }); - - tagsHound.initialize(true); - - //configure the type ahead - $timeout(function () { - - $typeahead = $element.find('.tags-' + $scope.model.alias).typeahead( - { - //This causes some strangeness as it duplicates the textbox, best leave off for now. - hint: false, - highlight: true, - cacheKey: new Date(), // Force a cache refresh each time the control is initialized - minLength: 1 - }, { - //see: https://github.com/twitter/typeahead.js/blob/master/doc/jquery_typeahead.md#options - // name = the data set name, we'll make this the tag group name - name: $scope.model.config.group, - displayKey: "value", - source: function (query, cb) { - tagsHound.get(query, function (suggestions) { - cb(removeCurrentTagsFromSuggestions(suggestions)); - }); - } - }).bind("typeahead:selected", function (obj, datum, name) { - angularHelper.safeApply($scope, function () { - addTag(datum["value"]); - $scope.tagToAdd = ""; - // clear the typed text - $typeahead.typeahead('val', ''); - }); - - }).bind("typeahead:autocompleted", function (obj, datum, name) { - angularHelper.safeApply($scope, function () { - addTag(datum["value"]); - $scope.tagToAdd = ""; - }); - - }).bind("typeahead:opened", function (obj) { - //console.log("opened "); - }); - }); - - $scope.$on('$destroy', function () { - tagsHound.clearPrefetchCache(); - tagsHound.clearRemoteCache(); - $element.find('.tags-' + $scope.model.alias).typeahead('destroy'); - tagsHound = null; - }); - - }); + $scope.valueChanged = function(value) { + $scope.model.value = value; + } } ); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.html index f1d46e951e..69a4751226 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.html @@ -1,35 +1,10 @@
-
- Loading... -
- -
- - - - - - - - - - - - - - -
+ +
From 85efd4dc59e70f409dfcec06fb70ecfd24c3e399 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 6 Dec 2018 01:14:06 +1100 Subject: [PATCH 07/54] Moves SqlNullableEquals to SqlExpressionExtensions --- src/Umbraco.Core/ObjectExtensions.cs | 15 +-------------- .../Querying/SqlExpressionExtensions.cs | 15 +++++++++++++++ .../NPocoTests/NPocoSqlExtensionsTests.cs | 2 +- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/Umbraco.Core/ObjectExtensions.cs b/src/Umbraco.Core/ObjectExtensions.cs index cfd1eedb5a..6c2fd85dbe 100644 --- a/src/Umbraco.Core/ObjectExtensions.cs +++ b/src/Umbraco.Core/ObjectExtensions.cs @@ -788,19 +788,6 @@ namespace Umbraco.Core return BoolConvertCache[type] = false; } - /// - /// Indicates whether two nullable values are equal, substituting a fallback value for nulls. - /// - /// The nullable type. - /// The value to compare. - /// The value to compare to. - /// The value to use when any value is null. - /// Do not use outside of Sql expressions. - // see usage in ExpressionVisitorBase - public static bool SqlNullableEquals(this T? value, T? other, T fallbackValue) - where T : struct - { - return (value ?? fallbackValue).Equals(other ?? fallbackValue); - } + } } diff --git a/src/Umbraco.Core/Persistence/Querying/SqlExpressionExtensions.cs b/src/Umbraco.Core/Persistence/Querying/SqlExpressionExtensions.cs index 0f9eb47d77..710997472c 100644 --- a/src/Umbraco.Core/Persistence/Querying/SqlExpressionExtensions.cs +++ b/src/Umbraco.Core/Persistence/Querying/SqlExpressionExtensions.cs @@ -9,6 +9,21 @@ namespace Umbraco.Core.Persistence.Querying ///
internal static class SqlExpressionExtensions { + /// + /// Indicates whether two nullable values are equal, substituting a fallback value for nulls. + /// + /// The nullable type. + /// The value to compare. + /// The value to compare to. + /// The value to use when any value is null. + /// Do not use outside of Sql expressions. + // see usage in ExpressionVisitorBase + public static bool SqlNullableEquals(this T? value, T? other, T fallbackValue) + where T : struct + { + return (value ?? fallbackValue).Equals(other ?? fallbackValue); + } + public static bool SqlIn(this IEnumerable collection, T item) { return collection.Contains(item); diff --git a/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlExtensionsTests.cs b/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlExtensionsTests.cs index de1e3ad5ad..05723c50cd 100644 --- a/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlExtensionsTests.cs +++ b/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlExtensionsTests.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using NPoco; using NUnit.Framework; -using Umbraco.Core; +using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; using Umbraco.Tests.TestHelpers; From 45a6789fded5229db30f3b5063edab4ff181f0bb Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 6 Dec 2018 12:17:40 +1100 Subject: [PATCH 08/54] Added a failing test --- .../Services/ContentServiceTagsTests.cs | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs b/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs index 8bb61fc186..196af5c0bd 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs @@ -256,6 +256,102 @@ namespace Umbraco.Tests.Services Assert.IsFalse(enTagGroup.Any(x => x.Text == "plus")); } + [Test] + public void TagsCanBecomeInvariantByPropertyType() + { + var languageService = ServiceContext.LocalizationService; + languageService.Save(new Language("fr-FR")); // en-US is already there + + var enId = ServiceContext.LocalizationService.GetLanguageIdByIsoCode("en-US").Value; + + var contentService = ServiceContext.ContentService; + var contentTypeService = ServiceContext.ContentTypeService; + var tagService = ServiceContext.TagService; + var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); + PropertyType propertyType; + contentType.PropertyGroups.First().PropertyTypes.Add( + propertyType = new PropertyType("test", ValueStorageType.Ntext, "tags") + { + DataTypeId = 1041, + Variations = ContentVariation.Culture + }); + contentType.Variations = ContentVariation.Culture; + contentTypeService.Save(contentType); + + IContent content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + content1.SetCultureName("name-fr", "fr-FR"); + content1.SetCultureName("name-en", "en-US"); + content1.AssignTags("tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); + content1.AssignTags("tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); + contentService.SaveAndPublish(content1); + + propertyType.Variations = ContentVariation.Nothing; + contentTypeService.Save(contentType); + + // changes + content1 = contentService.GetById(content1.Id); + + // property value has been moved from en-US to invariant, fr-FR tags are gone + Assert.IsEmpty(content1.Properties["tags"].GetTagsValue("fr-FR")); + Assert.IsEmpty(content1.Properties["tags"].GetTagsValue("en-US")); + + var tags = content1.Properties["tags"].GetTagsValue().ToArray(); + Assert.AreEqual(4, tags.Length); + Assert.Contains("one", tags); + Assert.AreEqual(-1, tags.IndexOf("plus")); + + // tags have been copied from en-US to invariant, fr-FR tags are gone + var tagGroups = tagService.GetAllTags(culture: "*").GroupBy(x => x.LanguageId); + foreach (var tag in tagService.GetAllTags("*")) + Console.WriteLine($"{tag.Group}:{tag.Text} {tag.LanguageId}"); + Assert.AreEqual(1, tagGroups.Count()); + + var enTagGroup = tagGroups.FirstOrDefault(x => x.Key == null); + Assert.IsNotNull(enTagGroup); + Assert.AreEqual(4, enTagGroup.Count()); + Assert.IsTrue(enTagGroup.Any(x => x.Text == "one")); + Assert.IsFalse(enTagGroup.Any(x => x.Text == "plus")); + } + + [Test] + public void TagsCanBecomeInvariantByPropertyTypeAndBackToVariant() + { + var languageService = ServiceContext.LocalizationService; + languageService.Save(new Language("fr-FR")); // en-US is already there + + var enId = ServiceContext.LocalizationService.GetLanguageIdByIsoCode("en-US").Value; + + var contentService = ServiceContext.ContentService; + var contentTypeService = ServiceContext.ContentTypeService; + var tagService = ServiceContext.TagService; + var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); + PropertyType propertyType; + contentType.PropertyGroups.First().PropertyTypes.Add( + propertyType = new PropertyType("test", ValueStorageType.Ntext, "tags") + { + DataTypeId = 1041, + Variations = ContentVariation.Culture + }); + contentType.Variations = ContentVariation.Culture; + contentTypeService.Save(contentType); + + IContent content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + content1.SetCultureName("name-fr", "fr-FR"); + content1.SetCultureName("name-en", "en-US"); + content1.AssignTags("tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); + content1.AssignTags("tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); + contentService.SaveAndPublish(content1); + + propertyType.Variations = ContentVariation.Nothing; + contentTypeService.Save(contentType); + + //fixme: This throws due to index violations + propertyType.Variations = ContentVariation.Culture; + contentTypeService.Save(contentType); + + //TODO: Assert results + } + [Test] public void TagsAreUpdatedWhenContentIsTrashedAndUnTrashed_One() { From d63492bf413d3d4831b2591b5e5bbd0bc026f14b Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 6 Dec 2018 12:41:38 +1100 Subject: [PATCH 09/54] missing nullable parameter in ITagQuery, removes old wrappign logic in PublishedContentQuery --- src/Umbraco.Web/ITagQuery.cs | 2 +- src/Umbraco.Web/PublishedContentQuery.cs | 73 +++++------------------- src/Umbraco.Web/UmbracoHelper.cs | 8 +-- 3 files changed, 19 insertions(+), 64 deletions(-) diff --git a/src/Umbraco.Web/ITagQuery.cs b/src/Umbraco.Web/ITagQuery.cs index 031061ad01..1b96ea330c 100644 --- a/src/Umbraco.Web/ITagQuery.cs +++ b/src/Umbraco.Web/ITagQuery.cs @@ -24,7 +24,7 @@ namespace Umbraco.Web /// /// Gets all media tagged with any tag in the specified group. /// - IEnumerable GetMediaByTagGroup(string group, string culture); + IEnumerable GetMediaByTagGroup(string group, string culture = null); /// /// Gets all tags. diff --git a/src/Umbraco.Web/PublishedContentQuery.cs b/src/Umbraco.Web/PublishedContentQuery.cs index 363607fbcb..e0fac5773f 100644 --- a/src/Umbraco.Web/PublishedContentQuery.cs +++ b/src/Umbraco.Web/PublishedContentQuery.cs @@ -22,7 +22,6 @@ namespace Umbraco.Web /// public class PublishedContentQuery : IPublishedContentQuery { - private readonly IPublishedContentQuery _query; private readonly IPublishedContentCache _contentCache; private readonly IPublishedMediaCache _mediaCache; @@ -37,79 +36,52 @@ namespace Umbraco.Web _mediaCache = mediaCache ?? throw new ArgumentNullException(nameof(mediaCache)); } - /// - /// Constructor used to wrap the ITypedPublishedContentQuery object passed in - /// - /// - public PublishedContentQuery(IPublishedContentQuery query) - { - _query = query ?? throw new ArgumentNullException(nameof(query)); - } - #region Content public IPublishedContent Content(int id) { - return _query == null - ? ItemById(id, _contentCache) - : _query.Content(id); + return ItemById(id, _contentCache); } public IPublishedContent Content(Guid id) { - return _query == null - ? ItemById(id, _contentCache) - : _query.Content(id); + return ItemById(id, _contentCache); } public IPublishedContent Content(Udi id) { if (!(id is GuidUdi udi)) return null; - return _query == null - ? ItemById(udi.Guid, _contentCache) - : _query.Content(udi.Guid); + return ItemById(udi.Guid, _contentCache); } public IPublishedContent ContentSingleAtXPath(string xpath, params XPathVariable[] vars) { - return _query == null - ? ItemByXPath(xpath, vars, _contentCache) - : _query.ContentSingleAtXPath(xpath, vars); + return ItemByXPath(xpath, vars, _contentCache); } public IEnumerable Content(IEnumerable ids) { - return _query == null - ? ItemsByIds(_contentCache, ids) - : _query.Content(ids); + return ItemsByIds(_contentCache, ids); } public IEnumerable Content(IEnumerable ids) { - return _query == null - ? ItemsByIds(_contentCache, ids) - : _query.Content(ids); + return ItemsByIds(_contentCache, ids); } public IEnumerable ContentAtXPath(string xpath, params XPathVariable[] vars) { - return _query == null - ? ItemsByXPath(xpath, vars, _contentCache) - : _query.ContentAtXPath(xpath, vars); + return ItemsByXPath(xpath, vars, _contentCache); } public IEnumerable ContentAtXPath(XPathExpression xpath, params XPathVariable[] vars) { - return _query == null - ? ItemsByXPath(xpath, vars, _contentCache) - : _query.ContentAtXPath(xpath, vars); + return ItemsByXPath(xpath, vars, _contentCache); } public IEnumerable ContentAtRoot() { - return _query == null - ? ItemsAtRoot(_contentCache) - : _query.ContentAtRoot(); + return ItemsAtRoot(_contentCache); } #endregion @@ -118,45 +90,33 @@ namespace Umbraco.Web public IPublishedContent Media(int id) { - return _query == null - ? ItemById(id, _mediaCache) - : _query.Media(id); + return ItemById(id, _mediaCache); } public IPublishedContent Media(Guid id) { - return _query == null - ? ItemById(id, _mediaCache) - : _query.Media(id); + return ItemById(id, _mediaCache); } public IPublishedContent Media(Udi id) { if (!(id is GuidUdi udi)) return null; - return _query == null - ? ItemById(udi.Guid, _mediaCache) - : _query.Media(udi.Guid); + return ItemById(udi.Guid, _mediaCache); } public IEnumerable Media(IEnumerable ids) { - return _query == null - ? ItemsByIds(_mediaCache, ids) - : _query.Media(ids); + return ItemsByIds(_mediaCache, ids); } public IEnumerable Media(IEnumerable ids) { - return _query == null - ? ItemsByIds(_mediaCache, ids) - : _query.Media(ids); + return ItemsByIds(_mediaCache, ids); } public IEnumerable MediaAtRoot() { - return _query == null - ? ItemsAtRoot(_mediaCache) - : _query.MediaAtRoot(); + return ItemsAtRoot(_mediaCache); } @@ -231,8 +191,6 @@ namespace Umbraco.Web { //TODO: Can we inject IExamineManager? - if (_query != null) return _query.Search(skip, take, out totalRecords, term, useWildCards, indexName); - var indexer = string.IsNullOrEmpty(indexName) ? Examine.ExamineManager.Instance.GetIndexer(Constants.Examine.ExternalIndexer) : Examine.ExamineManager.Instance.GetIndexer(indexName); @@ -261,7 +219,6 @@ namespace Umbraco.Web /// public IEnumerable Search(int skip, int take, out int totalRecords, ISearchCriteria criteria, Examine.ISearcher searchProvider = null) { - if (_query != null) return _query.Search(skip, take, out totalRecords, criteria, searchProvider); //TODO: Can we inject IExamineManager? diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs index 1ce7e51a7f..ea66ec13da 100644 --- a/src/Umbraco.Web/UmbracoHelper.cs +++ b/src/Umbraco.Web/UmbracoHelper.cs @@ -33,7 +33,7 @@ namespace Umbraco.Web private readonly CacheHelper _appCache; private IUmbracoComponentRenderer _componentRenderer; - private PublishedContentQuery _query; + private IPublishedContentQuery _query; private MembershipHelper _membershipHelper; private ITagQuery _tag; private IDataTypeService _dataTypeService; @@ -133,10 +133,8 @@ namespace Umbraco.Web /// /// Gets the query context. /// - public PublishedContentQuery ContentQuery => _query ?? - (_query = _iQuery != null - ? new PublishedContentQuery(_iQuery) - : new PublishedContentQuery(UmbracoContext.ContentCache, UmbracoContext.MediaCache)); + public IPublishedContentQuery ContentQuery => _query ?? + (_query = new PublishedContentQuery(UmbracoContext.ContentCache, UmbracoContext.MediaCache)); /// /// Gets the Umbraco context. From 311b523c8e198e237c888dc1981248c49dc17fd2 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 6 Dec 2018 13:12:07 +1100 Subject: [PATCH 10/54] dont' write to console unless compiled in debug --- src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs | 3 +++ src/Umbraco.Core/Persistence/SqlTemplate.cs | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs b/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs index 86839cdaee..cd565c42b4 100644 --- a/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs +++ b/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs @@ -1184,12 +1184,15 @@ namespace Umbraco.Core.Persistence return string.IsNullOrWhiteSpace(attr?.Name) ? column.Name : attr.Name; } + internal static void WriteToConsole(this Sql sql) { +#if DEBUG Console.WriteLine(sql.SQL); var i = 0; foreach (var arg in sql.Arguments) Console.WriteLine($" @{i++}: {arg}"); +#endif } #endregion diff --git a/src/Umbraco.Core/Persistence/SqlTemplate.cs b/src/Umbraco.Core/Persistence/SqlTemplate.cs index 7304f45e7f..403b81e5de 100644 --- a/src/Umbraco.Core/Persistence/SqlTemplate.cs +++ b/src/Umbraco.Core/Persistence/SqlTemplate.cs @@ -97,7 +97,9 @@ namespace Umbraco.Core.Persistence internal void WriteToConsole() { +#if DEBUG new Sql(_sqlContext, _sql, _args.Values.ToArray()).WriteToConsole(); +#endif } /// From 65370cf4e6dae92bf420dbe1ab4556288fce3afb Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 6 Dec 2018 10:20:40 +0100 Subject: [PATCH 11/54] Fix copying tags when (un)variant --- .../Repositories/Implement/ContentTypeRepositoryBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index cd9681fbda..493eb33c82 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -811,7 +811,7 @@ AND umbracoNode.id <> @id", sqlSelect .InnerJoin().On((tag, rel) => tag.Id == rel.TagId) - .LeftJoin("xtags").On((tag, xtag) => tag.Text == xtag.Text && tag.Group == xtag.Group && tag.LanguageId.SqlNullableEquals(targetLanguageId, -1), aliasRight: "xtags"); + .LeftJoin("xtags").On((tag, xtag) => tag.Text == xtag.Text && tag.Group == xtag.Group && xtag.LanguageId.SqlNullableEquals(targetLanguageId, -1), aliasRight: "xtags"); if (contentTypeIds != null) sqlSelect From ccd0437b2e91329e8563cfb163e5f16ab6a776bd Mon Sep 17 00:00:00 2001 From: Stephan Date: Fri, 7 Dec 2018 12:06:25 +0100 Subject: [PATCH 12/54] Disable media tests that use Examine (no point) --- src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs index 784f534af4..508a005663 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs @@ -111,6 +111,7 @@ namespace Umbraco.Tests.PublishedContent } [Test] + [Ignore("No point testing with Examine, should refactor this test.")] public void Ensure_Children_Sorted_With_Examine() { var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Container.GetInstance(), IndexInitializer.GetMockMediaService()); @@ -138,6 +139,7 @@ namespace Umbraco.Tests.PublishedContent } [Test] + [Ignore("No point testing with Examine, should refactor this test.")] public void Do_Not_Find_In_Recycle_Bin() { var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Container.GetInstance(), IndexInitializer.GetMockMediaService()); @@ -185,6 +187,7 @@ namespace Umbraco.Tests.PublishedContent } [Test] + [Ignore("No point testing with Examine, should refactor this test.")] public void Children_With_Examine() { var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Container.GetInstance(), IndexInitializer.GetMockMediaService()); @@ -212,6 +215,7 @@ namespace Umbraco.Tests.PublishedContent } [Test] + [Ignore("No point testing with Examine, should refactor this test.")] public void Descendants_With_Examine() { var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Container.GetInstance(), IndexInitializer.GetMockMediaService()); @@ -239,6 +243,7 @@ namespace Umbraco.Tests.PublishedContent } [Test] + [Ignore("No point testing with Examine, should refactor this test.")] public void DescendantsOrSelf_With_Examine() { var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Container.GetInstance(), IndexInitializer.GetMockMediaService()); @@ -266,6 +271,7 @@ namespace Umbraco.Tests.PublishedContent } [Test] + [Ignore("No point testing with Examine, should refactor this test.")] public void Ancestors_With_Examine() { var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Container.GetInstance(), IndexInitializer.GetMockMediaService()); @@ -291,6 +297,7 @@ namespace Umbraco.Tests.PublishedContent } [Test] + [Ignore("No point testing with Examine, should refactor this test.")] public void AncestorsOrSelf_With_Examine() { var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Container.GetInstance(), IndexInitializer.GetMockMediaService()); From 1919fa8a0342b74d8d397c5c675cced3e459fb11 Mon Sep 17 00:00:00 2001 From: Stephan Date: Fri, 7 Dec 2018 12:44:54 +0100 Subject: [PATCH 13/54] Fix some tests --- .../ControllerTesting/TestControllerActivatorBase.cs | 3 --- src/Umbraco.Tests/Testing/TestingTests/MockTests.cs | 1 - src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs | 10 +++++++--- src/Umbraco.Web/UmbracoHelper.cs | 10 ++-------- 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs index c65faf76c9..2cf64f04d1 100644 --- a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs +++ b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs @@ -163,11 +163,8 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting var membershipHelper = new MembershipHelper(umbCtx, Mock.Of(), Mock.Of()); - var mockedTypedContent = Mock.Of(); - var umbHelper = new UmbracoHelper(umbCtx, Mock.Of(), - mockedTypedContent, Mock.Of(), Mock.Of(), Mock.Of(), diff --git a/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs b/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs index d5f5778d1a..51855f7e19 100644 --- a/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs +++ b/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs @@ -60,7 +60,6 @@ namespace Umbraco.Tests.Testing.TestingTests // ReSharper disable once UnusedVariable var helper = new UmbracoHelper(umbracoContext, Mock.Of(), - Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), diff --git a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs index 81f338da87..dce975d0c4 100644 --- a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs @@ -103,6 +103,13 @@ namespace Umbraco.Tests.Web.Mvc { var publishedSnapshot = new Mock(); publishedSnapshot.Setup(x => x.Members).Returns(Mock.Of()); + var contentCache = new Mock(); + var content = new Mock(); + content.Setup(x => x.Id).Returns(2); + contentCache.Setup(x => x.GetById(It.IsAny())).Returns(content.Object); + var mediaCache = new Mock(); + publishedSnapshot.Setup(x => x.Content).Returns(contentCache.Object); + publishedSnapshot.Setup(x => x.Media).Returns(mediaCache.Object); var publishedSnapshotService = new Mock(); publishedSnapshotService.Setup(x => x.CreatePublishedSnapshot(It.IsAny())).Returns(publishedSnapshot.Object); var globalSettings = TestObjects.GetGlobalSettings(); @@ -121,9 +128,6 @@ namespace Umbraco.Tests.Web.Mvc var helper = new UmbracoHelper( umbracoContext, Mock.Of(), - Mock.Of(query => query.Content(It.IsAny()) == - //return mock of IPublishedContent for any call to GetById - Mock.Of(content => content.Id == 2)), Mock.Of(), Mock.Of(), Mock.Of(), diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs index 297f586ebe..9698e3e024 100644 --- a/src/Umbraco.Web/UmbracoHelper.cs +++ b/src/Umbraco.Web/UmbracoHelper.cs @@ -11,7 +11,6 @@ using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; using Umbraco.Core.Xml; using Umbraco.Web.Composing; -using Umbraco.Core.Cache; using Umbraco.Web.Routing; using Umbraco.Web.Security; @@ -28,7 +27,6 @@ namespace Umbraco.Web private readonly UmbracoContext _umbracoContext; private readonly IPublishedContent _currentPage; - private readonly IPublishedContentQuery _iQuery; private readonly ServiceContext _services; private IUmbracoComponentRenderer _componentRenderer; @@ -44,22 +42,18 @@ namespace Umbraco.Web /// /// For tests. internal UmbracoHelper(UmbracoContext umbracoContext, IPublishedContent content, - IPublishedContentQuery query, ITagQuery tagQuery, ICultureDictionary cultureDictionary, IUmbracoComponentRenderer componentRenderer, MembershipHelper membershipHelper, ServiceContext services) { - if (tagQuery == null) throw new ArgumentNullException(nameof(tagQuery)); - _umbracoContext = umbracoContext ?? throw new ArgumentNullException(nameof(umbracoContext)); - _tag = tagQuery; + _tag = tagQuery ?? throw new ArgumentNullException(nameof(tagQuery)); _cultureDictionary = cultureDictionary ?? throw new ArgumentNullException(nameof(cultureDictionary)); _componentRenderer = componentRenderer ?? throw new ArgumentNullException(nameof(componentRenderer)); _membershipHelper = membershipHelper ?? throw new ArgumentNullException(nameof(membershipHelper)); _currentPage = content ?? throw new ArgumentNullException(nameof(content)); - _iQuery = query ?? throw new ArgumentNullException(nameof(query)); _services = services ?? throw new ArgumentNullException(nameof(services)); } @@ -105,7 +99,7 @@ namespace Umbraco.Web /// Gets the tag context. /// public ITagQuery TagQuery => _tag ?? - (_tag = new TagQuery(_services.TagService, _iQuery ?? ContentQuery)); + (_tag = new TagQuery(_services.TagService, ContentQuery)); /// /// Gets the query context. From 41b7d33d9a3ac1e4d1c3481a4872eef40a0e59a9 Mon Sep 17 00:00:00 2001 From: Stephan Date: Fri, 7 Dec 2018 13:01:18 +0100 Subject: [PATCH 14/54] Cleanup test --- src/Umbraco.Tests/UmbracoExamine/IndexTest.cs | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/Umbraco.Tests/UmbracoExamine/IndexTest.cs b/src/Umbraco.Tests/UmbracoExamine/IndexTest.cs index 78bdb37cae..29abfb9234 100644 --- a/src/Umbraco.Tests/UmbracoExamine/IndexTest.cs +++ b/src/Umbraco.Tests/UmbracoExamine/IndexTest.cs @@ -187,21 +187,21 @@ namespace Umbraco.Tests.UmbracoExamine [Test] public void Index_Move_Media_From_Non_Indexable_To_Indexable_ParentID() { + // create a validator with + // publishedValuesOnly false + // parentId 1116 (only content under that parent will be indexed) + var validator = new ContentValueSetValidator(false, 1116); using (var luceneDir = new RandomIdRamDirectory()) - using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, - //make parent id 1116 - validator: new ContentValueSetValidator(false, 1116))) + using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, validator: validator)) using (indexer.ProcessNonAsync()) { var searcher = indexer.GetSearcher(); //get a node from the data repo (this one exists underneath 2222) var node = _mediaService.GetLatestMediaByXpath("//*[string-length(@id)>0 and number(@id)>0]") - .Root - .Elements() - .Where(x => (int)x.Attribute("id") == 2112) - .First(); + .Root.Elements() + .First(x => (int) x.Attribute("id") == 2112); var currPath = (string)node.Attribute("path"); //should be : -1,1111,2222,2112 Assert.AreEqual("-1,1111,2222,2112", currPath); @@ -230,20 +230,21 @@ namespace Umbraco.Tests.UmbracoExamine [Test] public void Index_Move_Media_To_Non_Indexable_ParentID() { + // create a validator with + // publishedValuesOnly false + // parentId 2222 (only content under that parent will be indexed) + var validator = new ContentValueSetValidator(false, 2222); + using (var luceneDir = new RandomIdRamDirectory()) - using (var indexer1 = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, - //make parent id 2222 - validator: new ContentValueSetValidator(false, 2222))) + using (var indexer1 = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, validator: validator)) using (indexer1.ProcessNonAsync()) { var searcher = indexer1.GetSearcher(); //get a node from the data repo (this one exists underneath 2222) var node = _mediaService.GetLatestMediaByXpath("//*[string-length(@id)>0 and number(@id)>0]") - .Root - .Elements() - .Where(x => (int)x.Attribute("id") == 2112) - .First(); + .Root.Elements() + .First(x => (int) x.Attribute("id") == 2112); var currPath = (string)node.Attribute("path"); //should be : -1,1111,2222,2112 Assert.AreEqual("-1,1111,2222,2112", currPath); @@ -251,8 +252,6 @@ namespace Umbraco.Tests.UmbracoExamine //ensure it's indexed indexer1.IndexItem(node.ConvertToValueSet(IndexTypes.Media)); - - //it will exist because it exists under 2222 var results = searcher.Search(searcher.CreateCriteria().Id(2112).Compile()); Assert.AreEqual(1, results.Count()); @@ -264,8 +263,6 @@ namespace Umbraco.Tests.UmbracoExamine //now reindex the node, this should first delete it and then NOT add it because of the parent id constraint indexer1.IndexItems(new[] { node.ConvertToValueSet(IndexTypes.Media) }); - - //now ensure it's deleted results = searcher.Search(searcher.CreateCriteria().Id(2112).Compile()); Assert.AreEqual(0, results.Count()); From db1a535af4c39f64cb4d2deac6a64f756e7c119f Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 10 Dec 2018 14:06:25 +1100 Subject: [PATCH 15/54] Fixes published media tests with Examine and un-ignores them... more tests are better than less even if we aren't using Examine for real media cache --- src/Umbraco.Examine/ExamineExtensions.cs | 29 +++++++++++++++++++ .../Properties/AssemblyInfo.cs | 1 + .../PublishedContent/PublishedMediaTests.cs | 17 ++++++----- src/Umbraco.Web/Search/ExamineComponent.cs | 18 +----------- 4 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/Umbraco.Examine/ExamineExtensions.cs b/src/Umbraco.Examine/ExamineExtensions.cs index 3681979267..71e3e65c21 100644 --- a/src/Umbraco.Examine/ExamineExtensions.cs +++ b/src/Umbraco.Examine/ExamineExtensions.cs @@ -1,8 +1,11 @@ using System; +using System.Linq; +using Examine; using Examine.LuceneEngine.Providers; using Lucene.Net.Index; using Lucene.Net.Search; using Lucene.Net.Store; +using Umbraco.Core.Logging; namespace Umbraco.Examine { @@ -11,6 +14,32 @@ namespace Umbraco.Examine /// internal static class ExamineExtensions { + /// + /// Forcibly unlocks all lucene based indexes + /// + /// + /// This is not thread safe, use with care + /// + internal static void UnlockLuceneIndexes(this IExamineManager examineManager, ILogger logger) + { + foreach (var luceneIndexer in examineManager.Indexes.OfType()) + { + //We now need to disable waiting for indexing for Examine so that the appdomain is shutdown immediately and doesn't wait for pending + //indexing operations. We used to wait for indexing operations to complete but this can cause more problems than that is worth because + //that could end up halting shutdown for a very long time causing overlapping appdomains and many other problems. + luceneIndexer.WaitForIndexQueueOnShutdown = false; + + //we should check if the index is locked ... it shouldn't be! We are using simple fs lock now and we are also ensuring that + //the indexes are not operational unless MainDom is true + var dir = luceneIndexer.GetLuceneDirectory(); + if (IndexWriter.IsLocked(dir)) + { + logger.Info(typeof(ExamineExtensions), "Forcing index {IndexerName} to be unlocked since it was left in a locked state", luceneIndexer.Name); + IndexWriter.Unlock(dir); + } + } + } + /// /// Checks if the index can be read/opened /// diff --git a/src/Umbraco.Examine/Properties/AssemblyInfo.cs b/src/Umbraco.Examine/Properties/AssemblyInfo.cs index 6713111968..5c42a236f4 100644 --- a/src/Umbraco.Examine/Properties/AssemblyInfo.cs +++ b/src/Umbraco.Examine/Properties/AssemblyInfo.cs @@ -8,6 +8,7 @@ using System.Runtime.CompilerServices; // Umbraco Cms [assembly: InternalsVisibleTo("Umbraco.Tests")] +[assembly: InternalsVisibleTo("Umbraco.Web")] // code analysis // IDE1006 is broken, wants _value syntax for consts, etc - and it's even confusing ppl at MS, kill it diff --git a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs index 508a005663..d14ffb5001 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs @@ -106,12 +106,11 @@ namespace Umbraco.Tests.PublishedContent Assert.AreEqual("
This is some content
", propVal2.ToString()); var propVal3 = publishedMedia.Value("Content"); - Assert.IsInstanceOf(propVal3); + Assert.IsInstanceOf(propVal3); Assert.AreEqual("
This is some content
", propVal3.ToString()); } [Test] - [Ignore("No point testing with Examine, should refactor this test.")] public void Ensure_Children_Sorted_With_Examine() { var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Container.GetInstance(), IndexInitializer.GetMockMediaService()); @@ -119,7 +118,9 @@ namespace Umbraco.Tests.PublishedContent using (var luceneDir = new RandomIdRamDirectory()) using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, validator: new ContentValueSetValidator(true))) + using (indexer.ProcessNonAsync()) { + rebuilder.RegisterIndex(indexer.Name); rebuilder.Populate(indexer); var searcher = indexer.GetSearcher(); @@ -139,7 +140,6 @@ namespace Umbraco.Tests.PublishedContent } [Test] - [Ignore("No point testing with Examine, should refactor this test.")] public void Do_Not_Find_In_Recycle_Bin() { var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Container.GetInstance(), IndexInitializer.GetMockMediaService()); @@ -150,6 +150,7 @@ namespace Umbraco.Tests.PublishedContent validator: new ContentValueSetValidator(true))) using (indexer.ProcessNonAsync()) { + rebuilder.RegisterIndex(indexer.Name); rebuilder.Populate(indexer); var searcher = indexer.GetSearcher(); @@ -187,7 +188,6 @@ namespace Umbraco.Tests.PublishedContent } [Test] - [Ignore("No point testing with Examine, should refactor this test.")] public void Children_With_Examine() { var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Container.GetInstance(), IndexInitializer.GetMockMediaService()); @@ -197,6 +197,7 @@ namespace Umbraco.Tests.PublishedContent validator: new ContentValueSetValidator(true))) using (indexer.ProcessNonAsync()) { + rebuilder.RegisterIndex(indexer.Name); rebuilder.Populate(indexer); var searcher = indexer.GetSearcher(); @@ -215,7 +216,6 @@ namespace Umbraco.Tests.PublishedContent } [Test] - [Ignore("No point testing with Examine, should refactor this test.")] public void Descendants_With_Examine() { var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Container.GetInstance(), IndexInitializer.GetMockMediaService()); @@ -225,6 +225,7 @@ namespace Umbraco.Tests.PublishedContent validator: new ContentValueSetValidator(true))) using (indexer.ProcessNonAsync()) { + rebuilder.RegisterIndex(indexer.Name); rebuilder.Populate(indexer); var searcher = indexer.GetSearcher(); @@ -243,7 +244,6 @@ namespace Umbraco.Tests.PublishedContent } [Test] - [Ignore("No point testing with Examine, should refactor this test.")] public void DescendantsOrSelf_With_Examine() { var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Container.GetInstance(), IndexInitializer.GetMockMediaService()); @@ -253,6 +253,7 @@ namespace Umbraco.Tests.PublishedContent validator: new ContentValueSetValidator(true))) using (indexer.ProcessNonAsync()) { + rebuilder.RegisterIndex(indexer.Name); rebuilder.Populate(indexer); var searcher = indexer.GetSearcher(); @@ -271,7 +272,6 @@ namespace Umbraco.Tests.PublishedContent } [Test] - [Ignore("No point testing with Examine, should refactor this test.")] public void Ancestors_With_Examine() { var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Container.GetInstance(), IndexInitializer.GetMockMediaService()); @@ -282,6 +282,7 @@ namespace Umbraco.Tests.PublishedContent validator: new ContentValueSetValidator(true))) using (indexer.ProcessNonAsync()) { + rebuilder.RegisterIndex(indexer.Name); rebuilder.Populate(indexer); var ctx = GetUmbracoContext("/test"); @@ -297,7 +298,6 @@ namespace Umbraco.Tests.PublishedContent } [Test] - [Ignore("No point testing with Examine, should refactor this test.")] public void AncestorsOrSelf_With_Examine() { var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Container.GetInstance(), IndexInitializer.GetMockMediaService()); @@ -307,6 +307,7 @@ namespace Umbraco.Tests.PublishedContent validator: new ContentValueSetValidator(true))) using (indexer.ProcessNonAsync()) { + rebuilder.RegisterIndex(indexer.Name); rebuilder.Populate(indexer); diff --git a/src/Umbraco.Web/Search/ExamineComponent.cs b/src/Umbraco.Web/Search/ExamineComponent.cs index d8c1016c3e..f2d3168b45 100644 --- a/src/Umbraco.Web/Search/ExamineComponent.cs +++ b/src/Umbraco.Web/Search/ExamineComponent.cs @@ -219,23 +219,7 @@ namespace Umbraco.Web.Search if (_isConfigured) return; _isConfigured = true; - - foreach (var luceneIndexer in examineManager.Indexes.OfType()) - { - //We now need to disable waiting for indexing for Examine so that the appdomain is shutdown immediately and doesn't wait for pending - //indexing operations. We used to wait for indexing operations to complete but this can cause more problems than that is worth because - //that could end up halting shutdown for a very long time causing overlapping appdomains and many other problems. - luceneIndexer.WaitForIndexQueueOnShutdown = false; - - //we should check if the index is locked ... it shouldn't be! We are using simple fs lock now and we are also ensuring that - //the indexes are not operational unless MainDom is true - var dir = luceneIndexer.GetLuceneDirectory(); - if (IndexWriter.IsLocked(dir)) - { - logger.Info("Forcing index {IndexerName} to be unlocked since it was left in a locked state", luceneIndexer.Name); - IndexWriter.Unlock(dir); - } - } + examineManager.UnlockLuceneIndexes(logger); } } From 971e92d65993e54da703d7f45c21719182fa940c Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 10 Dec 2018 14:11:41 +1100 Subject: [PATCH 16/54] fixes last PublishedMediaTests --- src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs index d14ffb5001..d5fdd2bf0c 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs @@ -147,7 +147,7 @@ namespace Umbraco.Tests.PublishedContent using (var luceneDir = new RandomIdRamDirectory()) using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, //include unpublished content since this uses the 'internal' indexer, it's up to the media cache to filter - validator: new ContentValueSetValidator(true))) + validator: new ContentValueSetValidator(false))) using (indexer.ProcessNonAsync()) { rebuilder.RegisterIndex(indexer.Name); From c80a9b1402779ca3ef77ca4dd77be11df3c0ad1e Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 10 Dec 2018 17:26:15 +1100 Subject: [PATCH 17/54] Fixes the typeahead (mostly) --- src/Umbraco.Web.UI.Client/package-lock.json | 5614 ++++++++--------- .../components/events/events.directive.js | 4 +- .../imaging/umbimagecrop.directive.js | 2 +- .../imaging/umbimagethumbnail.directive.js | 48 +- .../tags/umbtagseditor.directive.js | 63 +- .../src/less/typeahead.less | 4 +- .../components/tags/umb-tags-editor.html | 1 - 7 files changed, 2858 insertions(+), 2878 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index cfba283cc7..fcfe5cd3b3 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -8,7 +8,7 @@ "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", "dev": true, "requires": { - "@babel/highlight": "7.0.0" + "@babel/highlight": "^7.0.0" } }, "@babel/core": { @@ -17,20 +17,20 @@ "integrity": "sha512-Hz6PJT6e44iUNpAn8AoyAs6B3bl60g7MJQaI0rZEar6ECzh6+srYO1xlIdssio34mPaUtAb1y+XlkkSJzok3yw==", "dev": true, "requires": { - "@babel/code-frame": "7.0.0", - "@babel/generator": "7.1.6", - "@babel/helpers": "7.1.5", - "@babel/parser": "7.1.6", - "@babel/template": "7.1.2", - "@babel/traverse": "7.1.6", - "@babel/types": "7.1.6", - "convert-source-map": "1.6.0", - "debug": "4.1.0", - "json5": "2.1.0", - "lodash": "4.17.11", - "resolve": "1.8.1", - "semver": "5.6.0", - "source-map": "0.5.7" + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.1.6", + "@babel/helpers": "^7.1.5", + "@babel/parser": "^7.1.6", + "@babel/template": "^7.1.2", + "@babel/traverse": "^7.1.6", + "@babel/types": "^7.1.6", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.10", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" } }, "@babel/generator": { @@ -39,11 +39,11 @@ "integrity": "sha512-brwPBtVvdYdGxtenbQgfCdDPmtkmUBZPjUoK5SXJEBuHaA5BCubh9ly65fzXz7R6o5rA76Rs22ES8Z+HCc0YIQ==", "dev": true, "requires": { - "@babel/types": "7.1.6", - "jsesc": "2.5.2", - "lodash": "4.17.11", - "source-map": "0.5.7", - "trim-right": "1.0.1" + "@babel/types": "^7.1.6", + "jsesc": "^2.5.1", + "lodash": "^4.17.10", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" } }, "@babel/helper-annotate-as-pure": { @@ -52,7 +52,7 @@ "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", "dev": true, "requires": { - "@babel/types": "7.1.6" + "@babel/types": "^7.0.0" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { @@ -61,8 +61,8 @@ "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", "dev": true, "requires": { - "@babel/helper-explode-assignable-expression": "7.1.0", - "@babel/types": "7.1.6" + "@babel/helper-explode-assignable-expression": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helper-call-delegate": { @@ -71,9 +71,9 @@ "integrity": "sha512-YEtYZrw3GUK6emQHKthltKNZwszBcHK58Ygcis+gVUrF4/FmTVr5CCqQNSfmvg2y+YDEANyYoaLz/SHsnusCwQ==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "7.0.0", - "@babel/traverse": "7.1.6", - "@babel/types": "7.1.6" + "@babel/helper-hoist-variables": "^7.0.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helper-define-map": { @@ -82,9 +82,9 @@ "integrity": "sha512-yPPcW8dc3gZLN+U1mhYV91QU3n5uTbx7DUdf8NnPbjS0RMwBuHi9Xt2MUgppmNz7CJxTBWsGczTiEp1CSOTPRg==", "dev": true, "requires": { - "@babel/helper-function-name": "7.1.0", - "@babel/types": "7.1.6", - "lodash": "4.17.11" + "@babel/helper-function-name": "^7.1.0", + "@babel/types": "^7.0.0", + "lodash": "^4.17.10" } }, "@babel/helper-explode-assignable-expression": { @@ -93,8 +93,8 @@ "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", "dev": true, "requires": { - "@babel/traverse": "7.1.6", - "@babel/types": "7.1.6" + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helper-function-name": { @@ -103,9 +103,9 @@ "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "7.0.0", - "@babel/template": "7.1.2", - "@babel/types": "7.1.6" + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helper-get-function-arity": { @@ -114,7 +114,7 @@ "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", "dev": true, "requires": { - "@babel/types": "7.1.6" + "@babel/types": "^7.0.0" } }, "@babel/helper-hoist-variables": { @@ -123,7 +123,7 @@ "integrity": "sha512-Ggv5sldXUeSKsuzLkddtyhyHe2YantsxWKNi7A+7LeD12ExRDWTRk29JCXpaHPAbMaIPZSil7n+lq78WY2VY7w==", "dev": true, "requires": { - "@babel/types": "7.1.6" + "@babel/types": "^7.0.0" } }, "@babel/helper-member-expression-to-functions": { @@ -132,7 +132,7 @@ "integrity": "sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==", "dev": true, "requires": { - "@babel/types": "7.1.6" + "@babel/types": "^7.0.0" } }, "@babel/helper-module-imports": { @@ -141,7 +141,7 @@ "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", "dev": true, "requires": { - "@babel/types": "7.1.6" + "@babel/types": "^7.0.0" } }, "@babel/helper-module-transforms": { @@ -150,12 +150,12 @@ "integrity": "sha512-0JZRd2yhawo79Rcm4w0LwSMILFmFXjugG3yqf+P/UsKsRS1mJCmMwwlHDlMg7Avr9LrvSpp4ZSULO9r8jpCzcw==", "dev": true, "requires": { - "@babel/helper-module-imports": "7.0.0", - "@babel/helper-simple-access": "7.1.0", - "@babel/helper-split-export-declaration": "7.0.0", - "@babel/template": "7.1.2", - "@babel/types": "7.1.6", - "lodash": "4.17.11" + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0", + "lodash": "^4.17.10" } }, "@babel/helper-optimise-call-expression": { @@ -164,7 +164,7 @@ "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", "dev": true, "requires": { - "@babel/types": "7.1.6" + "@babel/types": "^7.0.0" } }, "@babel/helper-plugin-utils": { @@ -179,7 +179,7 @@ "integrity": "sha512-TR0/N0NDCcUIUEbqV6dCO+LptmmSQFQ7q70lfcEB4URsjD0E1HzicrwUH+ap6BAQ2jhCX9Q4UqZy4wilujWlkg==", "dev": true, "requires": { - "lodash": "4.17.11" + "lodash": "^4.17.10" } }, "@babel/helper-remap-async-to-generator": { @@ -188,11 +188,11 @@ "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "7.0.0", - "@babel/helper-wrap-function": "7.1.0", - "@babel/template": "7.1.2", - "@babel/traverse": "7.1.6", - "@babel/types": "7.1.6" + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-wrap-function": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helper-replace-supers": { @@ -201,10 +201,10 @@ "integrity": "sha512-BvcDWYZRWVuDeXTYZWxekQNO5D4kO55aArwZOTFXw6rlLQA8ZaDicJR1sO47h+HrnCiDFiww0fSPV0d713KBGQ==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "7.0.0", - "@babel/helper-optimise-call-expression": "7.0.0", - "@babel/traverse": "7.1.6", - "@babel/types": "7.1.6" + "@babel/helper-member-expression-to-functions": "^7.0.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helper-simple-access": { @@ -213,8 +213,8 @@ "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", "dev": true, "requires": { - "@babel/template": "7.1.2", - "@babel/types": "7.1.6" + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helper-split-export-declaration": { @@ -223,7 +223,7 @@ "integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==", "dev": true, "requires": { - "@babel/types": "7.1.6" + "@babel/types": "^7.0.0" } }, "@babel/helper-wrap-function": { @@ -232,10 +232,10 @@ "integrity": "sha512-R6HU3dete+rwsdAfrOzTlE9Mcpk4RjU3aX3gi9grtmugQY0u79X7eogUvfXA5sI81Mfq1cn6AgxihfN33STjJA==", "dev": true, "requires": { - "@babel/helper-function-name": "7.1.0", - "@babel/template": "7.1.2", - "@babel/traverse": "7.1.6", - "@babel/types": "7.1.6" + "@babel/helper-function-name": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helpers": { @@ -244,9 +244,9 @@ "integrity": "sha512-2jkcdL02ywNBry1YNFAH/fViq4fXG0vdckHqeJk+75fpQ2OH+Az6076tX/M0835zA45E0Cqa6pV5Kiv9YOqjEg==", "dev": true, "requires": { - "@babel/template": "7.1.2", - "@babel/traverse": "7.1.6", - "@babel/types": "7.1.6" + "@babel/template": "^7.1.2", + "@babel/traverse": "^7.1.5", + "@babel/types": "^7.1.5" } }, "@babel/highlight": { @@ -255,9 +255,9 @@ "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", "dev": true, "requires": { - "chalk": "2.4.1", - "esutils": "2.0.2", - "js-tokens": "4.0.0" + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" } }, "@babel/parser": { @@ -272,9 +272,9 @@ "integrity": "sha512-Fq803F3Jcxo20MXUSDdmZZXrPe6BWyGcWBPPNB/M7WaUYESKDeKMOGIxEzQOjGSmW/NWb6UaPZrtTB2ekhB/ew==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-remap-async-to-generator": "7.1.0", - "@babel/plugin-syntax-async-generators": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0", + "@babel/plugin-syntax-async-generators": "^7.0.0" } }, "@babel/plugin-proposal-json-strings": { @@ -283,8 +283,8 @@ "integrity": "sha512-kfVdUkIAGJIVmHmtS/40i/fg/AGnw/rsZBCaapY5yjeO5RA9m165Xbw9KMOu2nqXP5dTFjEjHdfNdoVcHv133Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/plugin-syntax-json-strings": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-json-strings": "^7.0.0" } }, "@babel/plugin-proposal-object-rest-spread": { @@ -293,8 +293,8 @@ "integrity": "sha512-14fhfoPcNu7itSen7Py1iGN0gEm87hX/B+8nZPqkdmANyyYWYMY2pjA3r8WXbWVKMzfnSNS0xY8GVS0IjXi/iw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/plugin-syntax-object-rest-spread": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.0.0" } }, "@babel/plugin-proposal-optional-catch-binding": { @@ -303,8 +303,8 @@ "integrity": "sha512-JPqAvLG1s13B/AuoBjdBYvn38RqW6n1TzrQO839/sIpqLpbnXKacsAgpZHzLD83Sm8SDXMkkrAvEnJ25+0yIpw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/plugin-syntax-optional-catch-binding": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.0.0" } }, "@babel/plugin-proposal-unicode-property-regex": { @@ -313,9 +313,9 @@ "integrity": "sha512-tM3icA6GhC3ch2SkmSxv7J/hCWKISzwycub6eGsDrFDgukD4dZ/I+x81XgW0YslS6mzNuQ1Cbzh5osjIMgepPQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-regex": "7.0.0", - "regexpu-core": "4.2.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.2.0" } }, "@babel/plugin-syntax-async-generators": { @@ -324,7 +324,7 @@ "integrity": "sha512-im7ged00ddGKAjcZgewXmp1vxSZQQywuQXe2B1A7kajjZmDeY/ekMPmWr9zJgveSaQH0k7BcGrojQhcK06l0zA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-syntax-json-strings": { @@ -333,7 +333,7 @@ "integrity": "sha512-UlSfNydC+XLj4bw7ijpldc1uZ/HB84vw+U6BTuqMdIEmz/LDe63w/GHtpQMdXWdqQZFeAI9PjnHe/vDhwirhKA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-syntax-object-rest-spread": { @@ -342,7 +342,7 @@ "integrity": "sha512-5A0n4p6bIiVe5OvQPxBnesezsgFJdHhSs3uFSvaPdMqtsovajLZ+G2vZyvNe10EzJBWWo3AcHGKhAFUxqwp2dw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-syntax-optional-catch-binding": { @@ -351,7 +351,7 @@ "integrity": "sha512-Wc+HVvwjcq5qBg1w5RG9o9RVzmCaAg/Vp0erHCKpAYV8La6I94o4GQAmFYNmkzoMO6gzoOSulpKeSSz6mPEoZw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-arrow-functions": { @@ -360,7 +360,7 @@ "integrity": "sha512-2EZDBl1WIO/q4DIkIp4s86sdp4ZifL51MoIviLY/gG/mLSuOIEg7J8o6mhbxOTvUJkaN50n+8u41FVsr5KLy/w==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-async-to-generator": { @@ -369,9 +369,9 @@ "integrity": "sha512-rNmcmoQ78IrvNCIt/R9U+cixUHeYAzgusTFgIAv+wQb9HJU4szhpDD6e5GCACmj/JP5KxuCwM96bX3L9v4ZN/g==", "dev": true, "requires": { - "@babel/helper-module-imports": "7.0.0", - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-remap-async-to-generator": "7.1.0" + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0" } }, "@babel/plugin-transform-block-scoped-functions": { @@ -380,7 +380,7 @@ "integrity": "sha512-AOBiyUp7vYTqz2Jibe1UaAWL0Hl9JUXEgjFvvvcSc9MVDItv46ViXFw2F7SVt1B5k+KWjl44eeXOAk3UDEaJjQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-block-scoping": { @@ -389,8 +389,8 @@ "integrity": "sha512-jlYcDrz+5ayWC7mxgpn1Wj8zj0mmjCT2w0mPIMSwO926eXBRxpEgoN/uQVRBfjtr8ayjcmS+xk2G1jaP8JjMJQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "lodash": "4.17.11" + "@babel/helper-plugin-utils": "^7.0.0", + "lodash": "^4.17.10" } }, "@babel/plugin-transform-classes": { @@ -399,14 +399,14 @@ "integrity": "sha512-rNaqoD+4OCBZjM7VaskladgqnZ1LO6o2UxuWSDzljzW21pN1KXkB7BstAVweZdxQkHAujps5QMNOTWesBciKFg==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "7.0.0", - "@babel/helper-define-map": "7.1.0", - "@babel/helper-function-name": "7.1.0", - "@babel/helper-optimise-call-expression": "7.0.0", - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-replace-supers": "7.1.0", - "@babel/helper-split-export-declaration": "7.0.0", - "globals": "11.9.0" + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-define-map": "^7.1.0", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { @@ -415,7 +415,7 @@ "integrity": "sha512-ubouZdChNAv4AAWAgU7QKbB93NU5sHwInEWfp+/OzJKA02E6Woh9RVoX4sZrbRwtybky/d7baTUqwFx+HgbvMA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-destructuring": { @@ -424,7 +424,7 @@ "integrity": "sha512-Mb9M4DGIOspH1ExHOUnn2UUXFOyVTiX84fXCd+6B5iWrQg/QMeeRmSwpZ9lnjYLSXtZwiw80ytVMr3zue0ucYw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-dotall-regex": { @@ -433,9 +433,9 @@ "integrity": "sha512-00THs8eJxOJUFVx1w8i1MBF4XH4PsAjKjQ1eqN/uCH3YKwP21GCKfrn6YZFZswbOk9+0cw1zGQPHVc1KBlSxig==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-regex": "7.0.0", - "regexpu-core": "4.2.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.1.3" } }, "@babel/plugin-transform-duplicate-keys": { @@ -444,7 +444,7 @@ "integrity": "sha512-w2vfPkMqRkdxx+C71ATLJG30PpwtTpW7DDdLqYt2acXU7YjztzeWW2Jk1T6hKqCLYCcEA5UQM/+xTAm+QCSnuQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-exponentiation-operator": { @@ -453,8 +453,8 @@ "integrity": "sha512-uZt9kD1Pp/JubkukOGQml9tqAeI8NkE98oZnHZ2qHRElmeKCodbTZgOEUtujSCSLhHSBWbzNiFSDIMC4/RBTLQ==", "dev": true, "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "7.1.0", - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-for-of": { @@ -463,7 +463,7 @@ "integrity": "sha512-TlxKecN20X2tt2UEr2LNE6aqA0oPeMT1Y3cgz8k4Dn1j5ObT8M3nl9aA37LLklx0PBZKETC9ZAf9n/6SujTuXA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-function-name": { @@ -472,8 +472,8 @@ "integrity": "sha512-VxOa1TMlFMtqPW2IDYZQaHsFrq/dDoIjgN098NowhexhZcz3UGlvPgZXuE1jEvNygyWyxRacqDpCZt+par1FNg==", "dev": true, "requires": { - "@babel/helper-function-name": "7.1.0", - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-literals": { @@ -482,7 +482,7 @@ "integrity": "sha512-1NTDBWkeNXgpUcyoVFxbr9hS57EpZYXpje92zv0SUzjdu3enaRwF/l3cmyRnXLtIdyJASyiS6PtybK+CgKf7jA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-modules-amd": { @@ -491,8 +491,8 @@ "integrity": "sha512-wt8P+xQ85rrnGNr2x1iV3DW32W8zrB6ctuBkYBbf5/ZzJY99Ob4MFgsZDFgczNU76iy9PWsy4EuxOliDjdKw6A==", "dev": true, "requires": { - "@babel/helper-module-transforms": "7.1.0", - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-modules-commonjs": { @@ -501,9 +501,9 @@ "integrity": "sha512-wtNwtMjn1XGwM0AXPspQgvmE6msSJP15CX2RVfpTSTNPLhKhaOjaIfBaVfj4iUZ/VrFSodcFedwtPg/NxwQlPA==", "dev": true, "requires": { - "@babel/helper-module-transforms": "7.1.0", - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-simple-access": "7.1.0" + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0" } }, "@babel/plugin-transform-modules-systemjs": { @@ -512,8 +512,8 @@ "integrity": "sha512-PvTxgjxQAq4pvVUZF3mD5gEtVDuId8NtWkJsZLEJZMZAW3TvgQl1pmydLLN1bM8huHFVVU43lf0uvjQj9FRkKw==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "7.0.0", - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-hoist-variables": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-modules-umd": { @@ -522,8 +522,8 @@ "integrity": "sha512-enrRtn5TfRhMmbRwm7F8qOj0qEYByqUvTttPEGimcBH4CJHphjyK1Vg7sdU7JjeEmgSpM890IT/efS2nMHwYig==", "dev": true, "requires": { - "@babel/helper-module-transforms": "7.1.0", - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-new-target": { @@ -532,7 +532,7 @@ "integrity": "sha512-yin069FYjah+LbqfGeTfzIBODex/e++Yfa0rH0fpfam9uTbuEeEOx5GLGr210ggOV77mVRNoeqSYqeuaqSzVSw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-object-super": { @@ -541,8 +541,8 @@ "integrity": "sha512-/O02Je1CRTSk2SSJaq0xjwQ8hG4zhZGNjE8psTsSNPXyLRCODv7/PBozqT5AmQMzp7MI3ndvMhGdqp9c96tTEw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-replace-supers": "7.1.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.1.0" } }, "@babel/plugin-transform-parameters": { @@ -551,9 +551,9 @@ "integrity": "sha512-vHV7oxkEJ8IHxTfRr3hNGzV446GAb+0hgbA7o/0Jd76s+YzccdWuTU296FOCOl/xweU4t/Ya4g41yWz80RFCRw==", "dev": true, "requires": { - "@babel/helper-call-delegate": "7.1.0", - "@babel/helper-get-function-arity": "7.0.0", - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-call-delegate": "^7.1.0", + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-regenerator": { @@ -562,7 +562,7 @@ "integrity": "sha512-sj2qzsEx8KDVv1QuJc/dEfilkg3RRPvPYx/VnKLtItVQRWt1Wqf5eVCOLZm29CiGFfYYsA3VPjfizTCV0S0Dlw==", "dev": true, "requires": { - "regenerator-transform": "0.13.3" + "regenerator-transform": "^0.13.3" } }, "@babel/plugin-transform-shorthand-properties": { @@ -571,7 +571,7 @@ "integrity": "sha512-g/99LI4vm5iOf5r1Gdxq5Xmu91zvjhEG5+yZDJW268AZELAu4J1EiFLnkSG3yuUsZyOipVOVUKoGPYwfsTymhw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-spread": { @@ -580,7 +580,7 @@ "integrity": "sha512-L702YFy2EvirrR4shTj0g2xQp7aNwZoWNCkNu2mcoU0uyzMl0XRwDSwzB/xp6DSUFiBmEXuyAyEN16LsgVqGGQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-sticky-regex": { @@ -589,8 +589,8 @@ "integrity": "sha512-LFUToxiyS/WD+XEWpkx/XJBrUXKewSZpzX68s+yEOtIbdnsRjpryDw9U06gYc6klYEij/+KQVRnD3nz3AoKmjw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-regex": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0" } }, "@babel/plugin-transform-template-literals": { @@ -599,8 +599,8 @@ "integrity": "sha512-vA6rkTCabRZu7Nbl9DfLZE1imj4tzdWcg5vtdQGvj+OH9itNNB6hxuRMHuIY8SGnEt1T9g5foqs9LnrHzsqEFg==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "7.0.0", - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-typeof-symbol": { @@ -609,7 +609,7 @@ "integrity": "sha512-1r1X5DO78WnaAIvs5uC48t41LLckxsYklJrZjNKcevyz83sF2l4RHbw29qrCPr/6ksFsdfRpT/ZgxNWHXRnffg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-unicode-regex": { @@ -618,9 +618,9 @@ "integrity": "sha512-uJBrJhBOEa3D033P95nPHu3nbFwFE9ZgXsfEitzoIXIwqAZWk7uXcg06yFKXz9FSxBH5ucgU/cYdX0IV8ldHKw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-regex": "7.0.0", - "regexpu-core": "4.2.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.1.3" } }, "@babel/preset-env": { @@ -629,47 +629,47 @@ "integrity": "sha512-YIBfpJNQMBkb6MCkjz/A9J76SNCSuGVamOVBgoUkLzpJD/z8ghHi9I42LQ4pulVX68N/MmImz6ZTixt7Azgexw==", "dev": true, "requires": { - "@babel/helper-module-imports": "7.0.0", - "@babel/helper-plugin-utils": "7.0.0", - "@babel/plugin-proposal-async-generator-functions": "7.1.0", - "@babel/plugin-proposal-json-strings": "7.0.0", - "@babel/plugin-proposal-object-rest-spread": "7.0.0", - "@babel/plugin-proposal-optional-catch-binding": "7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "7.0.0", - "@babel/plugin-syntax-async-generators": "7.0.0", - "@babel/plugin-syntax-object-rest-spread": "7.0.0", - "@babel/plugin-syntax-optional-catch-binding": "7.0.0", - "@babel/plugin-transform-arrow-functions": "7.0.0", - "@babel/plugin-transform-async-to-generator": "7.1.0", - "@babel/plugin-transform-block-scoped-functions": "7.0.0", - "@babel/plugin-transform-block-scoping": "7.1.5", - "@babel/plugin-transform-classes": "7.1.0", - "@babel/plugin-transform-computed-properties": "7.0.0", - "@babel/plugin-transform-destructuring": "7.1.3", - "@babel/plugin-transform-dotall-regex": "7.0.0", - "@babel/plugin-transform-duplicate-keys": "7.0.0", - "@babel/plugin-transform-exponentiation-operator": "7.1.0", - "@babel/plugin-transform-for-of": "7.0.0", - "@babel/plugin-transform-function-name": "7.1.0", - "@babel/plugin-transform-literals": "7.0.0", - "@babel/plugin-transform-modules-amd": "7.1.0", - "@babel/plugin-transform-modules-commonjs": "7.1.0", - "@babel/plugin-transform-modules-systemjs": "7.1.3", - "@babel/plugin-transform-modules-umd": "7.1.0", - "@babel/plugin-transform-new-target": "7.0.0", - "@babel/plugin-transform-object-super": "7.1.0", - "@babel/plugin-transform-parameters": "7.1.0", - "@babel/plugin-transform-regenerator": "7.0.0", - "@babel/plugin-transform-shorthand-properties": "7.0.0", - "@babel/plugin-transform-spread": "7.0.0", - "@babel/plugin-transform-sticky-regex": "7.0.0", - "@babel/plugin-transform-template-literals": "7.0.0", - "@babel/plugin-transform-typeof-symbol": "7.0.0", - "@babel/plugin-transform-unicode-regex": "7.0.0", - "browserslist": "4.3.5", - "invariant": "2.2.4", - "js-levenshtein": "1.1.4", - "semver": "5.6.0" + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-async-generator-functions": "^7.1.0", + "@babel/plugin-proposal-json-strings": "^7.0.0", + "@babel/plugin-proposal-object-rest-spread": "^7.0.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.0.0", + "@babel/plugin-syntax-async-generators": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.0.0", + "@babel/plugin-transform-arrow-functions": "^7.0.0", + "@babel/plugin-transform-async-to-generator": "^7.1.0", + "@babel/plugin-transform-block-scoped-functions": "^7.0.0", + "@babel/plugin-transform-block-scoping": "^7.1.5", + "@babel/plugin-transform-classes": "^7.1.0", + "@babel/plugin-transform-computed-properties": "^7.0.0", + "@babel/plugin-transform-destructuring": "^7.0.0", + "@babel/plugin-transform-dotall-regex": "^7.0.0", + "@babel/plugin-transform-duplicate-keys": "^7.0.0", + "@babel/plugin-transform-exponentiation-operator": "^7.1.0", + "@babel/plugin-transform-for-of": "^7.0.0", + "@babel/plugin-transform-function-name": "^7.1.0", + "@babel/plugin-transform-literals": "^7.0.0", + "@babel/plugin-transform-modules-amd": "^7.1.0", + "@babel/plugin-transform-modules-commonjs": "^7.1.0", + "@babel/plugin-transform-modules-systemjs": "^7.0.0", + "@babel/plugin-transform-modules-umd": "^7.1.0", + "@babel/plugin-transform-new-target": "^7.0.0", + "@babel/plugin-transform-object-super": "^7.1.0", + "@babel/plugin-transform-parameters": "^7.1.0", + "@babel/plugin-transform-regenerator": "^7.0.0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0", + "@babel/plugin-transform-spread": "^7.0.0", + "@babel/plugin-transform-sticky-regex": "^7.0.0", + "@babel/plugin-transform-template-literals": "^7.0.0", + "@babel/plugin-transform-typeof-symbol": "^7.0.0", + "@babel/plugin-transform-unicode-regex": "^7.0.0", + "browserslist": "^4.1.0", + "invariant": "^2.2.2", + "js-levenshtein": "^1.1.3", + "semver": "^5.3.0" } }, "@babel/template": { @@ -678,9 +678,9 @@ "integrity": "sha512-SY1MmplssORfFiLDcOETrW7fCLl+PavlwMh92rrGcikQaRq4iWPVH0MpwPpY3etVMx6RnDjXtr6VZYr/IbP/Ag==", "dev": true, "requires": { - "@babel/code-frame": "7.0.0", - "@babel/parser": "7.1.6", - "@babel/types": "7.1.6" + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.1.2", + "@babel/types": "^7.1.2" } }, "@babel/traverse": { @@ -689,15 +689,15 @@ "integrity": "sha512-CXedit6GpISz3sC2k2FsGCUpOhUqKdyL0lqNrImQojagnUMXf8hex4AxYFRuMkNGcvJX5QAFGzB5WJQmSv8SiQ==", "dev": true, "requires": { - "@babel/code-frame": "7.0.0", - "@babel/generator": "7.1.6", - "@babel/helper-function-name": "7.1.0", - "@babel/helper-split-export-declaration": "7.0.0", - "@babel/parser": "7.1.6", - "@babel/types": "7.1.6", - "debug": "4.1.0", - "globals": "11.9.0", - "lodash": "4.17.11" + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.1.6", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/parser": "^7.1.6", + "@babel/types": "^7.1.6", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.10" } }, "@babel/types": { @@ -706,9 +706,9 @@ "integrity": "sha512-DMiUzlY9DSjVsOylJssxLHSgj6tWM9PRFJOGW/RaOglVOK9nzTxoOMfTfRQXGUCUQ/HmlG2efwC+XqUEJ5ay4w==", "dev": true, "requires": { - "esutils": "2.0.2", - "lodash": "4.17.11", - "to-fast-properties": "2.0.0" + "esutils": "^2.0.2", + "lodash": "^4.17.10", + "to-fast-properties": "^2.0.0" } }, "@mrmlnc/readdir-enhanced": { @@ -717,8 +717,8 @@ "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", "dev": true, "requires": { - "call-me-maybe": "1.0.1", - "glob-to-regexp": "0.3.0" + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" } }, "@nodelib/fs.stat": { @@ -745,7 +745,7 @@ "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", "dev": true, "requires": { - "mime-types": "2.1.21", + "mime-types": "~2.1.18", "negotiator": "0.6.1" } }, @@ -755,20 +755,20 @@ "integrity": "sha512-3OOR92FTc2p5/EcOzPcXp+Cbo+3C15nV9RXHlOUBCBpHhcB+0frbSNR9ehED/o7sTcyGVtqGJpguToEdlXhD0w==", "dev": true, "requires": { - "convert-source-map": "1.6.0", - "glob": "7.1.3", - "indx": "0.2.3", - "lodash.clone": "4.5.0", - "lodash.defaults": "4.2.0", - "lodash.flatten": "4.4.0", - "lodash.merge": "4.6.1", - "lodash.partialright": "4.2.1", - "lodash.pick": "4.4.0", - "lodash.uniq": "4.5.0", - "resolve": "1.8.1", - "semver": "5.6.0", - "uglify-js": "2.8.29", - "when": "3.7.8" + "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" }, "dependencies": { "glob": { @@ -777,12 +777,12 @@ "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.3.3", - "path-is-absolute": "1.0.1" + "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" } }, "minimatch": { @@ -791,7 +791,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } } } @@ -825,10 +825,10 @@ "integrity": "sha512-ZoJjft5B+EJBjUyu9C9Hc0OZyPZSSlOF+plzouTrg6UlA8f+e/n8NIgBFG/9tppJtpPWfthHakK7juJdNDODww==", "dev": true, "requires": { - "fast-deep-equal": "2.0.1", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.4.1", - "uri-js": "4.2.2" + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, "align-text": { @@ -837,9 +837,9 @@ "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, "requires": { - "kind-of": "3.2.2", - "longest": "1.0.1", - "repeat-string": "1.6.1" + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" }, "dependencies": { "kind-of": { @@ -848,7 +848,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -885,7 +885,7 @@ "resolved": "https://registry.npmjs.org/angular-dynamic-locale/-/angular-dynamic-locale-0.1.37.tgz", "integrity": "sha512-m5Kyk8W8/mOZSqRxuByOwHBjv8labLBAgvl0Z3iQx2xT/tWCqb94imKUPwumudszdPDjxeopwyucQvm8Sw7ogw==", "requires": { - "@types/angular": "1.6.51" + "@types/angular": "^1.6.25" } }, "angular-i18n": { @@ -928,9 +928,9 @@ "resolved": "https://registry.npmjs.org/angular-ui-sortable/-/angular-ui-sortable-0.19.0.tgz", "integrity": "sha512-u/uc981Nzg4XN1bMU9qKleMTSt7F1XjMWnyGw6gxPLIeQeLZm8jWNy7tj8y2r2HmvzXFbQVq2z6rObznFKAekQ==", "requires": { - "angular": "1.7.5", - "jquery": "3.3.1", - "jquery-ui-dist": "1.12.1" + "angular": ">=1.2.x", + "jquery": ">=3.1.x", + "jquery-ui-dist": ">=1.12.x" } }, "animejs": { @@ -940,11 +940,11 @@ }, "ansi-colors": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", "dev": true, "requires": { - "ansi-wrap": "0.1.0" + "ansi-wrap": "^0.1.0" } }, "ansi-cyan": { @@ -958,7 +958,7 @@ }, "ansi-escapes": { "version": "3.1.0", - "resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", "dev": true }, @@ -992,7 +992,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "1.9.3" + "color-convert": "^1.9.0" } }, "ansi-wrap": { @@ -1004,11 +1004,11 @@ "anymatch": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", - "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "integrity": "sha1-VT3Lj5HjyImEXf26NMd3IbkLnXo=", "dev": true, "requires": { - "micromatch": "2.3.11", - "normalize-path": "2.1.1" + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" }, "dependencies": { "arr-diff": { @@ -1017,7 +1017,7 @@ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", "dev": true, "requires": { - "arr-flatten": "1.1.0" + "arr-flatten": "^1.0.1" } }, "array-unique": { @@ -1032,9 +1032,9 @@ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", "dev": true, "requires": { - "expand-range": "1.8.2", - "preserve": "0.2.0", - "repeat-element": "1.1.3" + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" } }, "expand-brackets": { @@ -1043,7 +1043,7 @@ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", "dev": true, "requires": { - "is-posix-bracket": "0.1.1" + "is-posix-bracket": "^0.1.0" } }, "extglob": { @@ -1052,7 +1052,7 @@ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "is-extglob": { @@ -1067,7 +1067,7 @@ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "kind-of": { @@ -1076,7 +1076,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } }, "micromatch": { @@ -1085,19 +1085,19 @@ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", "dev": true, "requires": { - "arr-diff": "2.0.0", - "array-unique": "0.2.1", - "braces": "1.8.5", - "expand-brackets": "0.1.5", - "extglob": "0.3.2", - "filename-regex": "2.0.1", - "is-extglob": "1.0.0", - "is-glob": "2.0.1", - "kind-of": "3.2.2", - "normalize-path": "2.1.1", - "object.omit": "2.0.1", - "parse-glob": "3.0.4", - "regex-cache": "0.4.4" + "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" } } } @@ -1116,7 +1116,7 @@ "dev": true, "optional": true, "requires": { - "file-type": "4.4.0" + "file-type": "^4.2.0" }, "dependencies": { "file-type": { @@ -1137,10 +1137,10 @@ "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", "dev": true, "requires": { - "sprintf-js": "1.0.3" + "sprintf-js": "~1.0.2" } }, "arr-diff": { @@ -1152,7 +1152,7 @@ "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==", + "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", "dev": true }, "arr-union": { @@ -1191,7 +1191,7 @@ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { - "array-uniq": "1.0.3" + "array-uniq": "^1.0.1" } }, "array-uniq": { @@ -1231,7 +1231,7 @@ "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "dev": true, "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": "~2.1.0" } }, "assert-plus": { @@ -1282,12 +1282,12 @@ "integrity": "sha512-DY9gOh8z3tnCbJ13JIWaeQsoYncTGdsrgCceBaQSIL4nvdrLxgbRSBPevg2XbX7u4QCSfLheSJEEIUUSlkbx6Q==", "dev": true, "requires": { - "browserslist": "4.3.5", - "caniuse-lite": "1.0.30000913", - "normalize-range": "0.1.2", - "num2fraction": "1.2.2", - "postcss": "7.0.6", - "postcss-value-parser": "3.3.1" + "browserslist": "^4.3.3", + "caniuse-lite": "^1.0.30000898", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.5", + "postcss-value-parser": "^3.3.1" } }, "aws-sign2": { @@ -1317,16 +1317,16 @@ "base": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", "dev": true, "requires": { - "cache-base": "1.0.1", - "class-utils": "0.3.6", - "component-emitter": "1.2.1", - "define-property": "1.0.0", - "isobject": "3.0.1", - "mixin-deep": "1.3.1", - "pascalcase": "0.1.1" + "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" }, "dependencies": { "define-property": { @@ -1335,36 +1335,36 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "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==", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "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==", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -1399,7 +1399,7 @@ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "dev": true, "requires": { - "tweetnacl": "0.14.5" + "tweetnacl": "^0.14.3" } }, "beeper": { @@ -1424,11 +1424,11 @@ "dev": true, "optional": true, "requires": { - "decompress": "4.2.0", - "download": "6.2.5", - "execa": "0.7.0", - "p-map-series": "1.0.0", - "tempfile": "2.0.0" + "decompress": "^4.0.0", + "download": "^6.2.2", + "execa": "^0.7.0", + "p-map-series": "^1.0.0", + "tempfile": "^2.0.0" } }, "bin-check": { @@ -1438,8 +1438,8 @@ "dev": true, "optional": true, "requires": { - "execa": "0.7.0", - "executable": "4.1.1" + "execa": "^0.7.0", + "executable": "^4.1.0" } }, "bin-version": { @@ -1449,8 +1449,8 @@ "dev": true, "optional": true, "requires": { - "execa": "1.0.0", - "find-versions": "3.0.0" + "execa": "^1.0.0", + "find-versions": "^3.0.0" }, "dependencies": { "execa": { @@ -1460,13 +1460,13 @@ "dev": true, "optional": true, "requires": { - "cross-spawn": "6.0.5", - "get-stream": "4.1.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "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" } }, "get-stream": { @@ -1476,7 +1476,7 @@ "dev": true, "optional": true, "requires": { - "pump": "3.0.0" + "pump": "^3.0.0" } } } @@ -1488,9 +1488,9 @@ "dev": true, "optional": true, "requires": { - "bin-version": "3.0.0", - "semver": "5.6.0", - "semver-truncate": "1.1.2" + "bin-version": "^3.0.0", + "semver": "^5.6.0", + "semver-truncate": "^1.1.2" } }, "bin-wrapper": { @@ -1500,12 +1500,12 @@ "dev": true, "optional": true, "requires": { - "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" + "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" }, "dependencies": { "download": { @@ -1515,18 +1515,18 @@ "dev": true, "optional": true, "requires": { - "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.1.0", - "get-stream": "3.0.0", - "got": "8.3.2", - "make-dir": "1.3.0", - "p-event": "2.1.0", - "pify": "3.0.0" + "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" }, "dependencies": { "pify": { @@ -1545,23 +1545,23 @@ "dev": true, "optional": true, "requires": { - "@sindresorhus/is": "0.7.0", - "cacheable-request": "2.1.4", - "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", - "lowercase-keys": "1.0.1", - "mimic-response": "1.0.1", - "p-cancelable": "0.4.1", - "p-timeout": "2.0.1", - "pify": "3.0.0", - "safe-buffer": "5.1.2", - "timed-out": "4.0.1", - "url-parse-lax": "3.0.0", - "url-to-options": "1.0.1" + "@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" }, "dependencies": { "pify": { @@ -1587,7 +1587,7 @@ "dev": true, "optional": true, "requires": { - "p-timeout": "2.0.1" + "p-timeout": "^2.0.1" } }, "p-timeout": { @@ -1596,7 +1596,7 @@ "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", "dev": true, "requires": { - "p-finally": "1.0.0" + "p-finally": "^1.0.0" } }, "pify": { @@ -1620,7 +1620,7 @@ "dev": true, "optional": true, "requires": { - "prepend-http": "2.0.0" + "prepend-http": "^2.0.0" } } } @@ -1691,10 +1691,10 @@ "integrity": "sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk=", "dev": true, "requires": { - "continuable-cache": "0.3.1", - "error": "7.0.2", - "raw-body": "1.1.7", - "safe-json-parse": "1.0.1" + "continuable-cache": "^0.3.1", + "error": "^7.0.0", + "raw-body": "~1.1.0", + "safe-json-parse": "~1.0.1" } }, "body-parser": { @@ -1704,15 +1704,15 @@ "dev": true, "requires": { "bytes": "3.0.0", - "content-type": "1.0.4", + "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "1.1.2", - "http-errors": "1.6.3", + "depd": "~1.1.2", + "http-errors": "~1.6.3", "iconv-lite": "0.4.23", - "on-finished": "2.3.0", + "on-finished": "~2.3.0", "qs": "6.5.2", "raw-body": "2.3.3", - "type-is": "1.6.16" + "type-is": "~1.6.16" }, "dependencies": { "bytes": { @@ -1736,7 +1736,7 @@ "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", "dev": true, "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } }, "ms": { @@ -1781,36 +1781,36 @@ "resolved": "https://registry.npmjs.org/bootstrap-social/-/bootstrap-social-5.1.1.tgz", "integrity": "sha1-dTDGeK31bPj60/qCwp1NPl0CdQE=", "requires": { - "bootstrap": "3.3.7", - "font-awesome": "4.7.0" + "bootstrap": "~3", + "font-awesome": "~4.7" } }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "braces": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "integrity": "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk=", "dev": true, "requires": { - "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.3", - "snapdragon": "0.8.2", - "snapdragon-node": "2.1.1", - "split-string": "3.1.0", - "to-regex": "3.0.2" + "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" }, "dependencies": { "extend-shallow": { @@ -1819,7 +1819,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -1830,9 +1830,9 @@ "integrity": "sha512-z9ZhGc3d9e/sJ9dIx5NFXkKoaiQTnrvrMsN3R1fGb1tkWWNSz12UewJn9TNxGo1l7J23h0MRaPmk7jfeTZYs1w==", "dev": true, "requires": { - "caniuse-lite": "1.0.30000913", - "electron-to-chromium": "1.3.87", - "node-releases": "1.0.5" + "caniuse-lite": "^1.0.30000912", + "electron-to-chromium": "^1.3.86", + "node-releases": "^1.0.5" } }, "buffer": { @@ -1842,8 +1842,8 @@ "dev": true, "requires": { "base64-js": "0.0.8", - "ieee754": "1.1.12", - "isarray": "1.0.0" + "ieee754": "^1.1.4", + "isarray": "^1.0.0" }, "dependencies": { "isarray": { @@ -1857,17 +1857,17 @@ "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==", + "integrity": "sha1-iQ3ZDZI6hz4I4Q5f1RpX5bfM4Ow=", "dev": true, "requires": { - "buffer-alloc-unsafe": "1.1.0", - "buffer-fill": "1.0.0" + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" } }, "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==", + "integrity": "sha1-vX3CauKXLQ7aJTvgYdupkjScGfA=", "dev": true }, "buffer-crc32": { @@ -1894,7 +1894,7 @@ "integrity": "sha1-z7GtlWjTujz+k1upq92VLeiKqyo=", "dev": true, "requires": { - "readable-stream": "1.1.14" + "readable-stream": "^1.0.33" } }, "builtin-modules": { @@ -1912,18 +1912,18 @@ "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", "dev": true, "requires": { - "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" + "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" } }, "cacheable-request": { @@ -1956,9 +1956,9 @@ "dev": true, "optional": true, "requires": { - "prepend-http": "2.0.0", - "query-string": "5.1.1", - "sort-keys": "2.0.0" + "prepend-http": "^2.0.0", + "query-string": "^5.0.1", + "sort-keys": "^2.0.0" } }, "prepend-http": { @@ -1975,7 +1975,7 @@ "dev": true, "optional": true, "requires": { - "is-plain-obj": "1.1.0" + "is-plain-obj": "^1.0.0" } } } @@ -1992,7 +1992,7 @@ "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", "dev": true, "requires": { - "callsites": "2.0.0" + "callsites": "^2.0.0" } }, "caller-path": { @@ -2001,7 +2001,7 @@ "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", "dev": true, "requires": { - "caller-callsite": "2.0.0" + "caller-callsite": "^2.0.0" } }, "callsite": { @@ -2024,12 +2024,12 @@ }, "camelcase-keys": { "version": "2.1.0", - "resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "dev": true, "requires": { - "camelcase": "2.1.1", - "map-obj": "1.0.1" + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" } }, "caniuse-api": { @@ -2038,10 +2038,10 @@ "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", "dev": true, "requires": { - "browserslist": "4.3.5", - "caniuse-lite": "1.0.30000913", - "lodash.memoize": "4.1.2", - "lodash.uniq": "4.5.0" + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" } }, "caniuse-lite": { @@ -2052,7 +2052,7 @@ }, "canonical-path": { "version": "0.0.2", - "resolved": "http://registry.npmjs.org/canonical-path/-/canonical-path-0.0.2.tgz", + "resolved": "https://registry.npmjs.org/canonical-path/-/canonical-path-0.0.2.tgz", "integrity": "sha1-4x65N6jJPuKgHfGDl5RyGQKHRXQ=", "dev": true }, @@ -2068,10 +2068,10 @@ "integrity": "sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==", "dev": true, "requires": { - "get-proxy": "2.1.0", - "isurl": "1.0.0", - "tunnel-agent": "0.6.0", - "url-to-options": "1.0.1" + "get-proxy": "^2.0.0", + "isurl": "^1.0.0-alpha5", + "tunnel-agent": "^0.6.0", + "url-to-options": "^1.0.1" } }, "center-align": { @@ -2080,8 +2080,8 @@ "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", "dev": true, "requires": { - "align-text": "0.1.4", - "lazy-cache": "1.0.4" + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" } }, "chalk": { @@ -2090,9 +2090,9 @@ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.5.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "chardet": { @@ -2107,19 +2107,19 @@ "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", "dev": true, "requires": { - "anymatch": "2.0.0", - "async-each": "1.0.1", - "braces": "2.3.2", - "fsevents": "1.2.4", - "glob-parent": "3.1.0", - "inherits": "2.0.3", - "is-binary-path": "1.0.1", - "is-glob": "4.0.0", - "lodash.debounce": "4.0.8", - "normalize-path": "2.1.1", - "path-is-absolute": "1.0.1", - "readdirp": "2.2.1", - "upath": "1.1.0" + "anymatch": "^2.0.0", + "async-each": "^1.0.0", + "braces": "^2.3.0", + "fsevents": "^1.2.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "lodash.debounce": "^4.0.8", + "normalize-path": "^2.1.1", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0", + "upath": "^1.0.5" }, "dependencies": { "anymatch": { @@ -2128,8 +2128,8 @@ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "dev": true, "requires": { - "micromatch": "3.1.10", - "normalize-path": "2.1.1" + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" } }, "is-glob": { @@ -2138,7 +2138,7 @@ "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.1" } } } @@ -2152,13 +2152,13 @@ "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==", + "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=", "dev": true, "requires": { - "arr-union": "3.1.0", - "define-property": "0.2.5", - "isobject": "3.0.1", - "static-extend": "0.1.2" + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" }, "dependencies": { "define-property": { @@ -2167,7 +2167,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } } } @@ -2178,7 +2178,7 @@ "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", "dev": true, "requires": { - "source-map": "0.6.1" + "source-map": "~0.6.0" }, "dependencies": { "source-map": { @@ -2195,7 +2195,7 @@ "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", "dev": true, "requires": { - "restore-cursor": "2.0.0" + "restore-cursor": "^2.0.0" } }, "cli-width": { @@ -2209,9 +2209,9 @@ "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.4.tgz", "integrity": "sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ==", "requires": { - "good-listener": "1.2.2", - "select": "1.1.2", - "tiny-emitter": "2.0.2" + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" } }, "cliui": { @@ -2220,8 +2220,8 @@ "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", "dev": true, "requires": { - "center-align": "0.1.3", - "right-align": "0.1.3", + "center-align": "^0.1.1", + "right-align": "^0.1.1", "wordwrap": "0.0.2" }, "dependencies": { @@ -2252,7 +2252,7 @@ "dev": true, "optional": true, "requires": { - "mimic-response": "1.0.1" + "mimic-response": "^1.0.0" } }, "clone-stats": { @@ -2264,12 +2264,12 @@ "cloneable-readable": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.2.tgz", - "integrity": "sha512-Bq6+4t+lbM8vhTs/Bef5c5AdEMtapp/iFb6+s4/Hh9MVTt8OLKH7ZOOZSCT+Ys7hsHvqv0GuMPJ1lnQJVHvxpg==", + "integrity": "sha1-1ZHe5Kj4vBXaQ86X3O66E9Q+KmU=", "dev": true, "requires": { - "inherits": "2.0.3", - "process-nextick-args": "2.0.0", - "readable-stream": "2.3.6" + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" }, "dependencies": { "isarray": { @@ -2284,13 +2284,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "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" } }, "string_decoder": { @@ -2299,7 +2299,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -2310,7 +2310,7 @@ "integrity": "sha512-5wfTTO8E2/ja4jFSxePXlG5nRu5bBtL/r1HCIpJW/lzT6yDtKl0u0Z4o/Vpz32IpKmBn7HerheEZQgA9N2DarQ==", "dev": true, "requires": { - "q": "1.5.1" + "q": "^1.1.2" } }, "collection-visit": { @@ -2319,8 +2319,8 @@ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "dev": true, "requires": { - "map-visit": "1.0.0", - "object-visit": "1.0.1" + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" } }, "color": { @@ -2329,8 +2329,8 @@ "integrity": "sha512-CwyopLkuRYO5ei2EpzpIh6LqJMt6Mt+jZhO5VI5f/wJLZriXQE32/SSqzmrh+QB+AZT81Cj8yv+7zwToW8ahZg==", "dev": true, "requires": { - "color-convert": "1.9.3", - "color-string": "1.5.3" + "color-convert": "^1.9.1", + "color-string": "^1.5.2" } }, "color-convert": { @@ -2354,14 +2354,14 @@ "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", "dev": true, "requires": { - "color-name": "1.1.3", - "simple-swizzle": "0.2.2" + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" } }, "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==", + "integrity": "sha1-k4NDeaHMmgxh+C9S8NBDIiUb1aI=", "dev": true }, "colors": { @@ -2376,7 +2376,7 @@ "integrity": "sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y=", "dev": true, "requires": { - "lodash": "4.17.11" + "lodash": "^4.5.0" } }, "combined-stream": { @@ -2385,7 +2385,7 @@ "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", "dev": true, "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } }, "commander": { @@ -2427,10 +2427,10 @@ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "dev": true, "requires": { - "buffer-from": "1.1.1", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "typedarray": "0.0.6" + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" }, "dependencies": { "isarray": { @@ -2445,22 +2445,22 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "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" } }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "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.2" + "safe-buffer": "~5.1.0" } } } @@ -2468,16 +2468,16 @@ "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==", + "integrity": "sha1-1OqT8FriV5CVG5nns7CeOQikCC4=", "dev": true, "requires": { - "source-map": "0.6.1" + "source-map": "^0.6.1" }, "dependencies": { "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", "dev": true } } @@ -2488,8 +2488,8 @@ "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", "dev": true, "requires": { - "ini": "1.3.5", - "proto-list": "1.2.4" + "ini": "^1.3.4", + "proto-list": "~1.2.1" } }, "connect": { @@ -2500,7 +2500,7 @@ "requires": { "debug": "2.6.9", "finalhandler": "1.1.0", - "parseurl": "1.3.2", + "parseurl": "~1.3.2", "utils-merge": "1.0.1" }, "dependencies": { @@ -2540,7 +2540,7 @@ "integrity": "sha1-WiUEe8dvcwcmZ8jLUsmJiI9JTGM=", "dev": true, "requires": { - "bluebird": "3.5.3" + "bluebird": "^3.1.1" } }, "content-disposition": { @@ -2567,7 +2567,7 @@ "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.1" } }, "cookie": { @@ -2600,10 +2600,10 @@ "integrity": "sha512-PcLqxTKiDmNT6pSpy4N6KtuPwb53W+2tzNvwOZw0WH9N6O0vLIBq0x8aj8Oj75ere4YcGi48bDFCL+3fRJdlNA==", "dev": true, "requires": { - "import-fresh": "2.0.0", - "is-directory": "0.3.1", - "js-yaml": "3.12.0", - "parse-json": "4.0.0" + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.9.0", + "parse-json": "^4.0.0" } }, "cross-spawn": { @@ -2612,16 +2612,16 @@ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { - "nice-try": "1.0.5", - "path-key": "2.0.1", - "semver": "5.6.0", - "shebang-command": "1.2.0", - "which": "1.3.1" + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, "css-color-names": { "version": "0.0.4", - "resolved": "http://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", "dev": true }, @@ -2631,8 +2631,8 @@ "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", "dev": true, "requires": { - "postcss": "7.0.6", - "timsort": "0.3.0" + "postcss": "^7.0.1", + "timsort": "^0.3.0" } }, "css-select": { @@ -2641,10 +2641,10 @@ "integrity": "sha512-dSpYaDVoWaELjvZ3mS6IKZM/y2PMPa/XYoEfYNZePL4U/XgyxZNroHEHReDx/d+VgXh9VbCTtFqLkFbmeqeaRQ==", "dev": true, "requires": { - "boolbase": "1.0.0", - "css-what": "2.1.2", - "domutils": "1.7.0", - "nth-check": "1.0.2" + "boolbase": "^1.0.0", + "css-what": "^2.1.2", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" } }, "css-select-base-adapter": { @@ -2659,8 +2659,8 @@ "integrity": "sha512-joNNW1gCp3qFFzj4St6zk+Wh/NBv0vM5YbEreZk0SD4S23S+1xBKb6cLDg2uj4P4k/GUMlIm6cKIDqIG+vdt0w==", "dev": true, "requires": { - "mdn-data": "1.1.4", - "source-map": "0.5.7" + "mdn-data": "~1.1.0", + "source-map": "^0.5.3" } }, "css-unit-converter": { @@ -2693,10 +2693,10 @@ "integrity": "sha512-AiXL90l+MDuQmRNyypG2P7ux7K4XklxYzNNUd5HXZCNcH8/N9bHPcpN97v8tXgRVeFL/Ed8iP8mVmAAu0ZpT7A==", "dev": true, "requires": { - "cosmiconfig": "5.0.7", - "cssnano-preset-default": "4.0.5", - "is-resolvable": "1.1.0", - "postcss": "7.0.6" + "cosmiconfig": "^5.0.0", + "cssnano-preset-default": "^4.0.5", + "is-resolvable": "^1.0.0", + "postcss": "^7.0.0" } }, "cssnano-preset-default": { @@ -2705,36 +2705,36 @@ "integrity": "sha512-f1uhya0ZAjPYtDD58QkBB0R+uYdzHPei7cDxJyQQIHt5acdhyGXaSXl2nDLzWHLwGFbZcHxQtkJS8mmNwnxTvw==", "dev": true, "requires": { - "css-declaration-sorter": "4.0.1", - "cssnano-util-raw-cache": "4.0.1", - "postcss": "7.0.6", - "postcss-calc": "7.0.1", - "postcss-colormin": "4.0.2", - "postcss-convert-values": "4.0.1", - "postcss-discard-comments": "4.0.1", - "postcss-discard-duplicates": "4.0.2", - "postcss-discard-empty": "4.0.1", - "postcss-discard-overridden": "4.0.1", - "postcss-merge-longhand": "4.0.9", - "postcss-merge-rules": "4.0.2", - "postcss-minify-font-values": "4.0.2", - "postcss-minify-gradients": "4.0.1", - "postcss-minify-params": "4.0.1", - "postcss-minify-selectors": "4.0.1", - "postcss-normalize-charset": "4.0.1", - "postcss-normalize-display-values": "4.0.1", - "postcss-normalize-positions": "4.0.1", - "postcss-normalize-repeat-style": "4.0.1", - "postcss-normalize-string": "4.0.1", - "postcss-normalize-timing-functions": "4.0.1", - "postcss-normalize-unicode": "4.0.1", - "postcss-normalize-url": "4.0.1", - "postcss-normalize-whitespace": "4.0.1", - "postcss-ordered-values": "4.1.1", - "postcss-reduce-initial": "4.0.2", - "postcss-reduce-transforms": "4.0.1", - "postcss-svgo": "4.0.1", - "postcss-unique-selectors": "4.0.1" + "css-declaration-sorter": "^4.0.1", + "cssnano-util-raw-cache": "^4.0.1", + "postcss": "^7.0.0", + "postcss-calc": "^7.0.0", + "postcss-colormin": "^4.0.2", + "postcss-convert-values": "^4.0.1", + "postcss-discard-comments": "^4.0.1", + "postcss-discard-duplicates": "^4.0.2", + "postcss-discard-empty": "^4.0.1", + "postcss-discard-overridden": "^4.0.1", + "postcss-merge-longhand": "^4.0.9", + "postcss-merge-rules": "^4.0.2", + "postcss-minify-font-values": "^4.0.2", + "postcss-minify-gradients": "^4.0.1", + "postcss-minify-params": "^4.0.1", + "postcss-minify-selectors": "^4.0.1", + "postcss-normalize-charset": "^4.0.1", + "postcss-normalize-display-values": "^4.0.1", + "postcss-normalize-positions": "^4.0.1", + "postcss-normalize-repeat-style": "^4.0.1", + "postcss-normalize-string": "^4.0.1", + "postcss-normalize-timing-functions": "^4.0.1", + "postcss-normalize-unicode": "^4.0.1", + "postcss-normalize-url": "^4.0.1", + "postcss-normalize-whitespace": "^4.0.1", + "postcss-ordered-values": "^4.1.1", + "postcss-reduce-initial": "^4.0.2", + "postcss-reduce-transforms": "^4.0.1", + "postcss-svgo": "^4.0.1", + "postcss-unique-selectors": "^4.0.1" } }, "cssnano-util-get-arguments": { @@ -2755,7 +2755,7 @@ "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", "dev": true, "requires": { - "postcss": "7.0.6" + "postcss": "^7.0.0" } }, "cssnano-util-same-parent": { @@ -2779,8 +2779,8 @@ "integrity": "sha512-sRNb1XydwkW9IOci6iB2xmy8IGCj6r/fr+JWitvJ2JxQRPzN3T4AGGVWCMlVmVwM1gtgALJRmGIlWv5ppnGGkg==", "dev": true, "requires": { - "mdn-data": "1.1.4", - "source-map": "0.5.7" + "mdn-data": "~1.1.0", + "source-map": "^0.5.3" } } } @@ -2791,7 +2791,7 @@ "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", "dev": true, "requires": { - "array-find-index": "1.0.2" + "array-find-index": "^1.0.1" } }, "custom-event": { @@ -2806,7 +2806,7 @@ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "dev": true, "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" } }, "date-format": { @@ -2827,7 +2827,7 @@ "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", "dev": true, "requires": { - "ms": "2.1.1" + "ms": "^2.1.1" } }, "decamelize": { @@ -2848,14 +2848,14 @@ "integrity": "sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=", "dev": true, "requires": { - "decompress-tar": "4.1.1", - "decompress-tarbz2": "4.1.1", - "decompress-targz": "4.1.1", - "decompress-unzip": "4.0.1", - "graceful-fs": "4.1.15", - "make-dir": "1.3.0", - "pify": "2.3.0", - "strip-dirs": "2.1.0" + "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" }, "dependencies": { "graceful-fs": { @@ -2878,7 +2878,7 @@ "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", "dev": true, "requires": { - "mimic-response": "1.0.1" + "mimic-response": "^1.0.0" } }, "decompress-tar": { @@ -2887,9 +2887,9 @@ "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", "dev": true, "requires": { - "file-type": "5.2.0", - "is-stream": "1.1.0", - "tar-stream": "1.6.2" + "file-type": "^5.2.0", + "is-stream": "^1.1.0", + "tar-stream": "^1.5.2" }, "dependencies": { "file-type": { @@ -2906,11 +2906,11 @@ "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", "dev": true, "requires": { - "decompress-tar": "4.1.1", - "file-type": "6.2.0", - "is-stream": "1.1.0", - "seek-bzip": "1.0.5", - "unbzip2-stream": "1.3.1" + "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" }, "dependencies": { "file-type": { @@ -2927,9 +2927,9 @@ "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", "dev": true, "requires": { - "decompress-tar": "4.1.1", - "file-type": "5.2.0", - "is-stream": "1.1.0" + "decompress-tar": "^4.1.1", + "file-type": "^5.2.0", + "is-stream": "^1.1.0" }, "dependencies": { "file-type": { @@ -2946,10 +2946,10 @@ "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", "dev": true, "requires": { - "file-type": "3.9.0", - "get-stream": "2.3.1", - "pify": "2.3.0", - "yauzl": "2.10.0" + "file-type": "^3.8.0", + "get-stream": "^2.2.0", + "pify": "^2.3.0", + "yauzl": "^2.4.2" }, "dependencies": { "file-type": { @@ -2964,8 +2964,8 @@ "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", "dev": true, "requires": { - "object-assign": "4.1.1", - "pinkie-promise": "2.0.1" + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" } }, "object-assign": { @@ -2994,7 +2994,7 @@ "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", "dev": true, "requires": { - "clone": "1.0.4" + "clone": "^1.0.2" } }, "define-properties": { @@ -3003,46 +3003,46 @@ "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "dev": true, "requires": { - "object-keys": "1.0.12" + "object-keys": "^1.0.12" } }, "define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "integrity": "sha1-1Flono1lS6d+AqgX+HENcCyxbp0=", "dev": true, "requires": { - "is-descriptor": "1.0.2", - "isobject": "3.0.1" + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" }, "dependencies": { "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==", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "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==", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -3099,8 +3099,8 @@ "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", "dev": true, "requires": { - "arrify": "1.0.1", - "path-type": "3.0.0" + "arrify": "^1.0.1", + "path-type": "^3.0.0" } }, "doctrine": { @@ -3109,7 +3109,7 @@ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { - "esutils": "2.0.2" + "esutils": "^2.0.2" } }, "dom-serialize": { @@ -3118,10 +3118,10 @@ "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", "dev": true, "requires": { - "custom-event": "1.0.1", - "ent": "2.2.0", - "extend": "3.0.2", - "void-elements": "2.0.1" + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" } }, "dom-serializer": { @@ -3130,8 +3130,8 @@ "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", "dev": true, "requires": { - "domelementtype": "1.1.3", - "entities": "1.1.2" + "domelementtype": "~1.1.1", + "entities": "~1.1.1" }, "dependencies": { "domelementtype": { @@ -3154,8 +3154,8 @@ "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", "dev": true, "requires": { - "dom-serializer": "0.1.0", - "domelementtype": "1.2.1" + "dom-serializer": "0", + "domelementtype": "1" } }, "dot-prop": { @@ -3164,7 +3164,7 @@ "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", "dev": true, "requires": { - "is-obj": "1.0.1" + "is-obj": "^1.0.0" } }, "download": { @@ -3174,17 +3174,17 @@ "dev": true, "optional": true, "requires": { - "caw": "2.0.1", - "content-disposition": "0.5.2", - "decompress": "4.2.0", - "ext-name": "5.0.0", + "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.1.0", - "get-stream": "3.0.0", - "got": "7.1.0", - "make-dir": "1.3.0", - "p-event": "1.3.0", - "pify": "3.0.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" }, "dependencies": { "file-type": { @@ -3198,7 +3198,7 @@ }, "duplexer": { "version": "0.1.1", - "resolved": "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", "dev": true }, @@ -3208,7 +3208,7 @@ "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", "dev": true, "requires": { - "readable-stream": "1.1.14" + "readable-stream": "~1.1.9" } }, "duplexer3": { @@ -3223,8 +3223,8 @@ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "dev": true, "requires": { - "jsbn": "0.1.1", - "safer-buffer": "2.1.2" + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" } }, "ee-first": { @@ -3251,7 +3251,7 @@ "integrity": "sha1-jhdyBsPICDfYVjLouTWd/osvbq8=", "dev": true, "requires": { - "once": "1.3.3" + "once": "~1.3.0" } }, "engine.io": { @@ -3260,12 +3260,12 @@ "integrity": "sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==", "dev": true, "requires": { - "accepts": "1.3.5", + "accepts": "~1.3.4", "base64id": "1.0.0", "cookie": "0.3.1", - "debug": "3.1.0", - "engine.io-parser": "2.1.3", - "ws": "3.3.3" + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" }, "dependencies": { "debug": { @@ -3293,14 +3293,14 @@ "requires": { "component-emitter": "1.2.1", "component-inherit": "0.0.3", - "debug": "3.1.0", - "engine.io-parser": "2.1.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.3", - "xmlhttprequest-ssl": "1.5.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", "yeast": "0.1.2" }, "dependencies": { @@ -3328,10 +3328,10 @@ "dev": true, "requires": { "after": "0.8.2", - "arraybuffer.slice": "0.0.7", + "arraybuffer.slice": "~0.0.7", "base64-arraybuffer": "0.1.5", "blob": "0.0.5", - "has-binary2": "1.0.3" + "has-binary2": "~1.0.2" } }, "ent": { @@ -3349,11 +3349,11 @@ "errno": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "integrity": "sha1-RoTXF3mtOa8Xfj8AeZb3xnyFJhg=", "dev": true, "optional": true, "requires": { - "prr": "1.0.1" + "prr": "~1.0.1" } }, "error": { @@ -3362,8 +3362,8 @@ "integrity": "sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI=", "dev": true, "requires": { - "string-template": "0.2.1", - "xtend": "4.0.1" + "string-template": "~0.2.1", + "xtend": "~4.0.0" } }, "error-ex": { @@ -3372,20 +3372,20 @@ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, "requires": { - "is-arrayish": "0.2.1" + "is-arrayish": "^0.2.1" } }, "es-abstract": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", - "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", + "integrity": "sha1-nbvdJ8aFbwABQhyhh4LXhr+KYWU=", "dev": true, "requires": { - "es-to-primitive": "1.2.0", - "function-bind": "1.1.1", - "has": "1.0.3", - "is-callable": "1.1.4", - "is-regex": "1.0.4" + "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" } }, "es-to-primitive": { @@ -3394,14 +3394,14 @@ "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", "dev": true, "requires": { - "is-callable": "1.1.4", - "is-date-object": "1.0.1", - "is-symbol": "1.0.2" + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" } }, "es6-promise": { "version": "3.3.1", - "resolved": "http://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=", "dev": true }, @@ -3423,11 +3423,11 @@ "integrity": "sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw==", "dev": true, "requires": { - "esprima": "3.1.3", - "estraverse": "4.2.0", - "esutils": "2.0.2", - "optionator": "0.8.2", - "source-map": "0.6.1" + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" }, "dependencies": { "esprima": { @@ -3451,44 +3451,44 @@ "integrity": "sha512-g4KWpPdqN0nth+goDNICNXGfJF7nNnepthp46CAlJoJtC5K/cLu3NgCM3AHu1CkJ5Hzt9V0Y0PBAO6Ay/gGb+w==", "dev": true, "requires": { - "@babel/code-frame": "7.0.0", - "ajv": "6.6.1", - "chalk": "2.4.1", - "cross-spawn": "6.0.5", - "debug": "4.1.0", - "doctrine": "2.1.0", - "eslint-scope": "4.0.0", - "eslint-utils": "1.3.1", - "eslint-visitor-keys": "1.0.0", - "espree": "4.1.0", - "esquery": "1.0.1", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "functional-red-black-tree": "1.0.1", - "glob": "7.1.3", - "globals": "11.9.0", - "ignore": "4.0.6", - "imurmurhash": "0.1.4", - "inquirer": "6.2.1", - "is-resolvable": "1.1.0", - "js-yaml": "3.12.0", - "json-stable-stringify-without-jsonify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.11", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "7.0.0", - "progress": "2.0.1", - "regexpp": "2.0.1", - "require-uncached": "1.0.3", - "semver": "5.6.0", - "strip-ansi": "4.0.0", - "strip-json-comments": "2.0.1", - "table": "5.1.1", - "text-table": "0.2.0" + "@babel/code-frame": "^7.0.0", + "ajv": "^6.5.3", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^2.1.0", + "eslint-scope": "^4.0.0", + "eslint-utils": "^1.3.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^4.0.0", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "imurmurhash": "^0.1.4", + "inquirer": "^6.1.0", + "is-resolvable": "^1.1.0", + "js-yaml": "^3.12.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.5", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^7.0.0", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "require-uncached": "^1.0.3", + "semver": "^5.5.1", + "strip-ansi": "^4.0.0", + "strip-json-comments": "^2.0.1", + "table": "^5.0.2", + "text-table": "^0.2.0" }, "dependencies": { "ansi-regex": { @@ -3503,12 +3503,12 @@ "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.3.3", - "path-is-absolute": "1.0.1" + "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" } }, "minimatch": { @@ -3517,7 +3517,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "strip-ansi": { @@ -3526,7 +3526,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } } } @@ -3537,8 +3537,8 @@ "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", "dev": true, "requires": { - "esrecurse": "4.2.1", - "estraverse": "4.2.0" + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" } }, "eslint-utils": { @@ -3559,9 +3559,9 @@ "integrity": "sha512-I5BycZW6FCVIub93TeVY1s7vjhP9CY6cXCznIRfiig7nRviKZYdRnj/sHEWC6A7WE9RDWOFq9+7OsWSYz8qv2w==", "dev": true, "requires": { - "acorn": "6.0.4", - "acorn-jsx": "5.0.1", - "eslint-visitor-keys": "1.0.0" + "acorn": "^6.0.2", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" } }, "esprima": { @@ -3576,7 +3576,7 @@ "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", "dev": true, "requires": { - "estraverse": "4.2.0" + "estraverse": "^4.0.0" } }, "esrecurse": { @@ -3585,7 +3585,7 @@ "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", "dev": true, "requires": { - "estraverse": "4.2.0" + "estraverse": "^4.1.0" } }, "estemplate": { @@ -3594,8 +3594,8 @@ "integrity": "sha1-FxSp1GGQc4rJWLyv1J4CnNpWo54=", "dev": true, "requires": { - "esprima": "2.7.3", - "estraverse": "4.2.0" + "esprima": "^2.7.2", + "estraverse": "^4.1.1" }, "dependencies": { "esprima": { @@ -3630,13 +3630,13 @@ "integrity": "sha512-vyibDcu5JL20Me1fP734QBH/kenBGLZap2n0+XXM7mvuUPzJ20Ydqj1aKcIeMdri1p+PU+4yAKugjN8KCVst+g==", "dev": true, "requires": { - "duplexer": "0.1.1", - "from": "0.1.7", + "duplexer": "^0.1.1", + "from": "^0.1.7", "map-stream": "0.0.7", - "pause-stream": "0.0.11", - "split": "1.0.1", - "stream-combiner": "0.2.2", - "through": "2.3.8" + "pause-stream": "^0.0.11", + "split": "^1.0.1", + "stream-combiner": "^0.2.2", + "through": "^2.3.8" } }, "eventemitter3": { @@ -3648,15 +3648,15 @@ "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==", + "integrity": "sha1-sWhtvZBMfPmC5lLB9aebHlVzCCs=", "dev": true, "optional": true, "requires": { - "execa": "0.7.0", - "p-finally": "1.0.0", - "pify": "3.0.0", - "rimraf": "2.6.2", - "tempfile": "2.0.0" + "execa": "^0.7.0", + "p-finally": "^1.0.0", + "pify": "^3.0.0", + "rimraf": "^2.5.4", + "tempfile": "^2.0.0" } }, "execa": { @@ -3665,13 +3665,13 @@ "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "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" }, "dependencies": { "cross-spawn": { @@ -3680,9 +3680,9 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "lru-cache": "4.1.5", - "shebang-command": "1.2.0", - "which": "1.3.1" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, "lru-cache": { @@ -3691,8 +3691,8 @@ "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "dev": true, "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } } } @@ -3704,7 +3704,7 @@ "dev": true, "optional": true, "requires": { - "pify": "2.3.0" + "pify": "^2.2.0" }, "dependencies": { "pify": { @@ -3722,9 +3722,9 @@ "integrity": "sha1-SIsdHSRRyz06axks/AMPRMWFX+o=", "dev": true, "requires": { - "array-slice": "0.2.3", - "array-unique": "0.2.1", - "braces": "0.1.5" + "array-slice": "^0.2.3", + "array-unique": "^0.2.1", + "braces": "^0.1.2" }, "dependencies": { "array-slice": { @@ -3745,17 +3745,17 @@ "integrity": "sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY=", "dev": true, "requires": { - "expand-range": "0.1.1" + "expand-range": "^0.1.0" } }, "expand-range": { "version": "0.1.1", - "resolved": "http://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz", "integrity": "sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ=", "dev": true, "requires": { - "is-number": "0.1.1", - "repeat-string": "0.2.2" + "is-number": "^0.1.1", + "repeat-string": "^0.2.2" } }, "is-number": { @@ -3778,13 +3778,13 @@ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "posix-character-classes": "0.1.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "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" }, "dependencies": { "debug": { @@ -3802,7 +3802,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -3811,7 +3811,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } }, "ms": { @@ -3824,24 +3824,24 @@ }, "expand-range": { "version": "1.8.2", - "resolved": "http://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", "dev": true, "requires": { - "fill-range": "2.2.4" + "fill-range": "^2.1.0" }, "dependencies": { "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==", + "integrity": "sha1-6x53OrsFbc2N8r/favWbizqTZWU=", "dev": true, "requires": { - "is-number": "2.1.0", - "isobject": "2.1.0", - "randomatic": "3.1.1", - "repeat-element": "1.1.3", - "repeat-string": "1.6.1" + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" } }, "is-number": { @@ -3850,7 +3850,7 @@ "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" } }, "isarray": { @@ -3874,7 +3874,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -3885,7 +3885,7 @@ "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", "dev": true, "requires": { - "homedir-polyfill": "1.0.1" + "homedir-polyfill": "^1.0.1" } }, "ext-list": { @@ -3894,7 +3894,7 @@ "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", "dev": true, "requires": { - "mime-db": "1.37.0" + "mime-db": "^1.28.0" } }, "ext-name": { @@ -3903,8 +3903,8 @@ "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", "dev": true, "requires": { - "ext-list": "2.2.2", - "sort-keys-length": "1.0.1" + "ext-list": "^2.0.0", + "sort-keys-length": "^1.0.0" } }, "extend": { @@ -3919,17 +3919,17 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "1.0.0", - "is-extendable": "1.0.1" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" }, "dependencies": { "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==", + "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -3940,25 +3940,25 @@ "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", "dev": true, "requires": { - "chardet": "0.7.0", - "iconv-lite": "0.4.24", - "tmp": "0.0.33" + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" } }, "extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=", "dev": true, "requires": { - "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.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "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" }, "dependencies": { "define-property": { @@ -3967,7 +3967,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "extend-shallow": { @@ -3976,36 +3976,36 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } }, "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==", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "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==", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -4037,7 +4037,7 @@ "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", "dev": true, "requires": { - "pend": "1.2.0" + "pend": "~1.2.0" } }, "ms": { @@ -4052,7 +4052,7 @@ "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", "dev": true, "requires": { - "fd-slicer": "1.0.1" + "fd-slicer": "~1.0.1" } } } @@ -4069,10 +4069,10 @@ "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", "dev": true, "requires": { - "ansi-gray": "0.1.1", - "color-support": "1.1.3", - "parse-node-version": "1.0.0", - "time-stamp": "1.1.0" + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "parse-node-version": "^1.0.0", + "time-stamp": "^1.0.0" } }, "fast-deep-equal": { @@ -4087,12 +4087,12 @@ "integrity": "sha512-FjK2nCGI/McyzgNtTESqaWP3trPvHyRyoyY70hxjc3oKPNmDe8taohLZpoVKoUjW85tbU5txaYUZCNtVzygl1g==", "dev": true, "requires": { - "@mrmlnc/readdir-enhanced": "2.2.1", - "@nodelib/fs.stat": "1.1.3", - "glob-parent": "3.1.0", - "is-glob": "4.0.0", - "merge2": "1.2.3", - "micromatch": "3.1.10" + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" }, "dependencies": { "is-glob": { @@ -4101,7 +4101,7 @@ "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.1" } } } @@ -4124,7 +4124,7 @@ "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", "dev": true, "requires": { - "websocket-driver": "0.7.0" + "websocket-driver": ">=0.5.1" } }, "fd-slicer": { @@ -4133,7 +4133,7 @@ "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", "dev": true, "requires": { - "pend": "1.2.0" + "pend": "~1.2.0" } }, "figures": { @@ -4142,7 +4142,7 @@ "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", "dev": true, "requires": { - "escape-string-regexp": "1.0.5" + "escape-string-regexp": "^1.0.5" } }, "file-entry-cache": { @@ -4151,8 +4151,8 @@ "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", "dev": true, "requires": { - "flat-cache": "1.3.4", - "object-assign": "4.1.1" + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" }, "dependencies": { "object-assign": { @@ -4187,9 +4187,9 @@ "integrity": "sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA==", "dev": true, "requires": { - "filename-reserved-regex": "2.0.0", - "strip-outer": "1.0.1", - "trim-repeated": "1.0.0" + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.0", + "trim-repeated": "^1.0.0" } }, "fill-range": { @@ -4198,10 +4198,10 @@ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-number": "3.0.0", - "repeat-string": "1.6.1", - "to-regex-range": "2.1.1" + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" }, "dependencies": { "extend-shallow": { @@ -4210,7 +4210,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -4222,12 +4222,12 @@ "dev": true, "requires": { "debug": "2.6.9", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.2", - "statuses": "1.3.1", - "unpipe": "1.0.0" + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.3.1", + "unpipe": "~1.0.0" }, "dependencies": { "debug": { @@ -4259,8 +4259,8 @@ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "find-versions": { @@ -4270,8 +4270,8 @@ "dev": true, "optional": true, "requires": { - "array-uniq": "2.0.0", - "semver-regex": "2.0.0" + "array-uniq": "^2.0.0", + "semver-regex": "^2.0.0" }, "dependencies": { "array-uniq": { @@ -4289,10 +4289,10 @@ "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", "dev": true, "requires": { - "detect-file": "1.0.0", - "is-glob": "3.1.0", - "micromatch": "3.1.10", - "resolve-dir": "1.0.1" + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" } }, "fined": { @@ -4301,11 +4301,11 @@ "integrity": "sha1-s33IRLdqL15wgeiE98CuNE8VNHY=", "dev": true, "requires": { - "expand-tilde": "2.0.2", - "is-plain-object": "2.0.4", - "object.defaults": "1.1.0", - "object.pick": "1.3.0", - "parse-filepath": "1.0.2" + "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" } }, "first-chunk-stream": { @@ -4326,10 +4326,10 @@ "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", "dev": true, "requires": { - "circular-json": "0.3.3", - "graceful-fs": "4.1.15", - "rimraf": "2.6.2", - "write": "0.2.1" + "circular-json": "^0.3.1", + "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", + "write": "^0.2.1" }, "dependencies": { "graceful-fs": { @@ -4351,7 +4351,7 @@ "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", "dev": true, "requires": { - "debug": "3.1.0" + "debug": "=3.1.0" }, "dependencies": { "debug": { @@ -4388,7 +4388,7 @@ "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", "dev": true, "requires": { - "for-in": "1.0.2" + "for-in": "^1.0.1" } }, "forever-agent": { @@ -4403,9 +4403,9 @@ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "dev": true, "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.7", - "mime-types": "2.1.21" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" } }, "fragment-cache": { @@ -4414,7 +4414,7 @@ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "requires": { - "map-cache": "0.2.2" + "map-cache": "^0.2.2" } }, "fresh": { @@ -4436,8 +4436,8 @@ "dev": true, "optional": true, "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.6" + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" }, "dependencies": { "isarray": { @@ -4454,13 +4454,13 @@ "dev": true, "optional": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "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" } }, "string_decoder": { @@ -4470,7 +4470,7 @@ "dev": true, "optional": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -4478,18 +4478,18 @@ "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==", + "integrity": "sha1-a+Dem+mYzhavivwkSXue6bfM2a0=", "dev": true }, "fs-extra": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", "dev": true, "requires": { - "graceful-fs": "4.1.15", - "jsonfile": "2.4.0", - "klaw": "1.3.1" + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0" }, "dependencies": { "graceful-fs": { @@ -4506,7 +4506,7 @@ "integrity": "sha1-gAI4I5gfn//+AWCei+Zo9prknnA=", "dev": true, "requires": { - "graceful-fs": "4.1.15" + "graceful-fs": "^4.1.2" }, "dependencies": { "graceful-fs": { @@ -4530,8 +4530,8 @@ "dev": true, "optional": true, "requires": { - "nan": "2.11.1", - "node-pre-gyp": "0.10.0" + "nan": "^2.9.2", + "node-pre-gyp": "^0.10.0" }, "dependencies": { "abbrev": { @@ -4543,8 +4543,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -4565,14 +4564,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4587,20 +4584,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -4717,8 +4711,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -4730,7 +4723,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -4745,7 +4737,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -4753,14 +4744,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -4779,7 +4768,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -4860,8 +4848,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -4873,7 +4860,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -4959,8 +4945,7 @@ "safe-buffer": { "version": "5.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -4996,7 +4981,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5016,7 +5000,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -5060,21 +5043,19 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", "dev": true }, "functional-red-black-tree": { @@ -5089,7 +5070,7 @@ "integrity": "sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8=", "dev": true, "requires": { - "globule": "0.1.0" + "globule": "~0.1.0" } }, "get-proxy": { @@ -5098,7 +5079,7 @@ "integrity": "sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==", "dev": true, "requires": { - "npm-conf": "1.1.3" + "npm-conf": "^1.1.0" } }, "get-stdin": { @@ -5125,7 +5106,7 @@ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "dev": true, "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" } }, "gifsicle": { @@ -5135,10 +5116,10 @@ "dev": true, "optional": true, "requires": { - "bin-build": "3.0.0", - "bin-wrapper": "4.1.0", - "execa": "1.0.0", - "logalot": "2.1.0" + "bin-build": "^3.0.0", + "bin-wrapper": "^4.0.0", + "execa": "^1.0.0", + "logalot": "^2.0.0" }, "dependencies": { "execa": { @@ -5148,13 +5129,13 @@ "dev": true, "optional": true, "requires": { - "cross-spawn": "6.0.5", - "get-stream": "4.1.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "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" } }, "get-stream": { @@ -5164,7 +5145,7 @@ "dev": true, "optional": true, "requires": { - "pump": "3.0.0" + "pump": "^3.0.0" } } } @@ -5175,10 +5156,10 @@ "integrity": "sha1-xstz0yJsHv7wTePFbQEvAzd+4V8=", "dev": true, "requires": { - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "2.0.10", - "once": "1.3.3" + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^2.0.1", + "once": "^1.3.0" } }, "glob-base": { @@ -5187,8 +5168,8 @@ "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", "dev": true, "requires": { - "glob-parent": "2.0.0", - "is-glob": "2.0.1" + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" }, "dependencies": { "glob-parent": { @@ -5197,7 +5178,7 @@ "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", "dev": true, "requires": { - "is-glob": "2.0.1" + "is-glob": "^2.0.0" } }, "is-extglob": { @@ -5212,7 +5193,7 @@ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } } } @@ -5223,8 +5204,8 @@ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "requires": { - "is-glob": "3.1.0", - "path-dirname": "1.0.2" + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" } }, "glob-stream": { @@ -5233,34 +5214,34 @@ "integrity": "sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs=", "dev": true, "requires": { - "glob": "4.5.3", - "glob2base": "0.0.12", - "minimatch": "2.0.10", - "ordered-read-streams": "0.1.0", - "through2": "0.6.5", - "unique-stream": "1.0.0" + "glob": "^4.3.1", + "glob2base": "^0.0.12", + "minimatch": "^2.0.1", + "ordered-read-streams": "^0.1.0", + "through2": "^0.6.1", + "unique-stream": "^1.0.0" }, "dependencies": { "readable-stream": { "version": "1.0.34", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", "isarray": "0.0.1", - "string_decoder": "0.10.31" + "string_decoder": "~0.10.x" } }, "through2": { "version": "0.6.5", - "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, "requires": { - "readable-stream": "1.0.34", - "xtend": "4.0.1" + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" } } } @@ -5273,11 +5254,11 @@ }, "glob-watcher": { "version": "0.0.6", - "resolved": "http://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.6.tgz", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.6.tgz", "integrity": "sha1-uVtKjfdLOcgymLDAXJeLTZo7cQs=", "dev": true, "requires": { - "gaze": "0.5.2" + "gaze": "^0.5.1" } }, "glob2base": { @@ -5286,7 +5267,7 @@ "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", "dev": true, "requires": { - "find-index": "0.1.1" + "find-index": "^0.1.1" } }, "global-modules": { @@ -5295,9 +5276,9 @@ "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", "dev": true, "requires": { - "global-prefix": "1.0.2", - "is-windows": "1.0.2", - "resolve-dir": "1.0.1" + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" } }, "global-prefix": { @@ -5306,11 +5287,11 @@ "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", "dev": true, "requires": { - "expand-tilde": "2.0.2", - "homedir-polyfill": "1.0.1", - "ini": "1.3.5", - "is-windows": "1.0.2", - "which": "1.3.1" + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" } }, "globals": { @@ -5325,13 +5306,13 @@ "integrity": "sha512-oMrYrJERnKBLXNLVTqhm3vPEdJ/b2ZE28xN4YARiix1NOIOBPEpOUnm844K1iu/BkphCaf2WNFwMszv8Soi1pw==", "dev": true, "requires": { - "array-union": "1.0.2", - "dir-glob": "2.0.0", - "fast-glob": "2.2.4", - "glob": "7.1.3", - "ignore": "3.3.10", - "pify": "3.0.0", - "slash": "1.0.0" + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" }, "dependencies": { "glob": { @@ -5340,12 +5321,12 @@ "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.3.3", - "path-is-absolute": "1.0.1" + "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" } }, "ignore": { @@ -5360,7 +5341,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } } } @@ -5371,9 +5352,9 @@ "integrity": "sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU=", "dev": true, "requires": { - "glob": "3.1.21", - "lodash": "1.0.2", - "minimatch": "0.2.14" + "glob": "~3.1.21", + "lodash": "~1.0.1", + "minimatch": "~0.2.11" }, "dependencies": { "glob": { @@ -5382,14 +5363,14 @@ "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", "dev": true, "requires": { - "graceful-fs": "1.2.3", - "inherits": "1.0.2", - "minimatch": "0.2.14" + "graceful-fs": "~1.2.0", + "inherits": "1", + "minimatch": "~0.2.11" } }, "graceful-fs": { "version": "1.2.3", - "resolved": "http://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", "dev": true }, @@ -5401,7 +5382,7 @@ }, "lodash": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", "integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=", "dev": true }, @@ -5411,8 +5392,8 @@ "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", "dev": true, "requires": { - "lru-cache": "2.7.3", - "sigmund": "1.0.1" + "lru-cache": "2", + "sigmund": "~1.0.0" } } } @@ -5420,10 +5401,10 @@ "glogg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.1.tgz", - "integrity": "sha512-ynYqXLoluBKf9XGR1gA59yEJisIL7YHEH4xr3ZziHB5/yl4qWfaK8Js9jGe6gBGCSCKVqiyO30WnRZADvemUNw==", + "integrity": "sha1-3PdY5EeJzD89MsHzVio2duajSBA=", "dev": true, "requires": { - "sparkles": "1.0.1" + "sparkles": "^1.0.0" } }, "good-listener": { @@ -5431,7 +5412,7 @@ "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", "requires": { - "delegate": "3.2.0" + "delegate": "^3.1.2" } }, "got": { @@ -5441,29 +5422,29 @@ "dev": true, "optional": true, "requires": { - "decompress-response": "3.3.0", - "duplexer3": "0.1.4", - "get-stream": "3.0.0", - "is-plain-obj": "1.1.0", - "is-retry-allowed": "1.1.0", - "is-stream": "1.1.0", - "isurl": "1.0.0", - "lowercase-keys": "1.0.1", - "p-cancelable": "0.3.0", - "p-timeout": "1.2.1", - "safe-buffer": "5.1.2", - "timed-out": "4.0.1", - "url-parse-lax": "1.0.0", - "url-to-options": "1.0.1" + "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" } }, "graceful-fs": { "version": "3.0.11", - "resolved": "http://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz", "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=", "dev": true, "requires": { - "natives": "1.1.6" + "natives": "^1.1.0" } }, "graceful-readlink": { @@ -5478,19 +5459,19 @@ "integrity": "sha1-VxzkWSjdQK9lFPxAEYZgFsE4RbQ=", "dev": true, "requires": { - "archy": "1.0.0", - "chalk": "1.1.3", - "deprecated": "0.0.1", - "gulp-util": "3.0.8", - "interpret": "1.1.0", - "liftoff": "2.5.0", - "minimist": "1.2.0", - "orchestrator": "0.3.8", - "pretty-hrtime": "1.0.3", - "semver": "4.3.6", - "tildify": "1.2.0", - "v8flags": "2.1.1", - "vinyl-fs": "0.3.14" + "archy": "^1.0.0", + "chalk": "^1.0.0", + "deprecated": "^0.0.1", + "gulp-util": "^3.0.0", + "interpret": "^1.0.0", + "liftoff": "^2.1.0", + "minimist": "^1.1.0", + "orchestrator": "^0.3.0", + "pretty-hrtime": "^1.0.0", + "semver": "^4.1.0", + "tildify": "^1.0.0", + "v8flags": "^2.0.2", + "vinyl-fs": "^0.3.0" }, "dependencies": { "ansi-styles": { @@ -5505,11 +5486,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "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" } }, "semver": { @@ -5532,10 +5513,10 @@ "integrity": "sha512-oomaIqDXxFkg7lbpBou/gnUkX51/Y/M2ZfSjL2hdqXTAlSWZcgZtd2o0cOH0r/eE8LWD0+Q/PsLsr2DKOoqToQ==", "dev": true, "requires": { - "plugin-error": "1.0.1", - "replace-ext": "1.0.0", - "through2": "2.0.5", - "vinyl-sourcemaps-apply": "0.2.1" + "plugin-error": "^1.0.1", + "replace-ext": "^1.0.0", + "through2": "^2.0.0", + "vinyl-sourcemaps-apply": "^0.2.0" }, "dependencies": { "replace-ext": { @@ -5564,9 +5545,9 @@ "integrity": "sha512-9E1oLoOWfhSXHGv6QlwXJim7uNzd9EVlWK+21tCU9Ju/kR0/p2AZYPz4qSchgO8PlLIH4FpZYfzwS+rEksZjIg==", "dev": true, "requires": { - "inherits": "2.0.3", - "string_decoder": "1.2.0", - "util-deprecate": "1.0.2" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } }, "string_decoder": { @@ -5575,7 +5556,7 @@ "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } }, "through2": { @@ -5584,8 +5565,8 @@ "integrity": "sha512-8B+sevlqP4OiCjonI1Zw03Sf8PuV1eRsYQgLad5eonILOdyeRsY27A/2Ze8IlvlMvq31OH+3fz/styI7Ya62yQ==", "dev": true, "requires": { - "readable-stream": "3.0.6", - "xtend": "4.0.1" + "readable-stream": "2 || 3", + "xtend": "~4.0.1" } } } @@ -5596,9 +5577,9 @@ "integrity": "sha1-Yz0WyV2IUEYorQJmVmPO5aR5M1M=", "dev": true, "requires": { - "concat-with-sourcemaps": "1.1.0", - "through2": "2.0.5", - "vinyl": "2.2.0" + "concat-with-sourcemaps": "^1.0.0", + "through2": "^2.0.0", + "vinyl": "^2.0.0" }, "dependencies": { "clone": { @@ -5625,12 +5606,12 @@ "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", "dev": true, "requires": { - "clone": "2.1.2", - "clone-buffer": "1.0.0", - "clone-stats": "1.0.0", - "cloneable-readable": "1.1.2", - "remove-trailing-separator": "1.1.0", - "replace-ext": "1.0.0" + "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" } } } @@ -5641,15 +5622,15 @@ "integrity": "sha512-FknHeA6smZhiRNrK/3UVH8BHLCFHS7WZdE7Y2VbZHtxye1UTIa5ZY0Cnst6O9n3kL8z7y43QI+acx3nUtJoiHw==", "dev": true, "requires": { - "ansi-colors": "2.0.5", - "connect": "3.6.6", - "connect-livereload": "0.6.0", - "event-stream": "3.3.5", - "fancy-log": "1.3.3", - "send": "0.16.2", - "serve-index": "1.9.1", - "serve-static": "1.13.2", - "tiny-lr": "1.1.1" + "ansi-colors": "^2.0.5", + "connect": "^3.6.6", + "connect-livereload": "^0.6.0", + "event-stream": "^3.3.4", + "fancy-log": "^1.3.2", + "send": "^0.16.2", + "serve-index": "^1.9.1", + "serve-static": "^1.13.2", + "tiny-lr": "^1.1.1" }, "dependencies": { "ansi-colors": { @@ -5666,9 +5647,9 @@ "integrity": "sha512-9GUqCqh85C7rP9120cpxXuZz2ayq3BZc85pCTuPJS03VQYxne0aWPIXWx6LSvsGPa3uRqtSO537vaugOh+5cXg==", "dev": true, "requires": { - "eslint": "5.9.0", - "fancy-log": "1.3.3", - "plugin-error": "1.0.1" + "eslint": "^5.0.1", + "fancy-log": "^1.3.2", + "plugin-error": "^1.0.1" } }, "gulp-imagemin": { @@ -5677,17 +5658,17 @@ "integrity": "sha512-bKJMix4r6EQPVV2u8sUglw6Rn0PSp6i70pSK2ECN7j0dRy0w/Lz5SBbynY3MfGBZ0cTMZlaUq+6LyKlZgP74Ew==", "dev": true, "requires": { - "chalk": "2.4.1", - "fancy-log": "1.3.3", - "imagemin": "6.0.0", - "imagemin-gifsicle": "6.0.1", - "imagemin-jpegtran": "6.0.0", - "imagemin-optipng": "6.0.0", - "imagemin-svgo": "7.0.0", - "plugin-error": "1.0.1", - "plur": "3.0.1", - "pretty-bytes": "5.1.0", - "through2-concurrent": "2.0.0" + "chalk": "^2.4.1", + "fancy-log": "^1.3.2", + "imagemin": "^6.0.0", + "imagemin-gifsicle": "^6.0.1", + "imagemin-jpegtran": "^6.0.0", + "imagemin-optipng": "^6.0.0", + "imagemin-svgo": "^7.0.0", + "plugin-error": "^1.0.1", + "plur": "^3.0.1", + "pretty-bytes": "^5.1.0", + "through2-concurrent": "^2.0.0" } }, "gulp-less": { @@ -5696,13 +5677,13 @@ "integrity": "sha512-hmM2k0FfQp7Ptm3ZaqO2CkMX3hqpiIOn4OHtuSsCeFym63F7oWlEua5v6u1cIjVUKYsVIs9zPg9vbqTEb/udpA==", "dev": true, "requires": { - "accord": "0.29.0", - "less": "3.9.0", - "object-assign": "4.1.1", - "plugin-error": "0.1.2", - "replace-ext": "1.0.0", - "through2": "2.0.5", - "vinyl-sourcemaps-apply": "0.2.1" + "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" }, "dependencies": { "arr-diff": { @@ -5711,8 +5692,8 @@ "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=", "dev": true, "requires": { - "arr-flatten": "1.1.0", - "array-slice": "0.2.3" + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" } }, "arr-union": { @@ -5733,7 +5714,7 @@ "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", "dev": true, "requires": { - "kind-of": "1.1.0" + "kind-of": "^1.1.0" } }, "kind-of": { @@ -5754,11 +5735,11 @@ "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=", "dev": true, "requires": { - "ansi-cyan": "0.1.1", - "ansi-red": "0.1.1", - "arr-diff": "1.1.0", - "arr-union": "2.1.0", - "extend-shallow": "1.1.4" + "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" } }, "replace-ext": { @@ -5775,12 +5756,13 @@ "integrity": "sha1-J7Z6Ql6zh1ImNFq4lgTXN/Y1fCE=", "dev": true, "requires": { - "angular": "1.3.20", - "angular-animate": "1.3.20", + "angular": "~1.3.1", + "angular-animate": "~1.3.1", "canonical-path": "0.0.2", "extend": "1.3.0", "gulp-util": "3.0.0", "lodash": "2.4.1", + "marked": "0.3.2", "merge-stream": "0.1.5", "path": "0.4.9", "string_decoder": "0.10.31", @@ -5802,7 +5784,7 @@ }, "ansi-regex": { "version": "0.2.1", - "resolved": "http://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz", "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=", "dev": true }, @@ -5814,15 +5796,15 @@ }, "chalk": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=", "dev": true, "requires": { - "ansi-styles": "1.1.0", - "escape-string-regexp": "1.0.5", - "has-ansi": "0.1.0", - "strip-ansi": "0.3.0", - "supports-color": "0.2.0" + "ansi-styles": "^1.1.0", + "escape-string-regexp": "^1.0.0", + "has-ansi": "^0.1.0", + "strip-ansi": "^0.3.0", + "supports-color": "^0.2.0" } }, "clone": { @@ -5837,8 +5819,8 @@ "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", "dev": true, "requires": { - "get-stdin": "4.0.1", - "meow": "3.7.0" + "get-stdin": "^4.0.1", + "meow": "^3.3.0" } }, "extend": { @@ -5853,25 +5835,25 @@ "integrity": "sha1-b+7cR9aXKCO6zplH/F9GvYo0Zuc=", "dev": true, "requires": { - "chalk": "0.5.1", - "dateformat": "1.0.12", - "lodash": "2.4.1", - "lodash._reinterpolate": "2.4.1", - "lodash.template": "2.4.1", - "minimist": "0.2.0", - "multipipe": "0.1.2", - "through2": "0.5.1", - "vinyl": "0.2.3" + "chalk": "^0.5.0", + "dateformat": "^1.0.7-1.2.3", + "lodash": "^2.4.1", + "lodash._reinterpolate": "^2.4.1", + "lodash.template": "^2.4.1", + "minimist": "^0.2.0", + "multipipe": "^0.1.0", + "through2": "^0.5.0", + "vinyl": "^0.2.1" }, "dependencies": { "through2": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/through2/-/through2-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz", "integrity": "sha1-390BLrnHAOIyP9M084rGIqs3Lac=", "dev": true, "requires": { - "readable-stream": "1.0.34", - "xtend": "3.0.0" + "readable-stream": "~1.0.17", + "xtend": "~3.0.0" } } } @@ -5882,12 +5864,12 @@ "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=", "dev": true, "requires": { - "ansi-regex": "0.2.1" + "ansi-regex": "^0.2.0" } }, "lodash": { "version": "2.4.1", - "resolved": "http://registry.npmjs.org/lodash/-/lodash-2.4.1.tgz", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.1.tgz", "integrity": "sha1-W3cjA03aTSYuWkb7LFjXzCL3FCA=", "dev": true }, @@ -5903,8 +5885,8 @@ "integrity": "sha1-p+iIXwXmiFEUS24SqPNngCa8TFQ=", "dev": true, "requires": { - "lodash._objecttypes": "2.4.1", - "lodash.keys": "2.4.1" + "lodash._objecttypes": "~2.4.1", + "lodash.keys": "~2.4.1" } }, "lodash.escape": { @@ -5913,9 +5895,9 @@ "integrity": "sha1-LOEsXghNsKV92l5dHu659dF1o7Q=", "dev": true, "requires": { - "lodash._escapehtmlchar": "2.4.1", - "lodash._reunescapedhtml": "2.4.1", - "lodash.keys": "2.4.1" + "lodash._escapehtmlchar": "~2.4.1", + "lodash._reunescapedhtml": "~2.4.1", + "lodash.keys": "~2.4.1" } }, "lodash.keys": { @@ -5924,9 +5906,9 @@ "integrity": "sha1-SN6kbfj/djKxDXBrissmWR4rNyc=", "dev": true, "requires": { - "lodash._isnative": "2.4.1", - "lodash._shimkeys": "2.4.1", - "lodash.isobject": "2.4.1" + "lodash._isnative": "~2.4.1", + "lodash._shimkeys": "~2.4.1", + "lodash.isobject": "~2.4.1" } }, "lodash.template": { @@ -5935,13 +5917,13 @@ "integrity": "sha1-nmEQB+32KRKal0qzxIuBez4c8g0=", "dev": true, "requires": { - "lodash._escapestringchar": "2.4.1", - "lodash._reinterpolate": "2.4.1", - "lodash.defaults": "2.4.1", - "lodash.escape": "2.4.1", - "lodash.keys": "2.4.1", - "lodash.templatesettings": "2.4.1", - "lodash.values": "2.4.1" + "lodash._escapestringchar": "~2.4.1", + "lodash._reinterpolate": "~2.4.1", + "lodash.defaults": "~2.4.1", + "lodash.escape": "~2.4.1", + "lodash.keys": "~2.4.1", + "lodash.templatesettings": "~2.4.1", + "lodash.values": "~2.4.1" } }, "lodash.templatesettings": { @@ -5950,56 +5932,62 @@ "integrity": "sha1-6nbHXRHrhtTb6JqDiTu4YZKaxpk=", "dev": true, "requires": { - "lodash._reinterpolate": "2.4.1", - "lodash.escape": "2.4.1" + "lodash._reinterpolate": "~2.4.1", + "lodash.escape": "~2.4.1" } }, + "marked": { + "version": "0.3.2", + "resolved": "http://registry.npmjs.org/marked/-/marked-0.3.2.tgz", + "integrity": "sha1-AV2xWIZEOPJKZL3WGgQotBhwbQk=", + "dev": true + }, "merge-stream": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-0.1.5.tgz", "integrity": "sha1-5oIPet267gA/SMpKWMfFolPV4Fw=", "dev": true, "requires": { - "through2": "0.5.1" + "through2": "^0.5.1" }, "dependencies": { "through2": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/through2/-/through2-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz", "integrity": "sha1-390BLrnHAOIyP9M084rGIqs3Lac=", "dev": true, "requires": { - "readable-stream": "1.0.34", - "xtend": "3.0.0" + "readable-stream": "~1.0.17", + "xtend": "~3.0.0" } } } }, "minimist": { "version": "0.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.2.0.tgz", "integrity": "sha1-Tf/lJdriuGTGbC4jxicdev3s784=", "dev": true }, "readable-stream": { "version": "1.0.34", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", "isarray": "0.0.1", - "string_decoder": "0.10.31" + "string_decoder": "~0.10.x" } }, "strip-ansi": { "version": "0.3.0", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=", "dev": true, "requires": { - "ansi-regex": "0.2.1" + "ansi-regex": "^0.2.1" } }, "supports-color": { @@ -6010,12 +5998,12 @@ }, "through2": { "version": "0.6.1", - "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.1.tgz", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.1.tgz", "integrity": "sha1-90KzKJPovSYUbnieT9LMssB6cX4=", "dev": true, "requires": { - "readable-stream": "1.0.34", - "xtend": "4.0.1" + "readable-stream": ">=1.0.27-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" }, "dependencies": { "xtend": { @@ -6032,7 +6020,7 @@ "integrity": "sha1-vKk4IJWC7FpJrVOKAPofEl5RMlI=", "dev": true, "requires": { - "clone-stats": "0.0.1" + "clone-stats": "~0.0.1" } }, "vinyl-fs": { @@ -6041,14 +6029,14 @@ "integrity": "sha1-LiXP5t9cgIGPl/9Be/XCGkHkpJs=", "dev": true, "requires": { - "glob-stream": "3.1.18", - "glob-watcher": "0.0.6", - "graceful-fs": "3.0.11", - "lodash": "2.4.1", - "mkdirp": "0.5.1", - "strip-bom": "1.0.0", - "through2": "0.6.1", - "vinyl": "0.4.6" + "glob-stream": "^3.1.5", + "glob-watcher": "^0.0.6", + "graceful-fs": "^3.0.0", + "lodash": "^2.4.1", + "mkdirp": "^0.5.0", + "strip-bom": "^1.0.0", + "through2": "^0.6.1", + "vinyl": "^0.4.0" }, "dependencies": { "vinyl": { @@ -6057,8 +6045,8 @@ "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", "dev": true, "requires": { - "clone": "0.2.0", - "clone-stats": "0.0.1" + "clone": "^0.2.0", + "clone-stats": "^0.0.1" } } } @@ -6077,10 +6065,10 @@ "integrity": "sha512-dohokw+npnt48AsD0hhvCLEHLnDMqM35F+amvIfJlX1H2nNHYUClR0Oy1rI0TvbL1/pHiHGNLmohhk+kvwIKjA==", "dev": true, "requires": { - "colors": "1.1.2", + "colors": "^1.1.2", "opn": "5.2.0", - "plugin-log": "0.1.0", - "through2": "2.0.5" + "plugin-log": "^0.1.0", + "through2": "^2.0.1" } }, "gulp-postcss": { @@ -6089,11 +6077,11 @@ "integrity": "sha512-Wtl6vH7a+8IS/fU5W9IbOpcaLqKxd5L1DUOzaPmlnCbX1CrG0aWdwVnC3Spn8th0m8D59YbysV5zPUe1n/GJYg==", "dev": true, "requires": { - "fancy-log": "1.3.3", - "plugin-error": "1.0.1", - "postcss": "7.0.6", - "postcss-load-config": "2.0.0", - "vinyl-sourcemaps-apply": "0.2.1" + "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" } }, "gulp-rename": { @@ -6108,7 +6096,7 @@ "integrity": "sha1-xnYqLx8N4KP8WVohWZ0/rI26Gso=", "dev": true, "requires": { - "through2": "2.0.5" + "through2": "^2.0.1" } }, "gulp-util": { @@ -6117,24 +6105,24 @@ "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", "dev": true, "requires": { - "array-differ": "1.0.0", - "array-uniq": "1.0.3", - "beeper": "1.1.1", - "chalk": "1.1.3", - "dateformat": "2.2.0", - "fancy-log": "1.3.3", - "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.6.2", - "minimist": "1.2.0", - "multipipe": "0.1.2", - "object-assign": "3.0.0", + "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.5", - "vinyl": "0.5.3" + "through2": "^2.0.0", + "vinyl": "^0.5.0" }, "dependencies": { "ansi-styles": { @@ -6149,11 +6137,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "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": { @@ -6171,17 +6159,17 @@ "dev": true, "requires": { "ansi-colors": "1.1.0", - "anymatch": "1.3.2", - "chokidar": "2.0.4", + "anymatch": "^1.3.0", + "chokidar": "^2.0.0", "fancy-log": "1.3.2", - "glob-parent": "3.1.0", - "object-assign": "4.1.1", - "path-is-absolute": "1.0.1", + "glob-parent": "^3.0.1", + "object-assign": "^4.1.0", + "path-is-absolute": "^1.0.1", "plugin-error": "1.0.1", - "readable-stream": "2.3.6", - "slash": "1.0.0", - "vinyl": "2.2.0", - "vinyl-file": "2.0.0" + "readable-stream": "^2.2.2", + "slash": "^1.0.0", + "vinyl": "^2.1.0", + "vinyl-file": "^2.0.0" }, "dependencies": { "clone": { @@ -6202,9 +6190,9 @@ "integrity": "sha1-9BEl49hPLn2JpD0G2VjI94vha+E=", "dev": true, "requires": { - "ansi-gray": "0.1.1", - "color-support": "1.1.3", - "time-stamp": "1.1.0" + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "time-stamp": "^1.0.0" } }, "isarray": { @@ -6225,13 +6213,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "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" } }, "replace-ext": { @@ -6246,7 +6234,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } }, "vinyl": { @@ -6255,12 +6243,12 @@ "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", "dev": true, "requires": { - "clone": "2.1.2", - "clone-buffer": "1.0.0", - "clone-stats": "1.0.0", - "cloneable-readable": "1.1.2", - "remove-trailing-separator": "1.1.0", - "replace-ext": "1.0.0" + "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" } } } @@ -6271,16 +6259,16 @@ "integrity": "sha1-FaXCBI4nIecFOaYbrxw0oLxfJyk=", "dev": true, "requires": { - "consolidate": "0.14.5", - "es6-promise": "3.3.1", - "fs-readfile-promise": "2.0.1", - "js-yaml": "3.12.0", - "lodash": "4.17.11", - "node.extend": "1.1.8", - "plugin-error": "0.1.2", - "through2": "2.0.5", - "tryit": "1.0.3", - "vinyl-bufferstream": "1.0.1" + "consolidate": "^0.14.1", + "es6-promise": "^3.1.2", + "fs-readfile-promise": "^2.0.1", + "js-yaml": "^3.2.6", + "lodash": "^4.11.1", + "node.extend": "^1.1.2", + "plugin-error": "^0.1.2", + "through2": "^2.0.1", + "tryit": "^1.0.1", + "vinyl-bufferstream": "^1.0.1" }, "dependencies": { "arr-diff": { @@ -6289,8 +6277,8 @@ "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=", "dev": true, "requires": { - "arr-flatten": "1.1.0", - "array-slice": "0.2.3" + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" } }, "arr-union": { @@ -6311,7 +6299,7 @@ "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", "dev": true, "requires": { - "kind-of": "1.1.0" + "kind-of": "^1.1.0" } }, "kind-of": { @@ -6326,11 +6314,11 @@ "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=", "dev": true, "requires": { - "ansi-cyan": "0.1.1", - "ansi-red": "0.1.1", - "arr-diff": "1.1.0", - "arr-union": "2.1.0", - "extend-shallow": "1.1.4" + "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" } } } @@ -6341,12 +6329,12 @@ "integrity": "sha1-3uYqpISqupVHqT0f9c0MPQvtwDE=", "dev": true, "requires": { - "escodegen": "1.11.0", - "esprima": "2.7.3", - "estemplate": "0.5.1", - "gulp-util": "3.0.8", - "through2": "2.0.5", - "vinyl-sourcemaps-apply": "0.1.4" + "escodegen": "^1.6.1", + "esprima": "^2.3.0", + "estemplate": "*", + "gulp-util": "~3.0.5", + "through2": "*", + "vinyl-sourcemaps-apply": "^0.1.4" }, "dependencies": { "esprima": { @@ -6357,11 +6345,11 @@ }, "source-map": { "version": "0.1.43", - "resolved": "http://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", "dev": true, "requires": { - "amdefine": "1.0.1" + "amdefine": ">=0.0.4" } }, "vinyl-sourcemaps-apply": { @@ -6370,7 +6358,7 @@ "integrity": "sha1-xfy9Q+LyOEI8LcmL3db3m3K8NFs=", "dev": true, "requires": { - "source-map": "0.1.43" + "source-map": "^0.1.39" } } } @@ -6381,7 +6369,7 @@ "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", "dev": true, "requires": { - "glogg": "1.0.1" + "glogg": "^1.0.0" } }, "har-schema": { @@ -6396,8 +6384,8 @@ "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "dev": true, "requires": { - "ajv": "6.6.1", - "har-schema": "2.0.0" + "ajv": "^6.5.5", + "har-schema": "^2.0.0" } }, "has": { @@ -6406,7 +6394,7 @@ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { - "function-bind": "1.1.1" + "function-bind": "^1.1.1" } }, "has-ansi": { @@ -6415,7 +6403,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "has-binary2": { @@ -6453,7 +6441,7 @@ "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", "dev": true, "requires": { - "sparkles": "1.0.1" + "sparkles": "^1.0.0" } }, "has-symbol-support-x": { @@ -6474,7 +6462,7 @@ "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", "dev": true, "requires": { - "has-symbol-support-x": "1.4.2" + "has-symbol-support-x": "^1.4.1" } }, "has-value": { @@ -6483,9 +6471,9 @@ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "dev": true, "requires": { - "get-value": "2.0.6", - "has-values": "1.0.0", - "isobject": "3.0.1" + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" } }, "has-values": { @@ -6494,8 +6482,8 @@ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "dev": true, "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" + "is-number": "^3.0.0", + "kind-of": "^4.0.0" }, "dependencies": { "kind-of": { @@ -6504,7 +6492,7 @@ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -6515,8 +6503,8 @@ "integrity": "sha1-eNfL/B5tZjA/55g3NlmEUXsvbuE=", "dev": true, "requires": { - "is-stream": "1.1.0", - "pinkie-promise": "2.0.1" + "is-stream": "^1.0.1", + "pinkie-promise": "^2.0.0" } }, "hex-color-regex": { @@ -6531,7 +6519,7 @@ "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", "dev": true, "requires": { - "parse-passwd": "1.0.0" + "parse-passwd": "^1.0.0" } }, "hosted-git-info": { @@ -6571,10 +6559,10 @@ "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "dev": true, "requires": { - "depd": "1.1.2", + "depd": "~1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.0", - "statuses": "1.5.0" + "statuses": ">= 1.4.0 < 2" }, "dependencies": { "statuses": { @@ -6597,9 +6585,9 @@ "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", "dev": true, "requires": { - "eventemitter3": "3.1.0", - "follow-redirects": "1.5.10", - "requires-port": "1.0.0" + "eventemitter3": "^3.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" } }, "http-signature": { @@ -6608,9 +6596,9 @@ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "dev": true, "requires": { - "assert-plus": "1.0.0", - "jsprim": "1.4.1", - "sshpk": "1.15.2" + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, "iconv-lite": { @@ -6619,7 +6607,7 @@ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } }, "ieee754": { @@ -6647,12 +6635,12 @@ "integrity": "sha512-m4Mxwt2QvCp1F85HXoTungXk0Y6XzuvQGqrK9qEddQfo/7x4aZjRENmyXXfc29ei4Mk55rW002bORG86YM3/aQ==", "dev": true, "requires": { - "file-type": "8.1.0", - "globby": "8.0.1", - "make-dir": "1.3.0", - "p-pipe": "1.2.0", - "pify": "3.0.0", - "replace-ext": "1.0.0" + "file-type": "^8.1.0", + "globby": "^8.0.1", + "make-dir": "^1.0.0", + "p-pipe": "^1.1.0", + "pify": "^3.0.0", + "replace-ext": "^1.0.0" }, "dependencies": { "replace-ext": { @@ -6670,9 +6658,9 @@ "dev": true, "optional": true, "requires": { - "exec-buffer": "3.2.0", - "gifsicle": "4.0.1", - "is-gif": "3.0.0" + "exec-buffer": "^3.0.0", + "gifsicle": "^4.0.0", + "is-gif": "^3.0.0" } }, "imagemin-jpegtran": { @@ -6682,9 +6670,9 @@ "dev": true, "optional": true, "requires": { - "exec-buffer": "3.2.0", - "is-jpg": "2.0.0", - "jpegtran-bin": "4.0.0" + "exec-buffer": "^3.0.0", + "is-jpg": "^2.0.0", + "jpegtran-bin": "^4.0.0" } }, "imagemin-optipng": { @@ -6694,9 +6682,9 @@ "dev": true, "optional": true, "requires": { - "exec-buffer": "3.2.0", - "is-png": "1.1.0", - "optipng-bin": "5.0.0" + "exec-buffer": "^3.0.0", + "is-png": "^1.0.0", + "optipng-bin": "^5.0.0" } }, "imagemin-svgo": { @@ -6706,8 +6694,8 @@ "dev": true, "optional": true, "requires": { - "is-svg": "3.0.0", - "svgo": "1.1.1" + "is-svg": "^3.0.0", + "svgo": "^1.0.5" } }, "import-cwd": { @@ -6716,7 +6704,7 @@ "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", "dev": true, "requires": { - "import-from": "2.1.0" + "import-from": "^2.1.0" } }, "import-fresh": { @@ -6725,8 +6713,8 @@ "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", "dev": true, "requires": { - "caller-path": "2.0.0", - "resolve-from": "3.0.0" + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" } }, "import-from": { @@ -6735,7 +6723,7 @@ "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", "dev": true, "requires": { - "resolve-from": "3.0.0" + "resolve-from": "^3.0.0" } }, "import-lazy": { @@ -6757,7 +6745,7 @@ "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", "dev": true, "requires": { - "repeating": "2.0.1" + "repeating": "^2.0.0" } }, "indexes-of": { @@ -6784,8 +6772,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.3.3", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -6797,7 +6785,7 @@ "ini": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "integrity": "sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc=", "dev": true }, "inquirer": { @@ -6806,19 +6794,19 @@ "integrity": "sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg==", "dev": true, "requires": { - "ansi-escapes": "3.1.0", - "chalk": "2.4.1", - "cli-cursor": "2.1.0", - "cli-width": "2.2.0", - "external-editor": "3.0.3", - "figures": "2.0.0", - "lodash": "4.17.11", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.0", + "figures": "^2.0.0", + "lodash": "^4.17.10", "mute-stream": "0.0.7", - "run-async": "2.3.0", - "rxjs": "6.3.3", - "string-width": "2.1.1", - "strip-ansi": "5.0.0", - "through": "2.3.8" + "run-async": "^2.2.0", + "rxjs": "^6.1.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.0.0", + "through": "^2.3.6" }, "dependencies": { "ansi-regex": { @@ -6833,7 +6821,7 @@ "integrity": "sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==", "dev": true, "requires": { - "ansi-regex": "4.0.0" + "ansi-regex": "^4.0.0" } } } @@ -6851,8 +6839,8 @@ "dev": true, "optional": true, "requires": { - "from2": "2.3.0", - "p-is-promise": "1.1.0" + "from2": "^2.1.1", + "p-is-promise": "^1.1.0" } }, "invariant": { @@ -6861,7 +6849,7 @@ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "dev": true, "requires": { - "loose-envify": "1.4.0" + "loose-envify": "^1.0.0" } }, "irregular-plurals": { @@ -6882,8 +6870,8 @@ "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", "dev": true, "requires": { - "is-relative": "1.0.0", - "is-windows": "1.0.2" + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" } }, "is-absolute-url": { @@ -6898,7 +6886,7 @@ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -6907,7 +6895,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -6924,28 +6912,28 @@ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", "dev": true, "requires": { - "binary-extensions": "1.12.0" + "binary-extensions": "^1.0.0" } }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=", "dev": true }, "is-builtin-module": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { - "builtin-modules": "1.1.1" + "builtin-modules": "^1.0.0" } }, "is-callable": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "integrity": "sha1-HhrfIZ4e62hNaR+dagX/DTCiTXU=", "dev": true }, "is-color-stop": { @@ -6954,12 +6942,12 @@ "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", "dev": true, "requires": { - "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" + "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" } }, "is-data-descriptor": { @@ -6968,7 +6956,7 @@ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -6977,7 +6965,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -6991,18 +6979,18 @@ "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=", "dev": true, "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" }, "dependencies": { "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==", + "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", "dev": true } } @@ -7025,7 +7013,7 @@ "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", "dev": true, "requires": { - "is-primitive": "2.0.0" + "is-primitive": "^2.0.0" } }, "is-extendable": { @@ -7046,7 +7034,7 @@ "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "dev": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "is-fullwidth-code-point": { @@ -7062,7 +7050,7 @@ "dev": true, "optional": true, "requires": { - "file-type": "10.6.0" + "file-type": "^10.4.0" }, "dependencies": { "file-type": { @@ -7080,7 +7068,7 @@ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.0" } }, "is-jpg": { @@ -7102,7 +7090,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -7111,7 +7099,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -7137,10 +7125,10 @@ "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==", + "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" } }, "is-png": { @@ -7174,7 +7162,7 @@ "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", "dev": true, "requires": { - "has": "1.0.3" + "has": "^1.0.1" } }, "is-relative": { @@ -7183,7 +7171,7 @@ "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", "dev": true, "requires": { - "is-unc-path": "1.0.0" + "is-unc-path": "^1.0.0" } }, "is-resolvable": { @@ -7210,7 +7198,7 @@ "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", "dev": true, "requires": { - "html-comment-regex": "1.1.2" + "html-comment-regex": "^1.1.0" } }, "is-symbol": { @@ -7219,7 +7207,7 @@ "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", "dev": true, "requires": { - "has-symbols": "1.0.0" + "has-symbols": "^1.0.0" } }, "is-typedarray": { @@ -7234,7 +7222,7 @@ "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", "dev": true, "requires": { - "unc-path-regex": "0.1.2" + "unc-path-regex": "^0.1.2" } }, "is-utf8": { @@ -7246,7 +7234,7 @@ "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==", + "integrity": "sha1-0YUOuXkezRjmGCzhKjDzlmNLsZ0=", "dev": true }, "is-wsl": { @@ -7267,7 +7255,7 @@ "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", "dev": true, "requires": { - "buffer-alloc": "1.2.0" + "buffer-alloc": "^1.2.0" } }, "isexe": { @@ -7294,8 +7282,8 @@ "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", "dev": true, "requires": { - "has-to-string-tag-x": "1.4.1", - "is-object": "1.0.1" + "has-to-string-tag-x": "^1.2.0", + "is-object": "^1.0.1" } }, "jasmine-core": { @@ -7311,9 +7299,9 @@ "dev": true, "optional": true, "requires": { - "bin-build": "3.0.0", - "bin-wrapper": "4.1.0", - "logalot": "2.1.0" + "bin-build": "^3.0.0", + "bin-wrapper": "^4.0.0", + "logalot": "^2.0.0" } }, "jquery": { @@ -7349,8 +7337,8 @@ "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", "dev": true, "requires": { - "argparse": "1.0.10", - "esprima": "4.0.1" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } }, "jsbn": { @@ -7408,16 +7396,16 @@ "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", "dev": true, "requires": { - "minimist": "1.2.0" + "minimist": "^1.2.0" } }, "jsonfile": { "version": "2.4.0", - "resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "dev": true, "requires": { - "graceful-fs": "4.1.15" + "graceful-fs": "^4.1.6" }, "dependencies": { "graceful-fs": { @@ -7447,31 +7435,31 @@ "integrity": "sha512-NetT3wPCQMNB36uiL9LLyhrOt8SQwrEKt0xD3+KpTCfm0VxVyUJdPL5oTq2Ic5ouemgL/Iz4wqXEbF3zea9kQQ==", "dev": true, "requires": { - "bluebird": "3.5.3", - "body-parser": "1.18.3", - "chokidar": "2.0.4", - "colors": "1.1.2", - "combine-lists": "1.0.1", - "connect": "3.6.6", - "core-js": "2.5.7", - "di": "0.0.1", - "dom-serialize": "2.2.1", - "expand-braces": "0.1.2", - "glob": "7.1.3", - "graceful-fs": "4.1.15", - "http-proxy": "1.17.0", - "isbinaryfile": "3.0.3", - "lodash": "4.17.11", - "log4js": "3.0.6", - "mime": "2.4.0", - "minimatch": "3.0.4", - "optimist": "0.6.1", - "qjobs": "1.2.0", - "range-parser": "1.2.0", - "rimraf": "2.6.2", - "safe-buffer": "5.1.2", + "bluebird": "^3.3.0", + "body-parser": "^1.16.1", + "chokidar": "^2.0.3", + "colors": "^1.1.0", + "combine-lists": "^1.0.0", + "connect": "^3.6.0", + "core-js": "^2.2.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.0", + "expand-braces": "^0.1.1", + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "http-proxy": "^1.13.0", + "isbinaryfile": "^3.0.0", + "lodash": "^4.17.4", + "log4js": "^3.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", + "source-map": "^0.6.1", "tmp": "0.0.33", "useragent": "2.2.1" }, @@ -7482,12 +7470,12 @@ "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.3.3", - "path-is-absolute": "1.0.1" + "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" } }, "graceful-fs": { @@ -7508,7 +7496,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "source-map": { @@ -7525,7 +7513,7 @@ "integrity": "sha512-iuC0hmr9b+SNn1DaUD2QEYtUxkS1J+bSJSn7ejdEexs7P8EYvA1CWkEdrDQ+8jVH3AgWlCNwjYsT1chjcNW9lA==", "dev": true, "requires": { - "jasmine-core": "3.3.0" + "jasmine-core": "^3.3" } }, "karma-phantomjs-launcher": { @@ -7534,13 +7522,13 @@ "integrity": "sha1-0jyjSAG9qYY60xjju0vUBisTrNI=", "dev": true, "requires": { - "lodash": "4.17.11", - "phantomjs-prebuilt": "2.1.16" + "lodash": "^4.0.1", + "phantomjs-prebuilt": "^2.1.7" } }, "kew": { "version": "0.7.0", - "resolved": "http://registry.npmjs.org/kew/-/kew-0.7.0.tgz", + "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", "dev": true }, @@ -7557,7 +7545,7 @@ "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", "dev": true }, "klaw": { @@ -7566,7 +7554,7 @@ "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", "dev": true, "requires": { - "graceful-fs": "4.1.15" + "graceful-fs": "^4.1.9" }, "dependencies": { "graceful-fs": { @@ -7595,15 +7583,15 @@ "integrity": "sha512-31CmtPEZraNUtuUREYjSqRkeETFdyEHSEPAGq4erDlUXtda7pzNmctdljdIagSb589d/qXGWiiP31R5JVf+v0w==", "dev": true, "requires": { - "clone": "2.1.2", - "errno": "0.1.7", - "graceful-fs": "4.1.15", - "image-size": "0.5.5", - "mime": "1.4.1", - "mkdirp": "0.5.1", - "promise": "7.3.1", - "request": "2.88.0", - "source-map": "0.6.1" + "clone": "^2.1.2", + "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" }, "dependencies": { "clone": { @@ -7634,8 +7622,8 @@ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" } }, "liftoff": { @@ -7644,14 +7632,14 @@ "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=", "dev": true, "requires": { - "extend": "3.0.2", - "findup-sync": "2.0.0", - "fined": "1.1.0", - "flagged-respawn": "1.0.0", - "is-plain-object": "2.0.4", - "object.map": "1.0.1", - "rechoir": "0.6.2", - "resolve": "1.8.1" + "extend": "^3.0.0", + "findup-sync": "^2.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" } }, "livereload-js": { @@ -7662,15 +7650,15 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { - "graceful-fs": "4.1.15", - "parse-json": "2.2.0", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "strip-bom": "2.0.0" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" }, "dependencies": { "graceful-fs": { @@ -7685,7 +7673,7 @@ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { - "error-ex": "1.3.2" + "error-ex": "^1.2.0" } }, "pify": { @@ -7700,7 +7688,7 @@ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, "requires": { - "is-utf8": "0.2.1" + "is-utf8": "^0.2.0" } } } @@ -7735,7 +7723,7 @@ "integrity": "sha1-32fDu2t+jh6DGrSL+geVuSr+iZ0=", "dev": true, "requires": { - "lodash._htmlescapes": "2.4.1" + "lodash._htmlescapes": "~2.4.1" } }, "lodash._escapestringchar": { @@ -7798,8 +7786,8 @@ "integrity": "sha1-dHxPxAED6zu4oJduVx96JlnpO6c=", "dev": true, "requires": { - "lodash._htmlescapes": "2.4.1", - "lodash.keys": "2.4.1" + "lodash._htmlescapes": "~2.4.1", + "lodash.keys": "~2.4.1" }, "dependencies": { "lodash.keys": { @@ -7808,9 +7796,9 @@ "integrity": "sha1-SN6kbfj/djKxDXBrissmWR4rNyc=", "dev": true, "requires": { - "lodash._isnative": "2.4.1", - "lodash._shimkeys": "2.4.1", - "lodash.isobject": "2.4.1" + "lodash._isnative": "~2.4.1", + "lodash._shimkeys": "~2.4.1", + "lodash.isobject": "~2.4.1" } } } @@ -7827,7 +7815,7 @@ "integrity": "sha1-bpzJZm/wgfC1psl4uD4kLmlJ0gM=", "dev": true, "requires": { - "lodash._objecttypes": "2.4.1" + "lodash._objecttypes": "~2.4.1" } }, "lodash.clone": { @@ -7854,7 +7842,7 @@ "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", "dev": true, "requires": { - "lodash._root": "3.0.1" + "lodash._root": "^3.0.0" } }, "lodash.flatten": { @@ -7881,7 +7869,7 @@ "integrity": "sha1-Wi5H/mmVPx7mMafrof5k0tBlWPU=", "dev": true, "requires": { - "lodash._objecttypes": "2.4.1" + "lodash._objecttypes": "~2.4.1" } }, "lodash.keys": { @@ -7890,9 +7878,9 @@ "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", "dev": true, "requires": { - "lodash._getnative": "3.9.1", - "lodash.isarguments": "3.1.0", - "lodash.isarray": "3.0.4" + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" } }, "lodash.memoize": { @@ -7904,7 +7892,7 @@ "lodash.merge": { "version": "4.6.1", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", - "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==", + "integrity": "sha1-rcJdnLmbk5HFliTzefu6YNcRHVQ=", "dev": true }, "lodash.partialright": { @@ -7931,15 +7919,15 @@ "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", "dev": true, "requires": { - "lodash._basecopy": "3.0.1", - "lodash._basetostring": "3.0.1", - "lodash._basevalues": "3.0.0", - "lodash._isiterateecall": "3.0.9", - "lodash._reinterpolate": "3.0.0", - "lodash.escape": "3.2.0", - "lodash.keys": "3.1.2", - "lodash.restparam": "3.6.1", - "lodash.templatesettings": "3.1.1" + "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" } }, "lodash.templatesettings": { @@ -7948,8 +7936,8 @@ "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", "dev": true, "requires": { - "lodash._reinterpolate": "3.0.0", - "lodash.escape": "3.2.0" + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0" } }, "lodash.uniq": { @@ -7964,7 +7952,7 @@ "integrity": "sha1-q/UUQ2s8twUAFieXjLzzCxKA7qQ=", "dev": true, "requires": { - "lodash.keys": "2.4.1" + "lodash.keys": "~2.4.1" }, "dependencies": { "lodash.keys": { @@ -7973,9 +7961,9 @@ "integrity": "sha1-SN6kbfj/djKxDXBrissmWR4rNyc=", "dev": true, "requires": { - "lodash._isnative": "2.4.1", - "lodash._shimkeys": "2.4.1", - "lodash.isobject": "2.4.1" + "lodash._isnative": "~2.4.1", + "lodash._shimkeys": "~2.4.1", + "lodash.isobject": "~2.4.1" } } } @@ -7986,10 +7974,10 @@ "integrity": "sha512-ezXZk6oPJCWL483zj64pNkMuY/NcRX5MPiB0zE6tjZM137aeusrOnW1ecxgF9cmwMWkBMhjteQxBPoZBh9FDxQ==", "dev": true, "requires": { - "circular-json": "0.5.9", - "date-format": "1.2.0", - "debug": "3.2.6", - "rfdc": "1.1.2", + "circular-json": "^0.5.5", + "date-format": "^1.2.0", + "debug": "^3.1.0", + "rfdc": "^1.1.2", "streamroller": "0.7.0" }, "dependencies": { @@ -8005,7 +7993,7 @@ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "ms": "2.1.1" + "ms": "^2.1.1" } } } @@ -8017,8 +8005,8 @@ "dev": true, "optional": true, "requires": { - "figures": "1.7.0", - "squeak": "1.3.0" + "figures": "^1.3.5", + "squeak": "^1.0.0" }, "dependencies": { "figures": { @@ -8028,8 +8016,8 @@ "dev": true, "optional": true, "requires": { - "escape-string-regexp": "1.0.5", - "object-assign": "4.1.1" + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" } }, "object-assign": { @@ -8053,7 +8041,7 @@ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "dev": true, "requires": { - "js-tokens": "4.0.0" + "js-tokens": "^3.0.0 || ^4.0.0" } }, "loud-rejection": { @@ -8062,14 +8050,14 @@ "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", "dev": true, "requires": { - "currently-unhandled": "0.4.1", - "signal-exit": "3.0.2" + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" } }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "integrity": "sha1-b54wtHCE2XGnyCD/FabFFnt0wm8=", "dev": true }, "lpad-align": { @@ -8079,25 +8067,25 @@ "dev": true, "optional": true, "requires": { - "get-stdin": "4.0.1", - "indent-string": "2.1.0", - "longest": "1.0.1", - "meow": "3.7.0" + "get-stdin": "^4.0.1", + "indent-string": "^2.1.0", + "longest": "^1.0.0", + "meow": "^3.3.0" } }, "lru-cache": { "version": "2.7.3", - "resolved": "http://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", "dev": true }, "make-dir": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "integrity": "sha1-ecEDO4BRW9bSTsmTPoYMp17ifww=", "dev": true, "requires": { - "pify": "3.0.0" + "pify": "^3.0.0" } }, "make-iterator": { @@ -8106,7 +8094,7 @@ "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.2" } }, "map-cache": { @@ -8133,7 +8121,7 @@ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "dev": true, "requires": { - "object-visit": "1.0.1" + "object-visit": "^1.0.0" } }, "marked": { @@ -8151,31 +8139,31 @@ "mdn-data": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-1.1.4.tgz", - "integrity": "sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA==", + "integrity": "sha1-ULXU/8RXUnZXPE7tuHgIEqhBnwE=", "dev": true }, "media-typer": { "version": "0.3.0", - "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", "dev": true }, "meow": { "version": "3.7.0", - "resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "dev": true, "requires": { - "camelcase-keys": "2.1.0", - "decamelize": "1.2.0", - "loud-rejection": "1.6.0", - "map-obj": "1.0.1", - "minimist": "1.2.0", - "normalize-package-data": "2.4.0", - "object-assign": "4.1.1", - "read-pkg-up": "1.0.1", - "redent": "1.0.0", - "trim-newlines": "1.0.0" + "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" }, "dependencies": { "object-assign": { @@ -8192,7 +8180,7 @@ "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", "dev": true, "requires": { - "readable-stream": "2.3.6" + "readable-stream": "^2.0.1" }, "dependencies": { "isarray": { @@ -8207,13 +8195,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "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" } }, "string_decoder": { @@ -8222,7 +8210,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -8236,22 +8224,22 @@ "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "integrity": "sha1-cIWbyVyYQJUvNZoGij/En57PrCM=", "dev": true, "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "braces": "2.3.2", - "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.13", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "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" } }, "mime": { @@ -8272,7 +8260,7 @@ "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", "dev": true, "requires": { - "mime-db": "1.37.0" + "mime-db": "~1.37.0" } }, "mimic-fn": { @@ -8293,7 +8281,7 @@ "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.0.0" } }, "minimist": { @@ -8305,27 +8293,27 @@ "mixin-deep": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "integrity": "sha1-pJ5yaNzhoNlpjkUybFYm3zVD0P4=", "dev": true, "requires": { - "for-in": "1.0.2", - "is-extendable": "1.0.1" + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" }, "dependencies": { "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==", + "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } }, "mkdirp": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { @@ -8379,17 +8367,17 @@ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, "requires": { - "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.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "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" } }, "natives": { @@ -8427,7 +8415,7 @@ "integrity": "sha512-Ky7q0BO1BBkG/rQz6PkEZ59rwo+aSfhczHP1wwq8IowoVdN/FpiP7qp0XW0P2+BVCWe5fQUBozdbVd54q1RbCQ==", "dev": true, "requires": { - "semver": "5.6.0" + "semver": "^5.3.0" } }, "node.extend": { @@ -8436,20 +8424,20 @@ "integrity": "sha512-L/dvEBwyg3UowwqOUTyDsGBU6kjBQOpOhshio9V3i3BMPv5YUb9+mWNN8MK0IbWqT0AqaTSONZf0aTuMMahWgA==", "dev": true, "requires": { - "has": "1.0.3", - "is": "3.2.1" + "has": "^1.0.3", + "is": "^3.2.1" } }, "normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "integrity": "sha1-EvlaMH1YNSB1oEkHuErIvpisAS8=", "dev": true, "requires": { - "hosted-git-info": "2.7.1", - "is-builtin-module": "1.0.0", - "semver": "5.6.0", - "validate-npm-package-license": "3.0.4" + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, "normalize-path": { @@ -8458,7 +8446,7 @@ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "dev": true, "requires": { - "remove-trailing-separator": "1.1.0" + "remove-trailing-separator": "^1.0.1" } }, "normalize-range": { @@ -8483,132 +8471,132 @@ "resolved": "https://registry.npmjs.org/npm/-/npm-6.4.1.tgz", "integrity": "sha512-mXJL1NTVU136PtuopXCUQaNWuHlXCTp4McwlSW8S9/Aj8OEPAlSBgo8og7kJ01MjCDrkmqFQTvN5tTEhBMhXQg==", "requires": { - "JSONStream": "1.3.4", - "abbrev": "1.1.1", - "ansicolors": "0.3.2", - "ansistyles": "0.1.3", - "aproba": "1.2.0", - "archy": "1.0.0", - "bin-links": "1.1.2", - "bluebird": "3.5.1", - "byte-size": "4.0.3", - "cacache": "11.2.0", - "call-limit": "1.1.0", - "chownr": "1.0.1", - "ci-info": "1.4.0", - "cli-columns": "3.1.2", - "cli-table3": "0.5.0", - "cmd-shim": "2.0.2", - "columnify": "1.5.4", - "config-chain": "1.1.11", - "debuglog": "1.0.1", - "detect-indent": "5.0.0", - "detect-newline": "2.1.0", - "dezalgo": "1.0.3", - "editor": "1.0.0", - "figgy-pudding": "3.4.1", - "find-npm-prefix": "1.0.2", - "fs-vacuum": "1.2.10", - "fs-write-stream-atomic": "1.0.10", - "gentle-fs": "2.0.1", - "glob": "7.1.2", - "graceful-fs": "4.1.11", - "has-unicode": "2.0.1", - "hosted-git-info": "2.7.1", - "iferr": "1.0.2", - "imurmurhash": "0.1.4", - "inflight": "1.0.6", - "inherits": "2.0.3", - "ini": "1.3.5", - "init-package-json": "1.10.3", - "is-cidr": "2.0.6", - "json-parse-better-errors": "1.0.2", - "lazy-property": "1.0.0", - "libcipm": "2.0.2", - "libnpmhook": "4.0.1", - "libnpx": "10.2.0", - "lock-verify": "2.0.2", - "lockfile": "1.0.4", - "lodash._baseindexof": "3.1.0", - "lodash._baseuniq": "4.6.0", - "lodash._bindcallback": "3.0.1", - "lodash._cacheindexof": "3.0.2", - "lodash._createcache": "3.1.2", - "lodash._getnative": "3.9.1", - "lodash.clonedeep": "4.5.0", - "lodash.restparam": "3.6.1", - "lodash.union": "4.6.0", - "lodash.uniq": "4.5.0", - "lodash.without": "4.4.0", - "lru-cache": "4.1.3", - "meant": "1.0.1", - "mississippi": "3.0.0", - "mkdirp": "0.5.1", - "move-concurrently": "1.0.1", - "node-gyp": "3.8.0", - "nopt": "4.0.1", - "normalize-package-data": "2.4.0", - "npm-audit-report": "1.3.1", - "npm-cache-filename": "1.0.2", - "npm-install-checks": "3.0.0", - "npm-lifecycle": "2.1.0", - "npm-package-arg": "6.1.0", - "npm-packlist": "1.1.11", - "npm-pick-manifest": "2.1.0", - "npm-profile": "3.0.2", - "npm-registry-client": "8.6.0", - "npm-registry-fetch": "1.1.0", - "npm-user-validate": "1.0.0", - "npmlog": "4.1.2", - "once": "1.4.0", - "opener": "1.5.0", - "osenv": "0.1.5", - "pacote": "8.1.6", - "path-is-inside": "1.0.2", - "promise-inflight": "1.0.1", - "qrcode-terminal": "0.12.0", - "query-string": "6.1.0", - "qw": "1.0.1", - "read": "1.0.7", - "read-cmd-shim": "1.0.1", - "read-installed": "4.0.3", - "read-package-json": "2.0.13", - "read-package-tree": "5.2.1", - "readable-stream": "2.3.6", - "readdir-scoped-modules": "1.0.2", - "request": "2.88.0", - "retry": "0.12.0", - "rimraf": "2.6.2", - "safe-buffer": "5.1.2", - "semver": "5.5.0", - "sha": "2.0.1", - "slide": "1.1.6", - "sorted-object": "2.0.1", - "sorted-union-stream": "2.1.3", - "ssri": "6.0.0", - "stringify-package": "1.0.0", - "tar": "4.4.6", - "text-table": "0.2.0", - "tiny-relative-date": "1.3.0", + "JSONStream": "^1.3.4", + "abbrev": "~1.1.1", + "ansicolors": "~0.3.2", + "ansistyles": "~0.1.3", + "aproba": "~1.2.0", + "archy": "~1.0.0", + "bin-links": "^1.1.2", + "bluebird": "~3.5.1", + "byte-size": "^4.0.3", + "cacache": "^11.2.0", + "call-limit": "~1.1.0", + "chownr": "~1.0.1", + "ci-info": "^1.4.0", + "cli-columns": "^3.1.2", + "cli-table3": "^0.5.0", + "cmd-shim": "~2.0.2", + "columnify": "~1.5.4", + "config-chain": "~1.1.11", + "debuglog": "*", + "detect-indent": "~5.0.0", + "detect-newline": "^2.1.0", + "dezalgo": "~1.0.3", + "editor": "~1.0.0", + "figgy-pudding": "^3.4.1", + "find-npm-prefix": "^1.0.2", + "fs-vacuum": "~1.2.10", + "fs-write-stream-atomic": "~1.0.10", + "gentle-fs": "^2.0.1", + "glob": "~7.1.2", + "graceful-fs": "~4.1.11", + "has-unicode": "~2.0.1", + "hosted-git-info": "^2.7.1", + "iferr": "^1.0.2", + "imurmurhash": "*", + "inflight": "~1.0.6", + "inherits": "~2.0.3", + "ini": "^1.3.5", + "init-package-json": "^1.10.3", + "is-cidr": "^2.0.6", + "json-parse-better-errors": "^1.0.2", + "lazy-property": "~1.0.0", + "libcipm": "^2.0.2", + "libnpmhook": "^4.0.1", + "libnpx": "^10.2.0", + "lock-verify": "^2.0.2", + "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": "^4.1.3", + "meant": "~1.0.1", + "mississippi": "^3.0.0", + "mkdirp": "~0.5.1", + "move-concurrently": "^1.0.1", + "node-gyp": "^3.8.0", + "nopt": "~4.0.1", + "normalize-package-data": "~2.4.0", + "npm-audit-report": "^1.3.1", + "npm-cache-filename": "~1.0.2", + "npm-install-checks": "~3.0.0", + "npm-lifecycle": "^2.1.0", + "npm-package-arg": "^6.1.0", + "npm-packlist": "^1.1.11", + "npm-pick-manifest": "^2.1.0", + "npm-profile": "^3.0.2", + "npm-registry-client": "^8.6.0", + "npm-registry-fetch": "^1.1.0", + "npm-user-validate": "~1.0.0", + "npmlog": "~4.1.2", + "once": "~1.4.0", + "opener": "^1.5.0", + "osenv": "^0.1.5", + "pacote": "^8.1.6", + "path-is-inside": "~1.0.2", + "promise-inflight": "~1.0.1", + "qrcode-terminal": "^0.12.0", + "query-string": "^6.1.0", + "qw": "~1.0.1", + "read": "~1.0.7", + "read-cmd-shim": "~1.0.1", + "read-installed": "~4.0.3", + "read-package-json": "^2.0.13", + "read-package-tree": "^5.2.1", + "readable-stream": "^2.3.6", + "readdir-scoped-modules": "*", + "request": "^2.88.0", + "retry": "^0.12.0", + "rimraf": "~2.6.2", + "safe-buffer": "^5.1.2", + "semver": "^5.5.0", + "sha": "~2.0.1", + "slide": "~1.1.6", + "sorted-object": "~2.0.1", + "sorted-union-stream": "~2.1.3", + "ssri": "^6.0.0", + "stringify-package": "^1.0.0", + "tar": "^4.4.6", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", "uid-number": "0.0.6", - "umask": "1.1.0", - "unique-filename": "1.1.0", - "unpipe": "1.0.0", - "update-notifier": "2.5.0", - "uuid": "3.3.2", - "validate-npm-package-license": "3.0.4", - "validate-npm-package-name": "3.0.0", - "which": "1.3.1", - "worker-farm": "1.6.0", - "write-file-atomic": "2.3.0" + "umask": "~1.1.0", + "unique-filename": "~1.1.0", + "unpipe": "~1.0.0", + "update-notifier": "^2.5.0", + "uuid": "^3.3.2", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "~3.0.0", + "which": "^1.3.1", + "worker-farm": "^1.6.0", + "write-file-atomic": "^2.3.0" }, "dependencies": { "JSONStream": { "version": "1.3.4", "bundled": true, "requires": { - "jsonparse": "1.3.1", - "through": "2.3.8" + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" } }, "abbrev": { @@ -8619,31 +8607,31 @@ "version": "4.2.0", "bundled": true, "requires": { - "es6-promisify": "5.0.0" + "es6-promisify": "^5.0.0" } }, "agentkeepalive": { "version": "3.4.1", "bundled": true, "requires": { - "humanize-ms": "1.2.1" + "humanize-ms": "^1.2.1" } }, "ajv": { "version": "5.5.2", "bundled": true, "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" } }, "ansi-align": { "version": "2.0.0", "bundled": true, "requires": { - "string-width": "2.1.1" + "string-width": "^2.0.0" } }, "ansi-regex": { @@ -8654,7 +8642,7 @@ "version": "3.2.1", "bundled": true, "requires": { - "color-convert": "1.9.1" + "color-convert": "^1.9.0" } }, "ansicolors": { @@ -8677,8 +8665,8 @@ "version": "1.1.4", "bundled": true, "requires": { - "delegates": "1.0.0", - "readable-stream": "2.3.6" + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" } }, "asap": { @@ -8689,7 +8677,7 @@ "version": "0.2.4", "bundled": true, "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": "~2.1.0" } }, "assert-plus": { @@ -8717,25 +8705,25 @@ "bundled": true, "optional": true, "requires": { - "tweetnacl": "0.14.5" + "tweetnacl": "^0.14.3" } }, "bin-links": { "version": "1.1.2", "bundled": true, "requires": { - "bluebird": "3.5.1", - "cmd-shim": "2.0.2", - "gentle-fs": "2.0.1", - "graceful-fs": "4.1.11", - "write-file-atomic": "2.3.0" + "bluebird": "^3.5.0", + "cmd-shim": "^2.0.2", + "gentle-fs": "^2.0.0", + "graceful-fs": "^4.1.11", + "write-file-atomic": "^2.3.0" } }, "block-stream": { "version": "0.0.9", "bundled": true, "requires": { - "inherits": "2.0.3" + "inherits": "~2.0.0" } }, "bluebird": { @@ -8746,20 +8734,20 @@ "version": "1.3.0", "bundled": true, "requires": { - "ansi-align": "2.0.0", - "camelcase": "4.1.0", - "chalk": "2.4.1", - "cli-boxes": "1.0.0", - "string-width": "2.1.1", - "term-size": "1.2.0", - "widest-line": "2.0.0" + "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" } }, "brace-expansion": { "version": "1.1.11", "bundled": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -8787,20 +8775,20 @@ "version": "11.2.0", "bundled": true, "requires": { - "bluebird": "3.5.1", - "chownr": "1.0.1", - "figgy-pudding": "3.4.1", - "glob": "7.1.2", - "graceful-fs": "4.1.11", - "lru-cache": "4.1.3", - "mississippi": "3.0.0", - "mkdirp": "0.5.1", - "move-concurrently": "1.0.1", - "promise-inflight": "1.0.1", - "rimraf": "2.6.2", - "ssri": "6.0.0", - "unique-filename": "1.1.0", - "y18n": "4.0.0" + "bluebird": "^3.5.1", + "chownr": "^1.0.1", + "figgy-pudding": "^3.1.0", + "glob": "^7.1.2", + "graceful-fs": "^4.1.11", + "lru-cache": "^4.1.3", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.2", + "ssri": "^6.0.0", + "unique-filename": "^1.1.0", + "y18n": "^4.0.0" } }, "call-limit": { @@ -8823,9 +8811,9 @@ "version": "2.4.1", "bundled": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "chownr": { @@ -8840,7 +8828,7 @@ "version": "2.0.9", "bundled": true, "requires": { - "ip-regex": "2.1.0" + "ip-regex": "^2.1.0" } }, "cli-boxes": { @@ -8851,26 +8839,26 @@ "version": "3.1.2", "bundled": true, "requires": { - "string-width": "2.1.1", - "strip-ansi": "3.0.1" + "string-width": "^2.0.0", + "strip-ansi": "^3.0.1" } }, "cli-table3": { "version": "0.5.0", "bundled": true, "requires": { - "colors": "1.1.2", - "object-assign": "4.1.1", - "string-width": "2.1.1" + "colors": "^1.1.2", + "object-assign": "^4.1.0", + "string-width": "^2.1.1" } }, "cliui": { "version": "4.1.0", "bundled": true, "requires": { - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "wrap-ansi": "2.1.0" + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" }, "dependencies": { "ansi-regex": { @@ -8881,7 +8869,7 @@ "version": "4.0.0", "bundled": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } } } @@ -8894,8 +8882,8 @@ "version": "2.0.2", "bundled": true, "requires": { - "graceful-fs": "4.1.11", - "mkdirp": "0.5.1" + "graceful-fs": "^4.1.2", + "mkdirp": "~0.5.0" } }, "co": { @@ -8910,7 +8898,7 @@ "version": "1.9.1", "bundled": true, "requires": { - "color-name": "1.1.3" + "color-name": "^1.1.1" } }, "color-name": { @@ -8926,15 +8914,15 @@ "version": "1.5.4", "bundled": true, "requires": { - "strip-ansi": "3.0.1", - "wcwidth": "1.0.1" + "strip-ansi": "^3.0.0", + "wcwidth": "^1.0.0" } }, "combined-stream": { "version": "1.0.6", "bundled": true, "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } }, "concat-map": { @@ -8945,30 +8933,30 @@ "version": "1.6.2", "bundled": true, "requires": { - "buffer-from": "1.0.0", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "typedarray": "0.0.6" + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" } }, "config-chain": { "version": "1.1.11", "bundled": true, "requires": { - "ini": "1.3.5", - "proto-list": "1.2.4" + "ini": "^1.3.4", + "proto-list": "~1.2.1" } }, "configstore": { "version": "3.1.2", "bundled": true, "requires": { - "dot-prop": "4.2.0", - "graceful-fs": "4.1.11", - "make-dir": "1.3.0", - "unique-string": "1.0.0", - "write-file-atomic": "2.3.0", - "xdg-basedir": "3.0.0" + "dot-prop": "^4.1.0", + "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" } }, "console-control-strings": { @@ -8979,12 +8967,12 @@ "version": "1.0.5", "bundled": true, "requires": { - "aproba": "1.2.0", - "fs-write-stream-atomic": "1.0.10", - "iferr": "0.1.5", - "mkdirp": "0.5.1", - "rimraf": "2.6.2", - "run-queue": "1.0.3" + "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" }, "dependencies": { "iferr": { @@ -9001,16 +8989,16 @@ "version": "3.0.2", "bundled": true, "requires": { - "capture-stack-trace": "1.0.0" + "capture-stack-trace": "^1.0.0" } }, "cross-spawn": { "version": "5.1.0", "bundled": true, "requires": { - "lru-cache": "4.1.3", - "shebang-command": "1.2.0", - "which": "1.3.1" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, "crypto-random-string": { @@ -9025,7 +9013,7 @@ "version": "1.14.1", "bundled": true, "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" } }, "debug": { @@ -9061,7 +9049,7 @@ "version": "1.0.3", "bundled": true, "requires": { - "clone": "1.0.4" + "clone": "^1.0.2" } }, "delayed-stream": { @@ -9084,15 +9072,15 @@ "version": "1.0.3", "bundled": true, "requires": { - "asap": "2.0.6", - "wrappy": "1.0.2" + "asap": "^2.0.0", + "wrappy": "1" } }, "dot-prop": { "version": "4.2.0", "bundled": true, "requires": { - "is-obj": "1.0.1" + "is-obj": "^1.0.0" } }, "dotenv": { @@ -9107,10 +9095,10 @@ "version": "3.6.0", "bundled": true, "requires": { - "end-of-stream": "1.4.1", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "stream-shift": "1.0.0" + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" } }, "ecc-jsbn": { @@ -9118,8 +9106,8 @@ "bundled": true, "optional": true, "requires": { - "jsbn": "0.1.1", - "safer-buffer": "2.1.2" + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" } }, "editor": { @@ -9130,14 +9118,14 @@ "version": "0.1.12", "bundled": true, "requires": { - "iconv-lite": "0.4.23" + "iconv-lite": "~0.4.13" } }, "end-of-stream": { "version": "1.4.1", "bundled": true, "requires": { - "once": "1.4.0" + "once": "^1.4.0" } }, "err-code": { @@ -9148,7 +9136,7 @@ "version": "0.1.7", "bundled": true, "requires": { - "prr": "1.0.1" + "prr": "~1.0.1" } }, "es6-promise": { @@ -9159,7 +9147,7 @@ "version": "5.0.0", "bundled": true, "requires": { - "es6-promise": "4.2.4" + "es6-promise": "^4.0.3" } }, "escape-string-regexp": { @@ -9170,13 +9158,13 @@ "version": "0.7.0", "bundled": true, "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "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" } }, "extend": { @@ -9207,15 +9195,15 @@ "version": "2.1.0", "bundled": true, "requires": { - "locate-path": "2.0.0" + "locate-path": "^2.0.0" } }, "flush-write-stream": { "version": "1.0.3", "bundled": true, "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.6" + "inherits": "^2.0.1", + "readable-stream": "^2.0.4" } }, "forever-agent": { @@ -9226,43 +9214,43 @@ "version": "2.3.2", "bundled": true, "requires": { - "asynckit": "0.4.0", + "asynckit": "^0.4.0", "combined-stream": "1.0.6", - "mime-types": "2.1.19" + "mime-types": "^2.1.12" } }, "from2": { "version": "2.3.0", "bundled": true, "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.6" + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" } }, "fs-minipass": { "version": "1.2.5", "bundled": true, "requires": { - "minipass": "2.3.3" + "minipass": "^2.2.1" } }, "fs-vacuum": { "version": "1.2.10", "bundled": true, "requires": { - "graceful-fs": "4.1.11", - "path-is-inside": "1.0.2", - "rimraf": "2.6.2" + "graceful-fs": "^4.1.2", + "path-is-inside": "^1.0.1", + "rimraf": "^2.5.2" } }, "fs-write-stream-atomic": { "version": "1.0.10", "bundled": true, "requires": { - "graceful-fs": "4.1.11", - "iferr": "0.1.5", - "imurmurhash": "0.1.4", - "readable-stream": "2.3.6" + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" }, "dependencies": { "iferr": { @@ -9279,33 +9267,33 @@ "version": "1.0.11", "bundled": true, "requires": { - "graceful-fs": "4.1.11", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.6.2" + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" } }, "gauge": { "version": "2.7.4", "bundled": true, "requires": { - "aproba": "1.2.0", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" + "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" }, "dependencies": { "string-width": { "version": "1.0.2", "bundled": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } } } @@ -9318,14 +9306,14 @@ "version": "2.0.1", "bundled": true, "requires": { - "aproba": "1.2.0", - "fs-vacuum": "1.2.10", - "graceful-fs": "4.1.11", - "iferr": "0.1.5", - "mkdirp": "0.5.1", - "path-is-inside": "1.0.2", - "read-cmd-shim": "1.0.1", - "slide": "1.1.6" + "aproba": "^1.1.2", + "fs-vacuum": "^1.2.10", + "graceful-fs": "^4.1.11", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "path-is-inside": "^1.0.2", + "read-cmd-shim": "^1.0.1", + "slide": "^1.1.6" }, "dependencies": { "iferr": { @@ -9346,43 +9334,43 @@ "version": "0.1.7", "bundled": true, "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" } }, "glob": { "version": "7.1.2", "bundled": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "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" } }, "global-dirs": { "version": "0.1.1", "bundled": true, "requires": { - "ini": "1.3.5" + "ini": "^1.3.4" } }, "got": { "version": "6.7.1", "bundled": true, "requires": { - "create-error-class": "3.0.2", - "duplexer3": "0.1.4", - "get-stream": "3.0.0", - "is-redirect": "1.0.0", - "is-retry-allowed": "1.1.0", - "is-stream": "1.1.0", - "lowercase-keys": "1.0.1", - "safe-buffer": "5.1.2", - "timed-out": "4.0.1", - "unzip-response": "2.0.1", - "url-parse-lax": "1.0.0" + "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" } }, "graceful-fs": { @@ -9397,8 +9385,8 @@ "version": "5.1.0", "bundled": true, "requires": { - "ajv": "5.5.2", - "har-schema": "2.0.0" + "ajv": "^5.3.0", + "har-schema": "^2.0.0" } }, "has-flag": { @@ -9421,7 +9409,7 @@ "version": "2.1.0", "bundled": true, "requires": { - "agent-base": "4.2.0", + "agent-base": "4", "debug": "3.1.0" } }, @@ -9429,31 +9417,31 @@ "version": "1.2.0", "bundled": true, "requires": { - "assert-plus": "1.0.0", - "jsprim": "1.4.1", - "sshpk": "1.14.2" + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, "https-proxy-agent": { "version": "2.2.1", "bundled": true, "requires": { - "agent-base": "4.2.0", - "debug": "3.1.0" + "agent-base": "^4.1.0", + "debug": "^3.1.0" } }, "humanize-ms": { "version": "1.2.1", "bundled": true, "requires": { - "ms": "2.1.1" + "ms": "^2.0.0" } }, "iconv-lite": { "version": "0.4.23", "bundled": true, "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } }, "iferr": { @@ -9464,7 +9452,7 @@ "version": "3.0.1", "bundled": true, "requires": { - "minimatch": "3.0.4" + "minimatch": "^3.0.4" } }, "import-lazy": { @@ -9479,8 +9467,8 @@ "version": "1.0.6", "bundled": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -9495,14 +9483,14 @@ "version": "1.10.3", "bundled": true, "requires": { - "glob": "7.1.2", - "npm-package-arg": "6.1.0", - "promzard": "0.3.0", - "read": "1.0.7", - "read-package-json": "2.0.13", - "semver": "5.5.0", - "validate-npm-package-license": "3.0.4", - "validate-npm-package-name": "3.0.0" + "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" } }, "invert-kv": { @@ -9521,36 +9509,36 @@ "version": "1.0.0", "bundled": true, "requires": { - "builtin-modules": "1.1.1" + "builtin-modules": "^1.0.0" } }, "is-ci": { "version": "1.1.0", "bundled": true, "requires": { - "ci-info": "1.4.0" + "ci-info": "^1.0.0" } }, "is-cidr": { "version": "2.0.6", "bundled": true, "requires": { - "cidr-regex": "2.0.9" + "cidr-regex": "^2.0.8" } }, "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "is-installed-globally": { "version": "0.1.0", "bundled": true, "requires": { - "global-dirs": "0.1.1", - "is-path-inside": "1.0.1" + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" } }, "is-npm": { @@ -9565,7 +9553,7 @@ "version": "1.0.1", "bundled": true, "requires": { - "path-is-inside": "1.0.2" + "path-is-inside": "^1.0.1" } }, "is-redirect": { @@ -9635,7 +9623,7 @@ "version": "3.1.0", "bundled": true, "requires": { - "package-json": "4.0.1" + "package-json": "^4.0.0" } }, "lazy-property": { @@ -9646,46 +9634,46 @@ "version": "1.0.0", "bundled": true, "requires": { - "invert-kv": "1.0.0" + "invert-kv": "^1.0.0" } }, "libcipm": { "version": "2.0.2", "bundled": true, "requires": { - "bin-links": "1.1.2", - "bluebird": "3.5.1", - "find-npm-prefix": "1.0.2", - "graceful-fs": "4.1.11", - "lock-verify": "2.0.2", - "mkdirp": "0.5.1", - "npm-lifecycle": "2.1.0", - "npm-logical-tree": "1.2.1", - "npm-package-arg": "6.1.0", - "pacote": "8.1.6", - "protoduck": "5.0.0", - "read-package-json": "2.0.13", - "rimraf": "2.6.2", - "worker-farm": "1.6.0" + "bin-links": "^1.1.2", + "bluebird": "^3.5.1", + "find-npm-prefix": "^1.0.2", + "graceful-fs": "^4.1.11", + "lock-verify": "^2.0.2", + "mkdirp": "^0.5.1", + "npm-lifecycle": "^2.0.3", + "npm-logical-tree": "^1.2.1", + "npm-package-arg": "^6.1.0", + "pacote": "^8.1.6", + "protoduck": "^5.0.0", + "read-package-json": "^2.0.13", + "rimraf": "^2.6.2", + "worker-farm": "^1.6.0" } }, "libnpmhook": { "version": "4.0.1", "bundled": true, "requires": { - "figgy-pudding": "3.4.1", - "npm-registry-fetch": "3.1.1" + "figgy-pudding": "^3.1.0", + "npm-registry-fetch": "^3.0.0" }, "dependencies": { "npm-registry-fetch": { "version": "3.1.1", "bundled": true, "requires": { - "bluebird": "3.5.1", - "figgy-pudding": "3.4.1", - "lru-cache": "4.1.3", - "make-fetch-happen": "4.0.1", - "npm-package-arg": "6.1.0" + "bluebird": "^3.5.1", + "figgy-pudding": "^3.1.0", + "lru-cache": "^4.1.2", + "make-fetch-happen": "^4.0.0", + "npm-package-arg": "^6.0.0" } } } @@ -9694,37 +9682,37 @@ "version": "10.2.0", "bundled": true, "requires": { - "dotenv": "5.0.1", - "npm-package-arg": "6.1.0", - "rimraf": "2.6.2", - "safe-buffer": "5.1.2", - "update-notifier": "2.5.0", - "which": "1.3.1", - "y18n": "4.0.0", - "yargs": "11.0.0" + "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": "^11.0.0" } }, "locate-path": { "version": "2.0.0", "bundled": true, "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" } }, "lock-verify": { "version": "2.0.2", "bundled": true, "requires": { - "npm-package-arg": "6.1.0", - "semver": "5.5.0" + "npm-package-arg": "^5.1.2 || 6", + "semver": "^5.4.1" } }, "lockfile": { "version": "1.0.4", "bundled": true, "requires": { - "signal-exit": "3.0.2" + "signal-exit": "^3.0.2" } }, "lodash._baseindexof": { @@ -9735,8 +9723,8 @@ "version": "4.6.0", "bundled": true, "requires": { - "lodash._createset": "4.0.3", - "lodash._root": "3.0.1" + "lodash._createset": "~4.0.0", + "lodash._root": "~3.0.0" } }, "lodash._bindcallback": { @@ -9751,7 +9739,7 @@ "version": "3.1.2", "bundled": true, "requires": { - "lodash._getnative": "3.9.1" + "lodash._getnative": "^3.0.0" } }, "lodash._createset": { @@ -9794,32 +9782,32 @@ "version": "4.1.3", "bundled": true, "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } }, "make-dir": { "version": "1.3.0", "bundled": true, "requires": { - "pify": "3.0.0" + "pify": "^3.0.0" } }, "make-fetch-happen": { "version": "4.0.1", "bundled": true, "requires": { - "agentkeepalive": "3.4.1", - "cacache": "11.2.0", - "http-cache-semantics": "3.8.1", - "http-proxy-agent": "2.1.0", - "https-proxy-agent": "2.2.1", - "lru-cache": "4.1.3", - "mississippi": "3.0.0", - "node-fetch-npm": "2.0.2", - "promise-retry": "1.1.1", - "socks-proxy-agent": "4.0.1", - "ssri": "6.0.0" + "agentkeepalive": "^3.4.1", + "cacache": "^11.0.1", + "http-cache-semantics": "^3.8.1", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1", + "lru-cache": "^4.1.2", + "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" } }, "meant": { @@ -9830,7 +9818,7 @@ "version": "1.1.0", "bundled": true, "requires": { - "mimic-fn": "1.2.0" + "mimic-fn": "^1.0.0" } }, "mime-db": { @@ -9841,7 +9829,7 @@ "version": "2.1.19", "bundled": true, "requires": { - "mime-db": "1.35.0" + "mime-db": "~1.35.0" } }, "mimic-fn": { @@ -9852,7 +9840,7 @@ "version": "3.0.4", "bundled": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -9863,8 +9851,8 @@ "version": "2.3.3", "bundled": true, "requires": { - "safe-buffer": "5.1.2", - "yallist": "3.0.2" + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" }, "dependencies": { "yallist": { @@ -9877,23 +9865,23 @@ "version": "1.1.0", "bundled": true, "requires": { - "minipass": "2.3.3" + "minipass": "^2.2.1" } }, "mississippi": { "version": "3.0.0", "bundled": true, "requires": { - "concat-stream": "1.6.2", - "duplexify": "3.6.0", - "end-of-stream": "1.4.1", - "flush-write-stream": "1.0.3", - "from2": "2.3.0", - "parallel-transform": "1.1.0", - "pump": "3.0.0", - "pumpify": "1.5.1", - "stream-each": "1.2.2", - "through2": "2.0.3" + "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" } }, "mkdirp": { @@ -9907,12 +9895,12 @@ "version": "1.0.1", "bundled": true, "requires": { - "aproba": "1.2.0", - "copy-concurrently": "1.0.5", - "fs-write-stream-atomic": "1.0.10", - "mkdirp": "0.5.1", - "rimraf": "2.6.2", - "run-queue": "1.0.3" + "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" } }, "ms": { @@ -9927,34 +9915,34 @@ "version": "2.0.2", "bundled": true, "requires": { - "encoding": "0.1.12", - "json-parse-better-errors": "1.0.2", - "safe-buffer": "5.1.2" + "encoding": "^0.1.11", + "json-parse-better-errors": "^1.0.0", + "safe-buffer": "^5.1.1" } }, "node-gyp": { "version": "3.8.0", "bundled": true, "requires": { - "fstream": "1.0.11", - "glob": "7.1.2", - "graceful-fs": "4.1.11", - "mkdirp": "0.5.1", - "nopt": "3.0.6", - "npmlog": "4.1.2", - "osenv": "0.1.5", - "request": "2.88.0", - "rimraf": "2.6.2", - "semver": "5.3.0", - "tar": "2.2.1", - "which": "1.3.1" + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "^2.87.0", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" }, "dependencies": { "nopt": { "version": "3.0.6", "bundled": true, "requires": { - "abbrev": "1.1.1" + "abbrev": "1" } }, "semver": { @@ -9965,9 +9953,9 @@ "version": "2.2.1", "bundled": true, "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.11", - "inherits": "2.0.3" + "block-stream": "*", + "fstream": "^1.0.2", + "inherits": "2" } } } @@ -9976,26 +9964,26 @@ "version": "4.0.1", "bundled": true, "requires": { - "abbrev": "1.1.1", - "osenv": "0.1.5" + "abbrev": "1", + "osenv": "^0.1.4" } }, "normalize-package-data": { "version": "2.4.0", "bundled": true, "requires": { - "hosted-git-info": "2.7.1", - "is-builtin-module": "1.0.0", - "semver": "5.5.0", - "validate-npm-package-license": "3.0.4" + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, "npm-audit-report": { "version": "1.3.1", "bundled": true, "requires": { - "cli-table3": "0.5.0", - "console-control-strings": "1.1.0" + "cli-table3": "^0.5.0", + "console-control-strings": "^1.1.0" } }, "npm-bundled": { @@ -10010,21 +9998,21 @@ "version": "3.0.0", "bundled": true, "requires": { - "semver": "5.5.0" + "semver": "^2.3.0 || 3.x || 4 || 5" } }, "npm-lifecycle": { "version": "2.1.0", "bundled": true, "requires": { - "byline": "5.0.0", - "graceful-fs": "4.1.11", - "node-gyp": "3.8.0", - "resolve-from": "4.0.0", - "slide": "1.1.6", + "byline": "^5.0.0", + "graceful-fs": "^4.1.11", + "node-gyp": "^3.8.0", + "resolve-from": "^4.0.0", + "slide": "^1.1.6", "uid-number": "0.0.6", - "umask": "1.1.0", - "which": "1.3.1" + "umask": "^1.1.0", + "which": "^1.3.1" } }, "npm-logical-tree": { @@ -10035,52 +10023,52 @@ "version": "6.1.0", "bundled": true, "requires": { - "hosted-git-info": "2.7.1", - "osenv": "0.1.5", - "semver": "5.5.0", - "validate-npm-package-name": "3.0.0" + "hosted-git-info": "^2.6.0", + "osenv": "^0.1.5", + "semver": "^5.5.0", + "validate-npm-package-name": "^3.0.0" } }, "npm-packlist": { "version": "1.1.11", "bundled": true, "requires": { - "ignore-walk": "3.0.1", - "npm-bundled": "1.0.5" + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" } }, "npm-pick-manifest": { "version": "2.1.0", "bundled": true, "requires": { - "npm-package-arg": "6.1.0", - "semver": "5.5.0" + "npm-package-arg": "^6.0.0", + "semver": "^5.4.1" } }, "npm-profile": { "version": "3.0.2", "bundled": true, "requires": { - "aproba": "1.2.0", - "make-fetch-happen": "4.0.1" + "aproba": "^1.1.2 || 2", + "make-fetch-happen": "^2.5.0 || 3 || 4" } }, "npm-registry-client": { "version": "8.6.0", "bundled": true, "requires": { - "concat-stream": "1.6.2", - "graceful-fs": "4.1.11", - "normalize-package-data": "2.4.0", - "npm-package-arg": "6.1.0", - "npmlog": "4.1.2", - "once": "1.4.0", - "request": "2.88.0", - "retry": "0.10.1", - "safe-buffer": "5.1.2", - "semver": "5.5.0", - "slide": "1.1.6", - "ssri": "5.3.0" + "concat-stream": "^1.5.2", + "graceful-fs": "^4.1.6", + "normalize-package-data": "~1.0.1 || ^2.0.0", + "npm-package-arg": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0", + "npmlog": "2 || ^3.1.0 || ^4.0.0", + "once": "^1.3.3", + "request": "^2.74.0", + "retry": "^0.10.0", + "safe-buffer": "^5.1.1", + "semver": "2 >=2.2.1 || 3.x || 4 || 5", + "slide": "^1.1.3", + "ssri": "^5.2.4" }, "dependencies": { "retry": { @@ -10091,7 +10079,7 @@ "version": "5.3.0", "bundled": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "^5.1.1" } } } @@ -10100,47 +10088,47 @@ "version": "1.1.0", "bundled": true, "requires": { - "bluebird": "3.5.1", - "figgy-pudding": "2.0.1", - "lru-cache": "4.1.3", - "make-fetch-happen": "3.0.0", - "npm-package-arg": "6.1.0", - "safe-buffer": "5.1.2" + "bluebird": "^3.5.1", + "figgy-pudding": "^2.0.1", + "lru-cache": "^4.1.2", + "make-fetch-happen": "^3.0.0", + "npm-package-arg": "^6.0.0", + "safe-buffer": "^5.1.1" }, "dependencies": { "cacache": { "version": "10.0.4", "bundled": true, "requires": { - "bluebird": "3.5.1", - "chownr": "1.0.1", - "glob": "7.1.2", - "graceful-fs": "4.1.11", - "lru-cache": "4.1.3", - "mississippi": "2.0.0", - "mkdirp": "0.5.1", - "move-concurrently": "1.0.1", - "promise-inflight": "1.0.1", - "rimraf": "2.6.2", - "ssri": "5.3.0", - "unique-filename": "1.1.0", - "y18n": "4.0.0" + "bluebird": "^3.5.1", + "chownr": "^1.0.1", + "glob": "^7.1.2", + "graceful-fs": "^4.1.11", + "lru-cache": "^4.1.1", + "mississippi": "^2.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.2", + "ssri": "^5.2.4", + "unique-filename": "^1.1.0", + "y18n": "^4.0.0" }, "dependencies": { "mississippi": { "version": "2.0.0", "bundled": true, "requires": { - "concat-stream": "1.6.2", - "duplexify": "3.6.0", - "end-of-stream": "1.4.1", - "flush-write-stream": "1.0.3", - "from2": "2.3.0", - "parallel-transform": "1.1.0", - "pump": "2.0.1", - "pumpify": "1.5.1", - "stream-each": "1.2.2", - "through2": "2.0.3" + "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": "^2.0.1", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" } } } @@ -10153,25 +10141,25 @@ "version": "3.0.0", "bundled": true, "requires": { - "agentkeepalive": "3.4.1", - "cacache": "10.0.4", - "http-cache-semantics": "3.8.1", - "http-proxy-agent": "2.1.0", - "https-proxy-agent": "2.2.1", - "lru-cache": "4.1.3", - "mississippi": "3.0.0", - "node-fetch-npm": "2.0.2", - "promise-retry": "1.1.1", - "socks-proxy-agent": "3.0.1", - "ssri": "5.3.0" + "agentkeepalive": "^3.4.1", + "cacache": "^10.0.4", + "http-cache-semantics": "^3.8.1", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.0", + "lru-cache": "^4.1.2", + "mississippi": "^3.0.0", + "node-fetch-npm": "^2.0.2", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^3.0.1", + "ssri": "^5.2.4" } }, "pump": { "version": "2.0.1", "bundled": true, "requires": { - "end-of-stream": "1.4.1", - "once": "1.4.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, "smart-buffer": { @@ -10182,23 +10170,23 @@ "version": "1.1.10", "bundled": true, "requires": { - "ip": "1.1.5", - "smart-buffer": "1.1.15" + "ip": "^1.1.4", + "smart-buffer": "^1.0.13" } }, "socks-proxy-agent": { "version": "3.0.1", "bundled": true, "requires": { - "agent-base": "4.2.0", - "socks": "1.1.10" + "agent-base": "^4.1.0", + "socks": "^1.1.10" } }, "ssri": { "version": "5.3.0", "bundled": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "^5.1.1" } } } @@ -10207,7 +10195,7 @@ "version": "2.0.2", "bundled": true, "requires": { - "path-key": "2.0.1" + "path-key": "^2.0.0" } }, "npm-user-validate": { @@ -10218,10 +10206,10 @@ "version": "4.1.2", "bundled": true, "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" } }, "number-is-nan": { @@ -10240,7 +10228,7 @@ "version": "1.4.0", "bundled": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "opener": { @@ -10255,9 +10243,9 @@ "version": "2.1.0", "bundled": true, "requires": { - "execa": "0.7.0", - "lcid": "1.0.0", - "mem": "1.1.0" + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" } }, "os-tmpdir": { @@ -10268,8 +10256,8 @@ "version": "0.1.5", "bundled": true, "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" } }, "p-finally": { @@ -10280,14 +10268,14 @@ "version": "1.2.0", "bundled": true, "requires": { - "p-try": "1.0.0" + "p-try": "^1.0.0" } }, "p-locate": { "version": "2.0.0", "bundled": true, "requires": { - "p-limit": "1.2.0" + "p-limit": "^1.1.0" } }, "p-try": { @@ -10298,50 +10286,50 @@ "version": "4.0.1", "bundled": true, "requires": { - "got": "6.7.1", - "registry-auth-token": "3.3.2", - "registry-url": "3.1.0", - "semver": "5.5.0" + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" } }, "pacote": { "version": "8.1.6", "bundled": true, "requires": { - "bluebird": "3.5.1", - "cacache": "11.2.0", - "get-stream": "3.0.0", - "glob": "7.1.2", - "lru-cache": "4.1.3", - "make-fetch-happen": "4.0.1", - "minimatch": "3.0.4", - "minipass": "2.3.3", - "mississippi": "3.0.0", - "mkdirp": "0.5.1", - "normalize-package-data": "2.4.0", - "npm-package-arg": "6.1.0", - "npm-packlist": "1.1.11", - "npm-pick-manifest": "2.1.0", - "osenv": "0.1.5", - "promise-inflight": "1.0.1", - "promise-retry": "1.1.1", - "protoduck": "5.0.0", - "rimraf": "2.6.2", - "safe-buffer": "5.1.2", - "semver": "5.5.0", - "ssri": "6.0.0", - "tar": "4.4.6", - "unique-filename": "1.1.0", - "which": "1.3.1" + "bluebird": "^3.5.1", + "cacache": "^11.0.2", + "get-stream": "^3.0.0", + "glob": "^7.1.2", + "lru-cache": "^4.1.3", + "make-fetch-happen": "^4.0.1", + "minimatch": "^3.0.4", + "minipass": "^2.3.3", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "normalize-package-data": "^2.4.0", + "npm-package-arg": "^6.1.0", + "npm-packlist": "^1.1.10", + "npm-pick-manifest": "^2.1.0", + "osenv": "^0.1.5", + "promise-inflight": "^1.0.1", + "promise-retry": "^1.1.1", + "protoduck": "^5.0.0", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.2", + "semver": "^5.5.0", + "ssri": "^6.0.0", + "tar": "^4.4.3", + "unique-filename": "^1.1.0", + "which": "^1.3.0" } }, "parallel-transform": { "version": "1.1.0", "bundled": true, "requires": { - "cyclist": "0.2.2", - "inherits": "2.0.3", - "readable-stream": "2.3.6" + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" } }, "path-exists": { @@ -10384,8 +10372,8 @@ "version": "1.1.1", "bundled": true, "requires": { - "err-code": "1.1.2", - "retry": "0.10.1" + "err-code": "^1.0.0", + "retry": "^0.10.0" }, "dependencies": { "retry": { @@ -10398,7 +10386,7 @@ "version": "0.3.0", "bundled": true, "requires": { - "read": "1.0.7" + "read": "1" } }, "proto-list": { @@ -10409,7 +10397,7 @@ "version": "5.0.0", "bundled": true, "requires": { - "genfun": "4.0.1" + "genfun": "^4.0.1" } }, "prr": { @@ -10428,25 +10416,25 @@ "version": "3.0.0", "bundled": true, "requires": { - "end-of-stream": "1.4.1", - "once": "1.4.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, "pumpify": { "version": "1.5.1", "bundled": true, "requires": { - "duplexify": "3.6.0", - "inherits": "2.0.3", - "pump": "2.0.1" + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" }, "dependencies": { "pump": { "version": "2.0.1", "bundled": true, "requires": { - "end-of-stream": "1.4.1", - "once": "1.4.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } } } @@ -10467,8 +10455,8 @@ "version": "6.1.0", "bundled": true, "requires": { - "decode-uri-component": "0.2.0", - "strict-uri-encode": "2.0.0" + "decode-uri-component": "^0.2.0", + "strict-uri-encode": "^2.0.0" } }, "qw": { @@ -10479,10 +10467,10 @@ "version": "1.2.7", "bundled": true, "requires": { - "deep-extend": "0.5.1", - "ini": "1.3.5", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" + "deep-extend": "^0.5.1", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" }, "dependencies": { "minimist": { @@ -10495,113 +10483,113 @@ "version": "1.0.7", "bundled": true, "requires": { - "mute-stream": "0.0.7" + "mute-stream": "~0.0.4" } }, "read-cmd-shim": { "version": "1.0.1", "bundled": true, "requires": { - "graceful-fs": "4.1.11" + "graceful-fs": "^4.1.2" } }, "read-installed": { "version": "4.0.3", "bundled": true, "requires": { - "debuglog": "1.0.1", - "graceful-fs": "4.1.11", - "read-package-json": "2.0.13", - "readdir-scoped-modules": "1.0.2", - "semver": "5.5.0", - "slide": "1.1.6", - "util-extend": "1.0.3" + "debuglog": "^1.0.1", + "graceful-fs": "^4.1.2", + "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" } }, "read-package-json": { "version": "2.0.13", "bundled": true, "requires": { - "glob": "7.1.2", - "graceful-fs": "4.1.11", - "json-parse-better-errors": "1.0.2", - "normalize-package-data": "2.4.0", - "slash": "1.0.0" + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "json-parse-better-errors": "^1.0.1", + "normalize-package-data": "^2.0.0", + "slash": "^1.0.0" } }, "read-package-tree": { "version": "5.2.1", "bundled": true, "requires": { - "debuglog": "1.0.1", - "dezalgo": "1.0.3", - "once": "1.4.0", - "read-package-json": "2.0.13", - "readdir-scoped-modules": "1.0.2" + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "once": "^1.3.0", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0" } }, "readable-stream": { "version": "2.3.6", "bundled": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "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" } }, "readdir-scoped-modules": { "version": "1.0.2", "bundled": true, "requires": { - "debuglog": "1.0.1", - "dezalgo": "1.0.3", - "graceful-fs": "4.1.11", - "once": "1.4.0" + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" } }, "registry-auth-token": { "version": "3.3.2", "bundled": true, "requires": { - "rc": "1.2.7", - "safe-buffer": "5.1.2" + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" } }, "registry-url": { "version": "3.1.0", "bundled": true, "requires": { - "rc": "1.2.7" + "rc": "^1.0.1" } }, "request": { "version": "2.88.0", "bundled": true, "requires": { - "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" + "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" } }, "require-directory": { @@ -10624,14 +10612,14 @@ "version": "2.6.2", "bundled": true, "requires": { - "glob": "7.1.2" + "glob": "^7.0.5" } }, "run-queue": { "version": "1.0.3", "bundled": true, "requires": { - "aproba": "1.2.0" + "aproba": "^1.1.1" } }, "safe-buffer": { @@ -10650,7 +10638,7 @@ "version": "2.1.0", "bundled": true, "requires": { - "semver": "5.5.0" + "semver": "^5.0.3" } }, "set-blocking": { @@ -10661,15 +10649,15 @@ "version": "2.0.1", "bundled": true, "requires": { - "graceful-fs": "4.1.11", - "readable-stream": "2.3.6" + "graceful-fs": "^4.1.2", + "readable-stream": "^2.0.2" } }, "shebang-command": { "version": "1.2.0", "bundled": true, "requires": { - "shebang-regex": "1.0.0" + "shebang-regex": "^1.0.0" } }, "shebang-regex": { @@ -10696,16 +10684,16 @@ "version": "2.2.0", "bundled": true, "requires": { - "ip": "1.1.5", - "smart-buffer": "4.0.1" + "ip": "^1.1.5", + "smart-buffer": "^4.0.1" } }, "socks-proxy-agent": { "version": "4.0.1", "bundled": true, "requires": { - "agent-base": "4.2.0", - "socks": "2.2.0" + "agent-base": "~4.2.0", + "socks": "~2.2.0" } }, "sorted-object": { @@ -10716,16 +10704,16 @@ "version": "2.1.3", "bundled": true, "requires": { - "from2": "1.3.0", - "stream-iterate": "1.2.0" + "from2": "^1.3.0", + "stream-iterate": "^1.1.0" }, "dependencies": { "from2": { "version": "1.3.0", "bundled": true, "requires": { - "inherits": "2.0.3", - "readable-stream": "1.1.14" + "inherits": "~2.0.1", + "readable-stream": "~1.1.10" } }, "isarray": { @@ -10736,10 +10724,10 @@ "version": "1.1.14", "bundled": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", "isarray": "0.0.1", - "string_decoder": "0.10.31" + "string_decoder": "~0.10.x" } }, "string_decoder": { @@ -10752,8 +10740,8 @@ "version": "3.0.0", "bundled": true, "requires": { - "spdx-expression-parse": "3.0.0", - "spdx-license-ids": "3.0.0" + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" } }, "spdx-exceptions": { @@ -10764,8 +10752,8 @@ "version": "3.0.0", "bundled": true, "requires": { - "spdx-exceptions": "2.1.0", - "spdx-license-ids": "3.0.0" + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, "spdx-license-ids": { @@ -10776,15 +10764,15 @@ "version": "1.14.2", "bundled": true, "requires": { - "asn1": "0.2.4", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.2", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.2", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "safer-buffer": "2.1.2", - "tweetnacl": "0.14.5" + "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" } }, "ssri": { @@ -10795,16 +10783,16 @@ "version": "1.2.2", "bundled": true, "requires": { - "end-of-stream": "1.4.1", - "stream-shift": "1.0.0" + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" } }, "stream-iterate": { "version": "1.2.0", "bundled": true, "requires": { - "readable-stream": "2.3.6", - "stream-shift": "1.0.0" + "readable-stream": "^2.1.5", + "stream-shift": "^1.0.0" } }, "stream-shift": { @@ -10819,8 +10807,8 @@ "version": "2.1.1", "bundled": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" }, "dependencies": { "ansi-regex": { @@ -10835,7 +10823,7 @@ "version": "4.0.0", "bundled": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } } } @@ -10844,7 +10832,7 @@ "version": "1.1.1", "bundled": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } }, "stringify-package": { @@ -10855,7 +10843,7 @@ "version": "3.0.1", "bundled": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-eof": { @@ -10870,20 +10858,20 @@ "version": "5.4.0", "bundled": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } }, "tar": { "version": "4.4.6", "bundled": true, "requires": { - "chownr": "1.0.1", - "fs-minipass": "1.2.5", - "minipass": "2.3.3", - "minizlib": "1.1.0", - "mkdirp": "0.5.1", - "safe-buffer": "5.1.2", - "yallist": "3.0.2" + "chownr": "^1.0.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.3", + "minizlib": "^1.1.0", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" }, "dependencies": { "yallist": { @@ -10896,7 +10884,7 @@ "version": "1.2.0", "bundled": true, "requires": { - "execa": "0.7.0" + "execa": "^0.7.0" } }, "text-table": { @@ -10911,8 +10899,8 @@ "version": "2.0.3", "bundled": true, "requires": { - "readable-stream": "2.3.6", - "xtend": "4.0.1" + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" } }, "timed-out": { @@ -10927,15 +10915,15 @@ "version": "2.4.3", "bundled": true, "requires": { - "psl": "1.1.29", - "punycode": "1.4.1" + "psl": "^1.1.24", + "punycode": "^1.4.1" } }, "tunnel-agent": { "version": "0.6.0", "bundled": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "^5.0.1" } }, "tweetnacl": { @@ -10959,21 +10947,21 @@ "version": "1.1.0", "bundled": true, "requires": { - "unique-slug": "2.0.0" + "unique-slug": "^2.0.0" } }, "unique-slug": { "version": "2.0.0", "bundled": true, "requires": { - "imurmurhash": "0.1.4" + "imurmurhash": "^0.1.4" } }, "unique-string": { "version": "1.0.0", "bundled": true, "requires": { - "crypto-random-string": "1.0.0" + "crypto-random-string": "^1.0.0" } }, "unpipe": { @@ -10988,23 +10976,23 @@ "version": "2.5.0", "bundled": true, "requires": { - "boxen": "1.3.0", - "chalk": "2.4.1", - "configstore": "3.1.2", - "import-lazy": "2.1.0", - "is-ci": "1.1.0", - "is-installed-globally": "0.1.0", - "is-npm": "1.0.0", - "latest-version": "3.1.0", - "semver-diff": "2.1.0", - "xdg-basedir": "3.0.0" + "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" } }, "url-parse-lax": { "version": "1.0.0", "bundled": true, "requires": { - "prepend-http": "1.0.4" + "prepend-http": "^1.0.1" } }, "util-deprecate": { @@ -11023,38 +11011,38 @@ "version": "3.0.4", "bundled": true, "requires": { - "spdx-correct": "3.0.0", - "spdx-expression-parse": "3.0.0" + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" } }, "validate-npm-package-name": { "version": "3.0.0", "bundled": true, "requires": { - "builtins": "1.0.3" + "builtins": "^1.0.3" } }, "verror": { "version": "1.10.0", "bundled": true, "requires": { - "assert-plus": "1.0.0", + "assert-plus": "^1.0.0", "core-util-is": "1.0.2", - "extsprintf": "1.3.0" + "extsprintf": "^1.2.0" } }, "wcwidth": { "version": "1.0.1", "bundled": true, "requires": { - "defaults": "1.0.3" + "defaults": "^1.0.3" } }, "which": { "version": "1.3.1", "bundled": true, "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "which-module": { @@ -11065,16 +11053,16 @@ "version": "1.1.2", "bundled": true, "requires": { - "string-width": "1.0.2" + "string-width": "^1.0.2" }, "dependencies": { "string-width": { "version": "1.0.2", "bundled": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } } } @@ -11083,31 +11071,31 @@ "version": "2.0.0", "bundled": true, "requires": { - "string-width": "2.1.1" + "string-width": "^2.1.1" } }, "worker-farm": { "version": "1.6.0", "bundled": true, "requires": { - "errno": "0.1.7" + "errno": "~0.1.7" } }, "wrap-ansi": { "version": "2.1.0", "bundled": true, "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1" + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" }, "dependencies": { "string-width": { "version": "1.0.2", "bundled": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } } } @@ -11120,9 +11108,9 @@ "version": "2.3.0", "bundled": true, "requires": { - "graceful-fs": "4.1.11", - "imurmurhash": "0.1.4", - "signal-exit": "3.0.2" + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" } }, "xdg-basedir": { @@ -11145,18 +11133,18 @@ "version": "11.0.0", "bundled": true, "requires": { - "cliui": "4.1.0", - "decamelize": "1.2.0", - "find-up": "2.1.0", - "get-caller-file": "1.0.2", - "os-locale": "2.1.0", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "2.1.1", - "which-module": "2.0.0", - "y18n": "3.2.1", - "yargs-parser": "9.0.2" + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^9.0.2" }, "dependencies": { "y18n": { @@ -11169,7 +11157,7 @@ "version": "9.0.2", "bundled": true, "requires": { - "camelcase": "4.1.0" + "camelcase": "^4.1.0" } } } @@ -11180,8 +11168,8 @@ "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", "dev": true, "requires": { - "config-chain": "1.1.12", - "pify": "3.0.0" + "config-chain": "^1.1.11", + "pify": "^3.0.0" } }, "npm-run-path": { @@ -11190,7 +11178,7 @@ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { - "path-key": "2.0.1" + "path-key": "^2.0.0" } }, "nth-check": { @@ -11199,7 +11187,7 @@ "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", "dev": true, "requires": { - "boolbase": "1.0.0" + "boolbase": "~1.0.0" } }, "num2fraction": { @@ -11238,9 +11226,9 @@ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", "dev": true, "requires": { - "copy-descriptor": "0.1.1", - "define-property": "0.2.5", - "kind-of": "3.2.2" + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" }, "dependencies": { "define-property": { @@ -11249,7 +11237,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "kind-of": { @@ -11258,7 +11246,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -11266,7 +11254,7 @@ "object-keys": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", - "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", + "integrity": "sha1-CcU4VTd1dTEMymL1W7M0q/97PtI=", "dev": true }, "object-visit": { @@ -11275,7 +11263,7 @@ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.0" } }, "object.defaults": { @@ -11284,10 +11272,10 @@ "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", "dev": true, "requires": { - "array-each": "1.0.1", - "array-slice": "1.1.0", - "for-own": "1.0.0", - "isobject": "3.0.1" + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" } }, "object.getownpropertydescriptors": { @@ -11296,8 +11284,8 @@ "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", "dev": true, "requires": { - "define-properties": "1.1.3", - "es-abstract": "1.12.0" + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" } }, "object.map": { @@ -11306,8 +11294,8 @@ "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", "dev": true, "requires": { - "for-own": "1.0.0", - "make-iterator": "1.0.1" + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" } }, "object.omit": { @@ -11316,8 +11304,8 @@ "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", "dev": true, "requires": { - "for-own": "0.1.5", - "is-extendable": "0.1.1" + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" }, "dependencies": { "for-own": { @@ -11326,7 +11314,7 @@ "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", "dev": true, "requires": { - "for-in": "1.0.2" + "for-in": "^1.0.1" } } } @@ -11337,7 +11325,7 @@ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" } }, "object.values": { @@ -11346,10 +11334,10 @@ "integrity": "sha1-5STaCbT2b/Bd9FdUbscqyZ8TBpo=", "dev": true, "requires": { - "define-properties": "1.1.3", - "es-abstract": "1.12.0", - "function-bind": "1.1.1", - "has": "1.0.3" + "define-properties": "^1.1.2", + "es-abstract": "^1.6.1", + "function-bind": "^1.1.0", + "has": "^1.0.1" } }, "on-finished": { @@ -11367,7 +11355,7 @@ "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "onetime": { @@ -11376,7 +11364,7 @@ "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", "dev": true, "requires": { - "mimic-fn": "1.2.0" + "mimic-fn": "^1.0.0" } }, "opn": { @@ -11385,7 +11373,7 @@ "integrity": "sha512-Jd/GpzPyHF4P2/aNOVmS3lfMSWV9J7cOhCG1s08XCEAsPkB7lp6ddiU0J7XzyQRDUh8BqJ7PchfINjR8jyofRQ==", "dev": true, "requires": { - "is-wsl": "1.1.0" + "is-wsl": "^1.1.0" } }, "optimist": { @@ -11394,8 +11382,8 @@ "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, "requires": { - "minimist": "0.0.10", - "wordwrap": "0.0.3" + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" }, "dependencies": { "minimist": { @@ -11418,12 +11406,12 @@ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "dev": true, "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" } }, "optipng-bin": { @@ -11433,9 +11421,9 @@ "dev": true, "optional": true, "requires": { - "bin-build": "3.0.0", - "bin-wrapper": "4.1.0", - "logalot": "2.1.0" + "bin-build": "^3.0.0", + "bin-wrapper": "^4.0.0", + "logalot": "^2.0.0" } }, "orchestrator": { @@ -11444,9 +11432,9 @@ "integrity": "sha1-FOfp4nZPcxX7rBhOUGx6pt+UrX4=", "dev": true, "requires": { - "end-of-stream": "0.1.5", - "sequencify": "0.0.7", - "stream-consume": "0.1.1" + "end-of-stream": "~0.1.5", + "sequencify": "~0.0.7", + "stream-consume": "~0.1.0" } }, "ordered-read-streams": { @@ -11462,7 +11450,7 @@ "dev": true, "optional": true, "requires": { - "arch": "2.1.1" + "arch": "^2.1.0" } }, "os-homedir": { @@ -11473,7 +11461,7 @@ }, "os-tmpdir": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, @@ -11491,7 +11479,7 @@ "dev": true, "optional": true, "requires": { - "p-timeout": "1.2.1" + "p-timeout": "^1.1.1" } }, "p-finally": { @@ -11514,7 +11502,7 @@ "dev": true, "optional": true, "requires": { - "p-reduce": "1.0.0" + "p-reduce": "^1.0.0" } }, "p-pipe": { @@ -11536,7 +11524,7 @@ "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", "dev": true, "requires": { - "p-finally": "1.0.0" + "p-finally": "^1.0.0" } }, "parse-filepath": { @@ -11545,9 +11533,9 @@ "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", "dev": true, "requires": { - "is-absolute": "1.0.0", - "map-cache": "0.2.2", - "path-root": "0.1.1" + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" } }, "parse-glob": { @@ -11556,10 +11544,10 @@ "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", "dev": true, "requires": { - "glob-base": "0.3.0", - "is-dotfile": "1.0.3", - "is-extglob": "1.0.0", - "is-glob": "2.0.1" + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" }, "dependencies": { "is-extglob": { @@ -11574,7 +11562,7 @@ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } } } @@ -11585,8 +11573,8 @@ "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", "dev": true, "requires": { - "error-ex": "1.3.2", - "json-parse-better-errors": "1.0.2" + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" } }, "parse-node-version": { @@ -11607,7 +11595,7 @@ "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", "dev": true, "requires": { - "better-assert": "1.0.2" + "better-assert": "~1.0.0" } }, "parseuri": { @@ -11616,7 +11604,7 @@ "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", "dev": true, "requires": { - "better-assert": "1.0.2" + "better-assert": "~1.0.0" } }, "parseurl": { @@ -11649,12 +11637,12 @@ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, "requires": { - "pinkie-promise": "2.0.1" + "pinkie-promise": "^2.0.0" } }, "path-is-absolute": { "version": "1.0.1", - "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, @@ -11682,7 +11670,7 @@ "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", "dev": true, "requires": { - "path-root-regex": "0.1.2" + "path-root-regex": "^0.1.0" } }, "path-root-regex": { @@ -11697,16 +11685,16 @@ "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "requires": { - "pify": "3.0.0" + "pify": "^3.0.0" } }, "pause-stream": { "version": "0.0.11", - "resolved": "http://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", "dev": true, "requires": { - "through": "2.3.8" + "through": "~2.3" } }, "pend": { @@ -11727,15 +11715,15 @@ "integrity": "sha1-79ISpKOWbTZHaE6ouniFSb4q7+8=", "dev": true, "requires": { - "es6-promise": "4.2.5", - "extract-zip": "1.6.7", - "fs-extra": "1.0.0", - "hasha": "2.2.0", - "kew": "0.7.0", - "progress": "1.1.8", - "request": "2.88.0", - "request-progress": "2.0.1", - "which": "1.3.1" + "es6-promise": "^4.0.3", + "extract-zip": "^1.6.5", + "fs-extra": "^1.0.0", + "hasha": "^2.2.0", + "kew": "^0.7.0", + "progress": "^1.1.8", + "request": "^2.81.0", + "request-progress": "^2.0.1", + "which": "^1.2.10" }, "dependencies": { "es6-promise": { @@ -11746,7 +11734,7 @@ }, "progress": { "version": "1.1.8", - "resolved": "http://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", "dev": true } @@ -11770,7 +11758,7 @@ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "pinkie": "2.0.4" + "pinkie": "^2.0.0" } }, "plugin-error": { @@ -11779,10 +11767,10 @@ "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", "dev": true, "requires": { - "ansi-colors": "1.1.0", - "arr-diff": "4.0.0", - "arr-union": "3.1.0", - "extend-shallow": "3.0.2" + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" } }, "plugin-log": { @@ -11791,8 +11779,8 @@ "integrity": "sha1-hgSc9qsQgzOYqTHzaJy67nteEzM=", "dev": true, "requires": { - "chalk": "1.1.3", - "dateformat": "1.0.12" + "chalk": "^1.1.1", + "dateformat": "^1.0.11" }, "dependencies": { "ansi-styles": { @@ -11807,11 +11795,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "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" } }, "dateformat": { @@ -11820,8 +11808,8 @@ "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", "dev": true, "requires": { - "get-stdin": "4.0.1", - "meow": "3.7.0" + "get-stdin": "^4.0.1", + "meow": "^3.3.0" } }, "supports-color": { @@ -11838,7 +11826,7 @@ "integrity": "sha512-lJl0ojUynAM1BZn58Pas2WT/TXeC1+bS+UqShl0x9+49AtOn7DixRXVzaC8qrDOIxNDmepKnLuMTH7NQmkX0PA==", "dev": true, "requires": { - "irregular-plurals": "2.0.0" + "irregular-plurals": "^2.0.0" } }, "pluralize": { @@ -11859,9 +11847,9 @@ "integrity": "sha512-Nq/rNjnHFcKgCDDZYO0lNsl6YWe6U7tTy+ESN+PnLxebL8uBtYX59HZqvrj7YLK5UCyll2hqDsJOo3ndzEW8Ug==", "dev": true, "requires": { - "chalk": "2.4.1", - "source-map": "0.6.1", - "supports-color": "5.5.0" + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.5.0" }, "dependencies": { "source-map": { @@ -11878,10 +11866,10 @@ "integrity": "sha512-oXqx0m6tb4N3JGdmeMSc/i91KppbYsFZKdH0xMOqK8V1rJlzrKlTdokz8ozUXLVejydRN6u2IddxpcijRj2FqQ==", "dev": true, "requires": { - "css-unit-converter": "1.1.1", - "postcss": "7.0.6", - "postcss-selector-parser": "5.0.0-rc.4", - "postcss-value-parser": "3.3.1" + "css-unit-converter": "^1.1.1", + "postcss": "^7.0.5", + "postcss-selector-parser": "^5.0.0-rc.4", + "postcss-value-parser": "^3.3.1" } }, "postcss-colormin": { @@ -11890,11 +11878,11 @@ "integrity": "sha512-1QJc2coIehnVFsz0otges8kQLsryi4lo19WD+U5xCWvXd0uw/Z+KKYnbiNDCnO9GP+PvErPHCG0jNvWTngk9Rw==", "dev": true, "requires": { - "browserslist": "4.3.5", - "color": "3.1.0", - "has": "1.0.3", - "postcss": "7.0.6", - "postcss-value-parser": "3.3.1" + "browserslist": "^4.0.0", + "color": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-convert-values": { @@ -11903,8 +11891,8 @@ "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", "dev": true, "requires": { - "postcss": "7.0.6", - "postcss-value-parser": "3.3.1" + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-discard-comments": { @@ -11913,7 +11901,7 @@ "integrity": "sha512-Ay+rZu1Sz6g8IdzRjUgG2NafSNpp2MSMOQUb+9kkzzzP+kh07fP0yNbhtFejURnyVXSX3FYy2nVNW1QTnNjgBQ==", "dev": true, "requires": { - "postcss": "7.0.6" + "postcss": "^7.0.0" } }, "postcss-discard-duplicates": { @@ -11922,7 +11910,7 @@ "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", "dev": true, "requires": { - "postcss": "7.0.6" + "postcss": "^7.0.0" } }, "postcss-discard-empty": { @@ -11931,7 +11919,7 @@ "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", "dev": true, "requires": { - "postcss": "7.0.6" + "postcss": "^7.0.0" } }, "postcss-discard-overridden": { @@ -11940,7 +11928,7 @@ "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", "dev": true, "requires": { - "postcss": "7.0.6" + "postcss": "^7.0.0" } }, "postcss-load-config": { @@ -11949,8 +11937,8 @@ "integrity": "sha512-V5JBLzw406BB8UIfsAWSK2KSwIJ5yoEIVFb4gVkXci0QdKgA24jLmHZ/ghe/GgX0lJ0/D1uUK1ejhzEY94MChQ==", "dev": true, "requires": { - "cosmiconfig": "4.0.0", - "import-cwd": "2.1.0" + "cosmiconfig": "^4.0.0", + "import-cwd": "^2.0.0" }, "dependencies": { "cosmiconfig": { @@ -11959,10 +11947,10 @@ "integrity": "sha512-6e5vDdrXZD+t5v0L8CrurPeybg4Fmf+FCSYxXKYVAqLUtyCSbuyqE059d0kDthTNRzKVjL7QMgNpEUlsoYH3iQ==", "dev": true, "requires": { - "is-directory": "0.3.1", - "js-yaml": "3.12.0", - "parse-json": "4.0.0", - "require-from-string": "2.0.2" + "is-directory": "^0.3.1", + "js-yaml": "^3.9.0", + "parse-json": "^4.0.0", + "require-from-string": "^2.0.1" } } } @@ -11974,9 +11962,9 @@ "dev": true, "requires": { "css-color-names": "0.0.4", - "postcss": "7.0.6", - "postcss-value-parser": "3.3.1", - "stylehacks": "4.0.1" + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "stylehacks": "^4.0.0" } }, "postcss-merge-rules": { @@ -11985,12 +11973,12 @@ "integrity": "sha512-UiuXwCCJtQy9tAIxsnurfF0mrNHKc4NnNx6NxqmzNNjXpQwLSukUxELHTRF0Rg1pAmcoKLih8PwvZbiordchag==", "dev": true, "requires": { - "browserslist": "4.3.5", - "caniuse-api": "3.0.0", - "cssnano-util-same-parent": "4.0.1", - "postcss": "7.0.6", - "postcss-selector-parser": "3.1.1", - "vendors": "1.0.2" + "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" }, "dependencies": { "postcss-selector-parser": { @@ -11999,9 +11987,9 @@ "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", "dev": true, "requires": { - "dot-prop": "4.2.0", - "indexes-of": "1.0.1", - "uniq": "1.0.1" + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" } } } @@ -12012,8 +12000,8 @@ "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", "dev": true, "requires": { - "postcss": "7.0.6", - "postcss-value-parser": "3.3.1" + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-minify-gradients": { @@ -12022,10 +12010,10 @@ "integrity": "sha512-pySEW3E6Ly5mHm18rekbWiAjVi/Wj8KKt2vwSfVFAWdW6wOIekgqxKxLU7vJfb107o3FDNPkaYFCxGAJBFyogA==", "dev": true, "requires": { - "cssnano-util-get-arguments": "4.0.0", - "is-color-stop": "1.1.0", - "postcss": "7.0.6", - "postcss-value-parser": "3.3.1" + "cssnano-util-get-arguments": "^4.0.0", + "is-color-stop": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-minify-params": { @@ -12034,12 +12022,12 @@ "integrity": "sha512-h4W0FEMEzBLxpxIVelRtMheskOKKp52ND6rJv+nBS33G1twu2tCyurYj/YtgU76+UDCvWeNs0hs8HFAWE2OUFg==", "dev": true, "requires": { - "alphanum-sort": "1.0.2", - "browserslist": "4.3.5", - "cssnano-util-get-arguments": "4.0.0", - "postcss": "7.0.6", - "postcss-value-parser": "3.3.1", - "uniqs": "2.0.0" + "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" } }, "postcss-minify-selectors": { @@ -12048,10 +12036,10 @@ "integrity": "sha512-8+plQkomve3G+CodLCgbhAKrb5lekAnLYuL1d7Nz+/7RANpBEVdgBkPNwljfSKvZ9xkkZTZITd04KP+zeJTJqg==", "dev": true, "requires": { - "alphanum-sort": "1.0.2", - "has": "1.0.3", - "postcss": "7.0.6", - "postcss-selector-parser": "3.1.1" + "alphanum-sort": "^1.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" }, "dependencies": { "postcss-selector-parser": { @@ -12060,9 +12048,9 @@ "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", "dev": true, "requires": { - "dot-prop": "4.2.0", - "indexes-of": "1.0.1", - "uniq": "1.0.1" + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" } } } @@ -12073,7 +12061,7 @@ "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", "dev": true, "requires": { - "postcss": "7.0.6" + "postcss": "^7.0.0" } }, "postcss-normalize-display-values": { @@ -12082,9 +12070,9 @@ "integrity": "sha512-R5mC4vaDdvsrku96yXP7zak+O3Mm9Y8IslUobk7IMP+u/g+lXvcN4jngmHY5zeJnrQvE13dfAg5ViU05ZFDwdg==", "dev": true, "requires": { - "cssnano-util-get-match": "4.0.0", - "postcss": "7.0.6", - "postcss-value-parser": "3.3.1" + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-normalize-positions": { @@ -12093,10 +12081,10 @@ "integrity": "sha512-GNoOaLRBM0gvH+ZRb2vKCIujzz4aclli64MBwDuYGU2EY53LwiP7MxOZGE46UGtotrSnmarPPZ69l2S/uxdaWA==", "dev": true, "requires": { - "cssnano-util-get-arguments": "4.0.0", - "has": "1.0.3", - "postcss": "7.0.6", - "postcss-value-parser": "3.3.1" + "cssnano-util-get-arguments": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-normalize-repeat-style": { @@ -12105,10 +12093,10 @@ "integrity": "sha512-fFHPGIjBUyUiswY2rd9rsFcC0t3oRta4wxE1h3lpwfQZwFeFjXFSiDtdJ7APCmHQOnUZnqYBADNRPKPwFAONgA==", "dev": true, "requires": { - "cssnano-util-get-arguments": "4.0.0", - "cssnano-util-get-match": "4.0.0", - "postcss": "7.0.6", - "postcss-value-parser": "3.3.1" + "cssnano-util-get-arguments": "^4.0.0", + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-normalize-string": { @@ -12117,9 +12105,9 @@ "integrity": "sha512-IJoexFTkAvAq5UZVxWXAGE0yLoNN/012v7TQh5nDo6imZJl2Fwgbhy3J2qnIoaDBrtUP0H7JrXlX1jjn2YcvCQ==", "dev": true, "requires": { - "has": "1.0.3", - "postcss": "7.0.6", - "postcss-value-parser": "3.3.1" + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-normalize-timing-functions": { @@ -12128,9 +12116,9 @@ "integrity": "sha512-1nOtk7ze36+63ONWD8RCaRDYsnzorrj+Q6fxkQV+mlY5+471Qx9kspqv0O/qQNMeApg8KNrRf496zHwJ3tBZ7w==", "dev": true, "requires": { - "cssnano-util-get-match": "4.0.0", - "postcss": "7.0.6", - "postcss-value-parser": "3.3.1" + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-normalize-unicode": { @@ -12139,9 +12127,9 @@ "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", "dev": true, "requires": { - "browserslist": "4.3.5", - "postcss": "7.0.6", - "postcss-value-parser": "3.3.1" + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-normalize-url": { @@ -12150,10 +12138,10 @@ "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", "dev": true, "requires": { - "is-absolute-url": "2.1.0", - "normalize-url": "3.3.0", - "postcss": "7.0.6", - "postcss-value-parser": "3.3.1" + "is-absolute-url": "^2.0.0", + "normalize-url": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-normalize-whitespace": { @@ -12162,8 +12150,8 @@ "integrity": "sha512-U8MBODMB2L+nStzOk6VvWWjZgi5kQNShCyjRhMT3s+W9Jw93yIjOnrEkKYD3Ul7ChWbEcjDWmXq0qOL9MIAnAw==", "dev": true, "requires": { - "postcss": "7.0.6", - "postcss-value-parser": "3.3.1" + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-ordered-values": { @@ -12172,9 +12160,9 @@ "integrity": "sha512-PeJiLgJWPzkVF8JuKSBcylaU+hDJ/TX3zqAMIjlghgn1JBi6QwQaDZoDIlqWRcCAI8SxKrt3FCPSRmOgKRB97Q==", "dev": true, "requires": { - "cssnano-util-get-arguments": "4.0.0", - "postcss": "7.0.6", - "postcss-value-parser": "3.3.1" + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-reduce-initial": { @@ -12183,10 +12171,10 @@ "integrity": "sha512-epUiC39NonKUKG+P3eAOKKZtm5OtAtQJL7Ye0CBN1f+UQTHzqotudp+hki7zxXm7tT0ZAKDMBj1uihpPjP25ug==", "dev": true, "requires": { - "browserslist": "4.3.5", - "caniuse-api": "3.0.0", - "has": "1.0.3", - "postcss": "7.0.6" + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0" } }, "postcss-reduce-transforms": { @@ -12195,10 +12183,10 @@ "integrity": "sha512-sZVr3QlGs0pjh6JAIe6DzWvBaqYw05V1t3d9Tp+VnFRT5j+rsqoWsysh/iSD7YNsULjq9IAylCznIwVd5oU/zA==", "dev": true, "requires": { - "cssnano-util-get-match": "4.0.0", - "has": "1.0.3", - "postcss": "7.0.6", - "postcss-value-parser": "3.3.1" + "cssnano-util-get-match": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-selector-parser": { @@ -12207,9 +12195,9 @@ "integrity": "sha512-0XvfYuShrKlTk1ooUrVzMCFQRcypsdEIsGqh5IxC5rdtBi4/M/tDAJeSONwC2MTqEFsmPZYAV7Dd4X8rgAfV0A==", "dev": true, "requires": { - "cssesc": "2.0.0", - "indexes-of": "1.0.1", - "uniq": "1.0.1" + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" } }, "postcss-svgo": { @@ -12218,10 +12206,10 @@ "integrity": "sha512-YD5uIk5NDRySy0hcI+ZJHwqemv2WiqqzDgtvgMzO8EGSkK5aONyX8HMVFRFJSdO8wUWTuisUFn/d7yRRbBr5Qw==", "dev": true, "requires": { - "is-svg": "3.0.0", - "postcss": "7.0.6", - "postcss-value-parser": "3.3.1", - "svgo": "1.1.1" + "is-svg": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "svgo": "^1.0.0" } }, "postcss-unique-selectors": { @@ -12230,9 +12218,9 @@ "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", "dev": true, "requires": { - "alphanum-sort": "1.0.2", - "postcss": "7.0.6", - "uniqs": "2.0.0" + "alphanum-sort": "^1.0.0", + "postcss": "^7.0.0", + "uniqs": "^2.0.0" } }, "postcss-value-parser": { @@ -12281,7 +12269,7 @@ "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "integrity": "sha1-o31zL0JxtKsa0HDTVQjoKQeI/6o=", "dev": true }, "progress": { @@ -12293,11 +12281,11 @@ "promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=", "dev": true, "optional": true, "requires": { - "asap": "2.0.6" + "asap": "~2.0.3" } }, "proto-list": { @@ -12331,8 +12319,8 @@ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "requires": { - "end-of-stream": "1.4.1", - "once": "1.3.3" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" }, "dependencies": { "end-of-stream": { @@ -12341,7 +12329,7 @@ "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "dev": true, "requires": { - "once": "1.4.0" + "once": "^1.4.0" }, "dependencies": { "once": { @@ -12350,7 +12338,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } } } @@ -12388,9 +12376,9 @@ "dev": true, "optional": true, "requires": { - "decode-uri-component": "0.2.0", - "object-assign": "4.1.1", - "strict-uri-encode": "1.1.0" + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" }, "dependencies": { "object-assign": { @@ -12408,9 +12396,9 @@ "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", "dev": true, "requires": { - "is-number": "4.0.0", - "kind-of": "6.0.2", - "math-random": "1.0.1" + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" }, "dependencies": { "is-number": { @@ -12433,8 +12421,8 @@ "integrity": "sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU=", "dev": true, "requires": { - "bytes": "1.0.0", - "string_decoder": "0.10.31" + "bytes": "1", + "string_decoder": "0.10" } }, "read-pkg": { @@ -12443,9 +12431,9 @@ "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "dev": true, "requires": { - "load-json-file": "1.1.0", - "normalize-package-data": "2.4.0", - "path-type": "1.1.0" + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" }, "dependencies": { "graceful-fs": { @@ -12460,9 +12448,9 @@ "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "dev": true, "requires": { - "graceful-fs": "4.1.15", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "pify": { @@ -12479,20 +12467,20 @@ "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "dev": true, "requires": { - "find-up": "1.1.2", - "read-pkg": "1.1.0" + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" } }, "readable-stream": { "version": "1.1.14", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", "isarray": "0.0.1", - "string_decoder": "0.10.31" + "string_decoder": "~0.10.x" } }, "readdirp": { @@ -12501,9 +12489,9 @@ "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "dev": true, "requires": { - "graceful-fs": "4.1.15", - "micromatch": "3.1.10", - "readable-stream": "2.3.6" + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" }, "dependencies": { "graceful-fs": { @@ -12524,22 +12512,22 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "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" } }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "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.2" + "safe-buffer": "~5.1.0" } } } @@ -12550,7 +12538,7 @@ "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", "dev": true, "requires": { - "resolve": "1.8.1" + "resolve": "^1.1.6" } }, "redent": { @@ -12559,8 +12547,8 @@ "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", "dev": true, "requires": { - "indent-string": "2.1.0", - "strip-indent": "1.0.1" + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" } }, "regenerate": { @@ -12575,7 +12563,7 @@ "integrity": "sha512-s5NGghCE4itSlUS+0WUj88G6cfMVMmH8boTPNvABf8od+2dhT9WDlWu8n01raQAJZMOK8Ch6jSexaRO7swd6aw==", "dev": true, "requires": { - "regenerate": "1.4.0" + "regenerate": "^1.4.0" } }, "regenerator-transform": { @@ -12584,26 +12572,26 @@ "integrity": "sha512-5ipTrZFSq5vU2YoGoww4uaRVAK4wyYC4TSICibbfEPOruUu8FFP7ErV0BjmbIOEpn3O/k9na9UEdYR/3m7N6uA==", "dev": true, "requires": { - "private": "0.1.8" + "private": "^0.1.6" } }, "regex-cache": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "integrity": "sha1-db3FiioUls7EihKDW8VMjVYjNt0=", "dev": true, "requires": { - "is-equal-shallow": "0.1.3" + "is-equal-shallow": "^0.1.3" } }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "integrity": "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw=", "dev": true, "requires": { - "extend-shallow": "3.0.2", - "safe-regex": "1.1.0" + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" } }, "regexpp": { @@ -12618,12 +12606,12 @@ "integrity": "sha512-Z835VSnJJ46CNBttalHD/dB+Sj2ezmY6Xp38npwU87peK6mqOzOpV8eYktdkLTEkzzD+JsTcxd84ozd8I14+rw==", "dev": true, "requires": { - "regenerate": "1.4.0", - "regenerate-unicode-properties": "7.0.0", - "regjsgen": "0.4.0", - "regjsparser": "0.3.0", - "unicode-match-property-ecmascript": "1.0.4", - "unicode-match-property-value-ecmascript": "1.0.2" + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^7.0.0", + "regjsgen": "^0.4.0", + "regjsparser": "^0.3.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.0.2" } }, "regjsgen": { @@ -12638,12 +12626,12 @@ "integrity": "sha512-zza72oZBBHzt64G7DxdqrOo/30bhHkwMUoT0WqfGu98XLd7N+1tsy5MJ96Bk4MD0y74n629RhmrGW6XlnLLwCA==", "dev": true, "requires": { - "jsesc": "0.5.0" + "jsesc": "~0.5.0" }, "dependencies": { "jsesc": { "version": "0.5.0", - "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", "dev": true } @@ -12673,7 +12661,7 @@ "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "dev": true, "requires": { - "is-finite": "1.0.2" + "is-finite": "^1.0.0" } }, "replace-ext": { @@ -12688,26 +12676,26 @@ "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", "dev": true, "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.8.0", - "caseless": "0.12.0", - "combined-stream": "1.0.7", - "extend": "3.0.2", - "forever-agent": "0.6.1", - "form-data": "2.3.3", - "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.21", - "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" + "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" }, "dependencies": { "qs": { @@ -12724,7 +12712,7 @@ "integrity": "sha1-XTa7V5YcZzqlt4jbyBQf3yO0Tgg=", "dev": true, "requires": { - "throttleit": "1.0.0" + "throttleit": "^1.0.0" } }, "require-from-string": { @@ -12735,12 +12723,12 @@ }, "require-uncached": { "version": "1.0.3", - "resolved": "http://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", "dev": true, "requires": { - "caller-path": "0.1.0", - "resolve-from": "1.0.1" + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" }, "dependencies": { "caller-path": { @@ -12749,7 +12737,7 @@ "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", "dev": true, "requires": { - "callsites": "0.2.0" + "callsites": "^0.2.0" } }, "callsites": { @@ -12778,7 +12766,7 @@ "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", "dev": true, "requires": { - "path-parse": "1.0.6" + "path-parse": "^1.0.5" } }, "resolve-dir": { @@ -12787,8 +12775,8 @@ "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", "dev": true, "requires": { - "expand-tilde": "2.0.2", - "global-modules": "1.0.0" + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" } }, "resolve-from": { @@ -12810,7 +12798,7 @@ "dev": true, "optional": true, "requires": { - "lowercase-keys": "1.0.1" + "lowercase-keys": "^1.0.0" } }, "restore-cursor": { @@ -12819,14 +12807,14 @@ "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", "dev": true, "requires": { - "onetime": "2.0.1", - "signal-exit": "3.0.2" + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" } }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "integrity": "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w=", "dev": true }, "rfdc": { @@ -12853,16 +12841,16 @@ "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", "dev": true, "requires": { - "align-text": "0.1.4" + "align-text": "^0.1.1" } }, "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=", "dev": true, "requires": { - "glob": "7.1.3" + "glob": "^7.0.5" }, "dependencies": { "glob": { @@ -12871,12 +12859,12 @@ "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.3.3", - "path-is-absolute": "1.0.1" + "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" } }, "minimatch": { @@ -12885,7 +12873,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } } } @@ -12896,18 +12884,18 @@ "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", "dev": true, "requires": { - "is-promise": "2.1.0" + "is-promise": "^2.1.0" } }, "run-sequence": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/run-sequence/-/run-sequence-2.2.1.tgz", - "integrity": "sha512-qkzZnQWMZjcKbh3CNly2srtrkaO/2H/SI5f2eliMCapdRD3UhMrwjfOAZJAnZ2H8Ju4aBzFZkBGXUqFs9V0yxw==", + "integrity": "sha1-HOZD2jb9jH6n4akynaM/wriJhJU=", "dev": true, "requires": { - "chalk": "1.1.3", - "fancy-log": "1.3.3", - "plugin-error": "0.1.2" + "chalk": "^1.1.3", + "fancy-log": "^1.3.2", + "plugin-error": "^0.1.2" }, "dependencies": { "ansi-styles": { @@ -12922,8 +12910,8 @@ "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=", "dev": true, "requires": { - "arr-flatten": "1.1.0", - "array-slice": "0.2.3" + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" } }, "arr-union": { @@ -12944,11 +12932,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "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" } }, "extend-shallow": { @@ -12957,7 +12945,7 @@ "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", "dev": true, "requires": { - "kind-of": "1.1.0" + "kind-of": "^1.1.0" } }, "kind-of": { @@ -12972,11 +12960,11 @@ "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=", "dev": true, "requires": { - "ansi-cyan": "0.1.1", - "ansi-red": "0.1.1", - "arr-diff": "1.1.0", - "arr-union": "2.1.0", - "extend-shallow": "1.1.4" + "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" } }, "supports-color": { @@ -12993,13 +12981,13 @@ "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==", "dev": true, "requires": { - "tslib": "1.9.3" + "tslib": "^1.9.0" } }, "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==", + "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=", "dev": true }, "safe-json-parse": { @@ -13010,11 +12998,11 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { - "ret": "0.1.15" + "ret": "~0.1.10" } }, "safer-buffer": { @@ -13026,7 +13014,7 @@ "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=", "dev": true }, "seek-bzip": { @@ -13035,7 +13023,7 @@ "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", "dev": true, "requires": { - "commander": "2.8.1" + "commander": "~2.8.1" } }, "select": { @@ -13063,7 +13051,7 @@ "dev": true, "optional": true, "requires": { - "semver": "5.6.0" + "semver": "^5.3.0" } }, "send": { @@ -13073,18 +13061,18 @@ "dev": true, "requires": { "debug": "2.6.9", - "depd": "1.1.2", - "destroy": "1.0.4", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "1.6.3", + "http-errors": "~1.6.2", "mime": "1.4.1", "ms": "2.0.0", - "on-finished": "2.3.0", - "range-parser": "1.2.0", - "statuses": "1.4.0" + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" }, "dependencies": { "debug": { @@ -13122,13 +13110,13 @@ "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", "dev": true, "requires": { - "accepts": "1.3.5", + "accepts": "~1.3.4", "batch": "0.6.1", "debug": "2.6.9", - "escape-html": "1.0.3", - "http-errors": "1.6.3", - "mime-types": "2.1.21", - "parseurl": "1.3.2" + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" }, "dependencies": { "debug": { @@ -13154,22 +13142,22 @@ "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", "dev": true, "requires": { - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "parseurl": "1.3.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", "send": "0.16.2" } }, "set-value": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "integrity": "sha1-ca5KiPD+77v1LR6mBPP7MV67YnQ=", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "split-string": "3.1.0" + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" }, "dependencies": { "extend-shallow": { @@ -13178,7 +13166,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -13195,7 +13183,7 @@ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "1.0.0" + "shebang-regex": "^1.0.0" } }, "shebang-regex": { @@ -13221,7 +13209,7 @@ "resolved": "https://registry.npmjs.org/signalr/-/signalr-2.4.0.tgz", "integrity": "sha512-GPJHb3pcNk3IUui5/WG8lMuarEn+Vpc8wEvJ60w0KQ43W9FHnJcuNcF8dkZePr81eBslzicsRdyEunKNF7KjZQ==", "requires": { - "jquery": "3.3.1" + "jquery": ">=1.6.4" } }, "simple-swizzle": { @@ -13230,7 +13218,7 @@ "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", "dev": true, "requires": { - "is-arrayish": "0.3.2" + "is-arrayish": "^0.3.1" }, "dependencies": { "is-arrayish": { @@ -13253,25 +13241,25 @@ "integrity": "sha512-4j2WTWjp3GsZ+AOagyzVbzp4vWGtZ0hEZ/gDY/uTvm6MTxUfTUIsnMIFb1bn8o0RuXiqUw15H1bue8f22Vw2oQ==", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "astral-regex": "1.0.0", - "is-fullwidth-code-point": "2.0.0" + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" } }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "integrity": "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0=", "dev": true, "requires": { - "base": "0.11.2", - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "map-cache": "0.2.2", - "source-map": "0.5.7", - "source-map-resolve": "0.5.2", - "use": "3.1.1" + "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" }, "dependencies": { "debug": { @@ -13289,7 +13277,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -13298,7 +13286,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } }, "ms": { @@ -13312,12 +13300,12 @@ "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==", + "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", "dev": true, "requires": { - "define-property": "1.0.0", - "isobject": "3.0.1", - "snapdragon-util": "3.0.1" + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" }, "dependencies": { "define-property": { @@ -13326,36 +13314,36 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "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==", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "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==", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -13363,10 +13351,10 @@ "snapdragon-util": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.2.0" }, "dependencies": { "kind-of": { @@ -13375,7 +13363,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -13386,12 +13374,12 @@ "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", "dev": true, "requires": { - "debug": "3.1.0", - "engine.io": "3.2.1", - "has-binary2": "1.0.3", - "socket.io-adapter": "1.1.1", + "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" + "socket.io-parser": "~3.2.0" }, "dependencies": { "debug": { @@ -13427,15 +13415,15 @@ "base64-arraybuffer": "0.1.5", "component-bind": "1.0.0", "component-emitter": "1.2.1", - "debug": "3.1.0", - "engine.io-client": "3.2.1", - "has-binary2": "1.0.3", + "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", + "socket.io-parser": "~3.2.0", "to-array": "0.1.4" }, "dependencies": { @@ -13463,7 +13451,7 @@ "dev": true, "requires": { "component-emitter": "1.2.1", - "debug": "3.1.0", + "debug": "~3.1.0", "isarray": "2.0.1" }, "dependencies": { @@ -13496,7 +13484,7 @@ "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", "dev": true, "requires": { - "is-plain-obj": "1.1.0" + "is-plain-obj": "^1.0.0" } }, "sort-keys-length": { @@ -13505,7 +13493,7 @@ "integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=", "dev": true, "requires": { - "sort-keys": "1.1.2" + "sort-keys": "^1.0.0" } }, "source-map": { @@ -13520,11 +13508,11 @@ "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", "dev": true, "requires": { - "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" + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" } }, "source-map-url": { @@ -13545,8 +13533,8 @@ "integrity": "sha512-q9hedtzyXHr5S0A1vEPoK/7l8NpfkFYTq6iCY+Pno2ZbdZR6WexZFtqeVGkGxW3TEJMN914Z55EnAGMmenlIQQ==", "dev": true, "requires": { - "spdx-expression-parse": "3.0.0", - "spdx-license-ids": "3.0.2" + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" } }, "spdx-exceptions": { @@ -13558,11 +13546,11 @@ "spdx-expression-parse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "integrity": "sha1-meEZt6XaAOBUkcn6M4t5BII7QdA=", "dev": true, "requires": { - "spdx-exceptions": "2.2.0", - "spdx-license-ids": "3.0.2" + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, "spdx-license-ids": { @@ -13582,16 +13570,16 @@ "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", "dev": true, "requires": { - "through": "2.3.8" + "through": "2" } }, "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==", + "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=", "dev": true, "requires": { - "extend-shallow": "3.0.2" + "extend-shallow": "^3.0.0" } }, "sprintf-js": { @@ -13607,9 +13595,9 @@ "dev": true, "optional": true, "requires": { - "chalk": "1.1.3", - "console-stream": "0.1.1", - "lpad-align": "1.1.2" + "chalk": "^1.0.0", + "console-stream": "^0.1.1", + "lpad-align": "^1.0.1" }, "dependencies": { "ansi-styles": { @@ -13626,11 +13614,11 @@ "dev": true, "optional": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "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": { @@ -13648,21 +13636,21 @@ "integrity": "sha512-Ra/OXQtuh0/enyl4ETZAfTaeksa6BXks5ZcjpSUNrjBr0DvrJKX+1fsKDPpT9TBXgHAFsa4510aNVgI8g/+SzA==", "dev": true, "requires": { - "asn1": "0.2.4", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.2", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.2", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "safer-buffer": "2.1.2", - "tweetnacl": "0.14.5" + "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" } }, "stable": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "integrity": "sha1-g26zyDgv4pNv6vVEYxAXzn1Ho88=", "dev": true }, "static-extend": { @@ -13671,8 +13659,8 @@ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "dev": true, "requires": { - "define-property": "0.2.5", - "object-copy": "0.1.0" + "define-property": "^0.2.5", + "object-copy": "^0.1.0" }, "dependencies": { "define-property": { @@ -13681,7 +13669,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } } } @@ -13698,8 +13686,8 @@ "integrity": "sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg=", "dev": true, "requires": { - "duplexer": "0.1.1", - "through": "2.3.8" + "duplexer": "~0.1.1", + "through": "~2.3.4" } }, "stream-consume": { @@ -13714,10 +13702,10 @@ "integrity": "sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ==", "dev": true, "requires": { - "date-format": "1.2.0", - "debug": "3.2.6", - "mkdirp": "0.5.1", - "readable-stream": "2.3.6" + "date-format": "^1.2.0", + "debug": "^3.1.0", + "mkdirp": "^0.5.1", + "readable-stream": "^2.3.0" }, "dependencies": { "debug": { @@ -13726,7 +13714,7 @@ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "ms": "2.1.1" + "ms": "^2.1.1" } }, "isarray": { @@ -13737,26 +13725,26 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "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" } }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "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.2" + "safe-buffer": "~5.1.0" } } } @@ -13780,8 +13768,8 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" }, "dependencies": { "ansi-regex": { @@ -13796,24 +13784,24 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } } } }, "string_decoder": { "version": "0.10.31", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true }, "strip-ansi": { "version": "3.0.1", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-bom": { @@ -13822,8 +13810,8 @@ "integrity": "sha1-hbiGLzhEtabV7IRnqTWYFzo295Q=", "dev": true, "requires": { - "first-chunk-stream": "1.0.0", - "is-utf8": "0.2.1" + "first-chunk-stream": "^1.0.0", + "is-utf8": "^0.2.0" } }, "strip-bom-stream": { @@ -13832,8 +13820,8 @@ "integrity": "sha1-+H217yYT9paKpUWr/h7HKLaoKco=", "dev": true, "requires": { - "first-chunk-stream": "2.0.0", - "strip-bom": "2.0.0" + "first-chunk-stream": "^2.0.0", + "strip-bom": "^2.0.0" }, "dependencies": { "first-chunk-stream": { @@ -13842,7 +13830,7 @@ "integrity": "sha1-G97NuOCDwGZLkZRVgVd6Q6nzHXA=", "dev": true, "requires": { - "readable-stream": "2.3.6" + "readable-stream": "^2.0.2" } }, "isarray": { @@ -13857,13 +13845,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "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" } }, "string_decoder": { @@ -13872,7 +13860,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } }, "strip-bom": { @@ -13881,7 +13869,7 @@ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, "requires": { - "is-utf8": "0.2.1" + "is-utf8": "^0.2.0" } } } @@ -13892,7 +13880,7 @@ "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", "dev": true, "requires": { - "is-natural-number": "4.0.1" + "is-natural-number": "^4.0.1" } }, "strip-eof": { @@ -13907,7 +13895,7 @@ "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", "dev": true, "requires": { - "get-stdin": "4.0.1" + "get-stdin": "^4.0.1" } }, "strip-json-comments": { @@ -13919,10 +13907,10 @@ "strip-outer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", - "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "integrity": "sha1-sv0qv2YEudHmATBXGV34Nrip1jE=", "dev": true, "requires": { - "escape-string-regexp": "1.0.5" + "escape-string-regexp": "^1.0.2" } }, "stylehacks": { @@ -13931,9 +13919,9 @@ "integrity": "sha512-TK5zEPeD9NyC1uPIdjikzsgWxdQQN/ry1X3d1iOz1UkYDCmcr928gWD1KHgyC27F50UnE0xCTrBOO1l6KR8M4w==", "dev": true, "requires": { - "browserslist": "4.3.5", - "postcss": "7.0.6", - "postcss-selector-parser": "3.1.1" + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" }, "dependencies": { "postcss-selector-parser": { @@ -13942,9 +13930,9 @@ "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", "dev": true, "requires": { - "dot-prop": "4.2.0", - "indexes-of": "1.0.1", - "uniq": "1.0.1" + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" } } } @@ -13955,7 +13943,7 @@ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } }, "svgo": { @@ -13964,20 +13952,20 @@ "integrity": "sha512-GBkJbnTuFpM4jFbiERHDWhZc/S/kpHToqmZag3aEBjPYK44JAN2QBjvrGIxLOoCyMZjuFQIfTO2eJd8uwLY/9g==", "dev": true, "requires": { - "coa": "2.0.1", - "colors": "1.1.2", - "css-select": "2.0.2", - "css-select-base-adapter": "0.1.1", + "coa": "~2.0.1", + "colors": "~1.1.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "~0.1.0", "css-tree": "1.0.0-alpha.28", - "css-url-regex": "1.1.0", - "csso": "3.5.1", - "js-yaml": "3.12.0", - "mkdirp": "0.5.1", - "object.values": "1.0.4", - "sax": "1.2.4", - "stable": "0.1.8", - "unquote": "1.1.1", - "util.promisify": "1.0.0" + "css-url-regex": "^1.1.0", + "csso": "^3.5.0", + "js-yaml": "^3.12.0", + "mkdirp": "~0.5.1", + "object.values": "^1.0.4", + "sax": "~1.2.4", + "stable": "~0.1.6", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" } }, "table": { @@ -13986,10 +13974,10 @@ "integrity": "sha512-NUjapYb/qd4PeFW03HnAuOJ7OMcBkJlqeClWxeNlQ0lXGSb52oZXGzkO0/I0ARegQ2eUT1g2VDJH0eUxDRcHmw==", "dev": true, "requires": { - "ajv": "6.6.1", - "lodash": "4.17.11", + "ajv": "^6.6.1", + "lodash": "^4.17.11", "slice-ansi": "2.0.0", - "string-width": "2.1.1" + "string-width": "^2.1.1" } }, "tar-stream": { @@ -13998,22 +13986,22 @@ "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", "dev": true, "requires": { - "bl": "1.2.2", - "buffer-alloc": "1.2.0", - "end-of-stream": "1.4.1", - "fs-constants": "1.0.0", - "readable-stream": "2.3.6", - "to-buffer": "1.1.1", - "xtend": "4.0.1" + "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" }, "dependencies": { "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "integrity": "sha1-7SljTRm6ukY7bOa4CjchPqtx7EM=", "dev": true, "requires": { - "once": "1.4.0" + "once": "^1.4.0" } }, "isarray": { @@ -14028,7 +14016,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "readable-stream": { @@ -14037,22 +14025,22 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "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" } }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "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.2" + "safe-buffer": "~5.1.0" } } } @@ -14069,8 +14057,8 @@ "integrity": "sha1-awRGhWqbERTRhW/8vlCczLCXcmU=", "dev": true, "requires": { - "temp-dir": "1.0.0", - "uuid": "3.3.2" + "temp-dir": "^1.0.0", + "uuid": "^3.0.1" } }, "text-table": { @@ -14087,7 +14075,7 @@ }, "through": { "version": "2.3.8", - "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, @@ -14097,8 +14085,8 @@ "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "dev": true, "requires": { - "readable-stream": "2.3.6", - "xtend": "4.0.1" + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" }, "dependencies": { "isarray": { @@ -14113,13 +14101,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "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" } }, "string_decoder": { @@ -14128,7 +14116,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -14139,7 +14127,7 @@ "integrity": "sha512-R5/jLkfMvdmDD+seLwN7vB+mhbqzWop5fAjx5IX8/yQq7VhBhzDmhXgaHAOnhnWkCpRMM7gToYHycB0CS/pd+A==", "dev": true, "requires": { - "through2": "2.0.5" + "through2": "^2.0.0" } }, "tildify": { @@ -14148,7 +14136,7 @@ "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", "dev": true, "requires": { - "os-homedir": "1.0.2" + "os-homedir": "^1.0.0" } }, "time-stamp": { @@ -14180,12 +14168,12 @@ "integrity": "sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA==", "dev": true, "requires": { - "body": "5.1.0", - "debug": "3.2.6", - "faye-websocket": "0.10.0", - "livereload-js": "2.4.0", - "object-assign": "4.1.1", - "qs": "6.6.0" + "body": "^5.1.0", + "debug": "^3.1.0", + "faye-websocket": "~0.10.0", + "livereload-js": "^2.3.0", + "object-assign": "^4.1.0", + "qs": "^6.4.0" }, "dependencies": { "debug": { @@ -14194,7 +14182,7 @@ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "ms": "2.1.1" + "ms": "^2.1.1" } }, "object-assign": { @@ -14216,7 +14204,7 @@ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { - "os-tmpdir": "1.0.2" + "os-tmpdir": "~1.0.2" } }, "to-array": { @@ -14228,7 +14216,7 @@ "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==", + "integrity": "sha1-STvUj2LXxD/N7TE6A9ytsuEhOoA=", "dev": true }, "to-fast-properties": { @@ -14243,7 +14231,7 @@ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -14252,7 +14240,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -14260,13 +14248,13 @@ "to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "integrity": "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4=", "dev": true, "requires": { - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "regex-not": "1.0.2", - "safe-regex": "1.1.0" + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" } }, "to-regex-range": { @@ -14275,8 +14263,8 @@ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { - "is-number": "3.0.0", - "repeat-string": "1.6.1" + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" } }, "tough-cookie": { @@ -14285,8 +14273,8 @@ "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "dev": true, "requires": { - "psl": "1.1.29", - "punycode": "1.4.1" + "psl": "^1.1.24", + "punycode": "^1.4.1" }, "dependencies": { "punycode": { @@ -14309,7 +14297,7 @@ "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", "dev": true, "requires": { - "escape-string-regexp": "1.0.5" + "escape-string-regexp": "^1.0.2" } }, "trim-right": { @@ -14336,7 +14324,7 @@ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "^5.0.1" } }, "tweetnacl": { @@ -14351,7 +14339,7 @@ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { - "prelude-ls": "1.1.2" + "prelude-ls": "~1.1.2" } }, "type-is": { @@ -14361,7 +14349,7 @@ "dev": true, "requires": { "media-typer": "0.3.0", - "mime-types": "2.1.21" + "mime-types": "~2.1.18" } }, "typeahead.js": { @@ -14369,7 +14357,7 @@ "resolved": "https://registry.npmjs.org/typeahead.js/-/typeahead.js-0.11.1.tgz", "integrity": "sha1-TmTmcbIjEKhgb0rsgFkkuoSwFbg=", "requires": { - "jquery": "3.3.1" + "jquery": ">=1.7" } }, "typedarray": { @@ -14384,9 +14372,9 @@ "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", "dev": true, "requires": { - "source-map": "0.5.7", - "uglify-to-browserify": "1.0.2", - "yargs": "3.10.0" + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" } }, "uglify-to-browserify": { @@ -14408,8 +14396,8 @@ "integrity": "sha512-fIZnvdjblYs7Cru/xC6tCPVhz7JkYcVQQkePwMLyQELzYTds2Xn8QefPVnvdVhhZqubxNA1cASXEH5wcK0Bucw==", "dev": true, "requires": { - "buffer": "3.6.0", - "through": "2.3.8" + "buffer": "^3.0.1", + "through": "^2.3.6" } }, "unc-path-regex": { @@ -14435,8 +14423,8 @@ "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", "dev": true, "requires": { - "unicode-canonical-property-names-ecmascript": "1.0.4", - "unicode-property-aliases-ecmascript": "1.0.4" + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" } }, "unicode-match-property-value-ecmascript": { @@ -14457,10 +14445,10 @@ "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", "dev": true, "requires": { - "arr-union": "3.1.0", - "get-value": "2.0.6", - "is-extendable": "0.1.1", - "set-value": "0.4.3" + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" }, "dependencies": { "extend-shallow": { @@ -14469,7 +14457,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } }, "set-value": { @@ -14478,10 +14466,10 @@ "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "to-object-path": "0.3.0" + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" } } } @@ -14522,8 +14510,8 @@ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "requires": { - "has-value": "0.3.1", - "isobject": "3.0.1" + "has-value": "^0.3.1", + "isobject": "^3.0.0" }, "dependencies": { "has-value": { @@ -14532,9 +14520,9 @@ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "dev": true, "requires": { - "get-value": "2.0.6", - "has-values": "0.1.4", - "isobject": "2.1.0" + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" }, "dependencies": { "isobject": { @@ -14574,7 +14562,7 @@ "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "dev": true, "requires": { - "punycode": "2.1.1" + "punycode": "^2.1.0" } }, "urix": { @@ -14590,7 +14578,7 @@ "dev": true, "optional": true, "requires": { - "prepend-http": "1.0.4" + "prepend-http": "^1.0.1" } }, "url-to-options": { @@ -14617,8 +14605,8 @@ "integrity": "sha1-z1k+9PLRdYdei7ZY6pLhik/QbY4=", "dev": true, "requires": { - "lru-cache": "2.2.4", - "tmp": "0.0.33" + "lru-cache": "2.2.x", + "tmp": "0.0.x" }, "dependencies": { "lru-cache": { @@ -14638,11 +14626,11 @@ "util.promisify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "integrity": "sha1-RA9xZaRZyaFtwUXrjnLzVocJcDA=", "dev": true, "requires": { - "define-properties": "1.1.3", - "object.getownpropertydescriptors": "2.0.3" + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" } }, "utils-merge": { @@ -14663,7 +14651,7 @@ "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", "dev": true, "requires": { - "user-home": "1.1.1" + "user-home": "^1.1.1" } }, "validate-npm-package-license": { @@ -14672,14 +14660,14 @@ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, "requires": { - "spdx-correct": "3.0.2", - "spdx-expression-parse": "3.0.0" + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" } }, "vendors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.2.tgz", - "integrity": "sha512-w/hry/368nO21AN9QljsaIhb9ZiZtZARoVH5f3CsFbawdLdayCgKRPup7CggujvySMxx0I91NOyxdVENohprLQ==", + "integrity": "sha1-f8te759WI7FWvOqJ7DfWNnbyGAE=", "dev": true }, "verror": { @@ -14688,9 +14676,9 @@ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "dev": true, "requires": { - "assert-plus": "1.0.0", + "assert-plus": "^1.0.0", "core-util-is": "1.0.2", - "extsprintf": "1.3.0" + "extsprintf": "^1.2.0" } }, "vinyl": { @@ -14699,8 +14687,8 @@ "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", "dev": true, "requires": { - "clone": "1.0.4", - "clone-stats": "0.0.1", + "clone": "^1.0.0", + "clone-stats": "^0.0.1", "replace-ext": "0.0.1" } }, @@ -14719,12 +14707,12 @@ "integrity": "sha1-p+v1/779obfRjRQPyweyI++2dRo=", "dev": true, "requires": { - "graceful-fs": "4.1.15", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "strip-bom": "2.0.0", - "strip-bom-stream": "2.0.0", - "vinyl": "1.2.0" + "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" }, "dependencies": { "graceful-fs": { @@ -14745,7 +14733,7 @@ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, "requires": { - "is-utf8": "0.2.1" + "is-utf8": "^0.2.0" } }, "vinyl": { @@ -14754,8 +14742,8 @@ "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", "dev": true, "requires": { - "clone": "1.0.4", - "clone-stats": "0.0.1", + "clone": "^1.0.0", + "clone-stats": "^0.0.1", "replace-ext": "0.0.1" } } @@ -14767,14 +14755,14 @@ "integrity": "sha1-mmhRzhysHBzqX+hsCTHWIMLPqeY=", "dev": true, "requires": { - "defaults": "1.0.3", - "glob-stream": "3.1.18", - "glob-watcher": "0.0.6", - "graceful-fs": "3.0.11", - "mkdirp": "0.5.1", - "strip-bom": "1.0.0", - "through2": "0.6.5", - "vinyl": "0.4.6" + "defaults": "^1.0.0", + "glob-stream": "^3.1.5", + "glob-watcher": "^0.0.6", + "graceful-fs": "^3.0.0", + "mkdirp": "^0.5.0", + "strip-bom": "^1.0.0", + "through2": "^0.6.1", + "vinyl": "^0.4.0" }, "dependencies": { "clone": { @@ -14789,10 +14777,10 @@ "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", "isarray": "0.0.1", - "string_decoder": "0.10.31" + "string_decoder": "~0.10.x" } }, "through2": { @@ -14801,8 +14789,8 @@ "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, "requires": { - "readable-stream": "1.0.34", - "xtend": "4.0.1" + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" } }, "vinyl": { @@ -14811,8 +14799,8 @@ "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", "dev": true, "requires": { - "clone": "0.2.0", - "clone-stats": "0.0.1" + "clone": "^0.2.0", + "clone-stats": "^0.0.1" } } } @@ -14823,7 +14811,7 @@ "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", "dev": true, "requires": { - "source-map": "0.5.7" + "source-map": "^0.5.1" } }, "void-elements": { @@ -14838,14 +14826,14 @@ "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", "dev": true, "requires": { - "http-parser-js": "0.5.0", - "websocket-extensions": "0.1.3" + "http-parser-js": ">=0.4.0", + "websocket-extensions": ">=0.1.1" } }, "websocket-extensions": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", - "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", + "integrity": "sha1-XS/yKXcAPsaHpLhwc9+7rBRszyk=", "dev": true }, "when": { @@ -14860,7 +14848,7 @@ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "window-size": { @@ -14887,7 +14875,7 @@ "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", "dev": true, "requires": { - "mkdirp": "0.5.1" + "mkdirp": "^0.5.1" } }, "ws": { @@ -14896,9 +14884,9 @@ "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", "dev": true, "requires": { - "async-limiter": "1.0.0", - "safe-buffer": "5.1.2", - "ultron": "1.1.1" + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" } }, "xmlhttprequest-ssl": { @@ -14921,13 +14909,13 @@ }, "yargs": { "version": "3.10.0", - "resolved": "http://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", "dev": true, "requires": { - "camelcase": "1.2.1", - "cliui": "2.1.0", - "decamelize": "1.2.0", + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", "window-size": "0.1.0" }, "dependencies": { @@ -14945,8 +14933,8 @@ "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", "dev": true, "requires": { - "buffer-crc32": "0.2.13", - "fd-slicer": "1.1.0" + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" } }, "yeast": { diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/events/events.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/events/events.directive.js index a6a5336af0..7578ade867 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/events/events.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/events/events.directive.js @@ -95,7 +95,7 @@ angular.module('umbraco.directives') }; }) -.directive('onOutsideClick', function ($timeout) { +.directive('onOutsideClick', function ($timeout, angularHelper) { return function (scope, element, attrs) { var eventBindings = []; @@ -136,7 +136,7 @@ angular.module('umbraco.directives') return; } - scope.$apply(attrs.onOutsideClick); + angularHelper.safeApply(scope, attrs.onOutsideClick); } diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/imaging/umbimagecrop.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/imaging/umbimagecrop.directive.js index ffa76a57c3..73b74ead8b 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/imaging/umbimagecrop.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/imaging/umbimagecrop.directive.js @@ -274,7 +274,7 @@ angular.module("umbraco.directives") } //// INIT ///// - $image.load(function(){ + $image.on("load", function(){ $timeout(function(){ init($image); }); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/imaging/umbimagethumbnail.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/imaging/umbimagethumbnail.directive.js index dd6dcffc31..b1bb603ace 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/imaging/umbimagethumbnail.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/imaging/umbimagethumbnail.directive.js @@ -27,34 +27,34 @@ angular.module("umbraco.directives") var $image = element.find("img"); scope.loaded = false; - $image.load(function(){ - $timeout(function(){ - $image.width("auto"); - $image.height("auto"); + $image.on("load", function() { + $timeout(function () { + $image.width("auto"); + $image.height("auto"); - scope.image = {}; - scope.image.width = $image[0].width; - scope.image.height = $image[0].height; + scope.image = {}; + scope.image.width = $image[0].width; + scope.image.height = $image[0].height; - //we force a lower thumbnail size to fit the max size - //we do not compare to the image dimensions, but the thumbs - if(scope.maxSize){ - var ratioCalculation = cropperHelper.calculateAspectRatioFit( - scope.width, - scope.height, - scope.maxSize, - scope.maxSize, - false); + //we force a lower thumbnail size to fit the max size + //we do not compare to the image dimensions, but the thumbs + if (scope.maxSize) { + var ratioCalculation = cropperHelper.calculateAspectRatioFit( + scope.width, + scope.height, + scope.maxSize, + scope.maxSize, + false); - //so if we have a max size, override the thumb sizes - scope.width = ratioCalculation.width; - scope.height = ratioCalculation.height; - } + //so if we have a max size, override the thumb sizes + scope.width = ratioCalculation.width; + scope.height = ratioCalculation.height; + } - setPreviewStyle(); - scope.loaded = true; - }); - }); + setPreviewStyle(); + scope.loaded = true; + }); + }) /// WATCHERS //// scope.$watchCollection('[crop, center]', function(newValues, oldValues){ diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js index eed23b4de2..fbc237e3d3 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js @@ -34,7 +34,6 @@ vm.$onDestroy = onDestroy; vm.validateMandatory = validateMandatory; - vm.addTagOnEnter = addTagOnEnter; vm.addTag = addTag; vm.removeTag = removeTag; vm.showPrompt = showPrompt; @@ -60,20 +59,17 @@ tagsHound = new Bloodhound({ datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'), queryTokenizer: Bloodhound.tokenizers.whitespace, - dupDetector: function (remoteMatch, localMatch) { - return (remoteMatch["value"] == localMatch["value"]); - }, //pre-fetch the tags for this category prefetch: { url: umbRequestHelper.getApiUrl("tagsDataBaseUrl", "GetTags", { tagGroup: vm.config.group, culture: vm.culture }), //TTL = 5 minutes ttl: 300000, - filter: dataTransform + transform: dataTransform }, //dynamically get the tags for this category (they may have changed on the server) remote: { url: umbRequestHelper.getApiUrl("tagsDataBaseUrl", "GetTags", { tagGroup: vm.config.group, culture: vm.culture }), - filter: dataTransform + transform: dataTransform } }); @@ -82,31 +78,36 @@ //configure the type ahead $timeout(function () { - typeahead = $element.find('.tags-' + vm.htmlId).typeahead( - { - //This causes some strangeness as it duplicates the textbox, best leave off for now. - hint: false, - highlight: true, - cacheKey: new Date(), // Force a cache refresh each time the control is initialized - minLength: 1 - }, { - //see: https://github.com/twitter/typeahead.js/blob/master/doc/jquery_typeahead.md#options - // name = the data set name, we'll make this the tag group name - name: vm.config.group, - displayKey: "value", - source: function (query, cb) { - tagsHound.get(query, function (suggestions) { + var sources = { + //see: https://github.com/twitter/typeahead.js/blob/master/doc/jquery_typeahead.md#options + // name = the data set name, we'll make this the tag group name + name: vm.config.group, + display: "value", + //source: tagsHound + source: function (query, cb) { + tagsHound.search(query, + function(suggestions) { cb(removeCurrentTagsFromSuggestions(suggestions)); }); - } - }).bind("typeahead:selected", function (obj, datum, name) { + } + }; + + var opts = { + //This causes some strangeness as it duplicates the textbox, best leave off for now. + hint: false, + highlight: true, + cacheKey: new Date(), // Force a cache refresh each time the control is initialized + minLength: 1 + }; + + typeahead = $element.find('.tags-' + vm.htmlId).typeahead(opts, sources) + .bind("typeahead:selected", function (obj, datum, name) { angularHelper.safeApply($rootScope, function () { addTagInternal(datum["value"]); vm.tagToAdd = ""; // clear the typed text typeahead.typeahead('val', ''); }); - }).bind("typeahead:autocompleted", function (obj, datum, name) { angularHelper.safeApply($rootScope, function () { addTagInternal(datum["value"]); @@ -114,7 +115,7 @@ }); }).bind("typeahead:opened", function (obj) { - //console.log("opened "); + console.log("opened "); }); }); @@ -167,6 +168,9 @@ updateModelValue(vm.viewModel); } } + else if (angular.isArray(vm.value)) { + vm.viewModel = vm.value; + } } } @@ -199,17 +203,6 @@ } } - function addTagOnEnter(e) { - var code = e.keyCode || e.which; - if (code == 13) { //Enter keycode - if ($element.find('.tags-' + vm.htmlId).parent().find(".tt-dropdown-menu .tt-cursor").length === 0) { - //this is required, otherwise the html form will attempt to submit. - e.preventDefault(); - addTag(); - } - } - } - function addTag() { //ensure that we're not pressing the enter key whilst selecting a typeahead value from the drop down //we need to use jquery because typeahead duplicates the text box diff --git a/src/Umbraco.Web.UI.Client/src/less/typeahead.less b/src/Umbraco.Web.UI.Client/src/less/typeahead.less index da32a85f86..0426c2966a 100644 --- a/src/Umbraco.Web.UI.Client/src/less/typeahead.less +++ b/src/Umbraco.Web.UI.Client/src/less/typeahead.less @@ -33,7 +33,7 @@ color: @gray-8 !important; } -.tt-dropdown-menu { +.tt-menu { width: 422px; margin-top: 12px; padding: 8px 0; @@ -61,4 +61,4 @@ .tt-suggestion p { margin: 0; -} \ No newline at end of file +} diff --git a/src/Umbraco.Web.UI.Client/src/views/components/tags/umb-tags-editor.html b/src/Umbraco.Web.UI.Client/src/views/components/tags/umb-tags-editor.html index 4f83e05c17..4921bee386 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/tags/umb-tags-editor.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/tags/umb-tags-editor.html @@ -24,7 +24,6 @@ id="{{vm.htmlId}}" class="typeahead tags-{{vm.htmlId}}" ng-model="vm.tagToAdd" - ng-keydown="vm.addTagOnEnter($event)" on-blur="vm.addTag()" localize="placeholder" placeholder="@placeholders_enterTags" /> From 86b0ab7dab3e25bae6a2243a37e81969c32485f2 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 10 Dec 2018 17:32:10 +1100 Subject: [PATCH 18/54] Fixes the typeahead (mostly) --- .../components/tags/umbtagseditor.directive.js | 11 +++++++++++ .../src/views/components/tags/umb-tags-editor.html | 1 + 2 files changed, 12 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js index fbc237e3d3..8bad5ae8fd 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js @@ -34,6 +34,7 @@ vm.$onDestroy = onDestroy; vm.validateMandatory = validateMandatory; + vm.addTagOnEnter = addTagOnEnter; vm.addTag = addTag; vm.removeTag = removeTag; vm.showPrompt = showPrompt; @@ -203,6 +204,16 @@ } } + function addTagOnEnter(e) { + var code = e.keyCode || e.which; + if (code == 13) { //Enter keycode + if ($element.find('.tags-' + vm.htmlId).parent().find(".tt-menu .tt-cursor").length === 0) { + //this is required, otherwise the html form will attempt to submit. + e.preventDefault(); + addTag(); + } + } + } function addTag() { //ensure that we're not pressing the enter key whilst selecting a typeahead value from the drop down //we need to use jquery because typeahead duplicates the text box diff --git a/src/Umbraco.Web.UI.Client/src/views/components/tags/umb-tags-editor.html b/src/Umbraco.Web.UI.Client/src/views/components/tags/umb-tags-editor.html index 4921bee386..4f83e05c17 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/tags/umb-tags-editor.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/tags/umb-tags-editor.html @@ -24,6 +24,7 @@ id="{{vm.htmlId}}" class="typeahead tags-{{vm.htmlId}}" ng-model="vm.tagToAdd" + ng-keydown="vm.addTagOnEnter($event)" on-blur="vm.addTag()" localize="placeholder" placeholder="@placeholders_enterTags" /> From 35f4bba119dbf58142fb756b5c10069966f2799f Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 11 Dec 2018 10:00:55 +0100 Subject: [PATCH 19/54] fix UrlProvider for invariant under variant --- src/Umbraco.Web/Routing/UrlProvider.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Umbraco.Web/Routing/UrlProvider.cs b/src/Umbraco.Web/Routing/UrlProvider.cs index 36c3ba5533..b265d48923 100644 --- a/src/Umbraco.Web/Routing/UrlProvider.cs +++ b/src/Umbraco.Web/Routing/UrlProvider.cs @@ -96,7 +96,7 @@ namespace Umbraco.Web.Routing /// public string GetUrl(IPublishedContent content, bool absolute, string culture = null, Uri current = null) => GetUrl(content, GetMode(absolute), culture, current); - + /// /// Gets the url of a published content. /// @@ -196,10 +196,6 @@ namespace Umbraco.Web.Routing if (culture == null) culture = _variationContextAccessor?.VariationContext?.Culture ?? ""; } - else - { - culture = null; - } if (current == null) current = _umbracoContext.CleanedUmbracoUrl; From 27f9490837e3a457cb763adc06054f65bb6772d0 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 11 Dec 2018 10:14:18 +0100 Subject: [PATCH 20/54] fix docs build --- .../src/common/resources/relationtype.resource.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/relationtype.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/relationtype.resource.js index f17aae0a6b..7f13a46d2f 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/relationtype.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/relationtype.resource.js @@ -35,7 +35,7 @@ function relationTypeResource($q, $http, umbRequestHelper, umbDataFormatter) { /** * @ngdoc method * @name umbraco.resources.relationTypeResource#getRelationObjectTypes - * @methodof umbraco.resources.relationTypeResource + * @methodOf umbraco.resources.relationTypeResource * * @description * Gets a list of Umbraco object types which can be associated with a relation. @@ -54,7 +54,7 @@ function relationTypeResource($q, $http, umbRequestHelper, umbDataFormatter) { /** * @ngdoc method * @name umbraco.resources.relationTypeResource#save - * @methodof umbraco.resources.relationTypeResource + * @methodOf umbraco.resources.relationTypeResource * * @description * Updates a relation type. @@ -74,7 +74,7 @@ function relationTypeResource($q, $http, umbRequestHelper, umbDataFormatter) { /** * @ngdoc method * @name umbraco.resources.relationTypeResource#create - * @methodof umbraco.resources.relationTypeResource + * @methodOf umbraco.resources.relationTypeResource * * @description * Creates a new relation type. @@ -94,7 +94,7 @@ function relationTypeResource($q, $http, umbRequestHelper, umbDataFormatter) { /** * @ngdoc method * @name umbraco.resources.relationTypeResource#deleteById - * @methodof umbraco.resources.relationTypeResource + * @methodOf umbraco.resources.relationTypeResource * * @description * Deletes a relation type with a given ID. From 0ae9d30373a06fbe030c41493cc00b90d3f48bfd Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 11 Dec 2018 09:43:47 +0000 Subject: [PATCH 21/54] Revert recent change to Forms dashboard back into XML config - now that we have a way to modify from Umbraco Forms component --- .../App_Plugins/UmbracoForms/package.manifest | 10 ---------- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 1 - src/Umbraco.Web.UI/config/Dashboard.config | 11 +++++++++++ 3 files changed, 11 insertions(+), 11 deletions(-) delete mode 100644 src/Umbraco.Web.UI/App_Plugins/UmbracoForms/package.manifest diff --git a/src/Umbraco.Web.UI/App_Plugins/UmbracoForms/package.manifest b/src/Umbraco.Web.UI/App_Plugins/UmbracoForms/package.manifest deleted file mode 100644 index c7ed4a957a..0000000000 --- a/src/Umbraco.Web.UI/App_Plugins/UmbracoForms/package.manifest +++ /dev/null @@ -1,10 +0,0 @@ -{ - "dashboards": [ - { - "name": "Install Umbraco Forms", - "alias": "installUmbracoForms", - "view": "views/dashboard/forms/formsdashboardintro.html", - "sections": [ "forms" ] - } - ] -} diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 130015ad53..5751e9155c 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -231,7 +231,6 @@ - 404handlers.config diff --git a/src/Umbraco.Web.UI/config/Dashboard.config b/src/Umbraco.Web.UI/config/Dashboard.config index 785fb61681..fec6ab34ae 100644 --- a/src/Umbraco.Web.UI/config/Dashboard.config +++ b/src/Umbraco.Web.UI/config/Dashboard.config @@ -22,6 +22,17 @@ +
+ + forms + + + + views/dashboard/forms/formsdashboardintro.html + + +
+
media From d06ccebf7c7d7c9c2987dbb2d86e97e877ee059a Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 11 Dec 2018 13:03:18 +0100 Subject: [PATCH 22/54] update docs for infinite editing --- .../overlays/umboverlay.directive.js | 216 ------------------ .../src/common/services/editor.service.js | 159 ++++++++++++- 2 files changed, 155 insertions(+), 220 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/overlays/umboverlay.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/overlays/umboverlay.directive.js index 9f9f1aa21e..99b89bf8cf 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/overlays/umboverlay.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/overlays/umboverlay.directive.js @@ -124,58 +124,6 @@ - -

Content Picker

-Opens a content picker.
-view: contentpicker - - - - - - - - - - - - - -
ParamTypeDetails
model.multiPickerBooleanPick one or multiple items
- - - - - - - - - - - - - -
ReturnsTypeDetails
model.selectionArrayArray of content objects
- - -

Icon Picker

-Opens an icon picker.
-view: iconpicker - - - - - - - - - - - - - -
ReturnsTypeDetails
model.iconStringThe icon class
-

Item Picker

Opens an item picker.
view: itempicker @@ -220,170 +168,6 @@ Opens an item picker.
-

Macro Picker

-Opens a media picker.
-view: macropicker - - - - - - - - - - - - - - - -
ParamTypeDetails
model.dialogDataObjectObject which contains array of allowedMacros. Set to null to allow all.
- - - - - - - - - - - - - - - - - - - - -
ReturnsTypeDetails
model.macroParamsArrayArray of macro params
model.selectedMacroObjectThe selected macro
- -

Media Picker

-Opens a media picker.
-view: mediapicker - - - - - - - - - - - - - - - - - - - - - - - - - -
ParamTypeDetails
model.multiPickerBooleanPick one or multiple items
model.onlyImagesBooleanOnly display files that have an image file-extension
model.disableFolderSelectBooleanDisable folder selection
- - - - - - - - - - - - - - - -
ReturnsTypeDetails
model.selectedImagesArrayArray of selected images
- -

Member Group Picker

-Opens a member group picker.
-view: membergrouppicker - - - - - - - - - - - - - - - -
ParamTypeDetails
model.multiPickerBooleanPick one or multiple items
- - - - - - - - - - - - - - - - - - - - -
ReturnsTypeDetails
model.selectedMemberGroupStringThe selected member group
model.selectedMemberGroups (multiPicker)ArrayThe selected member groups
- -

Member Picker

-Opens a member picker.
-view: memberpicker - - - - - - - - - - - - - - - -
ParamTypeDetails
model.multiPickerBooleanPick one or multiple items
- - - - - - - - - - - - - - -
ReturnsTypeDetails
model.selectionArrayArray of selected members/td> -
-

YSOD

Opens an overlay to show a custom YSOD.
view: ysod 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 650a210784..0dbd27b7a5 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 @@ -4,6 +4,76 @@ * * @description * Added in Umbraco 8.0. Application-wide service for handling infinite editing. + * + * +

Markup example

+
+    
+ + + +
+
+ +

Controller example

+
+    (function () {
+
+        "use strict";
+
+        function Controller() {
+
+            var vm = this;
+
+            vm.open = open;
+
+            function open() {
+                var mediaPickerOptions = {
+                    multiPicker: true,
+                    submit: function(model) {
+                        editorService.close();
+                    },
+                    close: function() {
+                        editorService.close();
+                    }
+                }
+                editorService.mediaPicker(mediaPickerOptions);
+            };
+        }
+
+        angular.module("umbraco").controller("My.Controller", Controller);
+    })();
+
+ +

Custom view example

+
+    (function () {
+
+        "use strict";
+
+        function Controller() {
+
+            var vm = this;
+
+            vm.open = open;
+
+            function open() {
+                var options = {
+                    view: "path/to/view.html"
+                    submit: function(model) {
+                        editorService.close();
+                    },
+                    close: function() {
+                        editorService.close();
+                    }
+                }
+                editorService.open(options);
+            };
+        }
+
+        angular.module("umbraco").controller("My.Controller", Controller);
+    })();
+
*/ (function () { "use strict"; @@ -43,6 +113,10 @@ * * @description * Method to open a new editor in infinite editing + * + * @param {Object} editor rendering options + * @param {String} editor.view Path to view + * @param {String} editor.size Sets the size of the editor ("Small"). If nothing is set it will use full width. */ function open(editor) { @@ -108,8 +182,12 @@ * * @description * Opens a media editor in infinite editing, the submit callback returns the updated content item + * @param {Object} editor rendering options * @param {String} editor.id The id of the content item * @param {Boolean} editor.create Create new content item + * @param {Function} editor.submit Callback function when the publish and close button is clicked. Returns the editor model object + * @param {Function} editor.close Callback function when the close button is clicked. + * * @returns {Object} editor object */ function contentEditor(editor) { @@ -124,6 +202,12 @@ * * @description * Opens a content picker in infinite editing, the submit callback returns an array of selected items + * + * @param {Object} editor rendering options + * @param {Boolean} editor.multiPicker Pick one or multiple items + * @param {Function} editor.submit Callback function when the submit button is clicked. Returns the editor model object + * @param {Function} editor.close Callback function when the close button is clicked. + * * @returns {Object} editor object */ function contentPicker(editor) { @@ -218,11 +302,13 @@ * * @description * Opens an embed editor in infinite editing. + * @param {Object} editor rendering options + * @param {String} editor.icon The icon class + * @param {String} editor.color The color class * @param {Callback} editor.submit Saves, submits, and closes the editor * @param {Callback} editor.close Closes the editor * @returns {Object} editor object */ - function linkPicker(editor) { editor.view = "views/common/infiniteeditors/linkpicker/linkpicker.html"; editor.size = "small"; @@ -236,6 +322,7 @@ * * @description * Opens a media editor in infinite editing, the submit callback returns the updated media item + * @param {Object} editor rendering options * @param {String} editor.id The id of the media item * @param {Boolean} editor.create Create new media item * @param {Callback} editor.submit Saves, submits, and closes the editor @@ -254,6 +341,7 @@ * * @description * Opens a media picker in infinite editing, the submit callback returns an array of selected media items + * @param {Object} editor rendering options * @param {Boolean} editor.multiPicker Pick one or multiple items * @param {Boolean} editor.onlyImages Only display files that have an image file-extension * @param {Boolean} editor.disableFolderSelect Disable folder selection @@ -276,6 +364,7 @@ * * @description * Opens an icon picker in infinite editing, the submit callback returns the selected icon + * @param {Object} editor rendering options * @param {Callback} editor.submit Submits the editor * @param {Callback} editor.close Closes the editor * @returns {Object} editor object @@ -293,6 +382,7 @@ * * @description * Opens the document type editor in infinite editing, the submit callback returns the saved document type + * @param {Object} editor rendering options * @param {Callback} editor.submit Submits the editor * @param {Callback} editor.close Closes the editor * @returns {Object} editor object @@ -309,6 +399,7 @@ * * @description * Opens the media type editor in infinite editing, the submit callback returns the saved media type + * @param {Object} editor rendering options * @param {Callback} editor.submit Submits the editor * @param {Callback} editor.close Closes the editor * @returns {Object} editor object @@ -318,24 +409,75 @@ open(editor); } + /** + * @ngdoc method + * @name umbraco.services.editorService#queryBuilder + * @methodOf umbraco.services.editorService + * + * @description + * Opens the query builder in infinite editing, the submit callback returns the generted query + * @param {Object} editor rendering options + * @param {Callback} editor.submit Submits the editor + * @param {Callback} editor.close Closes the editor + * @returns {Object} editor object + */ function queryBuilder(editor) { editor.view = "views/common/infiniteeditors/querybuilder/querybuilder.html"; editor.size = "small"; open(editor); } + /** + * @ngdoc method + * @name umbraco.services.editorService#treePicker + * @methodOf umbraco.services.editorService + * + * @description + * Opens the query builder in infinite editing, the submit callback returns the generted query + * @param {Object} editor rendering options + * @param {String} options.section tree section to display + * @param {String} options.treeAlias specific tree to display + * @param {Boolean} options.multiPicker should the tree pick one or multiple items before returning + * @param {Callback} editor.submit Submits the editor + * @param {Callback} editor.close Closes the editor + * @returns {Object} editor object + */ function treePicker(editor) { editor.view = "views/common/infiniteeditors/treepicker/treepicker.html"; editor.size = "small"; open(editor); } + /** + * @ngdoc method + * @name umbraco.services.editorService#nodePermissions + * @methodOf umbraco.services.editorService + * + * @description + * Opens the an editor to set node permissions. + * @param {Object} editor rendering options + * @param {Callback} editor.submit Submits the editor + * @param {Callback} editor.close Closes the editor + * @returns {Object} editor object + */ function nodePermissions(editor) { editor.view = "views/common/infiniteeditors/nodepermissions/nodepermissions.html"; editor.size = "small"; open(editor); } + /** + * @ngdoc method + * @name umbraco.services.editorService#insertCodeSnippet + * @methodOf umbraco.services.editorService + * + * @description + * Open an editor to insert code snippets into the code editor + * @param {Object} editor rendering options + * @param {Callback} editor.submit Submits the editor + * @param {Callback} editor.close Closes the editor + * @returns {Object} editor object + */ function insertCodeSnippet(editor) { editor.view = "views/common/infiniteeditors/insertcodesnippet/insertcodesnippet.html"; editor.size = "small"; @@ -349,6 +491,7 @@ * * @description * Opens the user group picker in infinite editing, the submit callback returns an array of the selected user groups + * @param {Object} editor rendering options * @param {Callback} editor.submit Submits the editor * @param {Callback} editor.close Closes the editor * @returns {Object} editor object @@ -366,6 +509,7 @@ * * @description * Opens the user group picker in infinite editing, the submit callback returns the saved template + * @param {Object} editor rendering options * @param {String} editor.id The template id * @param {Callback} editor.submit Submits the editor * @param {Callback} editor.close Closes the editor @@ -382,7 +526,8 @@ * @methodOf umbraco.services.editorService * * @description - * Opens the section picker in infinite editing, the submit callback returns an array of the selected sections + * Opens the section picker in infinite editing, the submit callback returns an array of the selected sections¨ + * @param {Object} editor rendering options * @param {Callback} editor.submit Submits the editor * @param {Callback} editor.close Closes the editor * @returns {Object} editor object @@ -400,6 +545,7 @@ * * @description * Opens the insert field editor in infinite editing, the submit callback returns the code snippet + * @param {Object} editor rendering options * @param {Callback} editor.submit Submits the editor * @param {Callback} editor.close Closes the editor * @returns {Object} editor object @@ -417,6 +563,7 @@ * * @description * Opens the template sections editor in infinite editing, the submit callback returns the type to insert + * @param {Object} editor rendering options * @param {Callback} editor.submit Submits the editor * @param {Callback} editor.close Closes the editor * @returns {Object} editor object @@ -429,11 +576,12 @@ /** * @ngdoc method - * @name umbraco.services.editorService#sectionPicker + * @name umbraco.services.editorService#userPicker * @methodOf umbraco.services.editorService * * @description * Opens the section picker in infinite editing, the submit callback returns an array of the selected users + * @param {Object} editor rendering options * @param {Callback} editor.submit Submits the editor * @param {Callback} editor.close Closes the editor * @returns {Object} editor object @@ -452,6 +600,7 @@ * @description * Opens the section picker in infinite editing, the submit callback returns an array of the selected items * + * @param {Object} editor rendering options * @param {Array} editor.availableItems Array of available items. * @param {Array} editor.selectedItems Array of selected items. When passed in the selected items will be filtered from the available items. * @param {Boolean} editor.filter Set to false to hide the filter. @@ -485,12 +634,14 @@ /** * @ngdoc method - * @name umbraco.services.editorService#macroPicker + * @name umbraco.services.editorService#memberGroupPicker * @methodOf umbraco.services.editorService * * @description * Opens a member group picker in infinite editing. * + * @param {Object} editor rendering options + * @param {Object} editor.multiPicker Pick one or multiple items. * @param {Callback} editor.submit Submits the editor. * @param {Callback} editor.close Closes the editor. * @returns {Object} editor object From b19f9c81140991549118b7b7b5ee071c423e222f Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 11 Dec 2018 13:39:12 +0100 Subject: [PATCH 23/54] update styling on forms install dashboard --- src/Umbraco.Web.UI.Client/src/less/dashboards.less | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/dashboards.less b/src/Umbraco.Web.UI.Client/src/less/dashboards.less index 5fd0e25be1..cc13ad31fd 100644 --- a/src/Umbraco.Web.UI.Client/src/less/dashboards.less +++ b/src/Umbraco.Web.UI.Client/src/less/dashboards.less @@ -1,13 +1,14 @@ .umb-dashboards-forms-install { background: url('../img/forms/installer-background.png'); background-repeat: repeat-x; - position: relative; - top: -30px; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; padding-top: 30px; - box-shadow: inset 0px -40px 30px 25px rgba(255,255,255,1); - -moz-border-radius: 0px 0px 200px 200px; - -webkit-border-radius: 0px 0px 200px 200px; - border-radius: 0px 0px 200px 200px; + background-color: @white; + overflow: auto; small { font-size: 14px; From 0dff7680fd695088984cb93c8affcc20c7bdeffe Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 11 Dec 2018 14:02:54 +0100 Subject: [PATCH 24/54] Fix ContentTypeServiceTests (but, why???) --- .../Services/ContentTypeServiceTests.cs | 71 +++++++++++-------- 1 file changed, 43 insertions(+), 28 deletions(-) diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs index bc0854bdb7..8ea4856861 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs @@ -148,7 +148,7 @@ namespace Umbraco.Tests.Services //change the content type to be invariant, we will also update the name here to detect the copy changes doc.SetCultureName("Hello2", "en-US"); ServiceContext.ContentService.Save(doc); - contentType.Variations = ContentVariation.Nothing; + contentType.Variations = ContentVariation.Nothing; ServiceContext.ContentTypeService.Save(contentType); doc = ServiceContext.ContentService.GetById(doc.Id); //re-get @@ -372,7 +372,7 @@ namespace Umbraco.Tests.Services doc2 = ServiceContext.ContentService.GetById(doc2.Id); //re-get //this will be null because the doc type was changed back to variant but it's property types don't get changed back - Assert.IsNull(doc.GetValue("title", "en-US")); + Assert.IsNull(doc.GetValue("title", "en-US")); Assert.IsNull(doc2.GetValue("title", "en-US")); } @@ -1714,50 +1714,65 @@ namespace Umbraco.Tests.Services // Arrange var service = ServiceContext.ContentTypeService; + // create 'page' content type with a 'Content_' group var page = MockedContentTypes.CreateSimpleContentType("page", "Page", null, false, "Content_"); + Assert.IsTrue(page.PropertyGroups.Contains("Content_")); + Assert.AreEqual(3, page.PropertyTypes.Count()); service.Save(page); + + // create 'contentPage' content type as a child of 'page' var contentPage = MockedContentTypes.CreateSimpleContentType("contentPage", "Content Page", page, true); - service.Save(contentPage); - var composition = MockedContentTypes.CreateMetaContentType(); - composition.AddPropertyGroup("Content"); - service.Save(composition); - //Adding Meta-composition to child doc type - contentPage.AddContentType(composition); + Assert.AreEqual(3, contentPage.PropertyTypes.Count()); service.Save(contentPage); - // Act - var propertyTypeOne = new PropertyType(Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "testTextbox") + // add 'Content' group to 'meta' content type + var meta = MockedContentTypes.CreateMetaContentType(); + meta.AddPropertyGroup("Content"); + Assert.AreEqual(2, meta.PropertyTypes.Count()); + service.Save(meta); + + // add 'meta' content type to 'contentPage' composition + contentPage.AddContentType(meta); + service.Save(contentPage); + + // add property 'prop1' to 'contentPage' group 'Content_' + var prop1 = new PropertyType(Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "testTextbox") { Name = "Test Textbox", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }; - var firstOneAdded = contentPage.AddPropertyType(propertyTypeOne, "Content_"); - var propertyTypeTwo = new PropertyType(Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "anotherTextbox") + var prop1Added = contentPage.AddPropertyType(prop1, "Content_"); + Assert.IsTrue(prop1Added); + + // add property 'prop2' to 'contentPage' group 'Content' + var prop2 = new PropertyType(Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "anotherTextbox") { Name = "Another Test Textbox", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }; - var secondOneAdded = contentPage.AddPropertyType(propertyTypeTwo, "Content"); + var prop2Added = contentPage.AddPropertyType(prop2, "Content"); + Assert.IsTrue(prop2Added); + + // save 'contentPage' content type service.Save(contentPage); - Assert.That(page.PropertyGroups.Contains("Content_"), Is.True); - var propertyGroup = page.PropertyGroups["Content_"]; - page.PropertyGroups.Add(new PropertyGroup(true) { Id = propertyGroup.Id, Name = "ContentTab", SortOrder = 0}); + var group = page.PropertyGroups["Content_"]; + group.Name = "ContentTab"; // rename the group service.Save(page); + Assert.AreEqual(3, page.PropertyTypes.Count()); - // Assert - Assert.That(firstOneAdded, Is.True); - Assert.That(secondOneAdded, Is.True); + // get 'contentPage' content type again + var contentPageAgain = service.Get("contentPage"); + Assert.IsNotNull(contentPageAgain); - var contentType = service.Get("contentPage"); - Assert.That(contentType, Is.Not.Null); + // assert that 'Content_' group is still there because we don't propagate renames + var findGroup = contentPageAgain.CompositionPropertyGroups.FirstOrDefault(x => x.Name == "Content_"); + Assert.IsNotNull(findGroup); - var compositionPropertyGroups = contentType.CompositionPropertyGroups; - - // now it is still 1, because we don't propagate renames anymore - Assert.That(compositionPropertyGroups.Count(x => x.Name.Equals("Content_")), Is.EqualTo(1)); - - var propertyTypeCount = contentType.PropertyTypes.Count(); - var compPropertyTypeCount = contentType.CompositionPropertyTypes.Count(); + // count all property types (local and composed) + var propertyTypeCount = contentPageAgain.PropertyTypes.Count(); Assert.That(propertyTypeCount, Is.EqualTo(5)); + + // count composed property types + var compPropertyTypeCount = contentPageAgain.CompositionPropertyTypes.Count(); Assert.That(compPropertyTypeCount, Is.EqualTo(10)); } From b0157d7116603c6ab6211ce329c4c70021309e1c Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 11 Dec 2018 14:08:44 +0000 Subject: [PATCH 25/54] We do not need to ship with these Umbraco Forms trees in the config file --- src/Umbraco.Web.UI/config/trees.config | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI/config/trees.config b/src/Umbraco.Web.UI/config/trees.config index 2b99f8751f..7f7aeca8a7 100644 --- a/src/Umbraco.Web.UI/config/trees.config +++ b/src/Umbraco.Web.UI/config/trees.config @@ -30,9 +30,5 @@ - - - - - + From 767cd93f08b83acc175aa2311ff29936260147ee Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 11 Dec 2018 14:09:44 +0000 Subject: [PATCH 26/54] Adds in some logic if we have no child trees for that application/section then we create a SingleTreeRoot --- .../Trees/ApplicationTreeController.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web/Trees/ApplicationTreeController.cs b/src/Umbraco.Web/Trees/ApplicationTreeController.cs index c1192b6909..d824f32f4b 100644 --- a/src/Umbraco.Web/Trees/ApplicationTreeController.cs +++ b/src/Umbraco.Web/Trees/ApplicationTreeController.cs @@ -78,10 +78,20 @@ namespace Umbraco.Web.Trees } } - var multiTree = TreeRootNode.CreateMultiTreeRoot(collection); - multiTree.Name = Services.TextService.Localize("sections/" + application); + if(collection.Count > 0) + { + var multiTree = TreeRootNode.CreateMultiTreeRoot(collection); + multiTree.Name = Services.TextService.Localize("sections/" + application); - return multiTree; + return multiTree; + } + + //Otherwise its a application/section with no trees (aka a full screen app) + //For example we do not have a Forms tree definied in C# & can not attribute with [Tree(isSingleNodeTree:true0] + var rootId = Constants.System.Root.ToString(CultureInfo.InvariantCulture); + var section = Services.TextService.Localize("sections/" + application); + + return TreeRootNode.CreateSingleTreeRoot(rootId, null, null, section, TreeNodeCollection.Empty, true); } var rootNodeGroups = new List(); From e1743ae3ea2d8331b8f136d222c92f53c6d95f3f Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 12 Dec 2018 12:05:19 +1100 Subject: [PATCH 27/54] Changes IValueSetBuilder to not be strongly typed, no need for that --- src/Umbraco.Examine/IValueSetBuilder.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Examine/IValueSetBuilder.cs b/src/Umbraco.Examine/IValueSetBuilder.cs index 89aa907926..1c4890f404 100644 --- a/src/Umbraco.Examine/IValueSetBuilder.cs +++ b/src/Umbraco.Examine/IValueSetBuilder.cs @@ -5,18 +5,17 @@ using Umbraco.Core.Models; namespace Umbraco.Examine { /// - /// Creates a collection of to be indexed based on a collection of + /// Creates a collection of to be indexed based on a collection of /// - /// - public interface IValueSetBuilder - where TContent : IContentBase + /// + public interface IValueSetBuilder { /// - /// Creates a collection of to be indexed based on a collection of + /// Creates a collection of to be indexed based on a collection of /// /// /// - IEnumerable GetValueSets(params TContent[] content); + IEnumerable GetValueSets(params T[] content); } } From 15c7d7ce77b7c9c3e81340ec926b7fbc9da718c1 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 12 Dec 2018 12:37:21 +1100 Subject: [PATCH 28/54] Creates a sub-generic interface for creating indexes --- src/Umbraco.Examine/IIndexCreator.cs | 13 +++++++++++++ src/Umbraco.Examine/IIndexDiagnostics.cs | 3 --- src/Umbraco.Examine/Umbraco.Examine.csproj | 1 + src/Umbraco.Web/Search/IUmbracoIndexesCreator.cs | 5 +++-- 4 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 src/Umbraco.Examine/IIndexCreator.cs diff --git a/src/Umbraco.Examine/IIndexCreator.cs b/src/Umbraco.Examine/IIndexCreator.cs new file mode 100644 index 0000000000..3b8f683990 --- /dev/null +++ b/src/Umbraco.Examine/IIndexCreator.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Examine; + +namespace Umbraco.Examine +{ + /// + /// Creates 's + /// + public interface IIndexCreator + { + IEnumerable Create(); + } +} diff --git a/src/Umbraco.Examine/IIndexDiagnostics.cs b/src/Umbraco.Examine/IIndexDiagnostics.cs index 04ca4a6ab9..29d530c2d0 100644 --- a/src/Umbraco.Examine/IIndexDiagnostics.cs +++ b/src/Umbraco.Examine/IIndexDiagnostics.cs @@ -1,12 +1,9 @@ using System; using System.Collections.Generic; -using Examine; using Umbraco.Core; namespace Umbraco.Examine { - - /// /// Exposes diagnostic information about an index /// diff --git a/src/Umbraco.Examine/Umbraco.Examine.csproj b/src/Umbraco.Examine/Umbraco.Examine.csproj index 0aedf6e754..aa57707b2e 100644 --- a/src/Umbraco.Examine/Umbraco.Examine.csproj +++ b/src/Umbraco.Examine/Umbraco.Examine.csproj @@ -66,6 +66,7 @@ + diff --git a/src/Umbraco.Web/Search/IUmbracoIndexesCreator.cs b/src/Umbraco.Web/Search/IUmbracoIndexesCreator.cs index 58014597d2..d654e4effd 100644 --- a/src/Umbraco.Web/Search/IUmbracoIndexesCreator.cs +++ b/src/Umbraco.Web/Search/IUmbracoIndexesCreator.cs @@ -1,13 +1,14 @@ using System.Collections.Generic; using Examine; +using Umbraco.Examine; namespace Umbraco.Web.Search { + /// /// /// Used to create the Umbraco indexes /// - public interface IUmbracoIndexesCreator + public interface IUmbracoIndexesCreator : IIndexCreator { - IEnumerable Create(); } } From 7cb83373cae5c9961c7d88de8da5afc1fc385881 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 12 Dec 2018 12:46:58 +1100 Subject: [PATCH 29/54] Creates base class LuceneIndexCreator --- src/Umbraco.Examine/LuceneIndexCreator.cs | 39 +++++++++++++++++++ src/Umbraco.Examine/Umbraco.Examine.csproj | 1 + .../Search/UmbracoIndexesCreator.cs | 26 +++---------- 3 files changed, 46 insertions(+), 20 deletions(-) create mode 100644 src/Umbraco.Examine/LuceneIndexCreator.cs diff --git a/src/Umbraco.Examine/LuceneIndexCreator.cs b/src/Umbraco.Examine/LuceneIndexCreator.cs new file mode 100644 index 0000000000..c1fe7ae772 --- /dev/null +++ b/src/Umbraco.Examine/LuceneIndexCreator.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using System.IO; +using Examine; +using Lucene.Net.Store; +using Umbraco.Core.IO; + +namespace Umbraco.Examine +{ + /// + /// + /// Abstract class for creating Lucene based Indexes + /// + public abstract class LuceneIndexCreator : IIndexCreator + { + public abstract IEnumerable Create(); + + /// + /// Creates a file system based Lucene with the correct locking guidelines for Umbraco + /// + /// + /// + public virtual Lucene.Net.Store.Directory CreateFileSystemLuceneDirectory(string name) + { + //TODO: We should have a single AppSetting to be able to specify a default DirectoryFactory so we can have a single + //setting to configure all indexes that use this to easily swap the directory to Sync/%temp%/blog, etc... + + var dirInfo = new DirectoryInfo(Path.Combine(IOHelper.MapPath(SystemDirectories.Data), "TEMP", "ExamineIndexes", name)); + if (!dirInfo.Exists) + System.IO.Directory.CreateDirectory(dirInfo.FullName); + + var luceneDir = new SimpleFSDirectory(dirInfo); + //we want to tell examine to use a different fs lock instead of the default NativeFSFileLock which could cause problems if the appdomain + //terminates and in some rare cases would only allow unlocking of the file if IIS is forcefully terminated. Instead we'll rely on the simplefslock + //which simply checks the existence of the lock file + luceneDir.SetLockFactory(new NoPrefixSimpleFsLockFactory(dirInfo)); + return luceneDir; + } + } +} diff --git a/src/Umbraco.Examine/Umbraco.Examine.csproj b/src/Umbraco.Examine/Umbraco.Examine.csproj index aa57707b2e..66b1f09068 100644 --- a/src/Umbraco.Examine/Umbraco.Examine.csproj +++ b/src/Umbraco.Examine/Umbraco.Examine.csproj @@ -89,6 +89,7 @@ + Properties\SolutionInfo.cs diff --git a/src/Umbraco.Web/Search/UmbracoIndexesCreator.cs b/src/Umbraco.Web/Search/UmbracoIndexesCreator.cs index f8b2c6ef8b..3723dedc48 100644 --- a/src/Umbraco.Web/Search/UmbracoIndexesCreator.cs +++ b/src/Umbraco.Web/Search/UmbracoIndexesCreator.cs @@ -21,7 +21,7 @@ namespace Umbraco.Web.Search /// /// Creates the indexes used by Umbraco /// - public class UmbracoIndexesCreator : IUmbracoIndexesCreator + public class UmbracoIndexesCreator : LuceneIndexCreator, IUmbracoIndexesCreator { //TODO: we should inject the different IValueSetValidator so devs can just register them instead of overriding this class? @@ -45,7 +45,7 @@ namespace Umbraco.Web.Search /// Creates the Umbraco indexes ///
/// - public IEnumerable Create() + public override IEnumerable Create() { return new [] { @@ -61,7 +61,7 @@ namespace Umbraco.Web.Search Constants.UmbracoIndexes.InternalIndexName, //fixme - how to deal with languages like in UmbracoContentIndexer.CreateFieldValueTypes UmbracoExamineIndex.UmbracoIndexFieldDefinitions, - GetFileSystemLuceneDirectory(Constants.UmbracoIndexes.InternalIndexPath), + CreateFileSystemLuceneDirectory(Constants.UmbracoIndexes.InternalIndexPath), new CultureInvariantWhitespaceAnalyzer(), ProfilingLogger, LanguageService, @@ -75,7 +75,7 @@ namespace Umbraco.Web.Search Constants.UmbracoIndexes.ExternalIndexName, //fixme - how to deal with languages like in UmbracoContentIndexer.CreateFieldValueTypes UmbracoExamineIndex.UmbracoIndexFieldDefinitions, - GetFileSystemLuceneDirectory(Constants.UmbracoIndexes.ExternalIndexPath), + CreateFileSystemLuceneDirectory(Constants.UmbracoIndexes.ExternalIndexPath), new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30), ProfilingLogger, LanguageService, @@ -89,27 +89,13 @@ namespace Umbraco.Web.Search Constants.UmbracoIndexes.MembersIndexName, //fixme - how to deal with languages like in UmbracoContentIndexer.CreateFieldValueTypes UmbracoExamineIndex.UmbracoIndexFieldDefinitions, - GetFileSystemLuceneDirectory(Constants.UmbracoIndexes.MembersIndexPath), + CreateFileSystemLuceneDirectory(Constants.UmbracoIndexes.MembersIndexPath), new CultureInvariantWhitespaceAnalyzer(), ProfilingLogger, GetMemberValueSetValidator()); return index; } - - public virtual Lucene.Net.Store.Directory GetFileSystemLuceneDirectory(string name) - { - var dirInfo = new DirectoryInfo(Path.Combine(IOHelper.MapPath(SystemDirectories.Data), "TEMP", "ExamineIndexes", name)); - if (!dirInfo.Exists) - System.IO.Directory.CreateDirectory(dirInfo.FullName); - - var luceneDir = new SimpleFSDirectory(dirInfo); - //we want to tell examine to use a different fs lock instead of the default NativeFSFileLock which could cause problems if the appdomain - //terminates and in some rare cases would only allow unlocking of the file if IIS is forcefully terminated. Instead we'll rely on the simplefslock - //which simply checks the existence of the lock file - luceneDir.SetLockFactory(new NoPrefixSimpleFsLockFactory(dirInfo)); - return luceneDir; - } - + public virtual IContentValueSetValidator GetContentValueSetValidator() { return new ContentValueSetValidator(false, true, PublicAccessService); From b5da641d4823f96f3e8f18bbf8fcf54ad99e9548 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 12 Dec 2018 13:23:29 +1100 Subject: [PATCH 30/54] Uses the DefaultLockFactory to set the lock --- src/Umbraco.Examine/LuceneIndexCreator.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Examine/LuceneIndexCreator.cs b/src/Umbraco.Examine/LuceneIndexCreator.cs index c1fe7ae772..572de1e8a8 100644 --- a/src/Umbraco.Examine/LuceneIndexCreator.cs +++ b/src/Umbraco.Examine/LuceneIndexCreator.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.IO; using Examine; +using Examine.LuceneEngine.Directories; using Lucene.Net.Store; using Umbraco.Core.IO; @@ -29,10 +30,13 @@ namespace Umbraco.Examine System.IO.Directory.CreateDirectory(dirInfo.FullName); var luceneDir = new SimpleFSDirectory(dirInfo); + //we want to tell examine to use a different fs lock instead of the default NativeFSFileLock which could cause problems if the appdomain //terminates and in some rare cases would only allow unlocking of the file if IIS is forcefully terminated. Instead we'll rely on the simplefslock //which simply checks the existence of the lock file - luceneDir.SetLockFactory(new NoPrefixSimpleFsLockFactory(dirInfo)); + // The full syntax of this is: new NoPrefixSimpleFsLockFactory(dirInfo) + // however, we are setting the DefaultLockFactory in startup so we'll use that instead since it can be managed globally. + luceneDir.SetLockFactory(DirectoryFactory.DefaultLockFactory(dirInfo)); return luceneDir; } } From 85b25485da05f2fcc7e86b8e7b856f0756bfcd11 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 12 Dec 2018 13:34:54 +1100 Subject: [PATCH 31/54] removes trees from trees.Release.config --- src/Umbraco.Web.UI/config/trees.Release.config | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI/config/trees.Release.config b/src/Umbraco.Web.UI/config/trees.Release.config index 7b5a9e5e2a..bd75e97c38 100644 --- a/src/Umbraco.Web.UI/config/trees.Release.config +++ b/src/Umbraco.Web.UI/config/trees.Release.config @@ -30,9 +30,5 @@ - - - - - + From e3cd19fed5956411bf3901be325d1b965b638d45 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 12 Dec 2018 13:27:08 +0100 Subject: [PATCH 32/54] Fix tags (in)variant --- .../Implement/ContentTypeRepositoryBase.cs | 86 +++++++++++-------- 1 file changed, 50 insertions(+), 36 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index a7f8adf482..06fc25937b 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -772,26 +772,26 @@ AND umbracoNode.id <> @id", // delete existing relations (for target language) // do *not* delete existing tags - var sqlTagToDelete = Sql() + var sqlSelectTagsToDelete = Sql() .Select(x => x.Id) .From() .InnerJoin().On((tag, rel) => tag.Id == rel.TagId); if (contentTypeIds != null) - sqlTagToDelete + sqlSelectTagsToDelete .InnerJoin().On((rel, content) => rel.NodeId == content.NodeId) .WhereIn(x => x.ContentTypeId, contentTypeIds); - sqlTagToDelete + sqlSelectTagsToDelete .WhereIn(x => x.PropertyTypeId, propertyTypeIds) .Where(x => x.LanguageId.SqlNullableEquals(targetLanguageId, -1)); - var sqlDeleteRel = Sql() + var sqlDeleteRelations = Sql() .Delete() - .WhereIn(x => x.TagId, sqlTagToDelete); + .WhereIn(x => x.TagId, sqlSelectTagsToDelete); - sqlDeleteRel.WriteToConsole(); - Database.Execute(sqlDeleteRel); + sqlDeleteRelations.WriteToConsole(); + Database.Execute(sqlDeleteRelations); // do *not* delete the tags - they could be used by other content types / property types /* @@ -802,76 +802,90 @@ AND umbracoNode.id <> @id", */ // copy tags from source language to target language + // target tags may exist already, so we have to check for existence here + // + // select tags to insert: tags pointed to by a relation ship, for proper property/content types, + // and of source language, and where we cannot left join to an existing tag with same text, + // group and languageId var targetLanguageIdS = targetLanguageId.HasValue ? targetLanguageId.ToString() : "NULL"; - var sqlSelect = Sql() + var sqlSelectTagsToInsert = Sql() .Select(x => x.Text, x => x.Group) .Append(", " + targetLanguageIdS) .From(); - sqlSelect + sqlSelectTagsToInsert .InnerJoin().On((tag, rel) => tag.Id == rel.TagId) .LeftJoin("xtags").On((tag, xtag) => tag.Text == xtag.Text && tag.Group == xtag.Group && xtag.LanguageId.SqlNullableEquals(targetLanguageId, -1), aliasRight: "xtags"); if (contentTypeIds != null) - sqlSelect - .InnerJoin().On((rel, content) => rel.NodeId == content.NodeId); - - sqlSelect - .WhereIn(x => x.PropertyTypeId, propertyTypeIds) - .WhereNull(x => x.Id, "xtags"); // ie, not exists - - if (contentTypeIds != null) - sqlSelect + sqlSelectTagsToInsert + .InnerJoin().On((rel, content) => rel.NodeId == content.NodeId) .WhereIn(x => x.ContentTypeId, contentTypeIds); - sqlSelect.Where(x => x.LanguageId.SqlNullableEquals(sourceLanguageId, -1)); + sqlSelectTagsToInsert + .WhereIn(x => x.PropertyTypeId, propertyTypeIds) + .WhereNull(x => x.Id, "xtags") // ie, not exists + .Where(x => x.LanguageId.SqlNullableEquals(sourceLanguageId, -1)); var cols = Sql().Columns(x => x.Text, x => x.Group, x => x.LanguageId); - var sqlInsertTag = Sql($"INSERT INTO {TagDto.TableName} ({cols})").Append(sqlSelect); + var sqlInsertTags = Sql($"INSERT INTO {TagDto.TableName} ({cols})").Append(sqlSelectTagsToInsert); - sqlInsertTag.WriteToConsole(); - Database.Execute(sqlInsertTag); + sqlInsertTags.WriteToConsole(); + Database.Execute(sqlInsertTags); // create relations to new tags + // any existing relations have been deleted above, no need to check for existence here + // + // select node id and property type id from existing relations to tags of source language, + // for proper property/content types, and select new tag id from tags, with matching text, + // and group, but for the target language - var sqlFoo = Sql() + var sqlSelectRelationsToInsert = Sql() .Select(x => x.NodeId, x => x.PropertyTypeId) .AndSelect("otag", x => x.Id) .From() .InnerJoin().On((rel, tag) => rel.TagId == tag.Id) - .InnerJoin("otag").On((tag, otag) => tag.Text == otag.Text && tag.Group == otag.Group && otag.LanguageId.SqlNullableEquals(targetLanguageId, -1), aliasRight: "otag") - .Where(x => x.LanguageId.SqlNullableEquals(sourceLanguageId, -1)); + .InnerJoin("otag").On((tag, otag) => tag.Text == otag.Text && tag.Group == otag.Group && otag.LanguageId.SqlNullableEquals(targetLanguageId, -1), aliasRight: "otag"); - var cols2 = Sql().Columns(x => x.NodeId, x => x.PropertyTypeId, x => x.TagId); - var sqlInsertRel = Sql($"INSERT INTO {TagRelationshipDto.TableName} ({cols2})").Append(sqlFoo); + if (contentTypeIds != null) + sqlSelectRelationsToInsert + .InnerJoin().On((rel, content) => rel.NodeId == content.NodeId) + .WhereIn(x => x.ContentTypeId, contentTypeIds); - sqlInsertRel.WriteToConsole(); - Database.Execute(sqlInsertRel); + sqlSelectRelationsToInsert + .Where(x => x.LanguageId.SqlNullableEquals(sourceLanguageId, -1)) + .WhereIn(x => x.PropertyTypeId, propertyTypeIds); + + var relationColumnsToInsert = Sql().Columns(x => x.NodeId, x => x.PropertyTypeId, x => x.TagId); + var sqlInsertRelations = Sql($"INSERT INTO {TagRelationshipDto.TableName} ({relationColumnsToInsert})").Append(sqlSelectRelationsToInsert); + + sqlInsertRelations.WriteToConsole(); + Database.Execute(sqlInsertRelations); // delete original relations - *not* the tags - all of them // cannot really "go back" with relations, would have to do it with property values - sqlTagToDelete = Sql() + sqlSelectTagsToDelete = Sql() .Select(x => x.Id) .From() .InnerJoin().On((tag, rel) => tag.Id == rel.TagId); if (contentTypeIds != null) - sqlTagToDelete + sqlSelectTagsToDelete .InnerJoin().On((rel, content) => rel.NodeId == content.NodeId) .WhereIn(x => x.ContentTypeId, contentTypeIds); - sqlTagToDelete + sqlSelectTagsToDelete .WhereIn(x => x.PropertyTypeId, propertyTypeIds) .Where(x => !x.LanguageId.SqlNullableEquals(targetLanguageId, -1)); - sqlDeleteRel = Sql() + sqlDeleteRelations = Sql() .Delete() - .WhereIn(x => x.TagId, sqlTagToDelete); + .WhereIn(x => x.TagId, sqlSelectTagsToDelete); - sqlDeleteRel.WriteToConsole(); - Database.Execute(sqlDeleteRel); + sqlDeleteRelations.WriteToConsole(); + Database.Execute(sqlDeleteRelations); // no /* From d7e61515de573044224fe4b743e7e3edace593fc Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 17 Oct 2018 09:59:16 +0200 Subject: [PATCH 33/54] Refactor TypeLoader --- src/Umbraco.Core/Composing/TypeLoader.cs | 46 +++++++----------------- src/Umbraco.Core/Runtime/CoreRuntime.cs | 6 ++-- 2 files changed, 15 insertions(+), 37 deletions(-) diff --git a/src/Umbraco.Core/Composing/TypeLoader.cs b/src/Umbraco.Core/Composing/TypeLoader.cs index f79c288e91..78b9943976 100644 --- a/src/Umbraco.Core/Composing/TypeLoader.cs +++ b/src/Umbraco.Core/Composing/TypeLoader.cs @@ -42,6 +42,17 @@ namespace Umbraco.Core.Composing private static LocalTempStorage _localTempStorage = LocalTempStorage.Unknown; private static string _fileBasePath; + /// + /// Initializes a new instance of the class. + /// + /// The application runtime cache. + /// + /// A profiling logger. + /// Used by LightInject. + public TypeLoader(IRuntimeCacheProvider runtimeCache, IGlobalSettings globalSettings, ProfilingLogger logger) + : this(runtimeCache, globalSettings, logger, true) + { } + /// /// Initializes a new instance of the class. /// @@ -49,7 +60,7 @@ namespace Umbraco.Core.Composing /// /// A profiling logger. /// Whether to detect changes using hashes. - internal TypeLoader(IRuntimeCacheProvider runtimeCache, IGlobalSettings globalSettings, ProfilingLogger logger, bool detectChanges = true) + internal TypeLoader(IRuntimeCacheProvider runtimeCache, IGlobalSettings globalSettings, ProfilingLogger logger, bool detectChanges) { _runtimeCache = runtimeCache ?? throw new ArgumentNullException(nameof(runtimeCache)); _globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings)); @@ -401,39 +412,6 @@ namespace Umbraco.Core.Composing return _fileBasePath; } - //private string GetFilePath(string extension) - //{ - // string path; - // switch (_globalSettings.LocalTempStorageLocation) - // { - // case LocalTempStorage.AspNetTemp: - // path = Path.Combine(HttpRuntime.CodegenDir, "UmbracoData", "umbraco-types." + extension); - // break; - // case LocalTempStorage.EnvironmentTemp: - // // include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back - // // to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not - // // utilizing an old path - assuming we cannot have SHA1 collisions on AppDomainAppId - // var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1(); - // var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", appDomainHash); - // path = Path.Combine(cachePath, "umbraco-types." + extension); - // break; - // case LocalTempStorage.Default: - // default: - // var tempFolder = IOHelper.MapPath("~/App_Data/TEMP/TypesCache"); - // path = Path.Combine(tempFolder, "umbraco-types." + NetworkHelper.FileSafeMachineName + "." + extension); - // break; - // } - - // // ensure that the folder exists - // var directory = Path.GetDirectoryName(path); - // if (directory == null) - // throw new InvalidOperationException($"Could not determine folder for file \"{path}\"."); - // if (Directory.Exists(directory) == false) - // Directory.CreateDirectory(directory); - - // return path; - //} - // internal for tests internal void WriteCache() { diff --git a/src/Umbraco.Core/Runtime/CoreRuntime.cs b/src/Umbraco.Core/Runtime/CoreRuntime.cs index cf2712974d..cc35543b66 100755 --- a/src/Umbraco.Core/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Core/Runtime/CoreRuntime.cs @@ -237,10 +237,10 @@ namespace Umbraco.Core.Runtime // and only these things - the rest should be composed in runtime components // register basic things + // logging, runtime state, configuration container.RegisterSingleton(); container.RegisterSingleton(); container.RegisterSingleton(); - container.RegisterFrom(); // register caches @@ -254,8 +254,8 @@ namespace Umbraco.Core.Runtime new IsolatedRuntimeCache(type => new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider())))); container.RegisterSingleton(f => f.GetInstance().RuntimeCache); - // register the plugin manager - container.RegisterSingleton(f => new TypeLoader(f.GetInstance(), f.GetInstance(), f.GetInstance())); + // register the type loader + container.RegisterSingleton(); // register syntax providers - required by database factory container.Register("MySqlSyntaxProvider"); From e65470de8bec932be85fff9d19b62e32c0d24140 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 17 Oct 2018 09:59:55 +0200 Subject: [PATCH 34/54] Document SqlContext --- src/Umbraco.Core/Persistence/SqlContext.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Persistence/SqlContext.cs b/src/Umbraco.Core/Persistence/SqlContext.cs index feb92e0849..d11bce166f 100644 --- a/src/Umbraco.Core/Persistence/SqlContext.cs +++ b/src/Umbraco.Core/Persistence/SqlContext.cs @@ -30,10 +30,24 @@ namespace Umbraco.Core.Persistence Templates = new SqlTemplates(this); } - // fixme + /// + /// Initializes a new instance of the class. + /// + /// Initializes an empty context which must be fully initialized using the + /// method; this is done in + /// as soon as the factory is fully configured. internal SqlContext() { } + /// + /// Initializes this . + /// + /// The sql syntax provider. + /// The Poco data factory. + /// The database type. + /// The mappers. + /// Fully initializes an initially empty context; this is done in + /// as soon as the factory is fully configured. internal void Initialize(ISqlSyntaxProvider sqlSyntax, DatabaseType databaseType, IPocoDataFactory pocoDataFactory, IMapperCollection mappers = null) { // for tests From 11edbc86383c11776d93eb9f435f801f378d7207 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 17 Oct 2018 10:52:09 +0200 Subject: [PATCH 35/54] Remove obsolete post-migrations --- ...ediaXmlCacheForDeletedItemsAfterUpgrade.cs | 50 ------------- .../EnsureListViewDataTypeIsCreated.cs | 71 ------------------- .../OverwriteStylesheetFilesFromTempFiles.cs | 53 -------------- .../RebuildXmlCachesAfterUpgrade.cs | 57 --------------- src/Umbraco.Web/Umbraco.Web.csproj | 4 -- 5 files changed, 235 deletions(-) delete mode 100644 src/Umbraco.Web/Migrations/ClearMediaXmlCacheForDeletedItemsAfterUpgrade.cs delete mode 100644 src/Umbraco.Web/Migrations/EnsureListViewDataTypeIsCreated.cs delete mode 100644 src/Umbraco.Web/Migrations/OverwriteStylesheetFilesFromTempFiles.cs delete mode 100644 src/Umbraco.Web/Migrations/RebuildXmlCachesAfterUpgrade.cs diff --git a/src/Umbraco.Web/Migrations/ClearMediaXmlCacheForDeletedItemsAfterUpgrade.cs b/src/Umbraco.Web/Migrations/ClearMediaXmlCacheForDeletedItemsAfterUpgrade.cs deleted file mode 100644 index 991e77b4d0..0000000000 --- a/src/Umbraco.Web/Migrations/ClearMediaXmlCacheForDeletedItemsAfterUpgrade.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Semver; -using Umbraco.Core; -using Umbraco.Core.Logging; -using Umbraco.Core.Migrations; -using Umbraco.Core.Scoping; - -namespace Umbraco.Web.Migrations -{ - /// - /// This will execute after upgrading to remove any xml cache for media that are currently in the bin - /// - /// - /// This will execute for specific versions - - /// - /// * If current is less than or equal to 7.0.0 - /// - public class ClearMediaXmlCacheForDeletedItemsAfterUpgrade : IPostMigration - { - private readonly ILogger _logger; - - public ClearMediaXmlCacheForDeletedItemsAfterUpgrade(ILogger logger) - { - _logger = logger; - } - - public void Execute(string name, IScope scope, SemVersion originVersion, SemVersion targetVersion, ILogger logger) - { - if (name != Constants.System.UmbracoUpgradePlanName) return; - - var target70 = new SemVersion(7 /*, 0, 0*/); - - if (originVersion <= target70) - { - //This query is structured to work with MySql, SQLCE and SqlServer: - // http://issues.umbraco.org/issue/U4-3876 - - var syntax = scope.SqlContext.SqlSyntax; - - var sql = @"DELETE FROM cmsContentXml WHERE nodeId IN - (SELECT nodeId FROM (SELECT DISTINCT cmsContentXml.nodeId FROM cmsContentXml - INNER JOIN umbracoNode ON cmsContentXml.nodeId = umbracoNode.id - WHERE nodeObjectType = '" + Constants.ObjectTypes.Media + "' AND " + syntax.GetQuotedColumnName("path") + " LIKE '%-21%') x)"; - - var count = scope.Database.Execute(sql); - - _logger.Info("Cleared {Total} items from the media xml cache that were trashed and not meant to be there", count); - } - } - } -} diff --git a/src/Umbraco.Web/Migrations/EnsureListViewDataTypeIsCreated.cs b/src/Umbraco.Web/Migrations/EnsureListViewDataTypeIsCreated.cs deleted file mode 100644 index 2dbe6bd867..0000000000 --- a/src/Umbraco.Web/Migrations/EnsureListViewDataTypeIsCreated.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using NPoco; -using Semver; -using Umbraco.Core; -using Umbraco.Core.Logging; -using Umbraco.Core.Migrations; -using Umbraco.Core.Persistence.Dtos; -using Umbraco.Core.Scoping; - -namespace Umbraco.Web.Migrations -{ - /// - /// Creates the built in list view data types - /// - public class EnsureDefaultListViewDataTypesCreated : IPostMigration - { - public void Execute(string name, IScope scope, SemVersion originVersion, SemVersion targetVersion, ILogger logger) - { - if (name != Constants.System.UmbracoUpgradePlanName) return; - - var target720 = new SemVersion(7, 2, 0); - - if (originVersion > target720) - return; - - var syntax = scope.SqlContext.SqlSyntax; - - try - { - //Turn on identity insert if db provider is not mysql - if (syntax.SupportsIdentityInsert()) - scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", syntax.GetQuotedTableName("umbracoNode")))); - - if (scope.Database.Exists(Constants.DataTypes.DefaultContentListView)) - { - //If this already exists then just exit - return; - } - - scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = Constants.DataTypes.DefaultContentListView, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-95", SortOrder = 2, UniqueId = new Guid("C0808DD3-8133-4E4B-8CE8-E2BEA84A96A4"), Text = Constants.Conventions.DataTypes.ListViewPrefix + "Content", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); - scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = Constants.DataTypes.DefaultMediaListView, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-96", SortOrder = 2, UniqueId = new Guid("3A0156C4-3B8C-4803-BDC1-6871FAA83FFF"), Text = Constants.Conventions.DataTypes.ListViewPrefix + "Media", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); - scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = Constants.DataTypes.DefaultMembersListView, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-97", SortOrder = 2, UniqueId = new Guid("AA2C52A0-CE87-4E65-A47C-7DF09358585D"), Text = Constants.Conventions.DataTypes.ListViewPrefix + "Members", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); - } - finally - { - //Turn off identity insert if db provider is not mysql - if (syntax.SupportsIdentityInsert()) - scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF;", syntax.GetQuotedTableName("umbracoNode")))); - } - - try - { - //Turn on identity insert if db provider is not mysql - if (syntax.SupportsIdentityInsert()) - scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", syntax.GetQuotedTableName(Constants.DatabaseSchema.Tables.DataType)))); - - const string memberListViewConfiguration = "{\"pageSize\":10,\"orderBy\":Name,\"orderDirection\":asc,includeProperties:[{\"alias\":\"email\",\"isSystem\":1},{\"alias\":\"username\",\"isSystem\":1},{\"alias\":\"updateDate\",\"header\":\"Last edited\",\"isSystem\":1}]}"; - - scope.Database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = Constants.DataTypes.DefaultContentListView, EditorAlias = Constants.PropertyEditors.Aliases.ListView, DbType = "Nvarchar" }); - scope.Database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = Constants.DataTypes.DefaultMediaListView, EditorAlias = Constants.PropertyEditors.Aliases.ListView, DbType = "Nvarchar" }); - scope.Database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = Constants.DataTypes.DefaultMembersListView, EditorAlias = Constants.PropertyEditors.Aliases.ListView, DbType = "Nvarchar", Configuration = memberListViewConfiguration }); - } - finally - { - //Turn off identity insert if db provider is not mysql - if (syntax.SupportsIdentityInsert()) - scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF;", syntax.GetQuotedTableName(Constants.DatabaseSchema.Tables.DataType)))); - } - } - } -} diff --git a/src/Umbraco.Web/Migrations/OverwriteStylesheetFilesFromTempFiles.cs b/src/Umbraco.Web/Migrations/OverwriteStylesheetFilesFromTempFiles.cs deleted file mode 100644 index 7a752fa562..0000000000 --- a/src/Umbraco.Web/Migrations/OverwriteStylesheetFilesFromTempFiles.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.IO; -using Semver; -using Umbraco.Core; -using Umbraco.Core.IO; -using Umbraco.Core.Logging; -using Umbraco.Core.Migrations; -using Umbraco.Core.Migrations.Upgrade; -using Umbraco.Core.Scoping; - -namespace Umbraco.Web.Migrations -{ - - /// - /// When upgrading version 7.3 the migration MigrateStylesheetDataToFile will execute but we don't want to overwrite the developers - /// files during the migration since other parts of the migration might fail. So once the migration is complete, we'll then copy over the temp - /// files that this migration created over top of the developer's files. We'll also create a backup of their files. - /// - public sealed class OverwriteStylesheetFilesFromTempFiles : IPostMigration - { - public void Execute(string name, IScope scope, SemVersion originVersion, SemVersion targetVersion, ILogger logger) - { - if (name != Constants.System.UmbracoUpgradePlanName) return; - - var target73 = new SemVersion(7, 3, 0); - - if (originVersion <= target73) - { - var tempCssFolder = IOHelper.MapPath("~/App_Data/TEMP/CssMigration/"); - var cssFolder = IOHelper.MapPath("~/css"); - if (Directory.Exists(tempCssFolder)) - { - var files = Directory.GetFiles(tempCssFolder, "*.css", SearchOption.AllDirectories); - foreach (var file in files) - { - var relativePath = file.TrimStart(tempCssFolder).TrimStart("\\"); - var cssFilePath = Path.Combine(cssFolder, relativePath); - if (File.Exists(cssFilePath)) - { - //backup - var targetPath = Path.Combine(tempCssFolder, relativePath.EnsureEndsWith(".bak")); - logger.Info("CSS file is being backed up from {CssFilePath}, to {TargetPath} before being migrated to new format", cssFilePath, targetPath); - File.Copy(cssFilePath, targetPath, true); - } - - //ensure the sub folder eixts - Directory.CreateDirectory(Path.GetDirectoryName(cssFilePath)); - File.Copy(file, cssFilePath, true); - } - } - } - } - } -} diff --git a/src/Umbraco.Web/Migrations/RebuildXmlCachesAfterUpgrade.cs b/src/Umbraco.Web/Migrations/RebuildXmlCachesAfterUpgrade.cs deleted file mode 100644 index 2181eea367..0000000000 --- a/src/Umbraco.Web/Migrations/RebuildXmlCachesAfterUpgrade.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using Semver; -using Umbraco.Core; -using Umbraco.Core.Logging; -using Umbraco.Core.Migrations; -using Umbraco.Core.Scoping; -using Umbraco.Web.Composing; -using Umbraco.Web.PublishedCache.XmlPublishedCache; - -namespace Umbraco.Web.Migrations -{ - /// - /// Rebuilds the Xml caches after upgrading. - /// This will execute after upgrading to rebuild the xml cache - /// - /// - /// This cannot execute as part of a DB migration since it needs access to services and repositories. - /// Executes for: - /// - Media Xml : if current is less than, or equal to, 7.0.0 (superceeded by the next rule) - /// - Media & Content Xml : if current is less than, or equal to, 7.3.0 - because 7.3.0 adds .Key to cached items - /// - /// - public class RebuildXmlCachesAfterUpgrade : IPostMigration - { - public void Execute(string name, IScope scope, SemVersion originVersion, SemVersion targetVersion, ILogger logger) - { - if (name != Constants.System.UmbracoUpgradePlanName) return; - - var v730 = new SemVersion(new Version(7, 3, 0)); - - var doMedia = originVersion < v730; - var doContent = originVersion < v730; - - if (doMedia) - { - // fixme - maintain - for backward compatibility?! or replace with...?! - //var mediaService = (MediaService) ApplicationContext.Current.Services.MediaService; - //mediaService.RebuildXmlStructures(); - - var svc = Current.PublishedSnapshotService as PublishedSnapshotService; - svc?.RebuildMediaXml(); - - // note: not re-indexing medias? - } - - if (doContent) - { - // fixme - maintain - for backward compatibility?! or replace with...?! - //var contentService = (ContentService) ApplicationContext.Current.Services.ContentService; - //contentService.RebuildXmlStructures(); - - var svc = Current.PublishedSnapshotService as PublishedSnapshotService; - svc?.RebuildContentAndPreviewXml(); - } - } - } -} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 4034dd2be6..699c985af3 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -835,9 +835,6 @@ - - - @@ -1005,7 +1002,6 @@ Resources.resx - From 7b3cded11544eb6c4401c2003a9e07dc3bfdf769 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 4 Jul 2018 14:44:59 +0200 Subject: [PATCH 36/54] Cleanup --- src/Umbraco.Core/Logging/Serilog/SerilogLogger.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Core/Logging/Serilog/SerilogLogger.cs b/src/Umbraco.Core/Logging/Serilog/SerilogLogger.cs index 6d3b2b28b3..c23a43a820 100644 --- a/src/Umbraco.Core/Logging/Serilog/SerilogLogger.cs +++ b/src/Umbraco.Core/Logging/Serilog/SerilogLogger.cs @@ -202,7 +202,6 @@ namespace Umbraco.Core.Logging.Serilog private static bool IsTimeoutThreadAbortException(Exception exception) { if (!(exception is ThreadAbortException abort)) return false; - if (abort.ExceptionState == null) return false; var stateType = abort.ExceptionState.GetType(); From 68ee1181cb0a983d60b0fa6049c4adeb3aad1a4b Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 4 Jul 2018 14:48:44 +0200 Subject: [PATCH 37/54] Execute true Sql in Migrations --- .../Expressions/Execute/ExecuteBuilder.cs | 19 +++++++++- .../ExecuteSqlStatementExpression.cs | 8 ++++ .../Expressions/Execute/IExecuteBuilder.cs | 9 ++++- .../Migrations/MigrationExpressionBase.cs | 26 ++++++++++++- .../Persistence/NPocoSqlExtensions.cs | 38 +++++++++++++++++-- .../Persistence/UmbracoDatabase.cs | 21 +++------- 6 files changed, 98 insertions(+), 23 deletions(-) diff --git a/src/Umbraco.Core/Migrations/Expressions/Execute/ExecuteBuilder.cs b/src/Umbraco.Core/Migrations/Expressions/Execute/ExecuteBuilder.cs index 0637d2e597..0ba2499c44 100644 --- a/src/Umbraco.Core/Migrations/Expressions/Execute/ExecuteBuilder.cs +++ b/src/Umbraco.Core/Migrations/Expressions/Execute/ExecuteBuilder.cs @@ -1,6 +1,7 @@ using NPoco; using Umbraco.Core.Migrations.Expressions.Common; using Umbraco.Core.Migrations.Expressions.Execute.Expressions; +using Umbraco.Core.Persistence; namespace Umbraco.Core.Migrations.Expressions.Execute { @@ -12,7 +13,16 @@ namespace Umbraco.Core.Migrations.Expressions.Execute { } /// - public void Do() => Expression.Execute(); + public void Do() + { + // slightly awkward, but doing it right would mean a *lot* + // of changes for MigrationExpressionBase + + if (Expression.SqlObject == null) + Expression.Execute(); + else + Expression.ExecuteSqlObject(); + } /// public IExecutableBuilder Sql(string sqlStatement) @@ -20,5 +30,12 @@ namespace Umbraco.Core.Migrations.Expressions.Execute Expression.SqlStatement = sqlStatement; return this; } + + /// + public IExecutableBuilder Sql(Sql sql) + { + Expression.SqlObject = sql; + return this; + } } } diff --git a/src/Umbraco.Core/Migrations/Expressions/Execute/Expressions/ExecuteSqlStatementExpression.cs b/src/Umbraco.Core/Migrations/Expressions/Execute/Expressions/ExecuteSqlStatementExpression.cs index b5c1fbdf6b..8b5da4f270 100644 --- a/src/Umbraco.Core/Migrations/Expressions/Execute/Expressions/ExecuteSqlStatementExpression.cs +++ b/src/Umbraco.Core/Migrations/Expressions/Execute/Expressions/ExecuteSqlStatementExpression.cs @@ -1,4 +1,5 @@ using NPoco; +using Umbraco.Core.Persistence; namespace Umbraco.Core.Migrations.Expressions.Execute.Expressions { @@ -10,6 +11,13 @@ namespace Umbraco.Core.Migrations.Expressions.Execute.Expressions public virtual string SqlStatement { get; set; } + public virtual Sql SqlObject { get; set; } + + public void ExecuteSqlObject() + { + Execute(SqlObject); + } + protected override string GetSql() { return SqlStatement; diff --git a/src/Umbraco.Core/Migrations/Expressions/Execute/IExecuteBuilder.cs b/src/Umbraco.Core/Migrations/Expressions/Execute/IExecuteBuilder.cs index 5747eb2c1a..7f575fd3f8 100644 --- a/src/Umbraco.Core/Migrations/Expressions/Execute/IExecuteBuilder.cs +++ b/src/Umbraco.Core/Migrations/Expressions/Execute/IExecuteBuilder.cs @@ -1,4 +1,6 @@ -using Umbraco.Core.Migrations.Expressions.Common; +using NPoco; +using Umbraco.Core.Migrations.Expressions.Common; +using Umbraco.Core.Persistence; namespace Umbraco.Core.Migrations.Expressions.Execute { @@ -12,5 +14,10 @@ namespace Umbraco.Core.Migrations.Expressions.Execute /// Specifies the Sql statement to execute. ///
IExecutableBuilder Sql(string sqlStatement); + + /// + /// Specifies the Sql statement to execute. + /// + IExecutableBuilder Sql(Sql sql); } } diff --git a/src/Umbraco.Core/Migrations/MigrationExpressionBase.cs b/src/Umbraco.Core/Migrations/MigrationExpressionBase.cs index 6ac92a07aa..8b5d9cc78c 100644 --- a/src/Umbraco.Core/Migrations/MigrationExpressionBase.cs +++ b/src/Umbraco.Core/Migrations/MigrationExpressionBase.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Text; using NPoco; using Umbraco.Core.Logging; @@ -88,6 +87,31 @@ namespace Umbraco.Core.Migrations expression.Execute(); } + protected void Execute(Sql sql) + { + if (_executed) + throw new InvalidOperationException("This expression has already been executed."); + _executed = true; + + if (sql == null) + { + Logger.Info(GetType(), $"SQL [{Context.Index}]: "); + } + else + { + Logger.Info(GetType(), $"SQL [{Context.Index}]: {sql.ToText()}"); + Database.Execute(sql); + } + + Context.Index++; + + if (_expressions == null) + return; + + foreach (var expression in _expressions) + expression.Execute(); + } + private void ExecuteStatement(StringBuilder stmtBuilder) { var stmt = stmtBuilder.ToString(); diff --git a/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs b/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs index a5ab62d25f..6f814a7174 100644 --- a/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs +++ b/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs @@ -76,7 +76,7 @@ namespace Umbraco.Core.Persistence var (s, a) = sql.SqlContext.VisitDto(predicate, alias); return sql.Where(s, a); } - + /// /// Appends a WHERE clause to the Sql statement. /// @@ -1117,10 +1117,40 @@ namespace Umbraco.Core.Persistence internal static void WriteToConsole(this Sql sql) { - Console.WriteLine(sql.SQL); + Console.Write(sql.ToText()); + } + + internal static string ToText(this Sql sql) + { + var text = new StringBuilder(); + sql.ToText(text); + return text.ToString(); + } + + internal static void ToText(this Sql sql, StringBuilder text) + { + ToText(sql.SQL, sql.Arguments, text); + } + + internal static void ToText(string sql, object[] arguments, StringBuilder text) + { + text.AppendLine(sql); + + if (arguments.Length == 0) + return; + + text.Append(" --"); + var i = 0; - foreach (var arg in sql.Arguments) - Console.WriteLine($" @{i++}: {arg}"); + foreach (var arg in arguments) + { + text.Append(" @"); + text.Append(i++); + text.Append(":"); + text.Append(arg); + } + + text.AppendLine(); } #endregion diff --git a/src/Umbraco.Core/Persistence/UmbracoDatabase.cs b/src/Umbraco.Core/Persistence/UmbracoDatabase.cs index 64e4c0adca..9ec043d684 100644 --- a/src/Umbraco.Core/Persistence/UmbracoDatabase.cs +++ b/src/Umbraco.Core/Persistence/UmbracoDatabase.cs @@ -228,24 +228,13 @@ namespace Umbraco.Core.Persistence private string CommandToString(string sql, object[] args) { - var sb = new StringBuilder(); + var text = new StringBuilder(); #if DEBUG_DATABASES - sb.Append(InstanceId); - sb.Append(": "); + text.Append(InstanceId); + text.Append(": "); #endif - sb.Append(sql); - if (args.Length > 0) - sb.Append(" --"); - var i = 0; - foreach (var arg in args) - { - sb.Append(" @"); - sb.Append(i++); - sb.Append(":"); - sb.Append(arg); - } - - return sb.ToString(); + NPocoSqlExtensions.ToText(sql, args, text); + return text.ToString(); } protected override void OnExecutedCommand(DbCommand cmd) From 478522a573964ccd737eb57c26951340ffb7416c Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 4 Dec 2018 17:01:33 +0100 Subject: [PATCH 38/54] Migrations TLC --- src/Umbraco.Core/Migrations/MigrationPlan.cs | 67 +++++----- .../Migrations/Upgrade/UmbracoPlan.cs | 116 ++++++++++-------- .../Migrations/Upgrade/UmbracoUpgrader.cs | 23 +++- .../Migrations/Upgrade/Upgrader.cs | 63 ++++++++-- .../Migrations/AdvancedMigrationTests.cs | 37 +++--- .../Migrations/MigrationPlanTests.cs | 36 +++--- .../Migrations/MigrationTests.cs | 31 +++-- .../Migrations/PostMigrationTests.cs | 15 +-- 8 files changed, 233 insertions(+), 155 deletions(-) diff --git a/src/Umbraco.Core/Migrations/MigrationPlan.cs b/src/Umbraco.Core/Migrations/MigrationPlan.cs index 5c999ad6ef..1324abc134 100644 --- a/src/Umbraco.Core/Migrations/MigrationPlan.cs +++ b/src/Umbraco.Core/Migrations/MigrationPlan.cs @@ -64,23 +64,8 @@ namespace Umbraco.Core.Migrations ///
public string Name { get; } - /// - /// Adds an empty migration from source to target state. - /// - public MigrationPlan Add(string sourceState, string targetState) - => Add(sourceState, targetState); - - /// - /// Adds a migration from source to target state. - /// - public MigrationPlan Add(string sourceState, string targetState) - where TMigration : IMigration - => Add(sourceState, targetState, typeof(TMigration)); - - /// - /// Adds a migration from source to target state. - /// - public MigrationPlan Add(string sourceState, string targetState, Type migration) + // adds a transition + private MigrationPlan Add(string sourceState, string targetState, Type migration) { if (sourceState == null) throw new ArgumentNullException(nameof(sourceState)); if (string.IsNullOrWhiteSpace(targetState)) throw new ArgumentNullOrEmptyException(nameof(targetState)); @@ -113,26 +98,26 @@ namespace Umbraco.Core.Migrations } /// - /// Chains an empty migration from chain to target state. - /// - public MigrationPlan Chain(string targetState) - => Chain(targetState); + /// Adds a transition to a target state through an empty migration. + /// + public MigrationPlan To(string targetState) + => To(targetState); /// - /// Chains a migration from chain to target state. + /// Adds a transition to a target state through a migration. /// - public MigrationPlan Chain(string targetState) + public MigrationPlan To(string targetState) where TMigration : IMigration - => Chain(targetState, typeof(TMigration)); + => To(targetState, typeof(TMigration)); /// - /// Chains a migration from chain to target state. + /// Adds a transition to a target state through a migration. /// - public MigrationPlan Chain(string targetState, Type migration) + public MigrationPlan To(string targetState, Type migration) => Add(_prevState, targetState, migration); /// - /// Sets the chain state. + /// Sets the starting state. /// public MigrationPlan From(string sourceState) { @@ -141,19 +126,16 @@ namespace Umbraco.Core.Migrations } /// - /// Copies a chain. + /// Adds transitions to a target state by copying transitions from a start state to an end state. /// - /// Copies the chain going from startState to endState, with new states going from sourceState to targetState. - public MigrationPlan CopyChain(string sourceState, string startState, string endState, string targetState) + public MigrationPlan To(string targetState, string startState, string endState) { - if (sourceState == null) throw new ArgumentNullException(nameof(sourceState)); if (string.IsNullOrWhiteSpace(startState)) throw new ArgumentNullOrEmptyException(nameof(startState)); if (string.IsNullOrWhiteSpace(endState)) throw new ArgumentNullOrEmptyException(nameof(endState)); if (string.IsNullOrWhiteSpace(targetState)) throw new ArgumentNullOrEmptyException(nameof(targetState)); - if (sourceState == targetState) throw new ArgumentException("Source and target states cannot be identical."); + if (startState == endState) throw new ArgumentException("Start and end states cannot be identical."); - sourceState = sourceState.Trim(); startState = startState.Trim(); endState = endState.Trim(); targetState = targetState.Trim(); @@ -168,25 +150,36 @@ namespace Umbraco.Core.Migrations visited.Add(state); if (!_transitions.TryGetValue(state, out var transition)) - throw new InvalidOperationException($"There is no transition from state \"{sourceState}\"."); + throw new InvalidOperationException($"There is no transition from state \"{state}\"."); var newTargetState = transition.TargetState == endState ? targetState : Guid.NewGuid().ToString("B").ToUpper(); - Add(sourceState, newTargetState, transition.MigrationType); - sourceState = newTargetState; + To(newTargetState, transition.MigrationType); state = transition.TargetState; } return this; } + /// + /// Copies a chain. + /// + /// Copies the chain going from startState to endState, with new states going from sourceState to targetState. + [Obsolete("die", true)] + public MigrationPlan CopyChain(string sourceState, string startState, string endState, string targetState) + { + From(sourceState).To(targetState, startState, endState); + return this; + } + /// /// Copies a chain. /// /// Copies the chain going from startState to endState, with new states going from chain to targetState. + [Obsolete("die", true)] public MigrationPlan CopyChain(string startState, string endState, string targetState) - => CopyChain(_prevState, startState, endState, targetState); + => To(targetState, startState, endState); /// /// Gets the initial state. diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index ec49544976..e907ce09ab 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -85,65 +85,73 @@ namespace Umbraco.Core.Migrations.Upgrade // upgrades from 7 to 8, and then takes care of all eventual upgrades // From("{init-7.10.0}"); - Chain("{7C447271-CA3F-4A6A-A913-5D77015655CB}"); - Chain("{CBFF58A2-7B50-4F75-8E98-249920DB0F37}"); - Chain("{3D18920C-E84D-405C-A06A-B7CEE52FE5DD}"); - Chain("{FB0A5429-587E-4BD0-8A67-20F0E7E62FF7}"); - Chain("{F0C42457-6A3B-4912-A7EA-F27ED85A2092}"); - Chain("{8640C9E4-A1C0-4C59-99BB-609B4E604981}"); - Chain("{DD1B99AF-8106-4E00-BAC7-A43003EA07F8}"); - Chain("{9DF05B77-11D1-475C-A00A-B656AF7E0908}"); - Chain("{6FE3EF34-44A0-4992-B379-B40BC4EF1C4D}"); - Chain("{7F59355A-0EC9-4438-8157-EB517E6D2727}"); + To("{7C447271-CA3F-4A6A-A913-5D77015655CB}"); + To("{CBFF58A2-7B50-4F75-8E98-249920DB0F37}"); + To("{3D18920C-E84D-405C-A06A-B7CEE52FE5DD}"); + To("{FB0A5429-587E-4BD0-8A67-20F0E7E62FF7}"); + To("{F0C42457-6A3B-4912-A7EA-F27ED85A2092}"); + To("{8640C9E4-A1C0-4C59-99BB-609B4E604981}"); + To("{DD1B99AF-8106-4E00-BAC7-A43003EA07F8}"); + To("{9DF05B77-11D1-475C-A00A-B656AF7E0908}"); + To("{6FE3EF34-44A0-4992-B379-B40BC4EF1C4D}"); + To("{7F59355A-0EC9-4438-8157-EB517E6D2727}"); + //To("{941B2ABA-2D06-4E04-81F5-74224F1DB037}"); // AddVariationTables1 has been superseded by AddVariationTables2 + To("{76DF5CD7-A884-41A5-8DC6-7860D95B1DF5}"); - // AddVariationTables1 has been superceeded by AddVariationTables2 - //Chain("{941B2ABA-2D06-4E04-81F5-74224F1DB037}"); - Chain("{76DF5CD7-A884-41A5-8DC6-7860D95B1DF5}"); - // however, provide a path out of the old state - Add("{941B2ABA-2D06-4E04-81F5-74224F1DB037}", "{76DF5CD7-A884-41A5-8DC6-7860D95B1DF5}"); + // way out of the commented state + From("{941B2ABA-2D06-4E04-81F5-74224F1DB037}"); + To("{76DF5CD7-A884-41A5-8DC6-7860D95B1DF5}"); // resume at {76DF5CD7-A884-41A5-8DC6-7860D95B1DF5} ... - Chain("{A7540C58-171D-462A-91C5-7A9AA5CB8BFD}"); + To("{A7540C58-171D-462A-91C5-7A9AA5CB8BFD}"); + To("{3E44F712-E2E3-473A-AE49-5D7F8E67CE3F}"); // shannon added that one - let's keep it as the default path + //To("{65D6B71C-BDD5-4A2E-8D35-8896325E9151}"); // stephan added that one = merge conflict, remove + To("{4CACE351-C6B9-4F0C-A6BA-85A02BBD39E4}"); // but add it after shannon's, with a new target state - Chain("{3E44F712-E2E3-473A-AE49-5D7F8E67CE3F}"); // shannon added that one - let's keep it as the default path - //Chain("{65D6B71C-BDD5-4A2E-8D35-8896325E9151}"); // stephan added that one = merge conflict, remove, - Chain("{4CACE351-C6B9-4F0C-A6BA-85A02BBD39E4}"); // but add it after shannon's, with a new target state, - Add("{65D6B71C-BDD5-4A2E-8D35-8896325E9151}", "{4CACE351-C6B9-4F0C-A6BA-85A02BBD39E4}"); // and provide a path out of the conflict state + // way out of the commented state + From("{65D6B71C-BDD5-4A2E-8D35-8896325E9151}"); + To("{4CACE351-C6B9-4F0C-A6BA-85A02BBD39E4}"); // resume at {4CACE351-C6B9-4F0C-A6BA-85A02BBD39E4} ... - Chain("{1350617A-4930-4D61-852F-E3AA9E692173}"); - Chain("{39E5B1F7-A50B-437E-B768-1723AEC45B65}"); // from 7.12.0 - //Chain("{CF51B39B-9B9A-4740-BB7C-EAF606A7BFBF}"); // andy added that one = merge conflict, remove - Chain("{0541A62B-EF87-4CA2-8225-F0EB98ECCC9F}"); // from 7.12.0 - Chain("{EB34B5DC-BB87-4005-985E-D983EA496C38}"); // from 7.12.0 - Chain("{517CE9EA-36D7-472A-BF4B-A0D6FB1B8F89}"); // from 7.12.0 - Chain("{BBD99901-1545-40E4-8A5A-D7A675C7D2F2}"); // from 7.12.0 - //Chain("{2C87AA47-D1BC-4ECB-8A73-2D8D1046C27F}"); // stephan added that one = merge conflict, remove + To("{1350617A-4930-4D61-852F-E3AA9E692173}"); + To("{39E5B1F7-A50B-437E-B768-1723AEC45B65}"); // from 7.12.0 + //To("{CF51B39B-9B9A-4740-BB7C-EAF606A7BFBF}"); // andy added that one = merge conflict, remove + To("{0541A62B-EF87-4CA2-8225-F0EB98ECCC9F}"); // from 7.12.0 + To("{EB34B5DC-BB87-4005-985E-D983EA496C38}"); // from 7.12.0 + To("{517CE9EA-36D7-472A-BF4B-A0D6FB1B8F89}"); // from 7.12.0 + To("{BBD99901-1545-40E4-8A5A-D7A675C7D2F2}"); // from 7.12.0 + //To("{2C87AA47-D1BC-4ECB-8A73-2D8D1046C27F}"); // stephan added that one = merge conflict, remove - Chain("{8B14CEBD-EE47-4AAD-A841-93551D917F11}"); // add andy's after others, with a new target state - From("{CF51B39B-9B9A-4740-BB7C-EAF606A7BFBF}") // and provide a path out of andy's - .CopyChain("{39E5B1F7-A50B-437E-B768-1723AEC45B65}", "{BBD99901-1545-40E4-8A5A-D7A675C7D2F2}", "{8B14CEBD-EE47-4AAD-A841-93551D917F11}"); // to next + To("{8B14CEBD-EE47-4AAD-A841-93551D917F11}"); // add andy's after others, with a new target state + + // way out of andy's + From("{CF51B39B-9B9A-4740-BB7C-EAF606A7BFBF}"); + To("{8B14CEBD-EE47-4AAD-A841-93551D917F11}", "{39E5B1F7-A50B-437E-B768-1723AEC45B65}", "{BBD99901-1545-40E4-8A5A-D7A675C7D2F2}"); // resume at {8B14CEBD-EE47-4AAD-A841-93551D917F11} ... - Chain("{5F4597F4-A4E0-4AFE-90B5-6D2F896830EB}"); // add stephan's after others, with a new target state - From("{2C87AA47-D1BC-4ECB-8A73-2D8D1046C27F}") // and provide a path out of stephan's - .Chain("{5F4597F4-A4E0-4AFE-90B5-6D2F896830EB}"); // to next + To("{5F4597F4-A4E0-4AFE-90B5-6D2F896830EB}"); // add stephan's after others, with a new target state + + // way out of the commented state + From("{2C87AA47-D1BC-4ECB-8A73-2D8D1046C27F}"); + To("{5F4597F4-A4E0-4AFE-90B5-6D2F896830EB}"); // to next // resume at {5F4597F4-A4E0-4AFE-90B5-6D2F896830EB} ... - //Chain("{B19BF0F2-E1C6-4AEB-A146-BC559D97A2C6}"); - Chain("{290C18EE-B3DE-4769-84F1-1F467F3F76DA}"); - From("{B19BF0F2-E1C6-4AEB-A146-BC559D97A2C6}") - .Chain("{290C18EE-B3DE-4769-84F1-1F467F3F76DA}"); + //To("{B19BF0F2-E1C6-4AEB-A146-BC559D97A2C6}"); + To("{290C18EE-B3DE-4769-84F1-1F467F3F76DA}"); + + // way out of the commented state + From("{B19BF0F2-E1C6-4AEB-A146-BC559D97A2C6}"); + To("{290C18EE-B3DE-4769-84F1-1F467F3F76DA}"); // resume at {290C18EE-B3DE-4769-84F1-1F467F3F76DA}... - Chain("{6A2C7C1B-A9DB-4EA9-B6AB-78E7D5B722A7}"); - Chain("{77874C77-93E5-4488-A404-A630907CEEF0}"); - Chain("{8804D8E8-FE62-4E3A-B8A2-C047C2118C38}"); - Chain("{23275462-446E-44C7-8C2C-3B8C1127B07D}"); - Chain("{6B251841-3069-4AD5-8AE9-861F9523E8DA}"); - Chain("{EE429F1B-9B26-43CA-89F8-A86017C809A3}"); - Chain("{08919C4B-B431-449C-90EC-2B8445B5C6B1}"); - Chain("{7EB0254C-CB8B-4C75-B15B-D48C55B449EB}"); + To("{6A2C7C1B-A9DB-4EA9-B6AB-78E7D5B722A7}"); + To("{77874C77-93E5-4488-A404-A630907CEEF0}"); + To("{8804D8E8-FE62-4E3A-B8A2-C047C2118C38}"); + To("{23275462-446E-44C7-8C2C-3B8C1127B07D}"); + To("{6B251841-3069-4AD5-8AE9-861F9523E8DA}"); + To("{EE429F1B-9B26-43CA-89F8-A86017C809A3}"); + To("{08919C4B-B431-449C-90EC-2B8445B5C6B1}"); + To("{7EB0254C-CB8B-4C75-B15B-D48C55B449EB}"); //FINAL @@ -152,20 +160,20 @@ namespace Umbraco.Core.Migrations.Upgrade // and then, need to support upgrading from more recent 7.x // - From("{init-7.10.1}").Chain("{init-7.10.0}"); // same as 7.10.0 - From("{init-7.10.2}").Chain("{init-7.10.0}"); // same as 7.10.0 - From("{init-7.10.3}").Chain("{init-7.10.0}"); // same as 7.10.0 - From("{init-7.10.4}").Chain("{init-7.10.0}"); // same as 7.10.0 - From("{init-7.11.0}").Chain("{init-7.10.0}"); // same as 7.10.0 - From("{init-7.11.1}").Chain("{init-7.10.0}"); // same as 7.10.0 + From("{init-7.10.1}").To("{init-7.10.0}"); // same as 7.10.0 + From("{init-7.10.2}").To("{init-7.10.0}"); // same as 7.10.0 + From("{init-7.10.3}").To("{init-7.10.0}"); // same as 7.10.0 + From("{init-7.10.4}").To("{init-7.10.0}"); // same as 7.10.0 + From("{init-7.11.0}").To("{init-7.10.0}"); // same as 7.10.0 + From("{init-7.11.1}").To("{init-7.10.0}"); // same as 7.10.0 // 7.12.0 has migrations, define a custom chain which copies the chain // going from {init-7.10.0} to former final (1350617A) , and then goes straight to // main chain, skipping the migrations // From("{init-7.12.0}"); - // copy from copy to (former final) main chain - CopyChain("{init-7.10.0}", "{1350617A-4930-4D61-852F-E3AA9E692173}", "{BBD99901-1545-40E4-8A5A-D7A675C7D2F2}"); + // target copy from copy to (former final) + To("{BBD99901-1545-40E4-8A5A-D7A675C7D2F2}", "{init-7.10.0}", "{1350617A-4930-4D61-852F-E3AA9E692173}"); } } } diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoUpgrader.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoUpgrader.cs index b24ad2a20e..b78aec9cd4 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoUpgrader.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoUpgrader.cs @@ -10,16 +10,20 @@ namespace Umbraco.Core.Migrations.Upgrade { public class UmbracoUpgrader : Upgrader { - public UmbracoUpgrader(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, PostMigrationCollection postMigrations, ILogger logger) - : base(scopeProvider, migrationBuilder, keyValueService, postMigrations, logger) - { } + private readonly PostMigrationCollection _postMigrations; - protected override MigrationPlan GetPlan() + public UmbracoUpgrader(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, PostMigrationCollection postMigrations, ILogger logger) + : base(scopeProvider, migrationBuilder, keyValueService, logger) + { + _postMigrations = postMigrations ?? throw new ArgumentNullException(nameof(postMigrations)); + } + + protected override MigrationPlan CreatePlan() { return new UmbracoPlan(MigrationBuilder, Logger); } - protected override (SemVersion, SemVersion) GetVersions() + protected (SemVersion, SemVersion) GetVersions() { // assume we have something in web.config that makes some sense if (!SemVersion.TryParse(ConfigurationManager.AppSettings["umbracoConfigurationStatus"], out var currentVersion)) @@ -27,5 +31,14 @@ namespace Umbraco.Core.Migrations.Upgrade return (currentVersion, UmbracoVersion.SemanticVersion); } + + public override void AfterMigrations(IScope scope) + { + // run post-migrations + var (originVersion, targetVersion) = GetVersions(); + + foreach (var postMigration in _postMigrations) + postMigration.Execute(Name, scope, originVersion, targetVersion, Logger); + } } } diff --git a/src/Umbraco.Core/Migrations/Upgrade/Upgrader.cs b/src/Umbraco.Core/Migrations/Upgrade/Upgrader.cs index 974ed7b4f8..49f36a5099 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/Upgrader.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/Upgrader.cs @@ -1,47 +1,76 @@ using System; -using Semver; using Umbraco.Core.Logging; using Umbraco.Core.Scoping; using Umbraco.Core.Services; namespace Umbraco.Core.Migrations.Upgrade { + /// + /// Provides a base class for upgraders. + /// public abstract class Upgrader { private readonly IKeyValueService _keyValueService; - private readonly PostMigrationCollection _postMigrations; private MigrationPlan _plan; - protected Upgrader(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, PostMigrationCollection postMigrations, ILogger logger) + /// + /// Initializes a new instance of the class. + /// + protected Upgrader(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, ILogger logger) { ScopeProvider = scopeProvider ?? throw new ArgumentNullException(nameof(scopeProvider)); MigrationBuilder = migrationBuilder ?? throw new ArgumentNullException(nameof(migrationBuilder)); _keyValueService = keyValueService ?? throw new ArgumentNullException(nameof(keyValueService)); - _postMigrations = postMigrations ?? throw new ArgumentNullException(nameof(postMigrations)); Logger = logger ?? throw new ArgumentNullException(nameof(logger)); } + /// + /// Gets the name of the migration plan. + /// public string Name => Plan.Name; + /// + /// Gets the state value key corresponding to the migration plan. + /// public string StateValueKey => GetStateValueKey(Plan); + /// + /// Gets the scope provider. + /// protected IScopeProvider ScopeProvider { get; } + /// + /// Gets the migration builder. + /// protected IMigrationBuilder MigrationBuilder { get; } + /// + /// Gets the logger. + /// protected ILogger Logger { get; } - protected MigrationPlan Plan => _plan ?? (_plan = GetPlan()); + /// + /// Gets the migration plan. + /// + protected MigrationPlan Plan => _plan ?? (_plan = CreatePlan()); - protected abstract MigrationPlan GetPlan(); - protected abstract (SemVersion, SemVersion) GetVersions(); + /// + /// Creates the migration plan. + /// + /// + protected abstract MigrationPlan CreatePlan(); + /// + /// Executes. + /// public void Execute() { var plan = Plan; using (var scope = ScopeProvider.CreateScope()) { + BeforeMigrations(scope); + // read current state var currentState = _keyValueService.GetValue(StateValueKey); var forceState = false; @@ -63,15 +92,27 @@ namespace Umbraco.Core.Migrations.Upgrade else if (currentState != state) _keyValueService.SetValue(StateValueKey, currentState, state); - // run post-migrations - (var originVersion, var targetVersion) = GetVersions(); - foreach (var postMigration in _postMigrations) - postMigration.Execute(Name, scope, originVersion, targetVersion, Logger); + AfterMigrations(scope); scope.Complete(); } } + /// + /// Executes as part of the upgrade scope and before all migrations have executed. + /// + public virtual void BeforeMigrations(IScope scope) + { } + + /// + /// Executes as part of the upgrade scope and after all migrations have executed. + /// + public virtual void AfterMigrations(IScope scope) + { } + + /// + /// Gets the state value key for a migration plan. + /// public static string GetStateValueKey(MigrationPlan plan) => "Umbraco.Core.Upgrader.State+" + plan.Name; } } diff --git a/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs b/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs index 5505d7ecd7..f6dc3e1063 100644 --- a/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs +++ b/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs @@ -34,9 +34,10 @@ namespace Umbraco.Tests.Migrations using (var scope = ScopeProvider.CreateScope()) { - var upgrader = new MigrationTests.TestUpgrader(ScopeProvider, builder, Mock.Of(), new PostMigrationCollection(Enumerable.Empty()), logger, + var upgrader = new MigrationTests.TestUpgrader(ScopeProvider, builder, Mock.Of(), logger, new MigrationPlan("test", builder, logger) - .Add(string.Empty, "done")); + .From(string.Empty) + .To("done")); upgrader.Execute(); @@ -71,10 +72,11 @@ namespace Umbraco.Tests.Migrations using (var scope = ScopeProvider.CreateScope()) { - var upgrader = new MigrationTests.TestUpgrader(ScopeProvider, builder, Mock.Of(), new PostMigrationCollection(Enumerable.Empty()), logger, + var upgrader = new MigrationTests.TestUpgrader(ScopeProvider, builder, Mock.Of(), logger, new MigrationPlan("test", builder, logger) - .Add(string.Empty, "a") - .Add("a", "done")); + .From(string.Empty) + .To("a") + .To("done")); upgrader.Execute(); scope.Complete(); @@ -106,11 +108,12 @@ namespace Umbraco.Tests.Migrations using (var scope = ScopeProvider.CreateScope()) { - var upgrader = new MigrationTests.TestUpgrader(ScopeProvider, builder, Mock.Of(), new PostMigrationCollection(Enumerable.Empty()), logger, + var upgrader = new MigrationTests.TestUpgrader(ScopeProvider, builder, Mock.Of(), logger, new MigrationPlan("test", builder, logger) - .Add(string.Empty, "a") - .Add("a", "b") - .Add("b", "done")); + .From(string.Empty) + .To("a") + .To("b") + .To("done")); upgrader.Execute(); scope.Complete(); @@ -142,11 +145,12 @@ namespace Umbraco.Tests.Migrations using (var scope = ScopeProvider.CreateScope()) { - var upgrader = new MigrationTests.TestUpgrader(ScopeProvider, builder, Mock.Of(), new PostMigrationCollection(Enumerable.Empty()), logger, + var upgrader = new MigrationTests.TestUpgrader(ScopeProvider, builder, Mock.Of(), logger, new MigrationPlan("test", builder, logger) - .Add(string.Empty, "a") - .Add("a", "b") - .Add("b", "done")); + .From(string.Empty) + .To("a") + .To("b") + .To("done")); upgrader.Execute(); scope.Complete(); @@ -176,10 +180,11 @@ namespace Umbraco.Tests.Migrations using (var scope = ScopeProvider.CreateScope()) { - var upgrader = new MigrationTests.TestUpgrader(ScopeProvider, builder, Mock.Of(), new PostMigrationCollection(Enumerable.Empty()), logger, + var upgrader = new MigrationTests.TestUpgrader(ScopeProvider, builder, Mock.Of(), logger, new MigrationPlan("test", builder, logger) - .Add(string.Empty, "a") - .Add("a", "done")); + .From(string.Empty) + .To("a") + .To("done")); upgrader.Execute(); scope.Complete(); diff --git a/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs b/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs index ee1b2a56f5..b246472ee5 100644 --- a/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs +++ b/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs @@ -51,8 +51,8 @@ namespace Umbraco.Tests.Migrations var plan = new MigrationPlan("default", migrationBuilder, logger) .From(string.Empty) - .Chain("{4A9A1A8F-0DA1-4BCF-AD06-C19D79152E35}") - .Chain("VERSION.33"); + .To("{4A9A1A8F-0DA1-4BCF-AD06-C19D79152E35}") + .To("VERSION.33"); var kvs = Mock.Of(); Mock.Get(kvs).Setup(x => x.GetValue(It.IsAny())).Returns(k => k == "Umbraco.Tests.MigrationPlan" ? string.Empty : null); @@ -82,9 +82,11 @@ namespace Umbraco.Tests.Migrations public void CanAddMigrations() { var plan = new MigrationPlan("default", Mock.Of(), Mock.Of()); - plan.Add(string.Empty, "aaa"); - plan.Add("aaa", "bbb"); - plan.Add("bbb", "ccc"); + plan + .From(string.Empty) + .To("aaa") + .To("bbb") + .To("ccc"); } [Test] @@ -93,7 +95,7 @@ namespace Umbraco.Tests.Migrations var plan = new MigrationPlan("default", Mock.Of(), Mock.Of()); Assert.Throws(() => { - plan.Add("aaa", "aaa"); + plan.From("aaa").To("aaa"); }); } @@ -101,10 +103,10 @@ namespace Umbraco.Tests.Migrations public void OnlyOneTransitionPerState() { var plan = new MigrationPlan("default", Mock.Of(), Mock.Of()); - plan.Add("aaa", "bbb"); + plan.From("aaa").To("bbb"); Assert.Throws(() => { - plan.Add("aaa", "ccc"); + plan.From("aaa").To("ccc"); }); } @@ -112,9 +114,12 @@ namespace Umbraco.Tests.Migrations public void CannotContainTwoMoreHeads() { var plan = new MigrationPlan("default", Mock.Of(), Mock.Of()); - plan.Add(string.Empty, "aaa"); - plan.Add("aaa", "bbb"); - plan.Add("ccc", "ddd"); + plan + .From(string.Empty) + .To("aaa") + .To("bbb") + .From("ccc") + .To("ddd"); Assert.Throws(() => plan.Validate()); } @@ -122,10 +127,11 @@ namespace Umbraco.Tests.Migrations public void CannotContainLoops() { var plan = new MigrationPlan("default", Mock.Of(), Mock.Of()); - plan.Add(string.Empty, "aaa"); - plan.Add("aaa", "bbb"); - plan.Add("bbb", "ccc"); - plan.Add("ccc", "aaa"); + plan + .From("aaa") + .To("bbb") + .To("ccc") + .To("aaa"); Assert.Throws(() => plan.Validate()); } diff --git a/src/Umbraco.Tests/Migrations/MigrationTests.cs b/src/Umbraco.Tests/Migrations/MigrationTests.cs index d06cf2244e..4fc2928033 100644 --- a/src/Umbraco.Tests/Migrations/MigrationTests.cs +++ b/src/Umbraco.Tests/Migrations/MigrationTests.cs @@ -20,23 +20,38 @@ namespace Umbraco.Tests.Migrations { private readonly MigrationPlan _plan; - public TestUpgrader(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, PostMigrationCollection postMigrations, ILogger logger, MigrationPlan plan) - : base(scopeProvider, migrationBuilder, keyValueService, postMigrations, logger) + public TestUpgrader(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, ILogger logger, MigrationPlan plan) + : base(scopeProvider, migrationBuilder, keyValueService, logger) { _plan = plan; } - protected override MigrationPlan GetPlan() + protected override MigrationPlan CreatePlan() { return _plan; } - - protected override (SemVersion, SemVersion) GetVersions() - { - return (new SemVersion(0), new SemVersion(0)); - } } + public class TestUpgraderWithPostMigrations : TestUpgrader + { + private readonly PostMigrationCollection _postMigrations; + + public TestUpgraderWithPostMigrations(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, ILogger logger, PostMigrationCollection postMigrations, MigrationPlan plan) + : base(scopeProvider, migrationBuilder, keyValueService, logger, plan) + { + _postMigrations = postMigrations; + } + + public override void AfterMigrations(IScope scope) + { + // run post-migrations + var originVersion = new SemVersion(0); + var targetVersion = new SemVersion(0); + + foreach (var postMigration in _postMigrations) + postMigration.Execute(Name, scope, originVersion, targetVersion, Logger); + } + } public class TestScopeProvider : IScopeProvider { diff --git a/src/Umbraco.Tests/Migrations/PostMigrationTests.cs b/src/Umbraco.Tests/Migrations/PostMigrationTests.cs index d94a1cc917..5b7ec004d5 100644 --- a/src/Umbraco.Tests/Migrations/PostMigrationTests.cs +++ b/src/Umbraco.Tests/Migrations/PostMigrationTests.cs @@ -50,9 +50,8 @@ namespace Umbraco.Tests.Migrations var sqlContext = new SqlContext(new SqlCeSyntaxProvider(), DatabaseType.SQLCe, Mock.Of()); var scopeProvider = new MigrationTests.TestScopeProvider(scope) { SqlContext = sqlContext }; - var u1 = new MigrationTests.TestUpgrader(scopeProvider, builder, Mock.Of(), posts, logger, - new MigrationPlan("Test", builder, logger) - .Add(string.Empty, "done")); + var u1 = new MigrationTests.TestUpgraderWithPostMigrations(scopeProvider, builder, Mock.Of(), logger, posts, + new MigrationPlan("Test", builder, logger).From(string.Empty).To("done")); u1.Execute(); Assert.AreEqual(1, changed1.CountExecuted); @@ -94,17 +93,15 @@ namespace Umbraco.Tests.Migrations var sqlContext = new SqlContext(new SqlCeSyntaxProvider(), DatabaseType.SQLCe, Mock.Of()); var scopeProvider = new MigrationTests.TestScopeProvider(scope) { SqlContext = sqlContext }; - var u1 = new MigrationTests.TestUpgrader(scopeProvider, builder, Mock.Of(), posts, logger, - new MigrationPlan("Test1", builder, logger) - .Add(string.Empty, "done")); + var u1 = new MigrationTests.TestUpgraderWithPostMigrations(scopeProvider, builder, Mock.Of(), logger, posts, + new MigrationPlan("Test1", builder, logger).From(string.Empty).To("done")); u1.Execute(); Assert.AreEqual(1, changed1.CountExecuted); Assert.AreEqual(0, changed2.CountExecuted); - var u2 = new MigrationTests.TestUpgrader(scopeProvider, builder, Mock.Of(), posts, logger, - new MigrationPlan("Test2", builder, logger) - .Add(string.Empty, "done")); + var u2 = new MigrationTests.TestUpgraderWithPostMigrations(scopeProvider, builder, Mock.Of(), logger, posts, + new MigrationPlan("Test2", builder, logger).From(string.Empty).To("done")); u2.Execute(); Assert.AreEqual(1, changed1.CountExecuted); From 84e0d0571fdbb9b8ddf354bd8e9f088806859345 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 4 Jul 2018 15:07:09 +0200 Subject: [PATCH 39/54] Refactor migration plan and upgrader --- .../Migrations/Install/DatabaseBuilder.cs | 49 +------------ .../Migrations/Install/DatabaseDataCreator.cs | 6 +- src/Umbraco.Core/Migrations/MigrationPlan.cs | 48 ++++--------- .../Migrations/Upgrade/UmbracoPlan.cs | 8 --- .../Migrations/Upgrade/UmbracoUpgrader.cs | 40 +++++------ .../Migrations/Upgrade/Upgrader.cs | 70 ++++++------------- src/Umbraco.Core/Runtime/CoreRuntime.cs | 6 +- .../Migrations/AdvancedMigrationTests.cs | 30 ++++---- .../Migrations/MigrationPlanTests.cs | 19 +++-- .../Migrations/MigrationTests.cs | 20 ++++-- .../Migrations/PostMigrationTests.cs | 18 ++--- 11 files changed, 109 insertions(+), 205 deletions(-) diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs index 4986eeab02..ea818c60e3 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs @@ -534,56 +534,11 @@ namespace Umbraco.Core.Migrations.Install _logger.Info("Database upgrade started"); - //var database = scope.Database; - //var supportsCaseInsensitiveQueries = SqlSyntax.SupportsCaseInsensitiveQueries(database); - var message = GetResultMessageForMySql(); - // fixme - remove this code - //var schemaResult = ValidateDatabaseSchema(); - // - //var installedSchemaVersion = new SemVersion(schemaResult.DetermineInstalledVersion()); - //var installedMigrationVersion = schemaResult.DetermineInstalledVersionByMigrations(migrationEntryService); - //var targetVersion = UmbracoVersion.Current; - // - ////In some cases - like upgrading from 7.2.6 -> 7.3, there will be no migration information in the database and therefore it will - //// return a version of 0.0.0 and we don't necessarily want to run all migrations from 0 -> 7.3, so we'll just ensure that the - //// migrations are run for the target version - //if (installedMigrationVersion == new SemVersion(new Version(0, 0, 0)) && installedSchemaVersion > new SemVersion(new Version(0, 0, 0))) - //{ - // //set the installedMigrationVersion to be one less than the target so the latest migrations are guaranteed to execute - // installedMigrationVersion = new SemVersion(targetVersion.SubtractRevision()); - //} - // - ////Figure out what our current installed version is. If the web.config doesn't have a version listed, then we'll use the minimum - //// version detected between the schema installed and the migrations listed in the migration table. - //// If there is a version in the web.config, we'll take the minimum between the listed migration in the db and what - //// is declared in the web.config. - // - //var currentInstalledVersion = string.IsNullOrEmpty(GlobalSettings.ConfigurationStatus) - // //Take the minimum version between the detected schema version and the installed migration version - // ? new[] { installedSchemaVersion, installedMigrationVersion }.Min() - // //Take the minimum version between the installed migration version and the version specified in the config - // : new[] { SemVersion.Parse(GlobalSettings.ConfigurationStatus), installedMigrationVersion }.Min(); - // - ////Ok, another edge case here. If the current version is a pre-release, - //// then we want to ensure all migrations for the current release are executed. - //if (currentInstalledVersion.Prerelease.IsNullOrWhiteSpace() == false) - //{ - // currentInstalledVersion = new SemVersion(currentInstalledVersion.GetVersion().SubtractRevision()); - //} - // upgrade - var upgrader = new UmbracoUpgrader(_scopeProvider, _migrationBuilder, _keyValueService, _postMigrations, _logger); - upgrader.Execute(); - - // fixme remove this code - //var runner = new MigrationRunner(_scopeProvider, builder, migrationEntryService, _logger, currentInstalledVersion, UmbracoVersion.SemanticVersion, Constants.System.UmbracoMigrationName); - //var upgraded = runner.Execute(/*upgrade:true*/); - //if (upgraded == false) - //{ - // throw new ApplicationException("Upgrading failed, either an error occurred during the upgrade process or an event canceled the upgrade process, see log for full details"); - //} + var upgrader = new UmbracoUpgrader(); + upgrader.Execute(_scopeProvider, _migrationBuilder, _keyValueService, _logger, _postMigrations); message = message + "

Upgrade completed!

"; diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs index eb7cafcb01..f32ea1cb6f 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs @@ -321,9 +321,9 @@ namespace Umbraco.Core.Migrations.Install { // on install, initialize the umbraco migration plan with the final state - var plan = new UmbracoPlan(); - var stateValueKey = Upgrader.GetStateValueKey(plan); - var finalState = plan.FinalState; + var upgrader = new UmbracoUpgrader(); + var stateValueKey = upgrader.StateValueKey; + var finalState = upgrader.Plan.FinalState; _database.Insert(Constants.DatabaseSchema.Tables.KeyValue, "key", false, new KeyValueDto { Key = stateValueKey, Value = finalState, Updated = DateTime.Now }); } diff --git a/src/Umbraco.Core/Migrations/MigrationPlan.cs b/src/Umbraco.Core/Migrations/MigrationPlan.cs index 1324abc134..68402de85f 100644 --- a/src/Umbraco.Core/Migrations/MigrationPlan.cs +++ b/src/Umbraco.Core/Migrations/MigrationPlan.cs @@ -12,8 +12,6 @@ namespace Umbraco.Core.Migrations ///
public class MigrationPlan { - private readonly IMigrationBuilder _migrationBuilder; - private readonly ILogger _logger; private readonly Dictionary _transitions = new Dictionary(); private string _prevState; @@ -23,8 +21,6 @@ namespace Umbraco.Core.Migrations /// Initializes a new instance of the class. /// /// The name of the plan. - /// The plan cannot be executed. Use this constructor e.g. when only validating the plan, - /// or trying to get its final state, without actually needing to execute it. public MigrationPlan(string name) { if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullOrEmptyException(nameof(name)); @@ -35,25 +31,6 @@ namespace Umbraco.Core.Migrations DefinePlan(); } - /// - /// Initializes a new instance of the class. - /// - /// The name of the plan. - /// A migration builder. - /// A logger. - /// The plan can be executed. - public MigrationPlan(string name, IMigrationBuilder migrationBuilder, ILogger logger) - { - if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullOrEmptyException(nameof(name)); - Name = name; - _migrationBuilder = migrationBuilder ?? throw new ArgumentNullException(nameof(migrationBuilder)); - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - - // ReSharper disable once VirtualMemberCallInConstructor - // (accepted) - DefinePlan(); - } - /// /// Defines the plan. /// @@ -253,43 +230,48 @@ namespace Umbraco.Core.Migrations /// /// A scope. /// The state to start execution at. + /// A migration builder. + /// A logger. /// The final state. /// The plan executes within the scope, which must then be completed. - public string Execute(IScope scope, string fromState) + public string Execute(IScope scope, string fromState, IMigrationBuilder migrationBuilder, ILogger logger) { Validate(); - if (_migrationBuilder == null || _logger == null) - throw new InvalidOperationException("Cannot execute a non-executing plan."); + if (migrationBuilder == null || logger == null) + throw new InvalidOperationException("Cannot execute a non-executable plan."); - _logger.Info("Starting '{MigrationName}'...", Name); + logger.Info("Starting '{MigrationName}'...", Name); var origState = fromState ?? string.Empty; - _logger.Info("At {OrigState}", string.IsNullOrWhiteSpace(origState) ? "origin": origState); + logger.Info("At {OrigState}", string.IsNullOrWhiteSpace(origState) ? "origin": origState); if (!_transitions.TryGetValue(origState, out var transition)) throw new Exception($"Unknown state \"{origState}\"."); - var context = new MigrationContext(scope.Database, _logger); + var context = new MigrationContext(scope.Database, logger); while (transition != null) { - var migration = _migrationBuilder.Build(transition.MigrationType, context); + var migration = migrationBuilder.Build(transition.MigrationType, context); migration.Migrate(); var nextState = transition.TargetState; origState = nextState; - _logger.Info("At {OrigState}", origState); + logger.Info("At {OrigState}", origState); if (!_transitions.TryGetValue(origState, out transition)) throw new Exception($"Unknown state \"{origState}\"."); } - _logger.Info("Done (pending scope completion)."); + logger.Info("Done (pending scope completion)."); + + // safety check + if (origState != _finalState) + throw new Exception($"Internal error, reached state {origState} which is not final state {_finalState}"); - // fixme - what about post-migrations? return origState; } diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index e907ce09ab..15a329d75a 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -2,7 +2,6 @@ using System.Configuration; using Semver; using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; using Umbraco.Core.Migrations.Upgrade.V_7_12_0; using Umbraco.Core.Migrations.Upgrade.V_8_0_0; @@ -20,13 +19,6 @@ namespace Umbraco.Core.Migrations.Upgrade : base(Constants.System.UmbracoUpgradePlanName) { } - /// - /// Initializes a new instance of the class. - /// - public UmbracoPlan(IMigrationBuilder migrationBuilder, ILogger logger) - : base(Constants.System.UmbracoUpgradePlanName, migrationBuilder, logger) - { } - /// /// /// The default initial state in plans is string.Empty. diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoUpgrader.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoUpgrader.cs index b78aec9cd4..99c4821680 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoUpgrader.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoUpgrader.cs @@ -8,37 +8,37 @@ using Umbraco.Core.Services; namespace Umbraco.Core.Migrations.Upgrade { + /// + /// Represents the Umbraco upgrader. + /// public class UmbracoUpgrader : Upgrader { - private readonly PostMigrationCollection _postMigrations; + private PostMigrationCollection _postMigrations; - public UmbracoUpgrader(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, PostMigrationCollection postMigrations, ILogger logger) - : base(scopeProvider, migrationBuilder, keyValueService, logger) + /// + protected override MigrationPlan CreatePlan() => new UmbracoPlan(); + + /// + /// Executes. + /// + public void Execute(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, ILogger logger, PostMigrationCollection postMigrations) { - _postMigrations = postMigrations ?? throw new ArgumentNullException(nameof(postMigrations)); + _postMigrations = postMigrations; + Execute(scopeProvider, migrationBuilder, keyValueService, logger); } - protected override MigrationPlan CreatePlan() + /// + public override void AfterMigrations(IScope scope, ILogger logger) { - return new UmbracoPlan(MigrationBuilder, Logger); - } - - protected (SemVersion, SemVersion) GetVersions() - { - // assume we have something in web.config that makes some sense - if (!SemVersion.TryParse(ConfigurationManager.AppSettings["umbracoConfigurationStatus"], out var currentVersion)) + // assume we have something in web.config that makes some sense = the origin version + if (!SemVersion.TryParse(ConfigurationManager.AppSettings["umbracoConfigurationStatus"], out var originVersion)) throw new InvalidOperationException("Could not get current version from web.config umbracoConfigurationStatus appSetting."); - return (currentVersion, UmbracoVersion.SemanticVersion); - } - - public override void AfterMigrations(IScope scope) - { - // run post-migrations - var (originVersion, targetVersion) = GetVersions(); + // target version is the code version + var targetVersion = UmbracoVersion.SemanticVersion; foreach (var postMigration in _postMigrations) - postMigration.Execute(Name, scope, originVersion, targetVersion, Logger); + postMigration.Execute(Name, scope, originVersion, targetVersion, logger); } } } diff --git a/src/Umbraco.Core/Migrations/Upgrade/Upgrader.cs b/src/Umbraco.Core/Migrations/Upgrade/Upgrader.cs index 49f36a5099..4b966a5d80 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/Upgrader.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/Upgrader.cs @@ -6,73 +6,49 @@ using Umbraco.Core.Services; namespace Umbraco.Core.Migrations.Upgrade { /// - /// Provides a base class for upgraders. + /// Provides an abstract base class for creating upgraders. /// public abstract class Upgrader { - private readonly IKeyValueService _keyValueService; private MigrationPlan _plan; - /// - /// Initializes a new instance of the class. - /// - protected Upgrader(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, ILogger logger) - { - ScopeProvider = scopeProvider ?? throw new ArgumentNullException(nameof(scopeProvider)); - MigrationBuilder = migrationBuilder ?? throw new ArgumentNullException(nameof(migrationBuilder)); - _keyValueService = keyValueService ?? throw new ArgumentNullException(nameof(keyValueService)); - Logger = logger ?? throw new ArgumentNullException(nameof(logger)); - } - /// /// Gets the name of the migration plan. /// public string Name => Plan.Name; - /// - /// Gets the state value key corresponding to the migration plan. - /// - public string StateValueKey => GetStateValueKey(Plan); - - /// - /// Gets the scope provider. - /// - protected IScopeProvider ScopeProvider { get; } - - /// - /// Gets the migration builder. - /// - protected IMigrationBuilder MigrationBuilder { get; } - - /// - /// Gets the logger. - /// - protected ILogger Logger { get; } - /// /// Gets the migration plan. /// - protected MigrationPlan Plan => _plan ?? (_plan = CreatePlan()); + public MigrationPlan Plan => _plan ?? (_plan = CreatePlan()); /// /// Creates the migration plan. /// - /// protected abstract MigrationPlan CreatePlan(); + /// + /// Gets the key for the state value. + /// + public virtual string StateValueKey => "Umbraco.Core.Upgrader.State+" + Name; + /// /// Executes. /// - public void Execute() + /// A scope provider. + /// A migration builder. + /// A key-value service. + /// A logger. + public void Execute(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, ILogger logger) { var plan = Plan; - using (var scope = ScopeProvider.CreateScope()) + using (var scope = scopeProvider.CreateScope()) { - BeforeMigrations(scope); + BeforeMigrations(scope, logger); // read current state - var currentState = _keyValueService.GetValue(StateValueKey); + var currentState = keyValueService.GetValue(StateValueKey); var forceState = false; if (currentState == null) @@ -82,17 +58,17 @@ namespace Umbraco.Core.Migrations.Upgrade } // execute plan - var state = plan.Execute(scope, currentState); + var state = plan.Execute(scope, currentState, migrationBuilder, logger); if (string.IsNullOrWhiteSpace(state)) throw new Exception("Plan execution returned an invalid null or empty state."); // save new state if (forceState) - _keyValueService.SetValue(StateValueKey, state); + keyValueService.SetValue(StateValueKey, state); else if (currentState != state) - _keyValueService.SetValue(StateValueKey, currentState, state); + keyValueService.SetValue(StateValueKey, currentState, state); - AfterMigrations(scope); + AfterMigrations(scope, logger); scope.Complete(); } @@ -101,18 +77,14 @@ namespace Umbraco.Core.Migrations.Upgrade /// /// Executes as part of the upgrade scope and before all migrations have executed. /// - public virtual void BeforeMigrations(IScope scope) + public virtual void BeforeMigrations(IScope scope, ILogger logger) { } /// /// Executes as part of the upgrade scope and after all migrations have executed. /// - public virtual void AfterMigrations(IScope scope) + public virtual void AfterMigrations(IScope scope, ILogger logger) { } - /// - /// Gets the state value key for a migration plan. - /// - public static string GetStateValueKey(MigrationPlan plan) => "Umbraco.Core.Upgrader.State+" + plan.Name; } } diff --git a/src/Umbraco.Core/Runtime/CoreRuntime.cs b/src/Umbraco.Core/Runtime/CoreRuntime.cs index cc35543b66..dde91ad385 100755 --- a/src/Umbraco.Core/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Core/Runtime/CoreRuntime.cs @@ -389,14 +389,14 @@ namespace Umbraco.Core.Runtime protected virtual bool EnsureUmbracoUpgradeState(IUmbracoDatabaseFactory databaseFactory, ILogger logger) { - var umbracoPlan = new UmbracoPlan(); - var stateValueKey = Upgrader.GetStateValueKey(umbracoPlan); + var upgrader = new UmbracoUpgrader(); + var stateValueKey = upgrader.StateValueKey; // no scope, no service - just directly accessing the database using (var database = databaseFactory.CreateDatabase()) { _state.CurrentMigrationState = KeyValueService.GetValue(database, stateValueKey); - _state.FinalMigrationState = umbracoPlan.FinalState; + _state.FinalMigrationState = upgrader.Plan.FinalState; } logger.Debug("Final upgrade state is {FinalMigrationState}, database contains {DatabaseState}", _state.FinalMigrationState, _state.CurrentMigrationState ?? ""); diff --git a/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs b/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs index f6dc3e1063..07776fdee1 100644 --- a/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs +++ b/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs @@ -34,12 +34,12 @@ namespace Umbraco.Tests.Migrations using (var scope = ScopeProvider.CreateScope()) { - var upgrader = new MigrationTests.TestUpgrader(ScopeProvider, builder, Mock.Of(), logger, - new MigrationPlan("test", builder, logger) + var upgrader = new MigrationTests.TestUpgrader( + new MigrationPlan("test") .From(string.Empty) .To("done")); - upgrader.Execute(); + upgrader.Execute(ScopeProvider, builder, Mock.Of(), logger); var helper = new DatabaseSchemaCreator(scope.Database, logger); var exists = helper.TableExists("umbracoUser"); @@ -72,13 +72,13 @@ namespace Umbraco.Tests.Migrations using (var scope = ScopeProvider.CreateScope()) { - var upgrader = new MigrationTests.TestUpgrader(ScopeProvider, builder, Mock.Of(), logger, - new MigrationPlan("test", builder, logger) + var upgrader = new MigrationTests.TestUpgrader( + new MigrationPlan("test") .From(string.Empty) .To("a") .To("done")); - upgrader.Execute(); + upgrader.Execute(ScopeProvider, builder, Mock.Of(), logger); scope.Complete(); } } @@ -108,14 +108,14 @@ namespace Umbraco.Tests.Migrations using (var scope = ScopeProvider.CreateScope()) { - var upgrader = new MigrationTests.TestUpgrader(ScopeProvider, builder, Mock.Of(), logger, - new MigrationPlan("test", builder, logger) + var upgrader = new MigrationTests.TestUpgrader( + new MigrationPlan("test") .From(string.Empty) .To("a") .To("b") .To("done")); - upgrader.Execute(); + upgrader.Execute(ScopeProvider, builder, Mock.Of(), logger); scope.Complete(); } } @@ -145,14 +145,14 @@ namespace Umbraco.Tests.Migrations using (var scope = ScopeProvider.CreateScope()) { - var upgrader = new MigrationTests.TestUpgrader(ScopeProvider, builder, Mock.Of(), logger, - new MigrationPlan("test", builder, logger) + var upgrader = new MigrationTests.TestUpgrader( + new MigrationPlan("test") .From(string.Empty) .To("a") .To("b") .To("done")); - upgrader.Execute(); + upgrader.Execute(ScopeProvider, builder, Mock.Of(), logger); scope.Complete(); } } @@ -180,13 +180,13 @@ namespace Umbraco.Tests.Migrations using (var scope = ScopeProvider.CreateScope()) { - var upgrader = new MigrationTests.TestUpgrader(ScopeProvider, builder, Mock.Of(), logger, - new MigrationPlan("test", builder, logger) + var upgrader = new MigrationTests.TestUpgrader( + new MigrationPlan("test") .From(string.Empty) .To("a") .To("done")); - upgrader.Execute(); + upgrader.Execute(ScopeProvider, builder, Mock.Of(), logger); scope.Complete(); } } diff --git a/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs b/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs index b246472ee5..d6ac7abff4 100644 --- a/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs +++ b/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs @@ -46,10 +46,7 @@ namespace Umbraco.Tests.Migrations } }); - // fixme - NOT a migration collection builder, just a migration builder - // done, remove everywhere else, and delete migrationCollection stuff entirely - - var plan = new MigrationPlan("default", migrationBuilder, logger) + var plan = new MigrationPlan("default") .From(string.Empty) .To("{4A9A1A8F-0DA1-4BCF-AD06-C19D79152E35}") .To("VERSION.33"); @@ -64,7 +61,7 @@ namespace Umbraco.Tests.Migrations var sourceState = kvs.GetValue("Umbraco.Tests.MigrationPlan") ?? string.Empty; // execute plan - state = plan.Execute(s, sourceState); + state = plan.Execute(s, sourceState, migrationBuilder, logger); // save new state kvs.SetValue("Umbraco.Tests.MigrationPlan", sourceState, state); @@ -81,7 +78,7 @@ namespace Umbraco.Tests.Migrations [Test] public void CanAddMigrations() { - var plan = new MigrationPlan("default", Mock.Of(), Mock.Of()); + var plan = new MigrationPlan("default"); plan .From(string.Empty) .To("aaa") @@ -92,7 +89,7 @@ namespace Umbraco.Tests.Migrations [Test] public void CannotTransitionToSameState() { - var plan = new MigrationPlan("default", Mock.Of(), Mock.Of()); + var plan = new MigrationPlan("default"); Assert.Throws(() => { plan.From("aaa").To("aaa"); @@ -102,7 +99,7 @@ namespace Umbraco.Tests.Migrations [Test] public void OnlyOneTransitionPerState() { - var plan = new MigrationPlan("default", Mock.Of(), Mock.Of()); + var plan = new MigrationPlan("default"); plan.From("aaa").To("bbb"); Assert.Throws(() => { @@ -113,7 +110,7 @@ namespace Umbraco.Tests.Migrations [Test] public void CannotContainTwoMoreHeads() { - var plan = new MigrationPlan("default", Mock.Of(), Mock.Of()); + var plan = new MigrationPlan("default"); plan .From(string.Empty) .To("aaa") @@ -126,7 +123,7 @@ namespace Umbraco.Tests.Migrations [Test] public void CannotContainLoops() { - var plan = new MigrationPlan("default", Mock.Of(), Mock.Of()); + var plan = new MigrationPlan("default"); plan .From("aaa") .To("bbb") @@ -138,7 +135,7 @@ namespace Umbraco.Tests.Migrations [Test] public void ValidateUmbracoPlan() { - var plan = new UmbracoPlan(Mock.Of(), Mock.Of()); + var plan = new UmbracoPlan(); plan.Validate(); Console.WriteLine(plan.FinalState); Assert.IsFalse(string.IsNullOrWhiteSpace(plan.FinalState)); diff --git a/src/Umbraco.Tests/Migrations/MigrationTests.cs b/src/Umbraco.Tests/Migrations/MigrationTests.cs index 4fc2928033..c539cd0c7d 100644 --- a/src/Umbraco.Tests/Migrations/MigrationTests.cs +++ b/src/Umbraco.Tests/Migrations/MigrationTests.cs @@ -1,8 +1,10 @@ using System; +using System.Configuration; using System.Data; using Moq; using NUnit.Framework; using Semver; +using Umbraco.Core.Configuration; using Umbraco.Core.Events; using Umbraco.Core.Migrations; using Umbraco.Core.Migrations.Upgrade; @@ -20,8 +22,7 @@ namespace Umbraco.Tests.Migrations { private readonly MigrationPlan _plan; - public TestUpgrader(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, ILogger logger, MigrationPlan plan) - : base(scopeProvider, migrationBuilder, keyValueService, logger) + public TestUpgrader(MigrationPlan plan) { _plan = plan; } @@ -34,22 +35,27 @@ namespace Umbraco.Tests.Migrations public class TestUpgraderWithPostMigrations : TestUpgrader { - private readonly PostMigrationCollection _postMigrations; + private PostMigrationCollection _postMigrations; - public TestUpgraderWithPostMigrations(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, ILogger logger, PostMigrationCollection postMigrations, MigrationPlan plan) - : base(scopeProvider, migrationBuilder, keyValueService, logger, plan) + public TestUpgraderWithPostMigrations(MigrationPlan plan) + : base(plan) + { } + + public void Execute(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, ILogger logger, PostMigrationCollection postMigrations) { _postMigrations = postMigrations; + Execute(scopeProvider, migrationBuilder, keyValueService, logger); } - public override void AfterMigrations(IScope scope) + public override void AfterMigrations(IScope scope, ILogger logger) { // run post-migrations var originVersion = new SemVersion(0); var targetVersion = new SemVersion(0); + // run post-migrations foreach (var postMigration in _postMigrations) - postMigration.Execute(Name, scope, originVersion, targetVersion, Logger); + postMigration.Execute(Name, scope, originVersion, targetVersion, logger); } } diff --git a/src/Umbraco.Tests/Migrations/PostMigrationTests.cs b/src/Umbraco.Tests/Migrations/PostMigrationTests.cs index 5b7ec004d5..95f1f8afac 100644 --- a/src/Umbraco.Tests/Migrations/PostMigrationTests.cs +++ b/src/Umbraco.Tests/Migrations/PostMigrationTests.cs @@ -50,9 +50,9 @@ namespace Umbraco.Tests.Migrations var sqlContext = new SqlContext(new SqlCeSyntaxProvider(), DatabaseType.SQLCe, Mock.Of()); var scopeProvider = new MigrationTests.TestScopeProvider(scope) { SqlContext = sqlContext }; - var u1 = new MigrationTests.TestUpgraderWithPostMigrations(scopeProvider, builder, Mock.Of(), logger, posts, - new MigrationPlan("Test", builder, logger).From(string.Empty).To("done")); - u1.Execute(); + var u1 = new MigrationTests.TestUpgraderWithPostMigrations( + new MigrationPlan("Test").From(string.Empty).To("done")); + u1.Execute(scopeProvider, builder, Mock.Of(), logger, posts); Assert.AreEqual(1, changed1.CountExecuted); } @@ -93,16 +93,16 @@ namespace Umbraco.Tests.Migrations var sqlContext = new SqlContext(new SqlCeSyntaxProvider(), DatabaseType.SQLCe, Mock.Of()); var scopeProvider = new MigrationTests.TestScopeProvider(scope) { SqlContext = sqlContext }; - var u1 = new MigrationTests.TestUpgraderWithPostMigrations(scopeProvider, builder, Mock.Of(), logger, posts, - new MigrationPlan("Test1", builder, logger).From(string.Empty).To("done")); - u1.Execute(); + var u1 = new MigrationTests.TestUpgraderWithPostMigrations( + new MigrationPlan("Test1").From(string.Empty).To("done")); + u1.Execute(scopeProvider, builder, Mock.Of(), logger, posts); Assert.AreEqual(1, changed1.CountExecuted); Assert.AreEqual(0, changed2.CountExecuted); - var u2 = new MigrationTests.TestUpgraderWithPostMigrations(scopeProvider, builder, Mock.Of(), logger, posts, - new MigrationPlan("Test2", builder, logger).From(string.Empty).To("done")); - u2.Execute(); + var u2 = new MigrationTests.TestUpgraderWithPostMigrations( + new MigrationPlan("Test2").From(string.Empty).To("done")); + u2.Execute(scopeProvider, builder, Mock.Of(), logger, posts); Assert.AreEqual(1, changed1.CountExecuted); Assert.AreEqual(1, changed2.CountExecuted); From b086fd2f0bb083f6bf7e2b9ba1eedcde551f0801 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 4 Jul 2018 18:19:06 +0200 Subject: [PATCH 40/54] Cleanup the Umbraco migration plan --- src/Umbraco.Core/Migrations/MigrationPlan.cs | 49 +++++++++++++++++-- .../Migrations/Upgrade/Upgrader.cs | 5 ++ .../Migrations/MigrationPlanTests.cs | 36 ++++++++++++++ 3 files changed, 87 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Core/Migrations/MigrationPlan.cs b/src/Umbraco.Core/Migrations/MigrationPlan.cs index 68402de85f..49edf6cc05 100644 --- a/src/Umbraco.Core/Migrations/MigrationPlan.cs +++ b/src/Umbraco.Core/Migrations/MigrationPlan.cs @@ -4,6 +4,7 @@ using System.Linq; using Umbraco.Core.Exceptions; using Umbraco.Core.Logging; using Umbraco.Core.Scoping; +using Type = System.Type; namespace Umbraco.Core.Migrations { @@ -31,6 +32,11 @@ namespace Umbraco.Core.Migrations DefinePlan(); } + /// + /// Gets the transitions. + /// + public IReadOnlyDictionary Transitions => _transitions; + /// /// Defines the plan. /// @@ -238,8 +244,8 @@ namespace Umbraco.Core.Migrations { Validate(); - if (migrationBuilder == null || logger == null) - throw new InvalidOperationException("Cannot execute a non-executable plan."); + if (migrationBuilder == null) throw new ArgumentNullException(nameof(migrationBuilder)); + if (logger == null) throw new ArgumentNullException(nameof(logger)); logger.Info("Starting '{MigrationName}'...", Name); @@ -275,10 +281,47 @@ namespace Umbraco.Core.Migrations return origState; } + /// + /// Follows a path (for tests and debugging). + /// + /// Does the same thing Execute does, but does not actually execute migrations. + internal string FollowPath(string fromState, string toState = null) + { + toState = toState.NullOrWhiteSpaceAsNull(); + + Validate(); + + var origState = fromState ?? string.Empty; + + if (!_transitions.TryGetValue(origState, out var transition)) + throw new Exception($"Unknown state \"{origState}\"."); + + while (transition != null) + { + var nextState = transition.TargetState; + origState = nextState; + + if (nextState == toState) + { + transition = null; + continue; + } + + if (!_transitions.TryGetValue(origState, out transition)) + throw new Exception($"Unknown state \"{origState}\"."); + } + + // safety check + if (origState != (toState ?? _finalState)) + throw new Exception($"Internal error, reached state {origState} which is not state {toState ?? _finalState}"); + + return origState; + } + /// /// Represents a plan transition. /// - private class Transition + public class Transition { /// /// Initializes a new instance of the class. diff --git a/src/Umbraco.Core/Migrations/Upgrade/Upgrader.cs b/src/Umbraco.Core/Migrations/Upgrade/Upgrader.cs index 4b966a5d80..3795ed79af 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/Upgrader.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/Upgrader.cs @@ -41,6 +41,11 @@ namespace Umbraco.Core.Migrations.Upgrade /// A logger. public void Execute(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, ILogger logger) { + if (scopeProvider == null) throw new ArgumentNullException(nameof(scopeProvider)); + if (migrationBuilder == null) throw new ArgumentNullException(nameof(migrationBuilder)); + if (keyValueService == null) throw new ArgumentNullException(nameof(keyValueService)); + if (logger == null) throw new ArgumentNullException(nameof(logger)); + var plan = Plan; using (var scope = scopeProvider.CreateScope()) diff --git a/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs b/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs index d6ac7abff4..9aec42c252 100644 --- a/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs +++ b/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs @@ -1,7 +1,9 @@ using System; +using System.Linq; using Moq; using NPoco; using NUnit.Framework; +using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Migrations; using Umbraco.Core.Migrations.Upgrade; @@ -141,6 +143,40 @@ namespace Umbraco.Tests.Migrations Assert.IsFalse(string.IsNullOrWhiteSpace(plan.FinalState)); } + [Test] + public void CanCopyChain() + { + var plan = new MigrationPlan("default"); + plan + .From(string.Empty) + .To("aaa") + .To("bbb") + .To("ccc") + .To("ddd") + .To("eee"); + + plan + .From("xxx") + .To("yyy", "bbb", "ddd") + .To("eee"); + + WritePlanToConsole(plan); + + plan.Validate(); + Assert.AreEqual("eee", plan.FollowPath("xxx")); + Assert.AreEqual("yyy", plan.FollowPath("xxx", "yyy")); + } + + private void WritePlanToConsole(MigrationPlan plan) + { + var final = plan.Transitions.First(x => x.Value == null).Key; + + Console.WriteLine("plan \"{0}\" to final state \"{1}\":", plan.Name, final); + foreach (var (_, transition) in plan.Transitions) + if (transition != null) + Console.WriteLine(transition); + } + public class DeleteRedirectUrlTable : MigrationBase { public DeleteRedirectUrlTable(IMigrationContext context) From b60cda2e1bfaa7ae4b04752067891df4a92718e4 Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 4 Dec 2018 18:50:21 +0100 Subject: [PATCH 41/54] Add a missing null check --- src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs b/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs index 6f814a7174..ff5e1dec0e 100644 --- a/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs +++ b/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs @@ -1136,7 +1136,7 @@ namespace Umbraco.Core.Persistence { text.AppendLine(sql); - if (arguments.Length == 0) + if (arguments == null || arguments.Length == 0) return; text.Append(" --"); From 376203a4e10dcb99b5371f2cd9bbb3cb610fb20e Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 6 Dec 2018 07:48:26 +0100 Subject: [PATCH 42/54] Further simplify upgrader --- .../Migrations/Upgrade/UmbracoUpgrader.cs | 8 ++++++-- .../Migrations/Upgrade/Upgrader.cs | 19 ++++++++++--------- .../Migrations/AdvancedMigrationTests.cs | 11 ++++++----- .../Migrations/MigrationTests.cs | 19 +------------------ 4 files changed, 23 insertions(+), 34 deletions(-) diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoUpgrader.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoUpgrader.cs index 99c4821680..fa29e80a6b 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoUpgrader.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoUpgrader.cs @@ -15,8 +15,12 @@ namespace Umbraco.Core.Migrations.Upgrade { private PostMigrationCollection _postMigrations; - /// - protected override MigrationPlan CreatePlan() => new UmbracoPlan(); + /// + /// Initializes a new instance of the class. + /// + public UmbracoUpgrader() + : base(new UmbracoPlan()) + { } /// /// Executes. diff --git a/src/Umbraco.Core/Migrations/Upgrade/Upgrader.cs b/src/Umbraco.Core/Migrations/Upgrade/Upgrader.cs index 3795ed79af..f6df52bc1e 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/Upgrader.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/Upgrader.cs @@ -6,11 +6,17 @@ using Umbraco.Core.Services; namespace Umbraco.Core.Migrations.Upgrade { /// - /// Provides an abstract base class for creating upgraders. + /// Represents an upgrader. /// - public abstract class Upgrader + public class Upgrader { - private MigrationPlan _plan; + /// + /// Initializes a new instance of the class. + /// + public Upgrader(MigrationPlan plan) + { + Plan = plan; + } /// /// Gets the name of the migration plan. @@ -20,12 +26,7 @@ namespace Umbraco.Core.Migrations.Upgrade /// /// Gets the migration plan. /// - public MigrationPlan Plan => _plan ?? (_plan = CreatePlan()); - - /// - /// Creates the migration plan. - /// - protected abstract MigrationPlan CreatePlan(); + public MigrationPlan Plan { get; } /// /// Gets the key for the state value. diff --git a/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs b/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs index 07776fdee1..5ff0dcffc1 100644 --- a/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs +++ b/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs @@ -5,6 +5,7 @@ using NUnit.Framework; using Umbraco.Core.Logging; using Umbraco.Core.Migrations; using Umbraco.Core.Migrations.Install; +using Umbraco.Core.Migrations.Upgrade; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Services; @@ -34,7 +35,7 @@ namespace Umbraco.Tests.Migrations using (var scope = ScopeProvider.CreateScope()) { - var upgrader = new MigrationTests.TestUpgrader( + var upgrader = new Upgrader( new MigrationPlan("test") .From(string.Empty) .To("done")); @@ -72,7 +73,7 @@ namespace Umbraco.Tests.Migrations using (var scope = ScopeProvider.CreateScope()) { - var upgrader = new MigrationTests.TestUpgrader( + var upgrader = new Upgrader( new MigrationPlan("test") .From(string.Empty) .To("a") @@ -108,7 +109,7 @@ namespace Umbraco.Tests.Migrations using (var scope = ScopeProvider.CreateScope()) { - var upgrader = new MigrationTests.TestUpgrader( + var upgrader = new Upgrader( new MigrationPlan("test") .From(string.Empty) .To("a") @@ -145,7 +146,7 @@ namespace Umbraco.Tests.Migrations using (var scope = ScopeProvider.CreateScope()) { - var upgrader = new MigrationTests.TestUpgrader( + var upgrader = new Upgrader( new MigrationPlan("test") .From(string.Empty) .To("a") @@ -180,7 +181,7 @@ namespace Umbraco.Tests.Migrations using (var scope = ScopeProvider.CreateScope()) { - var upgrader = new MigrationTests.TestUpgrader( + var upgrader = new Upgrader( new MigrationPlan("test") .From(string.Empty) .To("a") diff --git a/src/Umbraco.Tests/Migrations/MigrationTests.cs b/src/Umbraco.Tests/Migrations/MigrationTests.cs index c539cd0c7d..8e84f88265 100644 --- a/src/Umbraco.Tests/Migrations/MigrationTests.cs +++ b/src/Umbraco.Tests/Migrations/MigrationTests.cs @@ -1,10 +1,8 @@ using System; -using System.Configuration; using System.Data; using Moq; using NUnit.Framework; using Semver; -using Umbraco.Core.Configuration; using Umbraco.Core.Events; using Umbraco.Core.Migrations; using Umbraco.Core.Migrations.Upgrade; @@ -18,22 +16,7 @@ namespace Umbraco.Tests.Migrations [TestFixture] public class MigrationTests { - public class TestUpgrader : Upgrader - { - private readonly MigrationPlan _plan; - - public TestUpgrader(MigrationPlan plan) - { - _plan = plan; - } - - protected override MigrationPlan CreatePlan() - { - return _plan; - } - } - - public class TestUpgraderWithPostMigrations : TestUpgrader + public class TestUpgraderWithPostMigrations : Upgrader { private PostMigrationCollection _postMigrations; From 54c352f1f96873f8fbd076e5baede56a28725ea3 Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 6 Dec 2018 07:54:53 +0100 Subject: [PATCH 43/54] Kill sql.WriteToConsole --- src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs | 5 ----- src/Umbraco.Core/Persistence/SqlTemplate.cs | 5 +++-- .../Persistence/NPocoTests/NPocoFetchTests.cs | 2 -- .../NPocoTests/NPocoSqlExtensionsTests.cs | 1 - .../NPocoTests/NPocoSqlTemplateTests.cs | 14 ++++---------- .../Persistence/NPocoTests/NPocoSqlTests.cs | 2 -- .../Persistence/Querying/QueryBuilderTests.cs | 2 -- 7 files changed, 7 insertions(+), 24 deletions(-) diff --git a/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs b/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs index ff5e1dec0e..9ce7bd9fee 100644 --- a/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs +++ b/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs @@ -1115,11 +1115,6 @@ namespace Umbraco.Core.Persistence return string.IsNullOrWhiteSpace(attr?.Name) ? column.Name : attr.Name; } - internal static void WriteToConsole(this Sql sql) - { - Console.Write(sql.ToText()); - } - internal static string ToText(this Sql sql) { var text = new StringBuilder(); diff --git a/src/Umbraco.Core/Persistence/SqlTemplate.cs b/src/Umbraco.Core/Persistence/SqlTemplate.cs index 7304f45e7f..e81da20f41 100644 --- a/src/Umbraco.Core/Persistence/SqlTemplate.cs +++ b/src/Umbraco.Core/Persistence/SqlTemplate.cs @@ -95,9 +95,10 @@ namespace Umbraco.Core.Persistence return new Sql(_sqlContext, isBuilt, _sql, args); } - internal void WriteToConsole() + internal string ToText() { - new Sql(_sqlContext, _sql, _args.Values.ToArray()).WriteToConsole(); + var sql = new Sql(_sqlContext, _sql, _args.Values.ToArray()); + return sql.ToText(); } /// diff --git a/src/Umbraco.Tests/Persistence/NPocoTests/NPocoFetchTests.cs b/src/Umbraco.Tests/Persistence/NPocoTests/NPocoFetchTests.cs index f33ee563b4..64bc825c3e 100644 --- a/src/Umbraco.Tests/Persistence/NPocoTests/NPocoFetchTests.cs +++ b/src/Umbraco.Tests/Persistence/NPocoTests/NPocoFetchTests.cs @@ -403,7 +403,6 @@ namespace Umbraco.Tests.Persistence.NPocoTests .From() .Where(x => x.Id == 1); - sql.WriteToConsole(); var dto = scope.Database.Fetch(sql).FirstOrDefault(); Assert.IsNotNull(dto); Assert.AreEqual("one", dto.Name); @@ -415,7 +414,6 @@ namespace Umbraco.Tests.Persistence.NPocoTests //Assert.AreEqual("one", dto.Name); var sql3 = new Sql(sql.SQL, 1); - sql.WriteToConsole(); dto = scope.Database.Fetch(sql3).FirstOrDefault(); Assert.IsNotNull(dto); Assert.AreEqual("one", dto.Name); diff --git a/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlExtensionsTests.cs b/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlExtensionsTests.cs index 458479b293..36b850d24d 100644 --- a/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlExtensionsTests.cs +++ b/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlExtensionsTests.cs @@ -117,7 +117,6 @@ INNER JOIN [dto2] ON [dto1].[id] = [dto2].[dto1id]".NoCrLf(), sql.SQL.NoCrLf()); var sql = Sql() .Update(u => u.Set(x => x.EditorAlias, "Umbraco.ColorPicker")) .Where(x => x.EditorAlias == "Umbraco.ColorPickerAlias"); - sql.WriteToConsole(); } [TableName("dto1")] diff --git a/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlTemplateTests.cs b/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlTemplateTests.cs index ac6df7897d..b24642e88b 100644 --- a/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlTemplateTests.cs +++ b/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlTemplateTests.cs @@ -27,15 +27,9 @@ namespace Umbraco.Tests.Persistence.NPocoTests .From("zbThing1") .Where("id=@id", new { id = SqlTemplate.Arg("id") })).Sql(new { id = 1 }); - sql.WriteToConsole(); - var sql2 = sqlTemplates.Get("xxx", x => throw new InvalidOperationException("Should be cached.")).Sql(1); - sql2.WriteToConsole(); - var sql3 = sqlTemplates.Get("xxx", x => throw new InvalidOperationException("Should be cached.")).Sql(new { id = 1 }); - - sql3.WriteToConsole(); } [Test] @@ -75,8 +69,8 @@ namespace Umbraco.Tests.Persistence.NPocoTests Assert.AreEqual(1, sql.Arguments.Length); Assert.AreEqual(123, sql.Arguments[0]); - Assert.Throws(() => template.Sql(new { xvalue = 123 }).WriteToConsole()); - Assert.Throws(() => template.Sql(new { value = 123, xvalue = 456 }).WriteToConsole()); + Assert.Throws(() => template.Sql(new { xvalue = 123 })); + Assert.Throws(() => template.Sql(new { value = 123, xvalue = 456 })); var i = 666; @@ -121,8 +115,8 @@ namespace Umbraco.Tests.Persistence.NPocoTests Assert.AreEqual(1, sql.Arguments.Length); Assert.AreEqual(123, sql.Arguments[0]); - Assert.Throws(() => template.Sql(new { j = 123 }).WriteToConsole()); - Assert.Throws(() => template.Sql(new { i = 123, j = 456 }).WriteToConsole()); + Assert.Throws(() => template.Sql(new { j = 123 })); + Assert.Throws(() => template.Sql(new { i = 123, j = 456 })); // now with more arguments diff --git a/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlTests.cs b/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlTests.cs index 6fa2af74cf..a04984eb64 100644 --- a/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlTests.cs +++ b/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlTests.cs @@ -305,12 +305,10 @@ namespace Umbraco.Tests.Persistence.NPocoTests .From() .Where(x => x.SessionId == sessionId); - sql.WriteToConsole(); Assert.AreEqual("SELECT * FROM [umbracoUserLogin] WHERE (([umbracoUserLogin].[sessionId] = @0))", sql.SQL.NoCrLf()); sql = sql.ForUpdate(); - sql.WriteToConsole(); Assert.AreEqual("SELECT * FROM [umbracoUserLogin] WITH (UPDLOCK) WHERE (([umbracoUserLogin].[sessionId] = @0))", sql.SQL.NoCrLf()); } } diff --git a/src/Umbraco.Tests/Persistence/Querying/QueryBuilderTests.cs b/src/Umbraco.Tests/Persistence/Querying/QueryBuilderTests.cs index a9928046d7..ca6b4cd5f0 100644 --- a/src/Umbraco.Tests/Persistence/Querying/QueryBuilderTests.cs +++ b/src/Umbraco.Tests/Persistence/Querying/QueryBuilderTests.cs @@ -107,8 +107,6 @@ namespace Umbraco.Tests.Persistence.Querying var translator = new SqlTranslator(sql, query); var result = translator.Translate(); - result.WriteToConsole(); - Assert.AreEqual("-1,1046,1076,1089%", result.Arguments[0]); Assert.AreEqual(1046, result.Arguments[1]); Assert.AreEqual(true, result.Arguments[2]); From a74052d647f7f08614ef6fd56d77694480630a72 Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 11 Dec 2018 10:26:58 +0100 Subject: [PATCH 44/54] Further simplify upgrader --- src/Umbraco.Core/Migrations/MigrationPlan.cs | 28 ------------------- .../Migrations/Upgrade/UmbracoPlan.cs | 8 ++++-- 2 files changed, 5 insertions(+), 31 deletions(-) diff --git a/src/Umbraco.Core/Migrations/MigrationPlan.cs b/src/Umbraco.Core/Migrations/MigrationPlan.cs index 49edf6cc05..2e2bc8b661 100644 --- a/src/Umbraco.Core/Migrations/MigrationPlan.cs +++ b/src/Umbraco.Core/Migrations/MigrationPlan.cs @@ -26,10 +26,6 @@ namespace Umbraco.Core.Migrations { if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullOrEmptyException(nameof(name)); Name = name; - - // ReSharper disable once VirtualMemberCallInConstructor - // (accepted) - DefinePlan(); } /// @@ -37,11 +33,6 @@ namespace Umbraco.Core.Migrations /// public IReadOnlyDictionary Transitions => _transitions; - /// - /// Defines the plan. - /// - protected virtual void DefinePlan() { } - /// /// Gets the name of the plan. /// @@ -145,25 +136,6 @@ namespace Umbraco.Core.Migrations return this; } - /// - /// Copies a chain. - /// - /// Copies the chain going from startState to endState, with new states going from sourceState to targetState. - [Obsolete("die", true)] - public MigrationPlan CopyChain(string sourceState, string startState, string endState, string targetState) - { - From(sourceState).To(targetState, startState, endState); - return this; - } - - /// - /// Copies a chain. - /// - /// Copies the chain going from startState to endState, with new states going from chain to targetState. - [Obsolete("die", true)] - public MigrationPlan CopyChain(string startState, string endState, string targetState) - => To(targetState, startState, endState); - /// /// Gets the initial state. /// diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index 15a329d75a..c5e24210c0 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -17,7 +17,9 @@ namespace Umbraco.Core.Migrations.Upgrade /// public UmbracoPlan() : base(Constants.System.UmbracoUpgradePlanName) - { } + { + DefinePlan(); + } /// /// @@ -53,8 +55,8 @@ namespace Umbraco.Core.Migrations.Upgrade } } - /// - protected override void DefinePlan() + // define the plan + protected void DefinePlan() { // MODIFYING THE PLAN // From 9649e61f17085aa30f04c10d7725fc47cb780d79 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Thu, 13 Dec 2018 11:54:32 +1100 Subject: [PATCH 45/54] Fixing #3866 - making a few methods public --- src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs index ea818c60e3..a54b997cb8 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs @@ -417,7 +417,7 @@ namespace Umbraco.Core.Migrations.Install #region Database Schema - internal DatabaseSchemaResult ValidateDatabaseSchema() + public DatabaseSchemaResult ValidateDatabaseSchema() { using (var scope = _scopeProvider.CreateScope()) { @@ -442,7 +442,7 @@ namespace Umbraco.Core.Migrations.Install return _databaseSchemaValidationResult; } - internal Result CreateDatabaseSchemaAndData() + public Result CreateDatabaseSchemaAndData() { using (var scope = _scopeProvider.CreateScope()) { @@ -522,7 +522,7 @@ namespace Umbraco.Core.Migrations.Install } // This assumes all of the previous checks are done! - internal Result UpgradeSchemaAndData() + public Result UpgradeSchemaAndData() { try { @@ -630,7 +630,7 @@ namespace Umbraco.Core.Migrations.Install }; } - internal class Result + public class Result { public bool RequiresUpgrade { get; set; } public string Message { get; set; } From ce3395cc1e43cf54cb41bd471f08c558dccd9be8 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 13 Dec 2018 15:13:56 +1100 Subject: [PATCH 46/54] fix build --- .../Repositories/Implement/ContentTypeRepositoryBase.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index 06fc25937b..055ed7ae74 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -790,7 +790,6 @@ AND umbracoNode.id <> @id", .Delete() .WhereIn(x => x.TagId, sqlSelectTagsToDelete); - sqlDeleteRelations.WriteToConsole(); Database.Execute(sqlDeleteRelations); // do *not* delete the tags - they could be used by other content types / property types @@ -831,7 +830,6 @@ AND umbracoNode.id <> @id", var cols = Sql().Columns(x => x.Text, x => x.Group, x => x.LanguageId); var sqlInsertTags = Sql($"INSERT INTO {TagDto.TableName} ({cols})").Append(sqlSelectTagsToInsert); - sqlInsertTags.WriteToConsole(); Database.Execute(sqlInsertTags); // create relations to new tags @@ -860,7 +858,6 @@ AND umbracoNode.id <> @id", var relationColumnsToInsert = Sql().Columns(x => x.NodeId, x => x.PropertyTypeId, x => x.TagId); var sqlInsertRelations = Sql($"INSERT INTO {TagRelationshipDto.TableName} ({relationColumnsToInsert})").Append(sqlSelectRelationsToInsert); - sqlInsertRelations.WriteToConsole(); Database.Execute(sqlInsertRelations); // delete original relations - *not* the tags - all of them @@ -884,7 +881,6 @@ AND umbracoNode.id <> @id", .Delete() .WhereIn(x => x.TagId, sqlSelectTagsToDelete); - sqlDeleteRelations.WriteToConsole(); Database.Execute(sqlDeleteRelations); // no From 96aff943d579a44b16d8fdd92aec024d5c767d34 Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 13 Dec 2018 09:15:29 +0100 Subject: [PATCH 47/54] Bugfix tags (in)variant --- .../Persistence/NPocoSqlExtensions.cs | 20 ++++++++ .../Implement/ContentTypeRepositoryBase.cs | 4 +- .../Services/ContentServiceTagsTests.cs | 47 +++++++++++++++++++ 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs b/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs index 18027bcc1b..7aa8b707be 100644 --- a/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs +++ b/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs @@ -662,6 +662,26 @@ namespace Umbraco.Core.Persistence return sql.Select(sql.GetColumns(columnExpressions: fields)); } + /// + /// Creates a SELECT DISTINCT Sql statement. + /// + /// The type of the DTO to select. + /// The origin sql. + /// Expressions indicating the columns to select. + /// The Sql statement. + /// + /// If is empty, all columns are selected. + /// + public static Sql SelectDistinct(this Sql sql, params Expression>[] fields) + { + if (sql == null) throw new ArgumentNullException(nameof(sql)); + var columns = sql.GetColumns(columnExpressions: fields); + sql.Append("SELECT DISTINCT " + string.Join(", ", columns)); + return sql; + } + + //this.Append("SELECT " + string.Join(", ", columns), new object[0]); + /// /// Creates a SELECT Sql statement. /// diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index 055ed7ae74..662254d1ee 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -809,7 +809,7 @@ AND umbracoNode.id <> @id", var targetLanguageIdS = targetLanguageId.HasValue ? targetLanguageId.ToString() : "NULL"; var sqlSelectTagsToInsert = Sql() - .Select(x => x.Text, x => x.Group) + .SelectDistinct(x => x.Text, x => x.Group) .Append(", " + targetLanguageIdS) .From(); @@ -840,7 +840,7 @@ AND umbracoNode.id <> @id", // and group, but for the target language var sqlSelectRelationsToInsert = Sql() - .Select(x => x.NodeId, x => x.PropertyTypeId) + .SelectDistinct(x => x.NodeId, x => x.PropertyTypeId) .AndSelect("otag", x => x.Id) .From() .InnerJoin().On((rel, tag) => rel.TagId == tag.Id) diff --git a/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs b/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs index 196af5c0bd..8f66e98b76 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs @@ -256,6 +256,53 @@ namespace Umbraco.Tests.Services Assert.IsFalse(enTagGroup.Any(x => x.Text == "plus")); } + [Test] + public void TagsCanBecomeInvariant2() + { + var languageService = ServiceContext.LocalizationService; + languageService.Save(new Language("fr-FR")); // en-US is already there + + var enId = ServiceContext.LocalizationService.GetLanguageIdByIsoCode("en-US").Value; + + var contentService = ServiceContext.ContentService; + var contentTypeService = ServiceContext.ContentTypeService; + var tagService = ServiceContext.TagService; + var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); + PropertyType propertyType; + contentType.PropertyGroups.First().PropertyTypes.Add( + propertyType = new PropertyType("test", ValueStorageType.Ntext, "tags") + { + DataTypeId = 1041, + Variations = ContentVariation.Culture + }); + contentType.Variations = ContentVariation.Culture; + contentTypeService.Save(contentType); + + IContent content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + content1.SetCultureName("name-fr", "fr-FR"); + content1.SetCultureName("name-en", "en-US"); + content1.AssignTags("tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); + content1.AssignTags("tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); + contentService.SaveAndPublish(content1); + + IContent content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", -1); + content2.SetCultureName("name-fr", "fr-FR"); + content2.SetCultureName("name-en", "en-US"); + content2.AssignTags("tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); + content2.AssignTags("tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); + contentService.SaveAndPublish(content2); + + //// pretend we already have invariant values + //using (var scope = ScopeProvider.CreateScope()) + //{ + // scope.Database.Execute("INSERT INTO [cmsTags] ([tag], [group], [languageId]) SELECT DISTINCT [tag], [group], NULL FROM [cmsTags] WHERE [languageId] IS NOT NULL"); + //} + + // this should work + propertyType.Variations = ContentVariation.Nothing; + Assert.DoesNotThrow(() => contentTypeService.Save(contentType)); + } + [Test] public void TagsCanBecomeInvariantByPropertyType() { From 33b9870aecb794cf6c534a2e70915a74838fd3e6 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Sun, 16 Dec 2018 21:52:45 +0100 Subject: [PATCH 48/54] Only perform save when previewing - not a publish --- .../src/common/directives/components/content/edit.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js index 407416f2a1..f1e2150579 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js @@ -815,7 +815,7 @@ //ensure the save flag is set selectedVariant.save = true; - performSave({ saveMethod: contentResource.publish, action: "save" }).then(function (data) { + performSave({ saveMethod: $scope.saveMethod(), action: "save" }).then(function (data) { previewWindow.location.href = redirect; }, function (err) { //validation issues .... From ebc689032d787e0cd6532a1ffce15a5d3ad77472 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 17 Dec 2018 10:48:33 +0100 Subject: [PATCH 49/54] fix dictionary pickers in code editors --- .../insertcodesnippet/insertcodesnippet.controller.js | 2 +- .../src/views/partialviewmacros/edit.controller.js | 2 +- .../src/views/partialviews/edit.controller.js | 2 +- .../src/views/templates/edit.controller.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/insertcodesnippet/insertcodesnippet.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/insertcodesnippet/insertcodesnippet.controller.js index 526d076048..2b40d496f5 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/insertcodesnippet/insertcodesnippet.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/insertcodesnippet/insertcodesnippet.controller.js @@ -77,7 +77,7 @@ var emptyStateMessage = values[2]; var dictionaryItemPicker = { - section: "settings", + section: "translation", treeAlias: "dictionary", entityType: "dictionary", multiPicker: false, diff --git a/src/Umbraco.Web.UI.Client/src/views/partialviewmacros/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/partialviewmacros/edit.controller.js index afc00bb7e2..372cecb36c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/partialviewmacros/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/partialviewmacros/edit.controller.js @@ -201,7 +201,7 @@ var emptyStateMessage = values[1]; var dictionaryPicker = { - section: "settings", + section: "translation", treeAlias: "dictionary", entityType: "dictionary", multiPicker: false, diff --git a/src/Umbraco.Web.UI.Client/src/views/partialviews/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/partialviews/edit.controller.js index ff14ea0ebd..292898814d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/partialviews/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/partialviews/edit.controller.js @@ -207,7 +207,7 @@ var emptyStateMessage = values[1]; var dictionaryItem = { - section: "settings", + section: "translation", treeAlias: "dictionary", entityType: "dictionary", multiPicker: false, diff --git a/src/Umbraco.Web.UI.Client/src/views/templates/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/templates/edit.controller.js index 8ac9dc78e8..1f6fb8863a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/templates/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/templates/edit.controller.js @@ -438,7 +438,7 @@ var emptyStateMessage = values[1]; var dictionaryItem = { - section: "settings", + section: "translation", treeAlias: "dictionary", entityType: "dictionary", multiPicker: false, From c020383c22a4514c93dcedffb4d42feb8346e3cb Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 13 Dec 2018 13:47:09 +0100 Subject: [PATCH 50/54] Remove confusing LazyCollectionBuilderBase.Remove --- .../Composing/LazyCollectionBuilderBase.cs | 31 ------------------- 1 file changed, 31 deletions(-) diff --git a/src/Umbraco.Core/Composing/LazyCollectionBuilderBase.cs b/src/Umbraco.Core/Composing/LazyCollectionBuilderBase.cs index 52e5a764fd..ee263f458f 100644 --- a/src/Umbraco.Core/Composing/LazyCollectionBuilderBase.cs +++ b/src/Umbraco.Core/Composing/LazyCollectionBuilderBase.cs @@ -75,37 +75,6 @@ namespace Umbraco.Core.Composing return This; } - /// - /// Removes a type from the collection. - /// - /// The type to remove. - /// The builder. - public TBuilder Remove() - where T : TItem - { - Configure(types => - { - var type = typeof(T); - if (types.Contains(type)) types.Remove(type); - }); - return This; - } - - /// - /// Removes a type from the collection. - /// - /// The type to remove. - /// The builder. - public TBuilder Remove(Type type) - { - Configure(types => - { - EnsureType(type, "remove"); - if (types.Contains(type)) types.Remove(type); - }); - return This; - } - /// /// Adds a types producer to the collection. /// From 8152862ad2b9d086b953996083453b3f15678313 Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 13 Dec 2018 15:08:12 +0100 Subject: [PATCH 51/54] Fix issue with figuring out whether a published content version is draft --- .../PublishedContent/IPublishedContent.cs | 2 +- .../PublishedContentWrapped.cs | 2 +- .../CaseInsensitiveDictionaryConverter.cs | 25 +++++++ src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../Published/NestedContentTests.cs | 2 +- .../PublishedContentDataTableTests.cs | 2 +- .../SolidPublishedSnapshot.cs | 3 +- .../TestHelpers/Stubs/TestPublishedContent.cs | 2 +- .../Models/PublishedContentBase.cs | 2 +- .../PublishedCache/NuCache/ContentCache.cs | 42 +++++------ .../NuCache/DataSource/ContentNestedData.cs | 3 + .../NuCache/DataSource/CultureVariation.cs | 3 + .../NuCache/DataSource/DatabaseDataSource.cs | 41 ++++++----- .../NuCache/Navigable/NavigableContent.cs | 2 +- .../NuCache/PublishedContent.cs | 23 +++++- .../NuCache/PublishedSnapshotService.cs | 3 +- .../PublishedCache/PublishedMember.cs | 2 +- .../DictionaryPublishedContent.cs | 2 +- .../XmlPublishedCache/XmlPublishedContent.cs | 9 +-- src/Umbraco.Web/PublishedContentExtensions.cs | 72 ++++++------------- src/Umbraco.Web/umbraco.presentation/page.cs | 4 +- 21 files changed, 136 insertions(+), 111 deletions(-) create mode 100644 src/Umbraco.Core/Serialization/CaseInsensitiveDictionaryConverter.cs diff --git a/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs b/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs index 5b604eff3f..0c049e81bf 100644 --- a/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs +++ b/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs @@ -151,7 +151,7 @@ namespace Umbraco.Core.Models.PublishedContent /// is the edited version) or false (document is published, and has not been edited, and /// what is returned is the published version). /// - bool IsDraft { get; } + bool IsDraft(string culture = null); // fixme - consider having an IsPublished flag too // so that when IsDraft is true, we can check whether there is a published version? diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs index 5bdeb3685d..6a69d0b9e1 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs @@ -109,7 +109,7 @@ namespace Umbraco.Core.Models.PublishedContent public virtual PublishedItemType ItemType => _content.ItemType; /// - public virtual bool IsDraft => _content.IsDraft; + public virtual bool IsDraft(string culture = null) => _content.IsDraft(culture); #endregion diff --git a/src/Umbraco.Core/Serialization/CaseInsensitiveDictionaryConverter.cs b/src/Umbraco.Core/Serialization/CaseInsensitiveDictionaryConverter.cs new file mode 100644 index 0000000000..a92d562a52 --- /dev/null +++ b/src/Umbraco.Core/Serialization/CaseInsensitiveDictionaryConverter.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Newtonsoft.Json.Converters; + +namespace Umbraco.Core.Serialization +{ + /// + /// Marks dictionaries so they are deserialized as case-insensitive. + /// + /// + /// [JsonConverter(typeof(CaseInsensitiveDictionaryConverter{PropertyData[]}))] + /// public Dictionary{string, PropertyData[]} PropertyData {{ get; set; }} + /// + public class CaseInsensitiveDictionaryConverter : CustomCreationConverter + { + public override bool CanWrite => false; + + public override bool CanRead => true; + + public override bool CanConvert(Type objectType) => typeof(IDictionary).IsAssignableFrom(objectType); + + public override IDictionary Create(Type objectType) => new Dictionary(StringComparer.OrdinalIgnoreCase); + } +} diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index d69fab18a1..cd5c005de7 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -1312,6 +1312,7 @@ + diff --git a/src/Umbraco.Tests/Published/NestedContentTests.cs b/src/Umbraco.Tests/Published/NestedContentTests.cs index 920fa2acd5..cf00345b65 100644 --- a/src/Umbraco.Tests/Published/NestedContentTests.cs +++ b/src/Umbraco.Tests/Published/NestedContentTests.cs @@ -262,7 +262,7 @@ namespace Umbraco.Tests.Published // ReSharper disable UnassignedGetOnlyAutoProperty public override PublishedItemType ItemType { get; } - public override bool IsDraft { get; } + public override bool IsDraft(string culture = null) => false; public override IPublishedContent Parent { get; } public override IEnumerable Children { get; } public override PublishedContentType ContentType { get; } diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs index a640423515..aa9e7e4918 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs @@ -216,7 +216,7 @@ namespace Umbraco.Tests.PublishedContent public DateTime UpdateDate { get; set; } public Guid Version { get; set; } public int Level { get; set; } - public bool IsDraft { get; set; } + public bool IsDraft(string culture = null) => false; public IEnumerable Properties { get; set; } diff --git a/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs b/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs index efd1c6ae8b..0c4059ca7c 100644 --- a/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs +++ b/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs @@ -162,7 +162,6 @@ namespace Umbraco.Tests.PublishedContent WriterId = CreatorId = 0; CreateDate = UpdateDate = DateTime.Now; Version = Guid.Empty; - IsDraft = false; ContentType = contentType; } @@ -192,7 +191,7 @@ namespace Umbraco.Tests.PublishedContent public string GetUrl(string culture = null) => throw new NotSupportedException(); public PublishedItemType ItemType { get { return PublishedItemType.Content; } } - public bool IsDraft { get; set; } + public bool IsDraft(string culture = null) => false; #endregion diff --git a/src/Umbraco.Tests/TestHelpers/Stubs/TestPublishedContent.cs b/src/Umbraco.Tests/TestHelpers/Stubs/TestPublishedContent.cs index 0faf1537b3..9c0bb61cb3 100644 --- a/src/Umbraco.Tests/TestHelpers/Stubs/TestPublishedContent.cs +++ b/src/Umbraco.Tests/TestHelpers/Stubs/TestPublishedContent.cs @@ -47,7 +47,7 @@ namespace Umbraco.Tests.TestHelpers.Stubs public string Url { get; set; } public string GetUrl(string culture = null) => throw new NotSupportedException(); public PublishedItemType ItemType => ContentType.ItemType; - public bool IsDraft { get; set; } + public bool IsDraft(string culture = null) => false; public IPublishedContent Parent { get; set; } public IEnumerable Children { get; set; } diff --git a/src/Umbraco.Web/Models/PublishedContentBase.cs b/src/Umbraco.Web/Models/PublishedContentBase.cs index 1b8128b4c0..667cf145bd 100644 --- a/src/Umbraco.Web/Models/PublishedContentBase.cs +++ b/src/Umbraco.Web/Models/PublishedContentBase.cs @@ -142,7 +142,7 @@ namespace Umbraco.Web.Models public abstract PublishedItemType ItemType { get; } /// - public abstract bool IsDraft { get; } + public abstract bool IsDraft(string culture = null); #endregion diff --git a/src/Umbraco.Web/PublishedCache/NuCache/ContentCache.cs b/src/Umbraco.Web/PublishedCache/NuCache/ContentCache.cs index edef545d2a..0197d2d640 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/ContentCache.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/ContentCache.cs @@ -147,7 +147,7 @@ namespace Umbraco.Web.PublishedCache.NuCache var urlSegment = n.GetUrlSegment(culture); var hasDomains = _domainHelper.NodeHasDomains(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; @@ -173,7 +173,7 @@ namespace Umbraco.Web.PublishedCache.NuCache var path = "/" + string.Join("/", pathParts); // will be "/" or "/foo" or "/foo/bar" etc //prefix the root node id containing the domain if it exists (this is a standard way of creating route paths) //and is done so that we know the ID of the domain node for the path - var route = (n?.Id.ToString(CultureInfo.InvariantCulture) ?? "") + path; + var route = (n?.Id.ToString(CultureInfo.InvariantCulture) ?? "") + path; return route; } @@ -223,24 +223,14 @@ namespace Umbraco.Web.PublishedCache.NuCache public override IPublishedContent GetById(bool preview, int contentId) { - var n = _snapshot.Get(contentId); - if (n == null) return null; - - // both .Draft and .Published cannot be null at the same time - return preview - ? n.Draft ?? GetPublishedContentAsPreviewing(n.Published) - : n.Published; + var node = _snapshot.Get(contentId); + return GetNodePublishedContent(node, preview); } public override IPublishedContent GetById(bool preview, Guid contentId) { - var n = _snapshot.Get(contentId); - if (n == null) return null; - - // both .Draft and .Published cannot be null at the same time - return preview - ? n.Draft ?? GetPublishedContentAsPreviewing(n.Published) - : n.Published; + var node = _snapshot.Get(contentId); + return GetNodePublishedContent(node, preview); } public override bool HasById(bool preview, int contentId) @@ -274,14 +264,24 @@ namespace Umbraco.Web.PublishedCache.NuCache var c = _snapshot.GetAtRoot(); // both .Draft and .Published cannot be null at the same time - return c.Select(n => preview - ? n.Draft ?? GetPublishedContentAsPreviewing(n.Published) - : n.Published).WhereNotNull().OrderBy(x => x.SortOrder); + return c.Select(n => GetNodePublishedContent(n, preview)).WhereNotNull().OrderBy(x => x.SortOrder); + } + + private static IPublishedContent GetNodePublishedContent(ContentNode node, bool preview) + { + if (node == null) + return null; + + // both .Draft and .Published cannot be null at the same time + + return preview + ? node.Draft ?? GetPublishedContentAsDraft(node.Published) + : node.Published; } // gets a published content as a previewing draft, if preview is true // this is for published content when previewing - internal static IPublishedContent GetPublishedContentAsPreviewing(IPublishedContent content /*, bool preview*/) + private static IPublishedContent GetPublishedContentAsDraft(IPublishedContent content /*, bool preview*/) { if (content == null /*|| preview == false*/) return null; //content; @@ -290,7 +290,7 @@ namespace Umbraco.Web.PublishedCache.NuCache // case we need to unwrap to get to the original IPublishedContentOrMedia. var inner = PublishedContent.UnwrapIPublishedContent(content); - return inner.AsPreviewingModel(); + return inner.AsDraft(); } public override bool HasContent(bool preview) diff --git a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/ContentNestedData.cs b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/ContentNestedData.cs index be3e813275..0f120024cc 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/ContentNestedData.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/ContentNestedData.cs @@ -1,5 +1,6 @@ using Newtonsoft.Json; using System.Collections.Generic; +using Umbraco.Core.Serialization; namespace Umbraco.Web.PublishedCache.NuCache.DataSource { @@ -9,9 +10,11 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource internal class ContentNestedData { [JsonProperty("properties")] + [JsonConverter(typeof(CaseInsensitiveDictionaryConverter))] public Dictionary PropertyData { get; set; } [JsonProperty("cultureData")] + [JsonConverter(typeof(CaseInsensitiveDictionaryConverter))] public Dictionary CultureData { get; set; } } } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/CultureVariation.cs b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/CultureVariation.cs index 50a2adaeb8..c6e603f5a9 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/CultureVariation.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/CultureVariation.cs @@ -13,5 +13,8 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource [JsonProperty("date")] public DateTime Date { get; set; } + + [JsonProperty("isDraft")] + public bool IsDraft { get; set; } } } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs index a143997fab..4531d37b2b 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs @@ -182,27 +182,30 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource ContentData d = null; ContentData p = null; - if (dto.EditData == null) + if (dto.Edited) { - if (Debugger.IsAttached) - throw new Exception("Missing cmsContentNu edited content for node " + dto.Id + ", consider rebuilding."); - Current.Logger.Warn("Missing cmsContentNu edited content for node {NodeId}, consider rebuilding.", dto.Id); - } - else - { - var nested = DeserializeNestedData(dto.EditData); - - d = new ContentData + if (dto.EditData == null) { - Name = dto.EditName, - Published = false, - TemplateId = dto.EditTemplateId, - VersionId = dto.VersionId, - VersionDate = dto.EditVersionDate, - WriterId = dto.EditWriterId, - Properties = nested.PropertyData, - CultureInfos = nested.CultureData - }; + if (Debugger.IsAttached) + throw new Exception("Missing cmsContentNu edited content for node " + dto.Id + ", consider rebuilding."); + Current.Logger.Warn("Missing cmsContentNu edited content for node {NodeId}, consider rebuilding.", dto.Id); + } + else + { + var nested = DeserializeNestedData(dto.EditData); + + d = new ContentData + { + Name = dto.EditName, + Published = false, + TemplateId = dto.EditTemplateId, + VersionId = dto.VersionId, + VersionDate = dto.EditVersionDate, + WriterId = dto.EditWriterId, + Properties = nested.PropertyData, + CultureInfos = nested.CultureData + }; + } } if (dto.Published) diff --git a/src/Umbraco.Web/PublishedCache/NuCache/Navigable/NavigableContent.cs b/src/Umbraco.Web/PublishedCache/NuCache/Navigable/NavigableContent.cs index ae34d0cb32..51badc8b9a 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/Navigable/NavigableContent.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/Navigable/NavigableContent.cs @@ -29,7 +29,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.Navigable XmlString(i++, _content.WriterId), XmlString(i++, _content.CreatorId), XmlString(i++, _content.UrlSegment), - XmlString(i, _content.IsDraft) + XmlString(i, _content.IsDraft()) }; } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs index a4610e82db..36e5698e32 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs @@ -273,8 +273,27 @@ namespace Umbraco.Web.PublishedCache.NuCache /// public override PublishedItemType ItemType => _contentNode.ContentType.ItemType; + // fixme + // was => _contentData.Published == false; /// - public override bool IsDraft => _contentData.Published == false; + public override bool IsDraft(string culture = null) + { + // if this is the 'published' published content, nothing can be draft + if (_contentData.Published) + return false; + + // not the 'published' published content, and does not vary = must be draft + if (!ContentType.VariesByCulture()) + return true; + + // handle context culture + if (culture == null) + culture = VariationContextAccessor?.VariationContext?.Culture ?? ""; + + // not the 'published' published content, and varies + // = depends on the culture + return _contentData.CultureInfos.TryGetValue(culture, out var cvar) && cvar.IsDraft; + } #endregion @@ -410,7 +429,7 @@ namespace Umbraco.Web.PublishedCache.NuCache private string AsPreviewingCacheKey => _asPreviewingCacheKey ?? (_asPreviewingCacheKey = CacheKeys.PublishedContentAsPreviewing(Key)); // used by ContentCache - internal IPublishedContent AsPreviewingModel() + internal IPublishedContent AsDraft() { if (IsPreviewing) return this; diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index 100833216e..4d6115f02d 100755 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -1206,7 +1206,8 @@ namespace Umbraco.Web.PublishedCache.NuCache foreach (var (culture, info) in infos) { - cultureData[culture] = new CultureVariation { Name = info.Name, Date = content.GetUpdateDate(culture) ?? DateTime.MinValue }; + var cultureIsDraft = !published && content is IContent d && d.IsCultureEdited(culture); + cultureData[culture] = new CultureVariation { Name = info.Name, Date = content.GetUpdateDate(culture) ?? DateTime.MinValue, IsDraft = cultureIsDraft }; } } diff --git a/src/Umbraco.Web/PublishedCache/PublishedMember.cs b/src/Umbraco.Web/PublishedCache/PublishedMember.cs index 44ce2328b7..56c8f440d8 100644 --- a/src/Umbraco.Web/PublishedCache/PublishedMember.cs +++ b/src/Umbraco.Web/PublishedCache/PublishedMember.cs @@ -79,7 +79,7 @@ namespace Umbraco.Web.PublishedCache public override PublishedItemType ItemType => PublishedItemType.Member; - public override bool IsDraft => false; + public override bool IsDraft(string culture = null) => false; public override IPublishedContent Parent => null; diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs index 7a8ce65ae3..4453fe7321 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs @@ -176,7 +176,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache public override int Level => _level; - public override bool IsDraft => false; + public override bool IsDraft(string culture = null) => false; public override IEnumerable Properties => _properties; diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs index 3c143a6066..af867cc089 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs @@ -221,13 +221,10 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache } } - public override bool IsDraft + public override bool IsDraft(string culture = null) { - get - { - EnsureNodeInitialized(); - return _isDraft; - } + EnsureNodeInitialized(); + return _isDraft; // bah } public override IEnumerable Properties diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index 2bc0d7be3f..eb47fd2f2d 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -141,50 +141,35 @@ namespace Umbraco.Web #endregion - // fixme - .HasValue() and .Value() refactoring - in progress - see exceptions below - - #region HasValue + #region HasValue, Value, Value /// /// Gets a value indicating whether the content has a value for a property identified by its alias. /// /// The content. /// The property alias. - /// A value indicating whether to navigate the tree upwards until a property with a value is found. + /// The variation language. + /// The variation segment. + /// Optional fallback strategy. /// A value indicating whether the content has a value for the property identified by the alias. - /// Returns true if GetProperty(alias, recurse) is not null and GetProperty(alias, recurse).HasValue is true. - public static bool HasValue(this IPublishedContent content, string alias, bool recurse) + /// Returns true if HasValue is true, or a fallback strategy can provide a value. + public static bool HasValue(this IPublishedContent content, string alias, string culture = null, string segment = null, Fallback fallback = default) { - throw new NotImplementedException("WorkInProgress"); + var property = content.GetProperty(alias); - //var prop = content.GetProperty(alias, recurse); - //return prop != null && prop.HasValue(); + // if we have a property, and it has a value, return that value + if (property != null && property.HasValue(culture, segment)) + return true; + + // else let fallback try to get a value + // fixme - really? + if (PublishedValueFallback.TryGetValue(content, alias, culture, segment, fallback, null, out _)) + return true; + + // else... no + return false; } - /// - /// Returns one of two strings depending on whether the content has a value for a property identified by its alias. - /// - /// The content. - /// The property alias. - /// A value indicating whether to navigate the tree upwards until a property with a value is found. - /// The value to return if the content has a value for the property. - /// The value to return if the content has no value for the property. - /// Either or depending on whether the content - /// has a value for the property identified by the alias. - public static IHtmlString HasValue(this IPublishedContent content, string alias, bool recurse, - string valueIfTrue, string valueIfFalse = null) - { - throw new NotImplementedException("WorkInProgress"); - - //return content.HasValue(alias, recurse) - // ? new HtmlString(valueIfTrue) - // : new HtmlString(valueIfFalse ?? string.Empty); - } - - #endregion - - #region Value - /// /// Gets the value of a content's property identified by its alias, if it exists, otherwise a default value. /// @@ -207,15 +192,14 @@ namespace Umbraco.Web if (PublishedValueFallback.TryGetValue(content, alias, culture, segment, fallback, defaultValue, out var value)) return value; + if (property == null) + return null; + // else... if we have a property, at least let the converter return its own - // vision of 'no value' (could be an empty enumerable) - otherwise, default - return property?.GetValue(culture, segment); + // vision of 'no value' (could be an empty enumerable) + return property.GetValue(culture, segment); } - #endregion - - #region Value - /// /// Gets the value of a content's property identified by its alias, converted to a specified type. /// @@ -383,16 +367,6 @@ namespace Umbraco.Web return recursive && content.IsComposedOf(docTypeAlias); } - public static bool IsNull(this IPublishedContent content, string alias, bool recurse) - { - return content.HasValue(alias, recurse) == false; - } - - public static bool IsNull(this IPublishedContent content, string alias) - { - return content.HasValue(alias) == false; - } - #endregion #region IsSomething: equality diff --git a/src/Umbraco.Web/umbraco.presentation/page.cs b/src/Umbraco.Web/umbraco.presentation/page.cs index e8d395881c..219e2101be 100644 --- a/src/Umbraco.Web/umbraco.presentation/page.cs +++ b/src/Umbraco.Web/umbraco.presentation/page.cs @@ -467,9 +467,9 @@ namespace umbraco get { return PublishedItemType.Content; } } - public bool IsDraft + public bool IsDraft(string culture = null) { - get { throw new NotImplementedException(); } + throw new NotImplementedException(); } public IPublishedContent Parent From d8d04c54e669dd6ab8de65b0e3943af5a55059f2 Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 18 Dec 2018 08:33:54 +0100 Subject: [PATCH 52/54] Fix IOHelper for debugging other apps --- src/Umbraco.Core/IO/IOHelper.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/IO/IOHelper.cs b/src/Umbraco.Core/IO/IOHelper.cs index 2f1675e08a..7773f378a5 100644 --- a/src/Umbraco.Core/IO/IOHelper.cs +++ b/src/Umbraco.Core/IO/IOHelper.cs @@ -284,11 +284,12 @@ namespace Umbraco.Core.IO binFolder = Path.Combine(GetRootDirectorySafe(), "bin"); -#if DEBUG + // do this all the time (no #if DEBUG) because Umbraco release + // can be used in tests by an app (eg Deploy) being debugged var debugFolder = Path.Combine(binFolder, "debug"); if (Directory.Exists(debugFolder)) return debugFolder; -#endif + var releaseFolder = Path.Combine(binFolder, "release"); if (Directory.Exists(releaseFolder)) return releaseFolder; From 53c67fad632d29dc522c738b01d3f81b0e355967 Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 18 Dec 2018 10:39:39 +0100 Subject: [PATCH 53/54] Rework for #3866 --- .../Migrations/Install/DatabaseBuilder.cs | 154 +++++++++--------- .../Install/DatabaseSchemaCreator.cs | 7 +- .../Install/DatabaseSchemaResult.cs | 146 +++-------------- .../Persistence/SchemaValidationTest.cs | 1 - .../Controllers/InstallApiController.cs | 2 +- .../InstallSteps/DatabaseConfigureStep.cs | 6 +- .../InstallSteps/DatabaseInstallStep.cs | 2 +- .../InstallSteps/DatabaseUpgradeStep.cs | 16 +- 8 files changed, 108 insertions(+), 226 deletions(-) diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs index a54b997cb8..ccf2365deb 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs @@ -33,6 +33,9 @@ namespace Umbraco.Core.Migrations.Install private DatabaseSchemaResult _databaseSchemaValidationResult; + /// + /// Initializes a new instance of the class. + /// public DatabaseBuilder(IScopeProvider scopeProvider, IGlobalSettings globalSettings, IUmbracoDatabaseFactory databaseFactory, IRuntimeState runtime, ILogger logger, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, PostMigrationCollection postMigrations) { _scopeProvider = scopeProvider; @@ -49,23 +52,20 @@ namespace Umbraco.Core.Migrations.Install /// /// Gets a value indicating whether the database is configured. It does not necessarily - /// mean that it is possible to connect, nor that Umbraco is installed, nor - /// up-to-date. + /// mean that it is possible to connect, nor that Umbraco is installed, nor up-to-date. /// public bool IsDatabaseConfigured => _databaseFactory.Configured; /// - /// Gets a value indicating whether it is possible to connect to the database. + /// Gets a value indicating whether it is possible to connect to the configured database. + /// It does not necessarily mean that Umbraco is installed, nor up-to-date. /// - public bool CanConnect => _databaseFactory.CanConnect; + public bool CanConnectToDatabase => _databaseFactory.CanConnect; - // that method was originally created by Per in DatabaseHelper- tests the db connection for install - // fixed by Shannon to not-ignore the provider - // fixed by Stephan as part of the v8 persistence cleanup, now using provider names + SqlCe exception - // moved by Stephan to DatabaseBuilder - // probably needs to be cleaned up - - public bool CheckConnection(string databaseType, string connectionString, string server, string database, string login, string password, bool integratedAuth) + /// + /// Verifies whether a it is possible to connect to a database. + /// + public bool CanConnect(string databaseType, string connectionString, string server, string database, string login, string password, bool integratedAuth) { // we do not test SqlCE connection if (databaseType.InvariantContains("sqlce")) @@ -93,7 +93,7 @@ namespace Umbraco.Core.Migrations.Install return DbConnectionExtensions.IsConnectionAvailable(connectionString, providerName); } - public bool HasSomeNonDefaultUser() + internal bool HasSomeNonDefaultUser() { using (var scope = _scopeProvider.CreateScope()) { @@ -417,17 +417,24 @@ namespace Umbraco.Core.Migrations.Install #region Database Schema - public DatabaseSchemaResult ValidateDatabaseSchema() + /// + /// Validates the database schema. + /// + /// + /// This assumes that the database exists and the connection string is + /// configured and it is possible to connect to the database. + /// + internal DatabaseSchemaResult ValidateSchema() { using (var scope = _scopeProvider.CreateScope()) { - var result = ValidateDatabaseSchema(scope); + var result = ValidateSchema(scope); scope.Complete(); return result; } } - private DatabaseSchemaResult ValidateDatabaseSchema(IScope scope) + private DatabaseSchemaResult ValidateSchema(IScope scope) { if (_databaseFactory.Configured == false) return new DatabaseSchemaResult(_databaseFactory.SqlContext.SqlSyntax); @@ -442,17 +449,24 @@ namespace Umbraco.Core.Migrations.Install return _databaseSchemaValidationResult; } - public Result CreateDatabaseSchemaAndData() + /// + /// Creates the database schema and inserts initial data. + /// + /// + /// This assumes that the database exists and the connection string is + /// configured and it is possible to connect to the database. + /// + public Result CreateSchemaAndData() { using (var scope = _scopeProvider.CreateScope()) { - var result = CreateDatabaseSchemaAndData(scope); + var result = CreateSchemaAndData(scope); scope.Complete(); return result; } } - private Result CreateDatabaseSchemaAndData(IScope scope) + private Result CreateSchemaAndData(IScope scope) { try { @@ -468,28 +482,14 @@ namespace Umbraco.Core.Migrations.Install // If MySQL, we're going to ensure that database calls are maintaining proper casing as to remove the necessity for checks // for case insensitive queries. In an ideal situation (which is what we're striving for), all calls would be case sensitive. - - /* - var supportsCaseInsensitiveQueries = SqlSyntax.SupportsCaseInsensitiveQueries(database); - if (supportsCaseInsensitiveQueries == false) - { - message = "

 

The database you're trying to use does not support case insensitive queries.
We currently do not support these types of databases.

" + - "

You can fix this by changing the following setting in your my.ini file in your MySQL installation directory:

" + - "
lower_case_table_names=1

" + - "

Note: Make sure to check with your hosting provider if they support case insensitive queries as well.

" + - "

For more technical information on case sensitivity in MySQL, have a look at " + - "the documentation on the subject

"; - - return new Result { Message = message, Success = false, Percentage = "15" }; - } - */ - - var message = GetResultMessageForMySql(); - var schemaResult = ValidateDatabaseSchema(); - var installedSchemaVersion = schemaResult.DetermineInstalledVersion(); + var message = database.DatabaseType.IsMySql() ? ResultMessageForMySql : ""; + var schemaResult = ValidateSchema(); + var hasInstalledVersion = schemaResult.DetermineHasInstalledVersion(); + //var installedSchemaVersion = schemaResult.DetermineInstalledVersion(); + //var hasInstalledVersion = !installedSchemaVersion.Equals(new Version(0, 0, 0)); //If Configuration Status is empty and the determined version is "empty" its a new install - otherwise upgrade the existing - if (string.IsNullOrEmpty(_globalSettings.ConfigurationStatus) && installedSchemaVersion.Equals(new Version(0, 0, 0))) + if (string.IsNullOrEmpty(_globalSettings.ConfigurationStatus) && !hasInstalledVersion) { if (_runtime.Level == RuntimeLevel.Run) throw new Exception("Umbraco is already configured!"); @@ -521,7 +521,14 @@ namespace Umbraco.Core.Migrations.Install } } - // This assumes all of the previous checks are done! + /// + /// Upgrades the database schema and data by running migrations. + /// + /// + /// This assumes that the database exists and the connection string is + /// configured and it is possible to connect to the database. + /// Runs whichever migrations need to run. + /// public Result UpgradeSchemaAndData() { try @@ -534,7 +541,7 @@ namespace Umbraco.Core.Migrations.Install _logger.Info("Database upgrade started"); - var message = GetResultMessageForMySql(); + var message = _scopeProvider.SqlContext.DatabaseType.IsMySql() ? ResultMessageForMySql : ""; // upgrade var upgrader = new UmbracoUpgrader(); @@ -554,47 +561,14 @@ namespace Umbraco.Core.Migrations.Install } } - private string GetResultMessageForMySql() - { - if (_databaseFactory.GetType() == typeof(MySqlSyntaxProvider)) - { - return "

 

Congratulations, the database step ran successfully!

" + - "

Note: You're using MySQL and the database instance you're connecting to seems to support case insensitive queries.

" + - "

However, your hosting provider may not support this option. Umbraco does not currently support MySQL installs that do not support case insensitive queries

" + - "

Make sure to check with your hosting provider if they support case insensitive queries as well.

" + - "

They can check this by looking for the following setting in the my.ini file in their MySQL installation directory:

" + - "
lower_case_table_names=1

" + - "

For more technical information on case sensitivity in MySQL, have a look at " + - "the documentation on the subject

"; - } - return string.Empty; - } - - /* - private string GetResultMessageForMySql(bool? supportsCaseInsensitiveQueries) - { - if (supportsCaseInsensitiveQueries == null) - { - return "

 

Warning! Could not check if your database type supports case insensitive queries.
We currently do not support these databases that do not support case insensitive queries.

" + - "

You can check this by looking for the following setting in your my.ini file in your MySQL installation directory:

" + - "
lower_case_table_names=1

" + - "

Note: Make sure to check with your hosting provider if they support case insensitive queries as well.

" + - "

For more technical information on case sensitivity in MySQL, have a look at " + - "the documentation on the subject

"; - } - if (SqlSyntax.GetType() == typeof(MySqlSyntaxProvider)) - { - return "

 

Congratulations, the database step ran successfully!

" + - "

Note: You're using MySQL and the database instance you're connecting to seems to support case insensitive queries.

" + - "

However, your hosting provider may not support this option. Umbraco does not currently support MySQL installs that do not support case insensitive queries

" + - "

Make sure to check with your hosting provider if they support case insensitive queries as well.

" + - "

They can check this by looking for the following setting in the my.ini file in their MySQL installation directory:

" + - "
lower_case_table_names=1

" + - "

For more technical information on case sensitivity in MySQL, have a look at " + - "the documentation on the subject

"; - } - return string.Empty; - }*/ + private const string ResultMessageForMySql = "

 

Congratulations, the database step ran successfully!

" + + "

Note: You're using MySQL and the database instance you're connecting to seems to support case insensitive queries.

" + + "

However, your hosting provider may not support this option. Umbraco does not currently support MySQL installs that do not support case insensitive queries

" + + "

Make sure to check with your hosting provider if they support case insensitive queries as well.

" + + "

They can check this by looking for the following setting in the my.ini file in their MySQL installation directory:

" + + "
lower_case_table_names=1

" + + "

For more technical information on case sensitivity in MySQL, have a look at " + + "the documentation on the subject

"; private Attempt CheckReadyForInstall() { @@ -630,11 +604,29 @@ namespace Umbraco.Core.Migrations.Install }; } + /// + /// Represents the result of a database creation or upgrade. + /// public class Result { + /// + /// Gets or sets ... fixme + /// public bool RequiresUpgrade { get; set; } + + /// + /// Gets or sets the message returned by the operation. + /// public string Message { get; set; } + + /// + /// Gets or sets a value indicating whether the operation succeeded. + /// public bool Success { get; set; } + + /// + /// Gets or sets ... fixme + /// public string Percentage { get; set; } } diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs b/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs index 64be8161f2..eba5e61390 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs @@ -138,9 +138,8 @@ namespace Umbraco.Core.Migrations.Install { var result = new DatabaseSchemaResult(SqlSyntax); - //get the db index defs - result.DbIndexDefinitions = SqlSyntax.GetDefinedIndexes(_database) - .Select(x => new DbIndexDefinition(x)).ToArray(); + result.IndexDefinitions.AddRange(SqlSyntax.GetDefinedIndexes(_database) + .Select(x => new DbIndexDefinition(x))); result.TableDefinitions.AddRange(OrderedTables .Select(x => DefinitionFactory.GetTableDefinition(x, SqlSyntax))); @@ -279,7 +278,7 @@ namespace Umbraco.Core.Migrations.Install { //These are just column indexes NOT constraints or Keys //var colIndexesInDatabase = result.DbIndexDefinitions.Where(x => x.IndexName.InvariantStartsWith("IX_")).Select(x => x.IndexName).ToList(); - var colIndexesInDatabase = result.DbIndexDefinitions.Select(x => x.IndexName).ToList(); + var colIndexesInDatabase = result.IndexDefinitions.Select(x => x.IndexName).ToList(); var indexesInSchema = result.TableDefinitions.SelectMany(x => x.Indexes.Select(y => y.Name)).ToList(); //Add valid and invalid index differences to the result object diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseSchemaResult.cs b/src/Umbraco.Core/Migrations/Install/DatabaseSchemaResult.cs index 0ec27cf0b1..4c68addebc 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseSchemaResult.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseSchemaResult.cs @@ -2,153 +2,55 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using Umbraco.Core.Configuration; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Migrations.Install { - public class DatabaseSchemaResult + /// + /// Represents ... + /// + internal class DatabaseSchemaResult { - private readonly ISqlSyntaxProvider _sqlSyntax; + private readonly bool _isMySql; public DatabaseSchemaResult(ISqlSyntaxProvider sqlSyntax) { - _sqlSyntax = sqlSyntax; + _isMySql = sqlSyntax is MySqlSyntaxProvider; + Errors = new List>(); TableDefinitions = new List(); ValidTables = new List(); ValidColumns = new List(); ValidConstraints = new List(); ValidIndexes = new List(); + IndexDefinitions = new List(); } - public List> Errors { get; set; } + public List> Errors { get; } - public List TableDefinitions { get; set; } + public List TableDefinitions { get; } - public List ValidTables { get; set; } + // fixme TableDefinitions are those that should be there, IndexDefinitions are those that... are in DB? + internal List IndexDefinitions { get; } - public List ValidColumns { get; set; } + public List ValidTables { get; } - public List ValidConstraints { get; set; } + public List ValidColumns { get; } - public List ValidIndexes { get; set; } + public List ValidConstraints { get; } - internal IEnumerable DbIndexDefinitions { get; set; } + public List ValidIndexes { get; } /// - /// Determines the version of the currently installed database by detecting the current database structure + /// Determines whether the database contains an installed version. /// - /// - /// A with Major and Minor values for - /// non-empty database, otherwise "0.0.0" for empty databases. - /// - public Version DetermineInstalledVersion() + /// + /// A database contains an installed version when it contains at least one valid table. + /// + public bool DetermineHasInstalledVersion() { - // v8 = kill versions older than 7 - - //If (ValidTables.Count == 0) database is empty and we return -> new Version(0, 0, 0); - if (ValidTables.Count == 0) - return new Version(0, 0, 0); - - // FIXME - but the whole detection is borked really - return new Version(8, 0, 0); - - //If Errors is empty or if TableDefinitions tables + columns correspond to valid tables + columns then we're at current version - if (Errors.Any() == false || - (TableDefinitions.All(x => ValidTables.Contains(x.Name)) - && TableDefinitions.SelectMany(definition => definition.Columns).All(x => ValidColumns.Contains(x.Name)))) - return UmbracoVersion.Current; - - //If Errors contains umbracoApp or umbracoAppTree its pre-6.0.0 -> new Version(4, 10, 0); - if (Errors.Any(x => x.Item1.Equals("Table") && (x.Item2.InvariantEquals("umbracoApp") || x.Item2.InvariantEquals("umbracoAppTree")))) - { - //If Errors contains umbracoUser2app or umbracoAppTree foreignkey to umbracoApp exists its pre-4.8.0 -> new Version(4, 7, 0); - if (Errors.Any(x => - x.Item1.Equals("Constraint") - && (x.Item2.InvariantContains("umbracoUser2app_umbracoApp") - || x.Item2.InvariantContains("umbracoAppTree_umbracoApp")))) - { - return new Version(4, 7, 0); - } - - return new Version(4, 8, 0); - } - - //if the error is for umbracoServer - if (Errors.Any(x => x.Item1.Equals("Table") && (x.Item2.InvariantEquals("umbracoServer")))) - { - return new Version(6, 0, 0); - } - - //if the error indicates a problem with the column cmsMacroProperty.macroPropertyType then it is not version 7 - // since these columns get removed in v7 - if (Errors.Any(x => x.Item1.Equals("Column") && (x.Item2.InvariantEquals("cmsMacroProperty,macroPropertyType")))) - { - //if the error is for this IX_umbracoNodeTrashed which is added in 6.2 AND in 7.1 but we do not have the above columns - // then it must mean that we aren't on 6.2 so must be 6.1 - if (Errors.Any(x => x.Item1.Equals("Index") && (x.Item2.InvariantEquals("IX_umbracoNodeTrashed")))) - { - return new Version(6, 1, 0); - } - else - { - //if there are no errors for that index, then the person must have 6.2 installed - return new Version(6, 2, 0); - } - } - - //if the error indicates a problem with the constraint FK_cms-OBSOLETE-Content_cmsContentType_nodeId then it is not version 7.2 - // since this gets added in 7.2.0 so it must be the previous version - if (Errors.Any(x => x.Item1.Equals("Constraint") && (x.Item2.InvariantEquals("FK_cms-OBSOLETE-Content_cmsContentType_nodeId")))) - { - return new Version(7, 0, 0); - } - - //if the error is for umbracoAccess it must be the previous version to 7.3 since that is when it is added - if (Errors.Any(x => x.Item1.Equals("Table") && (x.Item2.InvariantEquals("umbracoAccess")))) - { - return new Version(7, 2, 0); - } - - //if the error is for cms-OBSOLETE-PropertyData.dataDecimal it must be the previous version to 7.4 since that is when it is added - if (Errors.Any(x => x.Item1.Equals("Column") && (x.Item2.InvariantEquals("cms-OBSOLETE-PropertyData,dataDecimal")))) - { - return new Version(7, 3, 0); - } - - //if the error is for umbracoRedirectUrl it must be the previous version to 7.5 since that is when it is added - if (Errors.Any(x => x.Item1.Equals("Table") && (x.Item2.InvariantEquals("umbracoRedirectUrl")))) - { - return new Version(7, 4, 0); - } - - //if the error indicates a problem with the column cmsMacroProperty.uniquePropertyId then it is not version 7.6 since that is when it is added - if (Errors.Any(x => x.Item1.Equals("Column") && (x.Item2.InvariantEquals("cmsMacroProperty,uniquePropertyId")))) - { - return new Version(7, 5, 0); - } - - //if the error is for umbracoUserGroup it must be the previous version to 7.7 since that is when it is added - if (Errors.Any(x => x.Item1.Equals("Table") && (x.Item2.InvariantEquals("umbracoUserStartNode")))) - { - return new Version(7, 6, 0); - } - - //if the error is for cmsMedia it must be the previous version to 7.8 since that is when it is added - if (Errors.Any(x => x.Item1.Equals("Table") && (x.Item2.InvariantEquals("umbracoMedia")))) - { - return new Version(7, 7, 0); - } - - //if the error is for isSensitive column it must be the previous version to 7.9 since that is when it is added - if (Errors.Any(x => x.Item1.Equals("Column") && (x.Item2.InvariantEquals("cmsMemberType,isSensitive")))) - { - return new Version(7, 8, 0); - } - - return UmbracoVersion.Current; + return ValidTables.Count > 0; } /// @@ -200,9 +102,9 @@ namespace Umbraco.Core.Migrations.Install sb.AppendLine(" "); } - if (_sqlSyntax is MySqlSyntaxProvider) + if (_isMySql) { - sb.AppendLine("Please note that the constraints could not be validated because the current dataprovider is MySql."); + sb.AppendLine("Please note that the constraints could not be validated because the current data provider is MySql."); } return sb.ToString(); diff --git a/src/Umbraco.Tests/Persistence/SchemaValidationTest.cs b/src/Umbraco.Tests/Persistence/SchemaValidationTest.cs index b8f1fab918..2c875d6afc 100644 --- a/src/Umbraco.Tests/Persistence/SchemaValidationTest.cs +++ b/src/Umbraco.Tests/Persistence/SchemaValidationTest.cs @@ -26,7 +26,6 @@ namespace Umbraco.Tests.Persistence // Assert Assert.That(result.Errors.Count, Is.EqualTo(0)); - Assert.AreEqual(result.DetermineInstalledVersion(), UmbracoVersion.Current); } } } diff --git a/src/Umbraco.Web/Install/Controllers/InstallApiController.cs b/src/Umbraco.Web/Install/Controllers/InstallApiController.cs index 387360163a..81b1aac217 100644 --- a/src/Umbraco.Web/Install/Controllers/InstallApiController.cs +++ b/src/Umbraco.Web/Install/Controllers/InstallApiController.cs @@ -41,7 +41,7 @@ namespace Umbraco.Web.Install.Controllers public bool PostValidateDatabaseConnection(DatabaseModel model) { - var canConnect = _databaseBuilder.CheckConnection(model.DatabaseType.ToString(), model.ConnectionString, model.Server, model.DatabaseName, model.Login, model.Password, model.IntegratedAuth); + var canConnect = _databaseBuilder.CanConnect(model.DatabaseType.ToString(), model.ConnectionString, model.Server, model.DatabaseName, model.Login, model.Password, model.IntegratedAuth); return canConnect; } diff --git a/src/Umbraco.Web/Install/InstallSteps/DatabaseConfigureStep.cs b/src/Umbraco.Web/Install/InstallSteps/DatabaseConfigureStep.cs index a54b64733f..2fe6c0ceda 100644 --- a/src/Umbraco.Web/Install/InstallSteps/DatabaseConfigureStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/DatabaseConfigureStep.cs @@ -1,7 +1,6 @@ using System; using System.Configuration; using Umbraco.Core; -using Umbraco.Core.Configuration; using Umbraco.Core.Logging; using Umbraco.Core.Migrations.Install; using Umbraco.Web.Install.Models; @@ -29,7 +28,7 @@ namespace Umbraco.Web.Install.InstallSteps database = new DatabaseModel(); } - if (_databaseBuilder.CheckConnection(database.DatabaseType.ToString(), database.ConnectionString, database.Server, database.DatabaseName, database.Login, database.Password, database.IntegratedAuth) == false) + if (_databaseBuilder.CanConnect(database.DatabaseType.ToString(), database.ConnectionString, database.Server, database.DatabaseName, database.Login, database.Password, database.IntegratedAuth) == false) { throw new InstallException("Could not connect to the database"); } @@ -79,8 +78,7 @@ namespace Umbraco.Web.Install.InstallSteps try { //Since a connection string was present we verify the db can connect and query - var result = _databaseBuilder.ValidateDatabaseSchema(); - result.DetermineInstalledVersion(); + _ = _databaseBuilder.ValidateSchema(); return false; } catch (Exception ex) diff --git a/src/Umbraco.Web/Install/InstallSteps/DatabaseInstallStep.cs b/src/Umbraco.Web/Install/InstallSteps/DatabaseInstallStep.cs index c4cad38072..a9daee6e95 100644 --- a/src/Umbraco.Web/Install/InstallSteps/DatabaseInstallStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/DatabaseInstallStep.cs @@ -29,7 +29,7 @@ namespace Umbraco.Web.Install.InstallSteps if (_runtime.Level == RuntimeLevel.Run) throw new Exception("Umbraco is already configured!"); - var result = _databaseBuilder.CreateDatabaseSchemaAndData(); + var result = _databaseBuilder.CreateSchemaAndData(); if (result.Success == false) { diff --git a/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs b/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs index c078caf906..8283eb6bef 100644 --- a/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs @@ -63,18 +63,10 @@ namespace Umbraco.Web.Install.InstallSteps if (_databaseBuilder.IsConnectionStringConfigured(databaseSettings)) { - //Since a connection string was present we verify whether this is an upgrade or an empty db - var result = _databaseBuilder.ValidateDatabaseSchema(); - - var determinedVersion = result.DetermineInstalledVersion(); - if (determinedVersion.Equals(new Version(0, 0, 0))) - { - //Fresh install - return false; - } - - //Upgrade - return true; + // a connection string was present, determine whether this is an install/upgrade + // return true (upgrade) if there is an installed version, else false (install) + var result = _databaseBuilder.ValidateSchema(); + return result.DetermineHasInstalledVersion(); } //no connection string configured, probably a fresh install From 792bf4003710a88fdfb0f54dbf18ae16049b9f98 Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 18 Dec 2018 10:44:59 +0100 Subject: [PATCH 54/54] Rework for #3866 --- src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs index ccf2365deb..ef6b3b720b 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs @@ -610,7 +610,7 @@ namespace Umbraco.Core.Migrations.Install public class Result { /// - /// Gets or sets ... fixme + /// Gets or sets a value indicating whether an upgrade is required. /// public bool RequiresUpgrade { get; set; } @@ -625,7 +625,7 @@ namespace Umbraco.Core.Migrations.Install public bool Success { get; set; } /// - /// Gets or sets ... fixme + /// Gets or sets an install progress pseudo-percentage. /// public string Percentage { get; set; } }