diff --git a/src/Artemis.Core/Models/Profile/Profile.cs b/src/Artemis.Core/Models/Profile/Profile.cs index c511f9ec9..2a0d96a23 100644 --- a/src/Artemis.Core/Models/Profile/Profile.cs +++ b/src/Artemis.Core/Models/Profile/Profile.cs @@ -17,13 +17,12 @@ public sealed class Profile : ProfileElement private readonly ObservableCollection _scriptConfigurations; private readonly ObservableCollection _scripts; private bool _isFreshImport; - private ProfileElement? _lastSelectedProfileElement; internal Profile(ProfileConfiguration configuration, ProfileEntity profileEntity) : base(null!) { _scripts = new ObservableCollection(); _scriptConfigurations = new ObservableCollection(); - + Opacity = 0d; ShouldDisplay = true; Configuration = configuration; @@ -67,15 +66,6 @@ public sealed class Profile : ProfileElement set => SetAndNotify(ref _isFreshImport, value); } - /// - /// Gets or sets the last selected profile element of this profile - /// - public ProfileElement? LastSelectedProfileElement - { - get => _lastSelectedProfileElement; - set => SetAndNotify(ref _lastSelectedProfileElement, value); - } - /// /// Gets the profile entity this profile uses for persistent storage /// @@ -105,7 +95,7 @@ public sealed class Profile : ProfileElement profileScript.OnProfileUpdated(deltaTime); const double OPACITY_PER_SECOND = 1; - + if (ShouldDisplay && Opacity < 1) Opacity = Math.Clamp(Opacity + OPACITY_PER_SECOND * deltaTime, 0d, 1d); if (!ShouldDisplay && Opacity > 0) @@ -123,14 +113,14 @@ public sealed class Profile : ProfileElement foreach (ProfileScript profileScript in Scripts) profileScript.OnProfileRendering(canvas, canvas.LocalClipBounds); - + SKPaint? opacityPaint = null; bool applyOpacityLayer = Configuration.FadeInAndOut && Opacity < 1; - + if (applyOpacityLayer) { opacityPaint = new SKPaint(); - opacityPaint.Color = new SKColor(0, 0, 0, (byte)(255d * Easings.CubicEaseInOut(Opacity))); + opacityPaint.Color = new SKColor(0, 0, 0, (byte) (255d * Easings.CubicEaseInOut(Opacity))); canvas.SaveLayer(opacityPaint); } @@ -242,20 +232,13 @@ public sealed class Profile : ProfileElement AddChild(new Folder(this, this, rootFolder)); } - List renderElements = GetAllRenderElements(); - - if (ProfileEntity.LastSelectedProfileElement != Guid.Empty) - LastSelectedProfileElement = renderElements.FirstOrDefault(f => f.EntityId == ProfileEntity.LastSelectedProfileElement); - else - LastSelectedProfileElement = null; - while (_scriptConfigurations.Any()) RemoveScriptConfiguration(_scriptConfigurations[0]); foreach (ScriptConfiguration scriptConfiguration in ProfileEntity.ScriptConfigurations.Select(e => new ScriptConfiguration(e))) AddScriptConfiguration(scriptConfiguration); // Load node scripts last since they may rely on the profile structure being in place - foreach (RenderProfileElement renderProfileElement in renderElements) + foreach (RenderProfileElement renderProfileElement in GetAllRenderElements()) renderProfileElement.LoadNodeScript(); } @@ -312,7 +295,6 @@ public sealed class Profile : ProfileElement ProfileEntity.Id = EntityId; ProfileEntity.Name = Configuration.Name; ProfileEntity.IsFreshImport = IsFreshImport; - ProfileEntity.LastSelectedProfileElement = LastSelectedProfileElement?.EntityId ?? Guid.Empty; foreach (ProfileElement profileElement in Children) profileElement.Save(); diff --git a/src/Artemis.Core/Models/Profile/ProfileCategory.cs b/src/Artemis.Core/Models/Profile/ProfileCategory.cs index 13a3e2f4b..4dc3f73e6 100644 --- a/src/Artemis.Core/Models/Profile/ProfileCategory.cs +++ b/src/Artemis.Core/Models/Profile/ProfileCategory.cs @@ -98,6 +98,7 @@ public class ProfileCategory : CorePropertyChanged, IStorageModel /// public void AddProfileConfiguration(ProfileConfiguration configuration, int? targetIndex) { + // TODO: Look into this, it doesn't seem to make sense // Removing the original will shift every item in the list forwards, keep that in mind with the target index if (configuration.Category == this && targetIndex != null && targetIndex.Value > _profileConfigurations.IndexOf(configuration)) targetIndex -= 1; diff --git a/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfiguration.cs b/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfiguration.cs index 06a2090d3..b0dec1d29 100644 --- a/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfiguration.cs +++ b/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfiguration.cs @@ -147,16 +147,7 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable get => _activationConditionMet; private set => SetAndNotify(ref _activationConditionMet, value); } - - /// - /// Gets or sets a boolean indicating whether this profile configuration is being edited - /// - public bool IsBeingEdited - { - get => _isBeingEdited; - set => SetAndNotify(ref _isBeingEdited, value); - } - + /// /// Gets the profile of this profile configuration /// @@ -243,8 +234,6 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable { if (_disposed) throw new ObjectDisposedException("ProfileConfiguration"); - if (IsBeingEdited) - return true; if (Category.IsSuspended || IsSuspended || IsMissingModule) return false; diff --git a/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfigurationIcon.cs b/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfigurationIcon.cs index ed9646e7a..5a477b5fd 100644 --- a/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfigurationIcon.cs +++ b/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfigurationIcon.cs @@ -15,7 +15,6 @@ public class ProfileConfigurationIcon : CorePropertyChanged, IStorageModel private string? _iconName; private Stream? _iconStream; private ProfileConfigurationIconType _iconType; - private string? _originalFileName; internal ProfileConfigurationIcon(ProfileConfigurationEntity entity) { diff --git a/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs b/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs index 099138b92..59fae7a9d 100644 --- a/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs +++ b/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs @@ -28,19 +28,26 @@ public interface IProfileService : IArtemisService ReadOnlyCollection ProfileConfigurations { get; } /// - /// Gets or sets a boolean indicating whether hotkeys are enabled. + /// Gets or sets the focused profile configuration which is rendered exclusively. /// - bool HotkeysEnabled { get; set; } + ProfileConfiguration? FocusProfile { get; set; } /// - /// Gets or sets a boolean indicating whether rendering should only be done for profiles being edited. + /// Gets or sets the profile element which is rendered exclusively. /// - bool RenderForEditor { get; set; } + ProfileElement? FocusProfileElement { get; set; } /// - /// Gets or sets the profile element to focus on while rendering for the editor. + /// Gets or sets a value indicating whether the currently focused profile should receive updates. /// - ProfileElement? EditorFocus { get; set; } + bool UpdateFocusProfile { get; set; } + + /// + /// Creates a copy of the provided profile configuration. + /// + /// The profile configuration to clone. + /// The resulting clone. + ProfileConfiguration CloneProfileConfiguration(ProfileConfiguration profileConfiguration); /// /// Activates the profile of the given with the currently active surface. @@ -71,8 +78,9 @@ public interface IProfileService : IArtemisService /// Creates a new profile category and saves it to persistent storage. /// /// The name of the new profile category, must be unique. + /// A boolean indicating whether or not to add the category to the top. /// The newly created profile category. - ProfileCategory CreateProfileCategory(string name); + ProfileCategory CreateProfileCategory(string name, bool addToTop = false); /// /// Permanently deletes the provided profile category. @@ -119,7 +127,7 @@ public interface IProfileService : IArtemisService Task ExportProfile(ProfileConfiguration profileConfiguration); /// - /// Imports the provided base64 encoded GZIPed JSON as a profile configuration. + /// Imports the provided ZIP archive stream as a profile configuration. /// /// The zip archive containing the profile to import. /// The in which to import the profile. @@ -129,8 +137,17 @@ public interface IProfileService : IArtemisService /// any changes are made to it. /// /// Text to add after the name of the profile (separated by a dash). + /// The index at which to import the profile into the category. /// The resulting profile configuration. - Task ImportProfile(Stream archiveStream, ProfileCategory category, bool makeUnique, bool markAsFreshImport, string? nameAffix = "imported"); + Task ImportProfile(Stream archiveStream, ProfileCategory category, bool makeUnique, bool markAsFreshImport, string? nameAffix = "imported", int targetIndex = 0); + + /// + /// Imports the provided ZIP archive stream into the provided profile configuration + /// + /// The zip archive containing the profile to import. + /// The profile configuration to overwrite. + /// The resulting profile configuration. + Task OverwriteProfile(MemoryStream archiveStream, ProfileConfiguration profileConfiguration); /// /// Adapts a given profile to the currently active devices. @@ -168,4 +185,5 @@ public interface IProfileService : IArtemisService /// Occurs whenever a profile category is removed. /// public event EventHandler? ProfileCategoryRemoved; + } \ No newline at end of file diff --git a/src/Artemis.Core/Services/Storage/ProfileService.cs b/src/Artemis.Core/Services/Storage/ProfileService.cs index b01e6bc56..7321fc6b2 100644 --- a/src/Artemis.Core/Services/Storage/ProfileService.cs +++ b/src/Artemis.Core/Services/Storage/ProfileService.cs @@ -19,14 +19,14 @@ namespace Artemis.Core.Services; internal class ProfileService : IProfileService { private readonly ILogger _logger; + private readonly IRgbService _rgbService; + private readonly IProfileCategoryRepository _profileCategoryRepository; + private readonly IPluginManagementService _pluginManagementService; private readonly List _pendingKeyboardEvents = new(); - private readonly IPluginManagementService _pluginManagementService; private readonly List _profileCategories; - private readonly IProfileCategoryRepository _profileCategoryRepository; private readonly IProfileRepository _profileRepository; private readonly List _renderExceptions = new(); - private readonly IRgbService _rgbService; private readonly List _updateExceptions = new(); private DateTime _lastRenderExceptionLog; private DateTime _lastUpdateExceptionLog; @@ -49,7 +49,6 @@ internal class ProfileService : IProfileService _pluginManagementService.PluginFeatureEnabled += PluginManagementServiceOnPluginFeatureToggled; _pluginManagementService.PluginFeatureDisabled += PluginManagementServiceOnPluginFeatureToggled; - HotkeysEnabled = true; inputService.KeyboardKeyUp += InputServiceOnKeyboardKeyUp; if (!_profileCategories.Any()) @@ -57,11 +56,488 @@ internal class ProfileService : IProfileService UpdateModules(); } - private void InputServiceOnKeyboardKeyUp(object? sender, ArtemisKeyboardKeyEventArgs e) + public ProfileConfiguration? FocusProfile { get; set; } + public ProfileElement? FocusProfileElement { get; set; } + public bool UpdateFocusProfile { get; set; } + + /// + public void UpdateProfiles(double deltaTime) { - if (!HotkeysEnabled) + // If there is a focus profile update only that, and only if UpdateFocusProfile is true + if (FocusProfile != null) + { + if (UpdateFocusProfile) + FocusProfile.Profile?.Update(deltaTime); + return; + } + + lock (_profileCategories) + { + // Iterate the children in reverse because the first category must be rendered last to end up on top + for (int i = _profileCategories.Count - 1; i > -1; i--) + { + ProfileCategory profileCategory = _profileCategories[i]; + for (int j = profileCategory.ProfileConfigurations.Count - 1; j > -1; j--) + { + ProfileConfiguration profileConfiguration = profileCategory.ProfileConfigurations[j]; + + // Process hotkeys that where pressed since this profile last updated + ProcessPendingKeyEvents(profileConfiguration); + + bool shouldBeActive = profileConfiguration.ShouldBeActive(false); + if (shouldBeActive) + { + profileConfiguration.Update(); + shouldBeActive = profileConfiguration.ActivationConditionMet; + } + + try + { + // Make sure the profile is active or inactive according to the parameters above + if (shouldBeActive && profileConfiguration.Profile == null && profileConfiguration.BrokenState != "Failed to activate profile") + profileConfiguration.TryOrBreak(() => ActivateProfile(profileConfiguration), "Failed to activate profile"); + if (shouldBeActive && profileConfiguration.Profile != null && !profileConfiguration.Profile.ShouldDisplay) + profileConfiguration.Profile.ShouldDisplay = true; + else if (!shouldBeActive && profileConfiguration.Profile != null) + { + if (!profileConfiguration.FadeInAndOut) + DeactivateProfile(profileConfiguration); + else if (!profileConfiguration.Profile.ShouldDisplay && profileConfiguration.Profile.Opacity <= 0) + DeactivateProfile(profileConfiguration); + else if (profileConfiguration.Profile.Opacity > 0) + RequestDeactivation(profileConfiguration); + } + + profileConfiguration.Profile?.Update(deltaTime); + } + catch (Exception e) + { + _updateExceptions.Add(e); + } + } + } + + LogProfileUpdateExceptions(); + _pendingKeyboardEvents.Clear(); + } + } + + /// + public void RenderProfiles(SKCanvas canvas) + { + // If there is a focus profile, render only that + if (FocusProfile != null) + { + FocusProfile.Profile?.Render(canvas, SKPointI.Empty, FocusProfileElement); + return; + } + + lock (_profileCategories) + { + // Iterate the children in reverse because the first category must be rendered last to end up on top + for (int i = _profileCategories.Count - 1; i > -1; i--) + { + ProfileCategory profileCategory = _profileCategories[i]; + for (int j = profileCategory.ProfileConfigurations.Count - 1; j > -1; j--) + { + try + { + ProfileConfiguration profileConfiguration = profileCategory.ProfileConfigurations[j]; + // Ensure all criteria are met before rendering + bool fadingOut = profileConfiguration.Profile?.ShouldDisplay == false && profileConfiguration.Profile?.Opacity > 0; + if (!profileConfiguration.IsSuspended && !profileConfiguration.IsMissingModule && (profileConfiguration.ActivationConditionMet || fadingOut)) + profileConfiguration.Profile?.Render(canvas, SKPointI.Empty, null); + } + catch (Exception e) + { + _renderExceptions.Add(e); + } + } + } + + LogProfileRenderExceptions(); + } + } + + /// + public ReadOnlyCollection ProfileCategories + { + get + { + lock (_profileRepository) + { + return _profileCategories.AsReadOnly(); + } + } + } + + /// + public ReadOnlyCollection ProfileConfigurations + { + get + { + lock (_profileRepository) + { + return _profileCategories.SelectMany(c => c.ProfileConfigurations).ToList().AsReadOnly(); + } + } + } + + /// + public void LoadProfileConfigurationIcon(ProfileConfiguration profileConfiguration) + { + if (profileConfiguration.Icon.IconType == ProfileConfigurationIconType.MaterialIcon) return; + using Stream? stream = _profileCategoryRepository.GetProfileIconStream(profileConfiguration.Entity.FileIconId); + if (stream != null) + profileConfiguration.Icon.SetIconByStream(stream); + } + + /// + public void SaveProfileConfigurationIcon(ProfileConfiguration profileConfiguration) + { + if (profileConfiguration.Icon.IconType == ProfileConfigurationIconType.MaterialIcon) + return; + + using Stream? stream = profileConfiguration.Icon.GetIconStream(); + if (stream != null) + _profileCategoryRepository.SaveProfileIconStream(profileConfiguration.Entity, stream); + } + + /// + public ProfileConfiguration CloneProfileConfiguration(ProfileConfiguration profileConfiguration) + { + return new ProfileConfiguration(profileConfiguration.Category, profileConfiguration.Entity); + } + + /// + public Profile ActivateProfile(ProfileConfiguration profileConfiguration) + { + if (profileConfiguration.Profile != null) + { + profileConfiguration.Profile.ShouldDisplay = true; + return profileConfiguration.Profile; + } + + ProfileEntity profileEntity; + try + { + profileEntity = _profileRepository.Get(profileConfiguration.Entity.ProfileId); + } + catch (Exception e) + { + profileConfiguration.SetBrokenState("Failed to activate profile", e); + throw; + } + + if (profileEntity == null) + throw new ArtemisCoreException($"Cannot find profile named: {profileConfiguration.Name} ID: {profileConfiguration.Entity.ProfileId}"); + + Profile profile = new(profileConfiguration, profileEntity); + profile.PopulateLeds(_rgbService.EnabledDevices); + + if (profile.IsFreshImport) + { + _logger.Debug("Profile is a fresh import, adapting to surface - {profile}", profile); + AdaptProfile(profile); + } + + profileConfiguration.Profile = profile; + + OnProfileActivated(new ProfileConfigurationEventArgs(profileConfiguration)); + return profile; + } + + /// + public void DeactivateProfile(ProfileConfiguration profileConfiguration) + { + if (FocusProfile == profileConfiguration) + throw new ArtemisCoreException("Cannot disable a profile that is being edited, that's rude"); + if (profileConfiguration.Profile == null) + return; + + Profile profile = profileConfiguration.Profile; + profileConfiguration.Profile = null; + profile.Dispose(); + + OnProfileDeactivated(new ProfileConfigurationEventArgs(profileConfiguration)); + } + + private void RequestDeactivation(ProfileConfiguration profileConfiguration) + { + if (FocusProfile == profileConfiguration) + throw new ArtemisCoreException("Cannot disable a profile that is being edited, that's rude"); + if (profileConfiguration.Profile == null) + return; + + profileConfiguration.Profile.ShouldDisplay = false; + } + + /// + public void DeleteProfile(ProfileConfiguration profileConfiguration) + { + DeactivateProfile(profileConfiguration); + + ProfileEntity profileEntity = _profileRepository.Get(profileConfiguration.Entity.ProfileId); + if (profileEntity == null) + return; + + profileConfiguration.Category.RemoveProfileConfiguration(profileConfiguration); + _profileRepository.Remove(profileEntity); + SaveProfileCategory(profileConfiguration.Category); + } + + /// + public ProfileCategory CreateProfileCategory(string name, bool addToTop = false) + { + ProfileCategory profileCategory; + lock (_profileRepository) + { + if (addToTop) + { + profileCategory = new ProfileCategory(name, 1); + foreach (ProfileCategory category in _profileCategories) + { + category.Order++; + category.Save(); + _profileCategoryRepository.Save(category.Entity); + } + } + else + { + profileCategory = new ProfileCategory(name, _profileCategories.Count + 1); + } + + _profileCategories.Add(profileCategory); + SaveProfileCategory(profileCategory); + } + + OnProfileCategoryAdded(new ProfileCategoryEventArgs(profileCategory)); + return profileCategory; + } + + /// + public void DeleteProfileCategory(ProfileCategory profileCategory) + { + List profileConfigurations = profileCategory.ProfileConfigurations.ToList(); + foreach (ProfileConfiguration profileConfiguration in profileConfigurations) + RemoveProfileConfiguration(profileConfiguration); + + lock (_profileRepository) + { + _profileCategories.Remove(profileCategory); + _profileCategoryRepository.Remove(profileCategory.Entity); + } + + OnProfileCategoryRemoved(new ProfileCategoryEventArgs(profileCategory)); + } + + /// + public ProfileConfiguration CreateProfileConfiguration(ProfileCategory category, string name, string icon) + { + ProfileConfiguration configuration = new(category, name, icon); + ProfileEntity entity = new(); + _profileRepository.Add(entity); + + configuration.Entity.ProfileId = entity.Id; + category.AddProfileConfiguration(configuration, 0); + return configuration; + } + + /// + public void RemoveProfileConfiguration(ProfileConfiguration profileConfiguration) + { + profileConfiguration.Category.RemoveProfileConfiguration(profileConfiguration); + + DeactivateProfile(profileConfiguration); + SaveProfileCategory(profileConfiguration.Category); + ProfileEntity profileEntity = _profileRepository.Get(profileConfiguration.Entity.ProfileId); + if (profileEntity != null) + _profileRepository.Remove(profileEntity); + + profileConfiguration.Dispose(); + } + + /// + public void SaveProfileCategory(ProfileCategory profileCategory) + { + profileCategory.Save(); + _profileCategoryRepository.Save(profileCategory.Entity); + + lock (_profileCategories) + { + _profileCategories.Sort((a, b) => a.Order - b.Order); + } + } + + /// + public void SaveProfile(Profile profile, bool includeChildren) + { + _logger.Debug("Updating profile - Saving {Profile}", profile); + profile.Save(); + if (includeChildren) + { + foreach (RenderProfileElement child in profile.GetAllRenderElements()) + child.Save(); + } + + // At this point the user made actual changes, save that + profile.IsFreshImport = false; + profile.ProfileEntity.IsFreshImport = false; + + _profileRepository.Save(profile.ProfileEntity); + + // If the provided profile is external (cloned or from the workshop?) but it is loaded locally too, reload the local instance + // A bit dodge but it ensures local instances always represent the latest stored version + ProfileConfiguration? localInstance = ProfileConfigurations.FirstOrDefault(p => p.Profile != null && p.Profile != profile && p.ProfileId == profile.ProfileEntity.Id); + if (localInstance == null) + return; + DeactivateProfile(localInstance); + ActivateProfile(localInstance); + } + + /// + public async Task ExportProfile(ProfileConfiguration profileConfiguration) + { + ProfileEntity? profileEntity = _profileRepository.Get(profileConfiguration.Entity.ProfileId); + if (profileEntity == null) + throw new ArtemisCoreException("Could not locate profile entity"); + + string configurationJson = JsonConvert.SerializeObject(profileConfiguration.Entity, IProfileService.ExportSettings); + string profileJson = JsonConvert.SerializeObject(profileEntity, IProfileService.ExportSettings); + + MemoryStream archiveStream = new(); + + // Create a ZIP archive + using (ZipArchive archive = new(archiveStream, ZipArchiveMode.Create, true)) + { + ZipArchiveEntry configurationEntry = archive.CreateEntry("configuration.json"); + await using (Stream entryStream = configurationEntry.Open()) + { + await entryStream.WriteAsync(Encoding.Default.GetBytes(configurationJson)); + } + + ZipArchiveEntry profileEntry = archive.CreateEntry("profile.json"); + await using (Stream entryStream = profileEntry.Open()) + { + await entryStream.WriteAsync(Encoding.Default.GetBytes(profileJson)); + } + + await using Stream? iconStream = profileConfiguration.Icon.GetIconStream(); + if (iconStream != null) + { + ZipArchiveEntry iconEntry = archive.CreateEntry("icon.png"); + await using Stream entryStream = iconEntry.Open(); + await iconStream.CopyToAsync(entryStream); + } + } + + archiveStream.Seek(0, SeekOrigin.Begin); + return archiveStream; + } + + /// + public async Task ImportProfile(Stream archiveStream, ProfileCategory category, bool makeUnique, bool markAsFreshImport, string? nameAffix, int targetIndex = 0) + { + using ZipArchive archive = new(archiveStream, ZipArchiveMode.Read, true); + + // There should be a configuration.json and profile.json + ZipArchiveEntry? configurationEntry = archive.Entries.FirstOrDefault(e => e.Name.EndsWith("configuration.json")); + ZipArchiveEntry? profileEntry = archive.Entries.FirstOrDefault(e => e.Name.EndsWith("profile.json")); + ZipArchiveEntry? iconEntry = archive.Entries.FirstOrDefault(e => e.Name.EndsWith("icon.png")); + + if (configurationEntry == null) + throw new ArtemisCoreException("Could not import profile, configuration.json missing"); + if (profileEntry == null) + throw new ArtemisCoreException("Could not import profile, profile.json missing"); + + await using Stream configurationStream = configurationEntry.Open(); + using StreamReader configurationReader = new(configurationStream); + ProfileConfigurationEntity? configurationEntity = JsonConvert.DeserializeObject(await configurationReader.ReadToEndAsync(), IProfileService.ExportSettings); + if (configurationEntity == null) + throw new ArtemisCoreException("Could not import profile, failed to deserialize configuration.json"); + + await using Stream profileStream = profileEntry.Open(); + using StreamReader profileReader = new(profileStream); + ProfileEntity? profileEntity = JsonConvert.DeserializeObject(await profileReader.ReadToEndAsync(), IProfileService.ExportSettings); + if (profileEntity == null) + throw new ArtemisCoreException("Could not import profile, failed to deserialize profile.json"); + + // Assign a new GUID to make sure it is unique in case of a previous import of the same content + if (makeUnique) + profileEntity.UpdateGuid(Guid.NewGuid()); + else + { + // If the profile already exists and this one is not to be made unique, return the existing profile + ProfileConfiguration? existing = ProfileCategories.SelectMany(c => c.ProfileConfigurations).FirstOrDefault(p => p.ProfileId == profileEntity.Id); + if (existing != null) + return existing; + } + + if (nameAffix != null) + profileEntity.Name = $"{profileEntity.Name} - {nameAffix}"; + if (markAsFreshImport) + profileEntity.IsFreshImport = true; + + if (_profileRepository.Get(profileEntity.Id) == null) + _profileRepository.Add(profileEntity); + else + throw new ArtemisCoreException($"Cannot import this profile without {nameof(makeUnique)} being true"); + + // A new GUID will be given on save + configurationEntity.FileIconId = Guid.Empty; + ProfileConfiguration profileConfiguration = new(category, configurationEntity); + if (nameAffix != null) + profileConfiguration.Name = $"{profileConfiguration.Name} - {nameAffix}"; + + // If an icon was provided, import that as well + if (iconEntry != null) + { + await using Stream iconStream = iconEntry.Open(); + profileConfiguration.Icon.SetIconByStream(iconStream); + SaveProfileConfigurationIcon(profileConfiguration); + } + + profileConfiguration.Entity.ProfileId = profileEntity.Id; + category.AddProfileConfiguration(profileConfiguration, targetIndex); + + List modules = _pluginManagementService.GetFeaturesOfType(); + profileConfiguration.LoadModules(modules); + SaveProfileCategory(category); + + return profileConfiguration; + } + + /// + public async Task OverwriteProfile(MemoryStream archiveStream, ProfileConfiguration profileConfiguration) + { + ProfileConfiguration imported = await ImportProfile(archiveStream, profileConfiguration.Category, true, true, null, profileConfiguration.Order + 1); + + DeleteProfile(profileConfiguration); + SaveProfileCategory(imported.Category); + + return imported; + } + + /// + public void AdaptProfile(Profile profile) + { + List devices = _rgbService.EnabledDevices.ToList(); + foreach (Layer layer in profile.GetAllLayers()) + layer.Adapter.Adapt(devices); + + profile.Save(); + + foreach (RenderProfileElement renderProfileElement in profile.GetAllRenderElements()) + renderProfileElement.Save(); + + _logger.Debug("Adapt profile - Saving " + profile); + _profileRepository.Save(profile.ProfileEntity); + } + + private void InputServiceOnKeyboardKeyUp(object? sender, ArtemisKeyboardKeyEventArgs e) + { lock (_profileCategories) { _pendingKeyboardEvents.Add(e); @@ -129,7 +605,7 @@ internal class ProfileService : IProfileService profileConfiguration.IsSuspended = true; } } - + // If suspension was changed, save the category if (before != profileConfiguration.IsSuspended) SaveProfileCategory(profileConfiguration.Category); @@ -185,432 +661,6 @@ internal class ProfileService : IProfileService _renderExceptions.Clear(); } - public bool HotkeysEnabled { get; set; } - public bool RenderForEditor { get; set; } - public ProfileElement? EditorFocus { get; set; } - - public void UpdateProfiles(double deltaTime) - { - lock (_profileCategories) - { - // Iterate the children in reverse because the first category must be rendered last to end up on top - for (int i = _profileCategories.Count - 1; i > -1; i--) - { - ProfileCategory profileCategory = _profileCategories[i]; - for (int j = profileCategory.ProfileConfigurations.Count - 1; j > -1; j--) - { - ProfileConfiguration profileConfiguration = profileCategory.ProfileConfigurations[j]; - - // Process hotkeys that where pressed since this profile last updated - ProcessPendingKeyEvents(profileConfiguration); - - // Profiles being edited are updated at their own leisure - if (profileConfiguration.IsBeingEdited && RenderForEditor) - continue; - - bool shouldBeActive = profileConfiguration.ShouldBeActive(false); - if (shouldBeActive) - { - profileConfiguration.Update(); - if (!profileConfiguration.IsBeingEdited) - shouldBeActive = profileConfiguration.ActivationConditionMet; - } - - try - { - // Make sure the profile is active or inactive according to the parameters above - if (shouldBeActive && profileConfiguration.Profile == null && profileConfiguration.BrokenState != "Failed to activate profile") - profileConfiguration.TryOrBreak(() => ActivateProfile(profileConfiguration), "Failed to activate profile"); - if (shouldBeActive && profileConfiguration.Profile != null && !profileConfiguration.Profile.ShouldDisplay) - profileConfiguration.Profile.ShouldDisplay = true; - else if (!shouldBeActive && profileConfiguration.Profile != null) - { - if (!profileConfiguration.FadeInAndOut) - DeactivateProfile(profileConfiguration); - else if (!profileConfiguration.Profile.ShouldDisplay && profileConfiguration.Profile.Opacity <= 0) - DeactivateProfile(profileConfiguration); - else if (profileConfiguration.Profile.Opacity > 0) - RequestDeactivation(profileConfiguration); - } - - profileConfiguration.Profile?.Update(deltaTime); - } - catch (Exception e) - { - _updateExceptions.Add(e); - } - } - } - - LogProfileUpdateExceptions(); - _pendingKeyboardEvents.Clear(); - } - } - - public void RenderProfiles(SKCanvas canvas) - { - lock (_profileCategories) - { - ProfileConfiguration? editedProfileConfiguration = _profileCategories.SelectMany(c => c.ProfileConfigurations).FirstOrDefault(p => p.IsBeingEdited); - if (editedProfileConfiguration != null) - { - editedProfileConfiguration.Profile?.Render(canvas, SKPointI.Empty, RenderForEditor ? EditorFocus : null); - return; - } - - if (RenderForEditor) - return; - - // Iterate the children in reverse because the first category must be rendered last to end up on top - for (int i = _profileCategories.Count - 1; i > -1; i--) - { - ProfileCategory profileCategory = _profileCategories[i]; - for (int j = profileCategory.ProfileConfigurations.Count - 1; j > -1; j--) - { - try - { - ProfileConfiguration profileConfiguration = profileCategory.ProfileConfigurations[j]; - // Ensure all criteria are met before rendering - bool fadingOut = profileConfiguration.Profile?.ShouldDisplay == false && profileConfiguration.Profile?.Opacity > 0; - if (!profileConfiguration.IsSuspended && !profileConfiguration.IsMissingModule && (profileConfiguration.ActivationConditionMet || fadingOut)) - profileConfiguration.Profile?.Render(canvas, SKPointI.Empty, null); - } - catch (Exception e) - { - _renderExceptions.Add(e); - } - } - } - - LogProfileRenderExceptions(); - } - } - - public ReadOnlyCollection ProfileCategories - { - get - { - lock (_profileRepository) - { - return _profileCategories.AsReadOnly(); - } - } - } - - public ReadOnlyCollection ProfileConfigurations - { - get - { - lock (_profileRepository) - { - return _profileCategories.SelectMany(c => c.ProfileConfigurations).ToList().AsReadOnly(); - } - } - } - - public void LoadProfileConfigurationIcon(ProfileConfiguration profileConfiguration) - { - if (profileConfiguration.Icon.IconType == ProfileConfigurationIconType.MaterialIcon) - return; - - using Stream? stream = _profileCategoryRepository.GetProfileIconStream(profileConfiguration.Entity.FileIconId); - if (stream != null) - profileConfiguration.Icon.SetIconByStream(stream); - } - - public void SaveProfileConfigurationIcon(ProfileConfiguration profileConfiguration) - { - if (profileConfiguration.Icon.IconType == ProfileConfigurationIconType.MaterialIcon) - return; - - using Stream? stream = profileConfiguration.Icon.GetIconStream(); - if (stream != null) - { - _profileCategoryRepository.SaveProfileIconStream(profileConfiguration.Entity, stream); - } - } - - public Profile ActivateProfile(ProfileConfiguration profileConfiguration) - { - if (profileConfiguration.Profile != null) - { - profileConfiguration.Profile.ShouldDisplay = true; - return profileConfiguration.Profile; - } - - ProfileEntity profileEntity; - try - { - profileEntity = _profileRepository.Get(profileConfiguration.Entity.ProfileId); - } - catch (Exception e) - { - profileConfiguration.SetBrokenState("Failed to activate profile", e); - throw; - } - - if (profileEntity == null) - throw new ArtemisCoreException($"Cannot find profile named: {profileConfiguration.Name} ID: {profileConfiguration.Entity.ProfileId}"); - - Profile profile = new(profileConfiguration, profileEntity); - profile.PopulateLeds(_rgbService.EnabledDevices); - - if (profile.IsFreshImport) - { - _logger.Debug("Profile is a fresh import, adapting to surface - {profile}", profile); - AdaptProfile(profile); - } - - profileConfiguration.Profile = profile; - - OnProfileActivated(new ProfileConfigurationEventArgs(profileConfiguration)); - return profile; - } - - public void DeactivateProfile(ProfileConfiguration profileConfiguration) - { - if (profileConfiguration.IsBeingEdited) - throw new ArtemisCoreException("Cannot disable a profile that is being edited, that's rude"); - if (profileConfiguration.Profile == null) - return; - - Profile profile = profileConfiguration.Profile; - profileConfiguration.Profile = null; - profile.Dispose(); - - OnProfileDeactivated(new ProfileConfigurationEventArgs(profileConfiguration)); - } - - private void RequestDeactivation(ProfileConfiguration profileConfiguration) - { - if (profileConfiguration.IsBeingEdited) - throw new ArtemisCoreException("Cannot disable a profile that is being edited, that's rude"); - if (profileConfiguration.Profile == null) - return; - - profileConfiguration.Profile.ShouldDisplay = false; - } - - public void DeleteProfile(ProfileConfiguration profileConfiguration) - { - DeactivateProfile(profileConfiguration); - - ProfileEntity profileEntity = _profileRepository.Get(profileConfiguration.Entity.ProfileId); - if (profileEntity == null) - return; - - profileConfiguration.Category.RemoveProfileConfiguration(profileConfiguration); - _profileRepository.Remove(profileEntity); - SaveProfileCategory(profileConfiguration.Category); - } - - public ProfileCategory CreateProfileCategory(string name) - { - ProfileCategory profileCategory; - lock (_profileRepository) - { - profileCategory = new ProfileCategory(name, _profileCategories.Count + 1); - _profileCategories.Add(profileCategory); - SaveProfileCategory(profileCategory); - } - - OnProfileCategoryAdded(new ProfileCategoryEventArgs(profileCategory)); - return profileCategory; - } - - public void DeleteProfileCategory(ProfileCategory profileCategory) - { - List profileConfigurations = profileCategory.ProfileConfigurations.ToList(); - foreach (ProfileConfiguration profileConfiguration in profileConfigurations) - RemoveProfileConfiguration(profileConfiguration); - - lock (_profileRepository) - { - _profileCategories.Remove(profileCategory); - _profileCategoryRepository.Remove(profileCategory.Entity); - } - - OnProfileCategoryRemoved(new ProfileCategoryEventArgs(profileCategory)); - } - - public ProfileConfiguration CreateProfileConfiguration(ProfileCategory category, string name, string icon) - { - ProfileConfiguration configuration = new(category, name, icon); - ProfileEntity entity = new(); - _profileRepository.Add(entity); - - configuration.Entity.ProfileId = entity.Id; - category.AddProfileConfiguration(configuration, 0); - return configuration; - } - - public void RemoveProfileConfiguration(ProfileConfiguration profileConfiguration) - { - profileConfiguration.Category.RemoveProfileConfiguration(profileConfiguration); - - DeactivateProfile(profileConfiguration); - SaveProfileCategory(profileConfiguration.Category); - ProfileEntity profileEntity = _profileRepository.Get(profileConfiguration.Entity.ProfileId); - if (profileEntity != null) - _profileRepository.Remove(profileEntity); - - profileConfiguration.Dispose(); - } - - public void SaveProfileCategory(ProfileCategory profileCategory) - { - profileCategory.Save(); - _profileCategoryRepository.Save(profileCategory.Entity); - - lock (_profileCategories) - { - _profileCategories.Sort((a, b) => a.Order - b.Order); - } - } - - public void SaveProfile(Profile profile, bool includeChildren) - { - _logger.Debug("Updating profile - Saving {Profile}", profile); - profile.Save(); - if (includeChildren) - foreach (RenderProfileElement child in profile.GetAllRenderElements()) - child.Save(); - - // At this point the user made actual changes, save that - profile.IsFreshImport = false; - profile.ProfileEntity.IsFreshImport = false; - - _profileRepository.Save(profile.ProfileEntity); - } - - /// - public async Task ExportProfile(ProfileConfiguration profileConfiguration) - { - ProfileEntity? profileEntity = _profileRepository.Get(profileConfiguration.Entity.ProfileId); - if (profileEntity == null) - throw new ArtemisCoreException("Could not locate profile entity"); - - string configurationJson = JsonConvert.SerializeObject(profileConfiguration.Entity, IProfileService.ExportSettings); - string profileJson = JsonConvert.SerializeObject(profileEntity, IProfileService.ExportSettings); - - MemoryStream archiveStream = new(); - - // Create a ZIP archive - using (ZipArchive archive = new(archiveStream, ZipArchiveMode.Create, true)) - { - ZipArchiveEntry configurationEntry = archive.CreateEntry("configuration.json"); - await using (Stream entryStream = configurationEntry.Open()) - { - await entryStream.WriteAsync(Encoding.Default.GetBytes(configurationJson)); - } - - ZipArchiveEntry profileEntry = archive.CreateEntry("profile.json"); - await using (Stream entryStream = profileEntry.Open()) - { - await entryStream.WriteAsync(Encoding.Default.GetBytes(profileJson)); - } - - await using Stream? iconStream = profileConfiguration.Icon.GetIconStream(); - if (iconStream != null) - { - ZipArchiveEntry iconEntry = archive.CreateEntry("icon.png"); - await using Stream entryStream = iconEntry.Open(); - await iconStream.CopyToAsync(entryStream); - } - } - - archiveStream.Seek(0, SeekOrigin.Begin); - return archiveStream; - } - - /// - public async Task ImportProfile(Stream archiveStream, ProfileCategory category, bool makeUnique, bool markAsFreshImport, string? nameAffix) - { - using ZipArchive archive = new(archiveStream, ZipArchiveMode.Read, true); - - // There should be a configuration.json and profile.json - ZipArchiveEntry? configurationEntry = archive.Entries.FirstOrDefault(e => e.Name.EndsWith("configuration.json")); - ZipArchiveEntry? profileEntry = archive.Entries.FirstOrDefault(e => e.Name.EndsWith("profile.json")); - ZipArchiveEntry? iconEntry = archive.Entries.FirstOrDefault(e => e.Name.EndsWith("icon.png")); - - if (configurationEntry == null) - throw new ArtemisCoreException("Could not import profile, configuration.json missing"); - if (profileEntry == null) - throw new ArtemisCoreException("Could not import profile, profile.json missing"); - - await using Stream configurationStream = configurationEntry.Open(); - using StreamReader configurationReader = new(configurationStream); - ProfileConfigurationEntity? configurationEntity = JsonConvert.DeserializeObject(await configurationReader.ReadToEndAsync(), IProfileService.ExportSettings); - if (configurationEntity == null) - throw new ArtemisCoreException("Could not import profile, failed to deserialize configuration.json"); - - await using Stream profileStream = profileEntry.Open(); - using StreamReader profileReader = new(profileStream); - ProfileEntity? profileEntity = JsonConvert.DeserializeObject(await profileReader.ReadToEndAsync(), IProfileService.ExportSettings); - if (profileEntity == null) - throw new ArtemisCoreException("Could not import profile, failed to deserialize profile.json"); - - // Assign a new GUID to make sure it is unique in case of a previous import of the same content - if (makeUnique) - profileEntity.UpdateGuid(Guid.NewGuid()); - else - { - // If the profile already exists and this one is not to be made unique, return the existing profile - ProfileConfiguration? existing = ProfileCategories.SelectMany(c => c.ProfileConfigurations).FirstOrDefault(p => p.ProfileId == profileEntity.Id); - if (existing != null) - return existing; - } - - if (nameAffix != null) - profileEntity.Name = $"{profileEntity.Name} - {nameAffix}"; - if (markAsFreshImport) - profileEntity.IsFreshImport = true; - - if (_profileRepository.Get(profileEntity.Id) == null) - _profileRepository.Add(profileEntity); - else - throw new ArtemisCoreException($"Cannot import this profile without {nameof(makeUnique)} being true"); - - // A new GUID will be given on save - configurationEntity.FileIconId = Guid.Empty; - ProfileConfiguration profileConfiguration = new(category, configurationEntity); - if (nameAffix != null) - profileConfiguration.Name = $"{profileConfiguration.Name} - {nameAffix}"; - - // If an icon was provided, import that as well - if (iconEntry != null) - { - await using Stream iconStream = iconEntry.Open(); - profileConfiguration.Icon.SetIconByStream(iconStream); - SaveProfileConfigurationIcon(profileConfiguration); - } - - profileConfiguration.Entity.ProfileId = profileEntity.Id; - category.AddProfileConfiguration(profileConfiguration, 0); - - List modules = _pluginManagementService.GetFeaturesOfType(); - profileConfiguration.LoadModules(modules); - SaveProfileCategory(category); - - return profileConfiguration; - } - - /// - public void AdaptProfile(Profile profile) - { - List devices = _rgbService.EnabledDevices.ToList(); - foreach (Layer layer in profile.GetAllLayers()) - layer.Adapter.Adapt(devices); - - profile.Save(); - - foreach (RenderProfileElement renderProfileElement in profile.GetAllRenderElements()) - renderProfileElement.Save(); - - _logger.Debug("Adapt profile - Saving " + profile); - _profileRepository.Save(profile.ProfileEntity); - } - #region Events public event EventHandler? ProfileActivated; diff --git a/src/Artemis.Storage/Entities/Profile/ProfileEntity.cs b/src/Artemis.Storage/Entities/Profile/ProfileEntity.cs index 8a8616ce7..da5bbb903 100644 --- a/src/Artemis.Storage/Entities/Profile/ProfileEntity.cs +++ b/src/Artemis.Storage/Entities/Profile/ProfileEntity.cs @@ -18,7 +18,6 @@ public class ProfileEntity public string Name { get; set; } public bool IsFreshImport { get; set; } - public Guid LastSelectedProfileElement { get; set; } public List Folders { get; set; } public List Layers { get; set; } diff --git a/src/Artemis.Storage/Entities/Workshop/EntryEntity.cs b/src/Artemis.Storage/Entities/Workshop/EntryEntity.cs new file mode 100644 index 000000000..86bff6dcd --- /dev/null +++ b/src/Artemis.Storage/Entities/Workshop/EntryEntity.cs @@ -0,0 +1,21 @@ +using System; + +namespace Artemis.Storage.Entities.Workshop; + +public class EntryEntity +{ + public Guid Id { get; set; } + + public long EntryId { get; set; } + public int EntryType { get; set; } + + public string Author { get; set; } + public string Name { get; set; } = string.Empty; + public string Summary { get; set; } = string.Empty; + + public long ReleaseId { get; set; } + public string ReleaseVersion { get; set; } + public DateTimeOffset InstalledAt { get; set; } + + public string LocalReference { get; set; } +} \ No newline at end of file diff --git a/src/Artemis.Storage/Repositories/EntryRepository.cs b/src/Artemis.Storage/Repositories/EntryRepository.cs new file mode 100644 index 000000000..61d3da672 --- /dev/null +++ b/src/Artemis.Storage/Repositories/EntryRepository.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using Artemis.Storage.Entities.Workshop; +using Artemis.Storage.Repositories.Interfaces; +using LiteDB; + +namespace Artemis.Storage.Repositories; + +internal class EntryRepository : IEntryRepository +{ + private readonly LiteRepository _repository; + + public EntryRepository(LiteRepository repository) + { + _repository = repository; + _repository.Database.GetCollection().EnsureIndex(s => s.Id); + _repository.Database.GetCollection().EnsureIndex(s => s.EntryId); + } + + public void Add(EntryEntity entryEntity) + { + _repository.Insert(entryEntity); + } + + public void Remove(EntryEntity entryEntity) + { + _repository.Delete(entryEntity.Id); + } + + public EntryEntity Get(Guid id) + { + return _repository.FirstOrDefault(s => s.Id == id); + } + + public EntryEntity GetByEntryId(long entryId) + { + return _repository.FirstOrDefault(s => s.EntryId == entryId); + } + + public List GetAll() + { + return _repository.Query().ToList(); + } + + public void Save(EntryEntity entryEntity) + { + _repository.Upsert(entryEntity); + } + + public void Save(IEnumerable entryEntities) + { + _repository.Upsert(entryEntities); + } +} \ No newline at end of file diff --git a/src/Artemis.Storage/Repositories/Interfaces/IEntryRepository.cs b/src/Artemis.Storage/Repositories/Interfaces/IEntryRepository.cs new file mode 100644 index 000000000..1e9ecd1c5 --- /dev/null +++ b/src/Artemis.Storage/Repositories/Interfaces/IEntryRepository.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using Artemis.Storage.Entities.Workshop; + +namespace Artemis.Storage.Repositories.Interfaces; + +public interface IEntryRepository : IRepository +{ + void Add(EntryEntity entryEntity); + void Remove(EntryEntity entryEntity); + EntryEntity Get(Guid id); + EntryEntity GetByEntryId(long entryId); + List GetAll(); + void Save(EntryEntity entryEntity); + void Save(IEnumerable entryEntities); +} \ No newline at end of file diff --git a/src/Artemis.UI.Linux/App.axaml b/src/Artemis.UI.Linux/App.axaml index a63d617b9..d2109667a 100644 --- a/src/Artemis.UI.Linux/App.axaml +++ b/src/Artemis.UI.Linux/App.axaml @@ -18,7 +18,7 @@ - + diff --git a/src/Artemis.UI.MacOS/App.axaml b/src/Artemis.UI.MacOS/App.axaml index 6ef3efd97..5a000915e 100644 --- a/src/Artemis.UI.MacOS/App.axaml +++ b/src/Artemis.UI.MacOS/App.axaml @@ -18,7 +18,7 @@ - + diff --git a/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj b/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj index d6c8ca8c9..5e84fa443 100644 --- a/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj +++ b/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj @@ -15,6 +15,7 @@ + diff --git a/src/Artemis.UI.Shared/Controls/NotificationHost.cs b/src/Artemis.UI.Shared/Controls/NotificationHost.cs new file mode 100644 index 000000000..4dce59804 --- /dev/null +++ b/src/Artemis.UI.Shared/Controls/NotificationHost.cs @@ -0,0 +1,54 @@ +using System; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using Avalonia.Layout; + +namespace Artemis.UI.Shared; + +internal class NotificationHost : ContentControl +{ + private IDisposable? _rootBoundsWatcher; + + public NotificationHost() + { + Background = null; + HorizontalAlignment = HorizontalAlignment.Center; + VerticalAlignment = VerticalAlignment.Center; + } + + protected override Type StyleKeyOverride => typeof(OverlayPopupHost); + + protected override Size MeasureOverride(Size availableSize) + { + _ = base.MeasureOverride(availableSize); + + if (VisualRoot is TopLevel tl) + return tl.ClientSize; + if (VisualRoot is Control c) + return c.Bounds.Size; + + return default; + } + + protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) + { + base.OnAttachedToVisualTree(e); + if (e.Root is Control wb) + // OverlayLayer is a Canvas, so we won't get a signal to resize if the window + // bounds change. Subscribe to force update + _rootBoundsWatcher = wb.GetObservable(BoundsProperty).Subscribe(_ => OnRootBoundsChanged()); + } + + protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) + { + base.OnDetachedFromVisualTree(e); + _rootBoundsWatcher?.Dispose(); + _rootBoundsWatcher = null; + } + + private void OnRootBoundsChanged() + { + InvalidateMeasure(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Controls/TagsInput/TagsInput.cs b/src/Artemis.UI.Shared/Controls/TagsInput/TagsInput.cs new file mode 100644 index 000000000..3b94d3766 --- /dev/null +++ b/src/Artemis.UI.Shared/Controls/TagsInput/TagsInput.cs @@ -0,0 +1,78 @@ +using System.Text.RegularExpressions; +using System.Windows.Input; +using Avalonia.Controls; +using Avalonia.Controls.Metadata; +using Avalonia.Controls.Primitives; +using Avalonia.Input; +using ReactiveUI; + +namespace Artemis.UI.Shared.TagsInput; + +[TemplatePart("PART_TagInputBox", typeof(TextBox))] +public partial class TagsInput : TemplatedControl +{ + public TextBox? TagInputBox { get; set; } + public ICommand RemoveTag { get; } + + /// + public TagsInput() + { + RemoveTag = ReactiveCommand.Create(ExecuteRemoveTag); + } + + /// + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) + { + if (TagInputBox != null) + { + TagInputBox.KeyDown -= TagInputBoxOnKeyDown; + TagInputBox.TextChanging -= TagInputBoxOnTextChanging; + } + + TagInputBox = e.NameScope.Find("PART_TagInputBox"); + + if (TagInputBox != null) + { + TagInputBox.KeyDown += TagInputBoxOnKeyDown; + TagInputBox.TextChanging += TagInputBoxOnTextChanging; + } + } + + private void ExecuteRemoveTag(string t) + { + Tags.Remove(t); + + if (TagInputBox != null) + TagInputBox.IsEnabled = Tags.Count < MaxLength; + } + + private void TagInputBoxOnTextChanging(object? sender, TextChangingEventArgs e) + { + if (TagInputBox?.Text == null) + return; + + TagInputBox.Text = CleanTagRegex().Replace(TagInputBox.Text.ToLower(), ""); + } + + private void TagInputBoxOnKeyDown(object? sender, KeyEventArgs e) + { + if (TagInputBox == null) + return; + + if (e.Key == Key.Space) + e.Handled = true; + if (e.Key != Key.Enter) + return; + + if (string.IsNullOrWhiteSpace(TagInputBox.Text) || Tags.Contains(TagInputBox.Text) || Tags.Count >= MaxLength) + return; + + Tags.Add(CleanTagRegex().Replace(TagInputBox.Text.ToLower(), "")); + + TagInputBox.Text = ""; + TagInputBox.IsEnabled = Tags.Count < MaxLength; + } + + [GeneratedRegex("[\\s\\-]+")] + private static partial Regex CleanTagRegex(); +} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Controls/TagsInput/TagsInput.properties.cs b/src/Artemis.UI.Shared/Controls/TagsInput/TagsInput.properties.cs new file mode 100644 index 000000000..2660e7bb8 --- /dev/null +++ b/src/Artemis.UI.Shared/Controls/TagsInput/TagsInput.properties.cs @@ -0,0 +1,54 @@ +using System.Collections.ObjectModel; +using Avalonia; +using Avalonia.Controls.Primitives; +using Avalonia.Data; + +namespace Artemis.UI.Shared.TagsInput; + +public partial class TagsInput : TemplatedControl +{ + /// + /// Defines the property + /// + public static readonly StyledProperty> TagsProperty = + AvaloniaProperty.Register>(nameof(Tags), new ObservableCollection()); + + /// + /// Gets or sets the selected tags. + /// + public ObservableCollection Tags + { + get => GetValue(TagsProperty); + set => SetValue(TagsProperty, value); + } + + /// + /// Defines the property + /// + public static readonly StyledProperty MaxLengthProperty = + AvaloniaProperty.Register(nameof(MaxLength), 20); + + /// + /// Gets or sets the max length of each tag + /// + public int MaxLength + { + get => GetValue(MaxLengthProperty); + set => SetValue(MaxLengthProperty, value); + } + + /// + /// Defines the property + /// + public static readonly StyledProperty MaxTagsProperty = + AvaloniaProperty.Register(nameof(MaxTags), 20); + + /// + /// Gets or sets the max amount of tags to be added + /// + public int MaxTags + { + get => GetValue(MaxTagsProperty); + set => SetValue(MaxTagsProperty, value); + } +} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Controls/TagsInput/TagsInputStyles.axaml b/src/Artemis.UI.Shared/Controls/TagsInput/TagsInputStyles.axaml new file mode 100644 index 000000000..e2a0ff8e5 --- /dev/null +++ b/src/Artemis.UI.Shared/Controls/TagsInput/TagsInputStyles.axaml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Extensions/HttpClientExtensions.cs b/src/Artemis.UI.Shared/Extensions/HttpClientExtensions.cs similarity index 78% rename from src/Artemis.UI/Extensions/HttpClientExtensions.cs rename to src/Artemis.UI.Shared/Extensions/HttpClientExtensions.cs index 50af33443..d9adda42f 100644 --- a/src/Artemis.UI/Extensions/HttpClientExtensions.cs +++ b/src/Artemis.UI.Shared/Extensions/HttpClientExtensions.cs @@ -3,12 +3,13 @@ using System.IO; using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using Artemis.UI.Shared.Utilities; -namespace Artemis.UI.Extensions +namespace Artemis.UI.Shared.Extensions { public static class HttpClientProgressExtensions { - public static async Task DownloadDataAsync(this HttpClient client, string requestUrl, Stream destination, IProgress? progress, CancellationToken cancellationToken) + public static async Task DownloadDataAsync(this HttpClient client, string requestUrl, Stream destination, IProgress? progress, CancellationToken cancellationToken) { using HttpResponseMessage response = await client.GetAsync(requestUrl, HttpCompletionOption.ResponseHeadersRead, cancellationToken); response.EnsureSuccessStatusCode(); @@ -23,13 +24,10 @@ namespace Artemis.UI.Extensions } // Such progress and contentLength much reporting Wow! - Progress progressWrapper = new(totalBytes => progress.Report(GetProgressPercentage(totalBytes, contentLength.Value))); - await download.CopyToAsync(destination, 81920, progressWrapper, cancellationToken); - - float GetProgressPercentage(float totalBytes, float currentBytes) => (totalBytes / currentBytes) * 100f; + await download.CopyToAsync(destination, 81920, progress, contentLength, cancellationToken); } - static async Task CopyToAsync(this Stream source, Stream destination, int bufferSize, IProgress progress, CancellationToken cancellationToken) + static async Task CopyToAsync(this Stream source, Stream destination, int bufferSize, IProgress progress, long? contentLength, CancellationToken cancellationToken) { if (bufferSize < 0) throw new ArgumentOutOfRangeException(nameof(bufferSize)); @@ -49,7 +47,7 @@ namespace Artemis.UI.Extensions { await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false); totalBytesRead += bytesRead; - progress?.Report(totalBytesRead); + progress?.Report(new StreamProgress(totalBytesRead, contentLength ?? totalBytesRead)); } } } diff --git a/src/Artemis.UI.Shared/Routing/Routable/IRoutableHostScreen.cs b/src/Artemis.UI.Shared/Routing/Routable/IRoutableHostScreen.cs new file mode 100644 index 000000000..b09afb676 --- /dev/null +++ b/src/Artemis.UI.Shared/Routing/Routable/IRoutableHostScreen.cs @@ -0,0 +1,13 @@ +namespace Artemis.UI.Shared.Routing; + +/// +/// For internal use. +/// +/// +/// +internal interface IRoutableHostScreen : IRoutableScreen +{ + bool RecycleScreen { get; } + IRoutableScreen? InternalScreen { get; } + void InternalChangeScreen(IRoutableScreen? screen); +} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Routing/Routable/IRoutableScreen.cs b/src/Artemis.UI.Shared/Routing/Routable/IRoutableScreen.cs new file mode 100644 index 000000000..3b28384cd --- /dev/null +++ b/src/Artemis.UI.Shared/Routing/Routable/IRoutableScreen.cs @@ -0,0 +1,14 @@ +using System.Threading; +using System.Threading.Tasks; +using ReactiveUI; + +namespace Artemis.UI.Shared.Routing; + +/// +/// For internal use. +/// +internal interface IRoutableScreen : IActivatableViewModel +{ + Task InternalOnNavigating(NavigationArguments args, CancellationToken cancellationToken); + Task InternalOnClosing(NavigationArguments args); +} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Routing/Routable/RoutableHostScreenOfTScreen.cs b/src/Artemis.UI.Shared/Routing/Routable/RoutableHostScreenOfTScreen.cs new file mode 100644 index 000000000..c61c27820 --- /dev/null +++ b/src/Artemis.UI.Shared/Routing/Routable/RoutableHostScreenOfTScreen.cs @@ -0,0 +1,42 @@ +namespace Artemis.UI.Shared.Routing; + +/// +/// Represents a view model to which routing can take place and which in turn can host another view model. +/// +/// The type of view model the screen can host. +public abstract class RoutableHostScreen : RoutableScreen, IRoutableHostScreen where TScreen : RoutableScreen +{ + private bool _recycleScreen = true; + private TScreen? _screen; + + /// + /// Gets the currently active child screen. + /// + public TScreen? Screen + { + get => _screen; + private set => RaiseAndSetIfChanged(ref _screen, value); + } + + /// + public bool RecycleScreen + { + get => _recycleScreen; + protected set => RaiseAndSetIfChanged(ref _recycleScreen, value); + } + + IRoutableScreen? IRoutableHostScreen.InternalScreen => Screen; + + void IRoutableHostScreen.InternalChangeScreen(IRoutableScreen? screen) + { + if (screen == null) + { + Screen = null; + return; + } + + if (screen is not TScreen typedScreen) + throw new ArtemisRoutingException($"Screen cannot be hosted, {screen.GetType().Name} is not assignable to {typeof(TScreen).Name}."); + Screen = typedScreen; + } +} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Routing/Routable/RoutableHostScreenOfTScreenTParam.cs b/src/Artemis.UI.Shared/Routing/Routable/RoutableHostScreenOfTScreenTParam.cs new file mode 100644 index 000000000..89773e8d4 --- /dev/null +++ b/src/Artemis.UI.Shared/Routing/Routable/RoutableHostScreenOfTScreenTParam.cs @@ -0,0 +1,44 @@ +namespace Artemis.UI.Shared.Routing; + +/// +/// Represents a view model to which routing with parameters can take place and which in turn can host another view +/// model. +/// +/// The type of view model the screen can host. +/// The type of parameters the screen expects. It must have a parameterless constructor. +public abstract class RoutableHostScreen : RoutableScreen, IRoutableHostScreen where TScreen : RoutableScreen where TParam : new() +{ + private bool _recycleScreen = true; + private TScreen? _screen; + + /// + /// Gets the currently active child screen. + /// + public TScreen? Screen + { + get => _screen; + private set => RaiseAndSetIfChanged(ref _screen, value); + } + + /// + public bool RecycleScreen + { + get => _recycleScreen; + protected set => RaiseAndSetIfChanged(ref _recycleScreen, value); + } + + IRoutableScreen? IRoutableHostScreen.InternalScreen => Screen; + + void IRoutableHostScreen.InternalChangeScreen(IRoutableScreen? screen) + { + if (screen == null) + { + Screen = null; + return; + } + + if (screen is not TScreen typedScreen) + throw new ArtemisRoutingException($"Screen cannot be hosted, {screen.GetType().Name} is not assignable to {typeof(TScreen).Name}."); + Screen = typedScreen; + } +} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Routing/Routable/RoutableScreen.cs b/src/Artemis.UI.Shared/Routing/Routable/RoutableScreen.cs index 53973de46..7db5dbe2e 100644 --- a/src/Artemis.UI.Shared/Routing/Routable/RoutableScreen.cs +++ b/src/Artemis.UI.Shared/Routing/Routable/RoutableScreen.cs @@ -1,24 +1,55 @@ using System.Threading; using System.Threading.Tasks; -using ReactiveUI; namespace Artemis.UI.Shared.Routing; /// -/// For internal use. +/// Represents a view model to which routing can take place. /// -/// -/// -internal interface IRoutableScreen : IActivatableViewModel +public abstract class RoutableScreen : ActivatableViewModelBase, IRoutableScreen { /// - /// Gets or sets a value indicating whether or not to reuse the child screen instance if the type has not changed. + /// Called before navigating to this screen. /// - /// Defaults to . - bool RecycleScreen { get; } + /// Navigation arguments containing information about the navigation action. + public virtual Task BeforeNavigating(NavigationArguments args) + { + return Task.CompletedTask; + } - object? InternalScreen { get; } - void InternalChangeScreen(object? screen); - Task InternalOnNavigating(NavigationArguments args, CancellationToken cancellationToken); - Task InternalOnClosing(NavigationArguments args); + /// + /// Called while navigating to this screen. + /// + /// Navigation arguments containing information about the navigation action. + /// + /// A cancellation token that can be used by other objects or threads to receive notice of + /// cancellation. + /// + public virtual Task OnNavigating(NavigationArguments args, CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + + /// + /// Called before navigating away from this screen. + /// + /// Navigation arguments containing information about the navigation action. + public virtual Task OnClosing(NavigationArguments args) + { + return Task.CompletedTask; + } + + #region Overrides of RoutableScreen + + async Task IRoutableScreen.InternalOnNavigating(NavigationArguments args, CancellationToken cancellationToken) + { + await OnNavigating(args, cancellationToken); + } + + async Task IRoutableScreen.InternalOnClosing(NavigationArguments args) + { + await OnClosing(args); + } + + #endregion } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Routing/Routable/RoutableScreenOfTScreenTParam.cs b/src/Artemis.UI.Shared/Routing/Routable/RoutableScreenOfTParam.cs similarity index 68% rename from src/Artemis.UI.Shared/Routing/Routable/RoutableScreenOfTScreenTParam.cs rename to src/Artemis.UI.Shared/Routing/Routable/RoutableScreenOfTParam.cs index ac62129dc..bbe71fe2a 100644 --- a/src/Artemis.UI.Shared/Routing/Routable/RoutableScreenOfTScreenTParam.cs +++ b/src/Artemis.UI.Shared/Routing/Routable/RoutableScreenOfTParam.cs @@ -4,39 +4,15 @@ using System.Linq; using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; -using Avalonia.Platform; namespace Artemis.UI.Shared.Routing; /// -/// Represents a view model to which routing with parameters can take place and which in turn can host another view -/// model. +/// Represents a view model to which routing with parameters can take place. /// -/// The type of view model the screen can host. /// The type of parameters the screen expects. It must have a parameterless constructor. -public abstract class RoutableScreen : ActivatableViewModelBase, IRoutableScreen where TScreen : class where TParam : new() +public abstract class RoutableScreen : RoutableScreen, IRoutableScreen where TParam : new() { - private bool _recycleScreen = true; - private TScreen? _screen; - - /// - /// Gets the currently active child screen. - /// - public TScreen? Screen - { - get => _screen; - private set => RaiseAndSetIfChanged(ref _screen, value); - } - - /// - /// Called before navigating to this screen. - /// - /// Navigation arguments containing information about the navigation action. - public virtual Task BeforeNavigating(NavigationArguments args) - { - return Task.CompletedTask; - } - /// /// Called while navigating to this screen. /// @@ -50,40 +26,7 @@ public abstract class RoutableScreen : ActivatableViewModelBase { return Task.CompletedTask; } - - /// - /// Called before navigating away from this screen. - /// - /// Navigation arguments containing information about the navigation action. - public virtual Task OnClosing(NavigationArguments args) - { - return Task.CompletedTask; - } - - /// - public bool RecycleScreen - { - get => _recycleScreen; - protected set => RaiseAndSetIfChanged(ref _recycleScreen, value); - } - - #region Overrides of RoutableScreen - - object? IRoutableScreen.InternalScreen => Screen; - - void IRoutableScreen.InternalChangeScreen(object? screen) - { - if (screen == null) - { - Screen = null; - return; - } - - if (screen is not TScreen typedScreen) - throw new ArtemisRoutingException($"Provided screen is not assignable to {typeof(TScreen).FullName}"); - Screen = typedScreen; - } - + async Task IRoutableScreen.InternalOnNavigating(NavigationArguments args, CancellationToken cancellationToken) { Func activator = GetParameterActivator(); @@ -92,6 +35,7 @@ public abstract class RoutableScreen : ActivatableViewModelBase throw new ArtemisRoutingException($"Did not retrieve the required amount of parameters, expects {_parameterPropertyCount}, got {args.SegmentParameters.Length}."); TParam parameters = activator(args.SegmentParameters); + await OnNavigating(args, cancellationToken); await OnNavigating(parameters, args, cancellationToken); } @@ -100,8 +44,6 @@ public abstract class RoutableScreen : ActivatableViewModelBase await OnClosing(args); } - #endregion - #region Parameter generation // ReSharper disable once StaticMemberInGenericType - That's intentional, each kind of TParam should have its own property count diff --git a/src/Artemis.UI.Shared/Routing/Routable/RoutableScreenOfTScreen.cs b/src/Artemis.UI.Shared/Routing/Routable/RoutableScreenOfTScreen.cs deleted file mode 100644 index b4f60ca47..000000000 --- a/src/Artemis.UI.Shared/Routing/Routable/RoutableScreenOfTScreen.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; - -namespace Artemis.UI.Shared.Routing; - -/// -/// Represents a view model to which routing can take place and which in turn can host another view model. -/// -/// The type of view model the screen can host. -public abstract class RoutableScreen : ActivatableViewModelBase, IRoutableScreen where TScreen : class -{ - private TScreen? _screen; - private bool _recycleScreen = true; - - /// - /// Gets the currently active child screen. - /// - public TScreen? Screen - { - get => _screen; - private set => RaiseAndSetIfChanged(ref _screen, value); - } - - /// - public bool RecycleScreen - { - get => _recycleScreen; - protected set => RaiseAndSetIfChanged(ref _recycleScreen, value); - } - - /// - /// Called before navigating to this screen. - /// - /// Navigation arguments containing information about the navigation action. - public virtual Task BeforeNavigating(NavigationArguments args) - { - return Task.CompletedTask; - } - - /// - /// Called while navigating to this screen. - /// - /// Navigation arguments containing information about the navigation action. - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - public virtual Task OnNavigating(NavigationArguments args, CancellationToken cancellationToken) - { - return Task.CompletedTask; - } - - /// - /// Called before navigating away from this screen. - /// - /// Navigation arguments containing information about the navigation action. - public virtual Task OnClosing(NavigationArguments args) - { - return Task.CompletedTask; - } - - #region Overrides of RoutableScreen - - object? IRoutableScreen.InternalScreen => Screen; - - void IRoutableScreen.InternalChangeScreen(object? screen) - { - if (screen == null) - { - Screen = null; - return; - } - - if (screen is not TScreen typedScreen) - throw new ArtemisRoutingException($"Screen cannot be hosted, {screen.GetType().Name} is not assignable to {typeof(TScreen).Name}."); - Screen = typedScreen; - } - - async Task IRoutableScreen.InternalOnNavigating(NavigationArguments args, CancellationToken cancellationToken) - { - await OnNavigating(args, cancellationToken); - } - - async Task IRoutableScreen.InternalOnClosing(NavigationArguments args) - { - await OnClosing(args); - } - - #endregion -} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Routing/Route/ParameterParsers/LongParameterParser.cs b/src/Artemis.UI.Shared/Routing/Route/ParameterParsers/LongParameterParser.cs new file mode 100644 index 000000000..a8e098579 --- /dev/null +++ b/src/Artemis.UI.Shared/Routing/Route/ParameterParsers/LongParameterParser.cs @@ -0,0 +1,17 @@ + +namespace Artemis.UI.Shared.Routing.ParameterParsers; + +internal class LongParameterParser : IRouteParameterParser +{ + /// + public bool IsMatch(RouteSegment segment, string source) + { + return long.TryParse(source, out _); + } + + /// + public object GetValue(RouteSegment segment, string source) + { + return long.Parse(source); + } +} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Routing/Route/RouteRegistration.cs b/src/Artemis.UI.Shared/Routing/Route/RouteRegistration.cs index 2d9f8508f..c62437d03 100644 --- a/src/Artemis.UI.Shared/Routing/Route/RouteRegistration.cs +++ b/src/Artemis.UI.Shared/Routing/Route/RouteRegistration.cs @@ -7,7 +7,7 @@ namespace Artemis.UI.Shared.Routing; /// Represents a registration for a route and its associated view model. /// /// The type of the view model associated with the route. -public class RouteRegistration : IRouterRegistration where TViewModel : ViewModelBase +public class RouteRegistration : IRouterRegistration where TViewModel : RoutableScreen { /// /// Initializes a new instance of the class. diff --git a/src/Artemis.UI.Shared/Routing/Route/RouteResolution.cs b/src/Artemis.UI.Shared/Routing/Route/RouteResolution.cs index 32d285ccd..b80bad548 100644 --- a/src/Artemis.UI.Shared/Routing/Route/RouteResolution.cs +++ b/src/Artemis.UI.Shared/Routing/Route/RouteResolution.cs @@ -74,19 +74,12 @@ internal class RouteResolution }; } - public object GetViewModel(IContainer container) + public RoutableScreen GetViewModel(IContainer container) { - if (ViewModel == null) - throw new ArtemisRoutingException("Cannot get a view model of a non-success route resolution"); - - object? viewModel = container.Resolve(ViewModel); - if (viewModel == null) - throw new ArtemisRoutingException($"Could not resolve view model of type {ViewModel}"); - - return viewModel; + return GetViewModel(container); } - public T GetViewModel(IContainer container) + public T GetViewModel(IContainer container) where T : RoutableScreen { if (ViewModel == null) throw new ArtemisRoutingException("Cannot get a view model of a non-success route resolution"); diff --git a/src/Artemis.UI.Shared/Routing/Route/RouteSegment.cs b/src/Artemis.UI.Shared/Routing/Route/RouteSegment.cs index 1f25b67da..b92e36c3a 100644 --- a/src/Artemis.UI.Shared/Routing/Route/RouteSegment.cs +++ b/src/Artemis.UI.Shared/Routing/Route/RouteSegment.cs @@ -79,6 +79,7 @@ public partial class RouteSegment return parameterType switch { "guid" => new GuidParameterParser(), + "long" => new LongParameterParser(), "int" => new IntParameterParser(), _ => new StringParameterParser() }; diff --git a/src/Artemis.UI.Shared/Routing/Router/IRouter.cs b/src/Artemis.UI.Shared/Routing/Router/IRouter.cs index 44d77bb5c..cfbd0eb89 100644 --- a/src/Artemis.UI.Shared/Routing/Router/IRouter.cs +++ b/src/Artemis.UI.Shared/Routing/Router/IRouter.cs @@ -50,7 +50,7 @@ public interface IRouter /// /// The root screen to set. /// The type of the root screen. It must be a class. - void SetRoot(RoutableScreen root) where TScreen : class; + void SetRoot(RoutableHostScreen root) where TScreen : RoutableScreen; /// /// Sets the root screen from which navigation takes place. @@ -58,7 +58,7 @@ public interface IRouter /// The root screen to set. /// The type of the root screen. It must be a class. /// The type of the parameters for the root screen. It must have a parameterless constructor. - void SetRoot(RoutableScreen root) where TScreen : class where TParam : new(); + void SetRoot(RoutableHostScreen root) where TScreen : RoutableScreen where TParam : new(); /// /// Clears the route used by the previous window, so that it is not restored when the main window opens. diff --git a/src/Artemis.UI.Shared/Routing/Router/Navigation.cs b/src/Artemis.UI.Shared/Routing/Router/Navigation.cs index d04fded6f..0d0f6083c 100644 --- a/src/Artemis.UI.Shared/Routing/Router/Navigation.cs +++ b/src/Artemis.UI.Shared/Routing/Router/Navigation.cs @@ -14,12 +14,12 @@ internal class Navigation private readonly IContainer _container; private readonly ILogger _logger; - private readonly IRoutableScreen _root; + private readonly IRoutableHostScreen _root; private readonly RouteResolution _resolution; private readonly RouterNavigationOptions _options; private CancellationTokenSource _cts; - public Navigation(IContainer container, ILogger logger, IRoutableScreen root, RouteResolution resolution, RouterNavigationOptions options) + public Navigation(IContainer container, ILogger logger, IRoutableHostScreen root, RouteResolution resolution, RouterNavigationOptions options) { _container = container; _logger = logger; @@ -54,21 +54,21 @@ internal class Navigation _cts.Cancel(); } - private async Task NavigateResolution(RouteResolution resolution, NavigationArguments args, IRoutableScreen host) + private async Task NavigateResolution(RouteResolution resolution, NavigationArguments args, IRoutableHostScreen host) { if (Cancelled) return; // Reuse the screen if its type has not changed, if a new one must be created, don't do so on the UI thread - object screen; + IRoutableScreen screen; if (_options.RecycleScreens && host.RecycleScreen && host.InternalScreen != null && host.InternalScreen.GetType() == resolution.ViewModel) screen = host.InternalScreen; else screen = await Task.Run(() => resolution.GetViewModel(_container)); // If resolution has a child, ensure the screen can host it - if (resolution.Child != null && screen is not IRoutableScreen) - throw new ArtemisRoutingException($"Route resolved with a child but view model of type {resolution.ViewModel} is does mot implement {nameof(IRoutableScreen)}."); + if (resolution.Child != null && screen is not IRoutableHostScreen) + throw new ArtemisRoutingException($"Route resolved with a child but view model of type {resolution.ViewModel} is does mot implement {nameof(IRoutableHostScreen)}."); // Only change the screen if it wasn't reused if (!ReferenceEquals(host.InternalScreen, screen)) @@ -87,27 +87,24 @@ internal class Navigation if (CancelIfRequested(args, "ChangeScreen", screen)) return; - - // If the screen implements some form of Navigable, activate it + + // Navigate on the screen args.SegmentParameters = resolution.Parameters ?? Array.Empty(); - if (screen is IRoutableScreen routableScreen) + try { - try - { - await routableScreen.InternalOnNavigating(args, _cts.Token); - } - catch (Exception e) - { - Cancel(); - if (e is not TaskCanceledException) - _logger.Error(e, "Failed to navigate to {Path}", resolution.Path); - } - - if (CancelIfRequested(args, "OnNavigating", screen)) - return; + await screen.InternalOnNavigating(args, _cts.Token); + } + catch (Exception e) + { + Cancel(); + if (e is not TaskCanceledException) + _logger.Error(e, "Failed to navigate to {Path}", resolution.Path); } - if (screen is IRoutableScreen childScreen) + if (CancelIfRequested(args, "OnNavigating", screen)) + return; + + if (screen is IRoutableHostScreen childScreen) { // Navigate the child too if (resolution.Child != null) @@ -121,11 +118,9 @@ internal class Navigation Completed = true; } - public bool PathEquals(string path, bool allowPartialMatch) + public bool PathEquals(string path, RouterNavigationOptions options) { - if (allowPartialMatch) - return _resolution.Path.StartsWith(path, StringComparison.InvariantCultureIgnoreCase); - return string.Equals(_resolution.Path, path, StringComparison.InvariantCultureIgnoreCase); + return options.PathEquals(_resolution.Path, path); } private bool CancelIfRequested(NavigationArguments args, string stage, object screen) diff --git a/src/Artemis.UI.Shared/Routing/Router/Router.cs b/src/Artemis.UI.Shared/Routing/Router/Router.cs index 028d7be02..282511c40 100644 --- a/src/Artemis.UI.Shared/Routing/Router/Router.cs +++ b/src/Artemis.UI.Shared/Routing/Router/Router.cs @@ -14,15 +14,15 @@ internal class Router : CorePropertyChanged, IRouter, IDisposable private readonly Stack _backStack = new(); private readonly BehaviorSubject _currentRouteSubject; private readonly Stack _forwardStack = new(); - private readonly Func _getNavigation; + private readonly Func _getNavigation; private readonly ILogger _logger; private readonly IMainWindowService _mainWindowService; private Navigation? _currentNavigation; - private IRoutableScreen? _root; + private IRoutableHostScreen? _root; private string? _previousWindowRoute; - public Router(ILogger logger, IMainWindowService mainWindowService, Func getNavigation) + public Router(ILogger logger, IMainWindowService mainWindowService, Func getNavigation) { _logger = logger; _mainWindowService = mainWindowService; @@ -45,28 +45,22 @@ internal class Router : CorePropertyChanged, IRouter, IDisposable return RouteResolution.AsFailure(path); } - private async Task RequestClose(object screen, NavigationArguments args) + private async Task RequestClose(IRoutableScreen screen, NavigationArguments args) { - if (screen is not IRoutableScreen routableScreen) - return true; - - await routableScreen.InternalOnClosing(args); - if (args.Cancelled) - { - _logger.Debug("Navigation to {Path} cancelled during RequestClose by {Screen}", args.Path, screen.GetType().Name); + // Drill down to child screens first + if (screen is IRoutableHostScreen hostScreen && hostScreen.InternalScreen != null && !await RequestClose(hostScreen.InternalScreen, args)) return false; - } - if (routableScreen.InternalScreen == null) + await screen.InternalOnClosing(args); + if (!args.Cancelled) return true; - return await RequestClose(routableScreen.InternalScreen, args); + _logger.Debug("Navigation to {Path} cancelled during RequestClose by {Screen}", args.Path, screen.GetType().Name); + return false; } - private bool PathEquals(string path, bool allowPartialMatch) + private bool PathEquals(string path, RouterNavigationOptions options) { - if (allowPartialMatch) - return _currentRouteSubject.Value != null && _currentRouteSubject.Value.StartsWith(path, StringComparison.InvariantCultureIgnoreCase); - return string.Equals(_currentRouteSubject.Value, path, StringComparison.InvariantCultureIgnoreCase); + return _currentRouteSubject.Value != null && options.PathEquals(_currentRouteSubject.Value, path); } /// @@ -88,7 +82,7 @@ internal class Router : CorePropertyChanged, IRouter, IDisposable { if (_root == null) throw new ArtemisRoutingException("Cannot navigate without a root having been set"); - if (PathEquals(path, options.IgnoreOnPartialMatch) || (_currentNavigation != null && _currentNavigation.PathEquals(path, options.IgnoreOnPartialMatch))) + if (PathEquals(path, options) || (_currentNavigation != null && _currentNavigation.PathEquals(path, options))) return; string? previousPath = _currentRouteSubject.Value; @@ -161,13 +155,13 @@ internal class Router : CorePropertyChanged, IRouter, IDisposable } /// - public void SetRoot(RoutableScreen root) where TScreen : class + public void SetRoot(RoutableHostScreen root) where TScreen : RoutableScreen { _root = root; } /// - public void SetRoot(RoutableScreen root) where TScreen : class where TParam : new() + public void SetRoot(RoutableHostScreen root) where TScreen : RoutableScreen where TParam : new() { _root = root; } diff --git a/src/Artemis.UI.Shared/Routing/Router/RouterNavigationOptions.cs b/src/Artemis.UI.Shared/Routing/Router/RouterNavigationOptions.cs index a5c63ab88..273f85c2c 100644 --- a/src/Artemis.UI.Shared/Routing/Router/RouterNavigationOptions.cs +++ b/src/Artemis.UI.Shared/Routing/Router/RouterNavigationOptions.cs @@ -1,3 +1,5 @@ +using System; + namespace Artemis.UI.Shared.Routing; /// @@ -21,9 +23,31 @@ public class RouterNavigationOptions /// If set to true, a route change from page/subpage1/subpage2 to page/subpage1 will be ignored. public bool IgnoreOnPartialMatch { get; set; } = false; + /// + /// Gets or sets the path to use when determining whether the path is a partial match, + /// only has any effect if is . + /// + public string? PartialMatchOverride { get; set; } + /// /// Gets or sets a boolean value indicating whether logging should be enabled. /// Errors and warnings are always logged. /// public bool EnableLogging { get; set; } = true; + + /// + /// Determines whether the given two paths are considered equal using these navigation options. + /// + /// The current path. + /// The target path. + /// if the paths are considered equal; otherwise . + internal bool PathEquals(string current, string target) + { + if (PartialMatchOverride != null && IgnoreOnPartialMatch) + target = PartialMatchOverride; + + if (IgnoreOnPartialMatch) + return current.StartsWith(target, StringComparison.InvariantCultureIgnoreCase); + return string.Equals(current, target, StringComparison.InvariantCultureIgnoreCase); + } } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Services/Builders/NotificationBuilder.cs b/src/Artemis.UI.Shared/Services/Builders/NotificationBuilder.cs index 5dfe0ecb9..805c5cbd0 100644 --- a/src/Artemis.UI.Shared/Services/Builders/NotificationBuilder.cs +++ b/src/Artemis.UI.Shared/Services/Builders/NotificationBuilder.cs @@ -2,11 +2,11 @@ using System.Threading.Tasks; using System.Windows.Input; using Avalonia.Controls; +using Avalonia.Controls.Primitives; using Avalonia.Layout; using Avalonia.Threading; using FluentAvalonia.UI.Controls; using ReactiveUI; -using Button = Avalonia.Controls.Button; namespace Artemis.UI.Shared.Services.Builders; @@ -117,34 +117,34 @@ public class NotificationBuilder /// public Action Show() { - Panel? panel = _parent.Find("NotificationContainer"); - if (panel == null) - throw new ArtemisSharedUIException("Can't display a notification on a window without a NotificationContainer."); - Dispatcher.UIThread.Post(() => { - panel.Children.Add(_infoBar); + OverlayLayer? overlayLayer = OverlayLayer.GetOverlayLayer(_parent); + if (overlayLayer == null) + throw new ArtemisSharedUIException("Can't display a notification on a window an overlay layer."); + + NotificationHost container = new() {Content = _infoBar}; + overlayLayer.Children.Add(container); _infoBar.Closed += InfoBarOnClosed; _infoBar.IsOpen = true; - }); - Task.Run(async () => - { - await Task.Delay(_timeout); - Dispatcher.UIThread.Post(() => _infoBar.IsOpen = false); + Dispatcher.UIThread.InvokeAsync(async () => + { + await Task.Delay(_timeout); + _infoBar.IsOpen = false; + }); + + return; + + void InfoBarOnClosed(InfoBar sender, InfoBarClosedEventArgs args) + { + overlayLayer.Children.Remove(container); + _infoBar.Closed -= InfoBarOnClosed; + } }); return () => Dispatcher.UIThread.Post(() => _infoBar.IsOpen = false); } - - private void InfoBarOnClosed(InfoBar sender, InfoBarClosedEventArgs args) - { - _infoBar.Closed -= InfoBarOnClosed; - if (_parent.Content is not Panel panel) - return; - - panel.Children.Remove(_infoBar); - } } /// @@ -180,7 +180,7 @@ public class NotificationButtonBuilder _action = action; return this; } - + /// /// Changes action that is called when the button is clicked. /// @@ -222,9 +222,13 @@ public class NotificationButtonBuilder button.Classes.Add("AppBarButton"); if (_action != null) + { button.Command = ReactiveCommand.Create(() => _action()); + } else if (_asyncAction != null) + { button.Command = ReactiveCommand.CreateFromTask(() => _asyncAction()); + } else if (_command != null) { button.Command = _command; diff --git a/src/Artemis.UI.Shared/Services/Interfaces/IWindowService.cs b/src/Artemis.UI.Shared/Services/Interfaces/IWindowService.cs index ff4394fde..15756d2a0 100644 --- a/src/Artemis.UI.Shared/Services/Interfaces/IWindowService.cs +++ b/src/Artemis.UI.Shared/Services/Interfaces/IWindowService.cs @@ -16,7 +16,7 @@ public interface IWindowService : IArtemisSharedUIService /// /// The type of view model to create /// The created view model - TViewModel ShowWindow(params object[] parameters); + Window ShowWindow(out TViewModel viewModel, params object[] parameters); /// /// Given a ViewModel, show its corresponding View as a window diff --git a/src/Artemis.UI.Shared/Services/ProfileEditor/ProfileEditorService.cs b/src/Artemis.UI.Shared/Services/ProfileEditor/ProfileEditorService.cs index 42390dd3e..f0c4cf085 100644 --- a/src/Artemis.UI.Shared/Services/ProfileEditor/ProfileEditorService.cs +++ b/src/Artemis.UI.Shared/Services/ProfileEditor/ProfileEditorService.cs @@ -10,7 +10,6 @@ using Artemis.Core; using Artemis.Core.Services; using Artemis.UI.Shared.Services.MainWindow; using Artemis.UI.Shared.Services.ProfileEditor.Commands; -using Avalonia.Threading; using DynamicData; using Serilog; @@ -140,14 +139,14 @@ internal class ProfileEditorService : IProfileEditorService private void ApplyFocusMode() { if (_suspendedEditingSubject.Value) - _profileService.EditorFocus = null; + _profileService.FocusProfileElement = null; - _profileService.EditorFocus = _focusModeSubject.Value switch + _profileService.FocusProfileElement = _focusModeSubject.Value switch { ProfileEditorFocusMode.None => null, ProfileEditorFocusMode.Folder => _profileElementSubject.Value?.Parent, ProfileEditorFocusMode.Selection => _profileElementSubject.Value, - _ => _profileService.EditorFocus + _ => _profileService.FocusProfileElement }; } @@ -164,52 +163,38 @@ internal class ProfileEditorService : IProfileEditorService public async Task ChangeCurrentProfileConfiguration(ProfileConfiguration? profileConfiguration) { - if (ReferenceEquals(_profileConfigurationSubject.Value, profileConfiguration)) + ProfileConfiguration? previous = _profileConfigurationSubject.Value; + if (ReferenceEquals(previous, profileConfiguration)) return; _logger.Verbose("ChangeCurrentProfileConfiguration {profile}", profileConfiguration); // Stop playing and save the current profile Pause(); - if (_profileConfigurationSubject.Value?.Profile != null) - { - _profileConfigurationSubject.Value.Profile.Reset(); - _profileConfigurationSubject.Value.Profile.LastSelectedProfileElement = _profileElementSubject.Value; - } - await SaveProfileAsync(); - // No need to deactivate the profile, if needed it will be deactivated next update - if (_profileConfigurationSubject.Value != null) - _profileConfigurationSubject.Value.IsBeingEdited = false; - // Deselect whatever profile element was active ChangeCurrentProfileElement(null); + ChangeSuspendedEditing(false); // Close the command scope if one was open _profileEditorHistoryScope?.Dispose(); - // The new profile may need activation - if (profileConfiguration != null) + // Activate the profile and it's mode off of the UI thread + await Task.Run(() => { - await Task.Run(() => - { - profileConfiguration.IsBeingEdited = true; - _moduleService.SetActivationOverride(profileConfiguration.Module); + // Activate the profile if one was provided + if (profileConfiguration != null) _profileService.ActivateProfile(profileConfiguration); - _profileService.RenderForEditor = true; - }); - if (profileConfiguration.Profile?.LastSelectedProfileElement is RenderProfileElement renderProfileElement) - ChangeCurrentProfileElement(renderProfileElement); - } - else - { - _moduleService.SetActivationOverride(null); - _profileService.RenderForEditor = false; - } + // If there is no profile configuration or module, deliberately set the override to null + _moduleService.SetActivationOverride(profileConfiguration?.Module); + }); + _profileService.FocusProfile = profileConfiguration; _profileConfigurationSubject.OnNext(profileConfiguration); + ChangeTime(TimeSpan.Zero); + previous?.Profile?.Reset(); } public void ChangeCurrentProfileElement(RenderProfileElement? renderProfileElement) @@ -238,23 +223,23 @@ internal class ProfileEditorService : IProfileEditorService if (_suspendedEditingSubject.Value == suspend) return; - _suspendedEditingSubject.OnNext(suspend); if (suspend) { Pause(); - _profileService.RenderForEditor = false; + _profileService.UpdateFocusProfile = true; _profileConfigurationSubject.Value?.Profile?.Reset(); } else { if (_profileConfigurationSubject.Value != null) - _profileService.RenderForEditor = true; + _profileService.UpdateFocusProfile = false; Tick(_timeSubject.Value); } + _suspendedEditingSubject.OnNext(suspend); ApplyFocusMode(); } - + public void ChangeFocusMode(ProfileEditorFocusMode focusMode) { if (_focusModeSubject.Value == focusMode) @@ -411,10 +396,8 @@ internal class ProfileEditorService : IProfileEditorService public void SaveProfile() { Profile? profile = _profileConfigurationSubject.Value?.Profile; - if (profile == null) - return; - - _profileService.SaveProfile(profile, true); + if (profile != null) + _profileService.SaveProfile(profile, true); } /// diff --git a/src/Artemis.UI.Shared/Services/Window/ExceptionDialogView.axaml b/src/Artemis.UI.Shared/Services/Window/ExceptionDialogView.axaml index 3bb950a0f..b228ebe2f 100644 --- a/src/Artemis.UI.Shared/Services/Window/ExceptionDialogView.axaml +++ b/src/Artemis.UI.Shared/Services/Window/ExceptionDialogView.axaml @@ -32,7 +32,7 @@ diff --git a/src/Artemis.UI.Shared/Services/Window/WindowService.cs b/src/Artemis.UI.Shared/Services/Window/WindowService.cs index c30688eef..5db1716d2 100644 --- a/src/Artemis.UI.Shared/Services/Window/WindowService.cs +++ b/src/Artemis.UI.Shared/Services/Window/WindowService.cs @@ -21,14 +21,13 @@ internal class WindowService : IWindowService _container = container; } - public T ShowWindow(params object[] parameters) + public Window ShowWindow(out T viewModel, params object[] parameters) { - T viewModel = _container.Resolve(parameters); + viewModel = _container.Resolve(parameters); if (viewModel == null) throw new ArtemisSharedUIException($"Failed to show window for VM of type {typeof(T).Name}, could not create instance."); - ShowWindow(viewModel); - return viewModel; + return ShowWindow(viewModel); } public Window ShowWindow(object viewModel) diff --git a/src/Artemis.UI.Shared/Styles/Artemis.axaml b/src/Artemis.UI.Shared/Styles/Artemis.axaml index 870b5f242..d32872413 100644 --- a/src/Artemis.UI.Shared/Styles/Artemis.axaml +++ b/src/Artemis.UI.Shared/Styles/Artemis.axaml @@ -15,6 +15,7 @@ + @@ -31,6 +32,7 @@ + diff --git a/src/Artemis.UI.Shared/Styles/Border.axaml b/src/Artemis.UI.Shared/Styles/Border.axaml index d753809a0..e3997e5ec 100644 --- a/src/Artemis.UI.Shared/Styles/Border.axaml +++ b/src/Artemis.UI.Shared/Styles/Border.axaml @@ -23,15 +23,11 @@ - - - 8 - - + + + + + + - - + + - - - - - + + \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Styles/Control.axaml b/src/Artemis.UI.Shared/Styles/Control.axaml new file mode 100644 index 000000000..b20c87ff5 --- /dev/null +++ b/src/Artemis.UI.Shared/Styles/Control.axaml @@ -0,0 +1,25 @@ + + + + + + + + + + + + diff --git a/src/Artemis.UI.Shared/Styles/Controls/DataModelPicker.axaml b/src/Artemis.UI.Shared/Styles/Controls/DataModelPicker.axaml index 662a1109f..0175ae880 100644 --- a/src/Artemis.UI.Shared/Styles/Controls/DataModelPicker.axaml +++ b/src/Artemis.UI.Shared/Styles/Controls/DataModelPicker.axaml @@ -66,7 +66,8 @@ @@ -81,7 +82,7 @@ IsVisible="{CompiledBinding IsEventPicker, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type dataModelPicker:DataModelPicker}}}"/> - + @@ -90,7 +91,8 @@ diff --git a/src/Artemis.UI.Shared/Styles/InfoBar.axaml b/src/Artemis.UI.Shared/Styles/InfoBar.axaml index 3f9b4a9bc..7b6f7f62c 100644 --- a/src/Artemis.UI.Shared/Styles/InfoBar.axaml +++ b/src/Artemis.UI.Shared/Styles/InfoBar.axaml @@ -17,6 +17,8 @@ + + diff --git a/src/Artemis.UI.Shared/Styles/Notifications.axaml b/src/Artemis.UI.Shared/Styles/Notifications.axaml index 0e9553ca2..94bc9039c 100644 --- a/src/Artemis.UI.Shared/Styles/Notifications.axaml +++ b/src/Artemis.UI.Shared/Styles/Notifications.axaml @@ -1,17 +1,14 @@  + xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" + xmlns:shared="clr-namespace:Artemis.UI.Shared"> - - - + + + + + + + + + + diff --git a/src/Artemis.UI.Shared/Utilities/ProgressableStreamContent.cs b/src/Artemis.UI.Shared/Utilities/ProgressableStreamContent.cs new file mode 100644 index 000000000..bac5bb9d1 --- /dev/null +++ b/src/Artemis.UI.Shared/Utilities/ProgressableStreamContent.cs @@ -0,0 +1,119 @@ +// Heavily based on: +// SkyClip +// - ProgressableStreamContent.cs +// -------------------------------------------------------------------- +// Author: Jeff Hansen +// Copyright (C) Jeff Hansen 2015. All rights reserved. + +using System; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + +namespace Artemis.UI.Shared.Utilities; + +/// +/// Provides HTTP content based on a stream with support for IProgress. +/// +public class ProgressableStreamContent : StreamContent +{ + private const int DEFAULT_BUFFER_SIZE = 4096; + + private readonly int _bufferSize; + private readonly IProgress _progress; + private readonly Stream _streamToWrite; + private bool _contentConsumed; + + /// + /// Initializes a new instance of the class. + /// + /// The stream to write. + /// The downloader. + public ProgressableStreamContent(Stream streamToWrite, IProgress progress) : this(streamToWrite, DEFAULT_BUFFER_SIZE, progress) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The stream to write. + /// The buffer size. + /// The downloader. + public ProgressableStreamContent(Stream streamToWrite, int bufferSize, IProgress progress) : base(streamToWrite, bufferSize) + { + if (bufferSize <= 0) + throw new ArgumentOutOfRangeException(nameof(bufferSize)); + + _streamToWrite = streamToWrite; + _bufferSize = bufferSize; + _progress = progress; + } + + /// + protected override void Dispose(bool disposing) + { + if (disposing) + _streamToWrite.Dispose(); + + base.Dispose(disposing); + } + + /// + protected override async Task SerializeToStreamAsync(Stream stream, TransportContext? context) + { + await SerializeToStreamAsync(stream, context, CancellationToken.None); + } + + /// + protected override async Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken) + { + PrepareContent(); + + byte[] buffer = new byte[_bufferSize]; + long size = _streamToWrite.Length; + int uploaded = 0; + + await using (_streamToWrite) + { + while (!cancellationToken.IsCancellationRequested) + { + int length = await _streamToWrite.ReadAsync(buffer, cancellationToken); + if (length <= 0) + break; + + uploaded += length; + _progress.Report(new StreamProgress(uploaded, size)); + await stream.WriteAsync(buffer, 0, length, cancellationToken); + } + } + } + + /// + protected override bool TryComputeLength(out long length) + { + length = _streamToWrite.Length; + return true; + } + + /// + /// Prepares the content. + /// + /// The stream has already been read. + private void PrepareContent() + { + if (_contentConsumed) + { + // If the content needs to be written to a target stream a 2nd time, then the stream must support + // seeking (e.g. a FileStream), otherwise the stream can't be copied a second time to a target + // stream (e.g. a NetworkStream). + if (_streamToWrite.CanSeek) + _streamToWrite.Position = 0; + else + throw new InvalidOperationException("The stream has already been read."); + } + + _contentConsumed = true; + } +} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Utilities/StreamProgress.cs b/src/Artemis.UI.Shared/Utilities/StreamProgress.cs new file mode 100644 index 000000000..eb0b7a713 --- /dev/null +++ b/src/Artemis.UI.Shared/Utilities/StreamProgress.cs @@ -0,0 +1,57 @@ +// Heavily based on: +// SkyClip +// - UploadProgress.cs +// -------------------------------------------------------------------- +// Author: Jeff Hansen +// Copyright (C) Jeff Hansen 2015. All rights reserved. + +namespace Artemis.UI.Shared.Utilities; + +/// +/// The upload progress. +/// +public class StreamProgress +{ + /// + /// Initializes a new instance of the class. + /// + /// + /// The bytes transfered. + /// + /// + /// The total bytes. + /// + public StreamProgress(long bytesTransfered, long? totalBytes) + { + BytesTransfered = bytesTransfered; + TotalBytes = totalBytes; + if (totalBytes.HasValue) + ProgressPercentage = (int) ((float) bytesTransfered / totalBytes.Value * 100); + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return string.Format("{0}% ({1} / {2})", ProgressPercentage, BytesTransfered, TotalBytes); + } + + /// + /// Gets the bytes transfered. + /// + public long BytesTransfered { get; } + + /// + /// Gets the progress percentage. + /// + public int ProgressPercentage { get; } + + /// + /// Gets the total bytes. + /// + public long? TotalBytes { get; } +} \ No newline at end of file diff --git a/src/Artemis.UI.Windows/App.axaml b/src/Artemis.UI.Windows/App.axaml index 836d6a11f..63ff0b8a1 100644 --- a/src/Artemis.UI.Windows/App.axaml +++ b/src/Artemis.UI.Windows/App.axaml @@ -18,7 +18,7 @@ - + diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj index 914c45ccd..c1b71c6f2 100644 --- a/src/Artemis.UI/Artemis.UI.csproj +++ b/src/Artemis.UI/Artemis.UI.csproj @@ -18,18 +18,24 @@ + + + + + - + + @@ -38,9 +44,30 @@ + + + + + + ProfileListView.axaml + Code + + + LayoutListView.axaml + Code + + + SubmissionsDetailView.axaml + Code + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Assets/Animations/email.json b/src/Artemis.UI/Assets/Animations/email.json new file mode 100644 index 000000000..0d274481c --- /dev/null +++ b/src/Artemis.UI/Assets/Animations/email.json @@ -0,0 +1 @@ +{"v":"5.7.1","fr":25,"ip":0,"op":200,"w":1000,"h":1000,"nm":"Work frome Home Mailing F","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[500,652,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":200,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"mail 4","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":99,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[183.055,-315.211,0],"ix":2},"a":{"a":0,"k":[2153.478,680.843,0],"ix":1},"s":{"a":0,"k":[56,56,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.758,-2.403],[0,0],[0,0],[0,0],[-21.953,-7.476],[-0.627,-0.393]],"o":[[0,0],[0,0],[0,0],[0,0],[9.299,3.167],[1.978,1.239]],"v":[[78.735,-34.708],[80.678,-28.718],[-58.964,72.319],[-68.916,40.154],[58.006,-46.114],[74.435,-40.273]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.174548238516,0.452203959227,0.890196084976,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 3","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1801.139,934.164],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[594,594],"ix":3},"r":{"a":0,"k":17.3,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"back 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":204,"st":-23,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"plane 2","parent":1,"tt":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-30.27,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.57,"y":1},"o":{"x":0.43,"y":0},"t":0,"s":[-417.664,54.901,0],"to":[29.664,67.099,0],"ti":[8.659,75.131,0]},{"i":{"x":0.57,"y":1},"o":{"x":0.444,"y":0},"t":50,"s":[384.659,-254.869,0],"to":[-6.219,-53.959,0],"ti":[-29.664,-67.099,0]},{"i":{"x":0.57,"y":1},"o":{"x":0.43,"y":0},"t":100,"s":[-417.664,54.901,0],"to":[29.664,67.099,0],"ti":[8.659,75.131,0]},{"i":{"x":0.595,"y":1},"o":{"x":0.444,"y":0},"t":150,"s":[384.659,-254.869,0],"to":[-6.219,-53.959,0],"ti":[-17.336,-57.901,0]},{"t":199,"s":[-417.664,54.901,0]}],"ix":2},"a":{"a":0,"k":[816.438,755.113,0],"ix":1},"s":{"a":0,"k":[65,65,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":-7,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[18.514,-6.941],[-33.276,21.927],[93.386,-0.562]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":3,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-6.915,-14.251],[-9.38,40.839],[47.51,-30.24]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":12,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[21.986,-29.805],[113.019,32.241],[42.547,-64.73]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":30,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.528,-14.328],[129.556,-5.673],[-49.243,-49.537]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":48,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[12.419,-8.39],[20.033,-35.22],[-88.885,-12.543]],"c":true}]},{"i":{"x":0.32,"y":1},"o":{"x":0.167,"y":0.167},"t":61,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[55.573,8.709],[-40.935,-18.354],[28.444,45.375]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":70,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[6.11,3.203],[-110.008,-19.184],[7.061,50.133]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":84,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[70.462,-13.025],[-68.13,-5.656],[131.7,43.826]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[18.514,-6.941],[-33.276,21.927],[93.387,-0.562]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":103,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-6.915,-14.251],[-9.38,40.839],[47.51,-30.24]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":112,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[21.986,-29.805],[113.019,32.241],[42.547,-64.73]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":130,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.528,-14.328],[129.556,-5.673],[-49.243,-49.537]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":148,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[12.419,-8.39],[20.033,-35.22],[-88.885,-12.543]],"c":true}]},{"i":{"x":0.32,"y":1},"o":{"x":0.167,"y":0.167},"t":161,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[55.573,8.709],[-40.935,-18.354],[28.444,45.375]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":170,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[6.11,3.203],[-110.008,-19.184],[7.061,50.133]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":184,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[70.462,-13.025],[-68.13,-5.656],[131.7,43.826]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":193,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[18.514,-6.941],[-33.276,21.927],[93.386,-0.562]],"c":true}]},{"t":203,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-6.915,-14.251],[-9.38,40.839],[47.51,-30.24]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":-7,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-33.276,21.927],[5.299,-10.555],[-29.451,-26.172]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":3,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-9.38,40.839],[-24.162,-11.06],[-91.62,-22.853]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":12,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[113.019,32.241],[-1.135,-26.615],[-113.019,-32.241]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":30,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[129.556,-5.673],[7.207,-4.426],[12.17,72.534]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":48,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[20.033,-35.22],[24.82,-6.359],[108.512,9]],"c":true}]},{"i":{"x":0.32,"y":1},"o":{"x":0.167,"y":0.167},"t":61,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-40.935,-18.354],[69.258,0.624],[114.118,-27.203]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":70,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-110.008,-19.184],[15.525,-1.402],[54.092,-19.43]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":84,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-68.13,-5.656],[63.129,-26.565],[63.443,-50.053]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-33.276,21.927],[5.299,-10.555],[-29.451,-26.172]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":103,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-9.38,40.839],[-24.162,-11.06],[-91.62,-22.853]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":112,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[113.019,32.241],[-1.135,-26.615],[-113.019,-32.241]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":130,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[129.556,-5.673],[7.207,-4.426],[12.17,72.534]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":148,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[20.033,-35.22],[24.82,-6.359],[108.512,9]],"c":true}]},{"i":{"x":0.32,"y":1},"o":{"x":0.167,"y":0.167},"t":161,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-40.935,-18.354],[69.258,0.624],[114.118,-27.203]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":170,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-110.008,-19.184],[15.525,-1.402],[54.092,-19.43]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":184,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-68.13,-5.656],[63.129,-26.565],[63.443,-50.053]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":193,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-33.276,21.927],[5.299,-10.555],[-29.451,-26.172]],"c":true}]},{"t":203,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-9.38,40.839],[-24.162,-11.06],[-91.62,-22.853]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.828505811504,0.876804486443,0.931862146714,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":-7,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-14.241,3.304],[-30.454,20.957],[19.514,-1.564],[11.823,5.95],[3.437,-9.631]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":3,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-21.862,17.885],[-9.38,40.839],[-6.915,-14.251],[-10.368,5.64],[-25.224,-7.275]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":12,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-24.159,12.674],[113.019,32.241],[21.986,-29.805],[17.357,-9.915],[-16.004,-3.872]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":30,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[55.35,-4.914],[129.556,-5.673],[-3.271,-18.353],[-13.529,7.902],[42.148,1]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":48,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[34.167,-10.201],[20.033,-35.22],[10.099,-7.209],[13.95,35.083],[26.183,-5.636]],"c":true}]},{"i":{"x":0.32,"y":1},"o":{"x":0.167,"y":0.167},"t":61,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[75.86,-3.345],[-40.935,-18.354],[42.881,12.14],[74.348,24.549],[70.369,1.013]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":70,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[12.51,-7.277],[-110.008,-19.184],[-19.192,3.494],[20.236,23.254],[16.22,-0.587]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":84,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-3.126,-17.964],[-61.192,-8.042],[72.921,0.195],[59.046,-10.343],[60.098,-29.814]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-14.241,3.304],[-30.454,20.957],[19.514,-1.564],[11.823,5.95],[3.437,-9.631]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":103,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-21.861,17.885],[-9.38,40.839],[-6.915,-14.251],[-10.368,5.64],[-25.224,-7.275]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":112,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-24.159,12.674],[113.019,32.241],[21.986,-29.805],[17.357,-9.915],[-16.004,-3.872]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":130,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[55.35,-4.914],[129.556,-5.673],[-3.271,-18.353],[-13.529,7.902],[42.148,1]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":148,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[34.167,-10.201],[20.033,-35.22],[10.099,-7.209],[13.95,35.083],[26.183,-5.636]],"c":true}]},{"i":{"x":0.32,"y":1},"o":{"x":0.167,"y":0.167},"t":161,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[75.86,-3.345],[-40.935,-18.354],[42.881,12.14],[74.348,24.549],[70.369,1.013]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":170,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[12.51,-7.277],[-110.008,-19.184],[-19.192,3.494],[20.236,23.254],[16.22,-0.587]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":184,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-3.126,-17.964],[-61.192,-8.042],[72.921,0.195],[59.046,-10.343],[60.098,-29.814]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":193,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-14.241,3.304],[-30.454,20.957],[19.514,-1.564],[11.823,5.95],[3.437,-9.631]],"c":true}]},{"t":203,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-21.862,17.885],[-9.38,40.839],[-6.915,-14.251],[-10.368,5.64],[-25.224,-7.275]],"c":true}]}],"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.65451594334,0.742976110122,0.858894258387,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 2","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[795.902,768.678],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":-7,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[18.514,-6.941],[-33.276,21.927],[93.386,-0.562]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":3,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-6.915,-14.251],[-9.38,40.839],[47.51,-30.24]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":12,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[21.986,-29.805],[113.019,32.241],[42.547,-64.73]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":30,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.528,-14.328],[129.556,-5.673],[-49.243,-49.537]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":48,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[12.419,-8.39],[20.033,-35.22],[-88.885,-12.543]],"c":true}]},{"i":{"x":0.32,"y":1},"o":{"x":0.167,"y":0.167},"t":61,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[55.573,8.709],[-40.935,-18.354],[28.444,45.375]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":70,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[6.11,3.203],[-110.008,-19.184],[7.061,50.133]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":84,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[70.462,-13.025],[-68.13,-5.656],[131.7,43.826]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[18.514,-6.941],[-33.276,21.927],[93.387,-0.562]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":103,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-6.915,-14.251],[-9.38,40.839],[47.51,-30.24]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":112,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[21.986,-29.805],[113.019,32.241],[42.547,-64.73]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":130,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.528,-14.328],[129.556,-5.673],[-49.243,-49.537]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":148,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[12.419,-8.39],[20.033,-35.22],[-88.885,-12.543]],"c":true}]},{"i":{"x":0.32,"y":1},"o":{"x":0.167,"y":0.167},"t":161,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[55.573,8.709],[-40.935,-18.354],[28.444,45.375]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":170,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[6.11,3.203],[-110.008,-19.184],[7.061,50.133]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":184,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[70.462,-13.025],[-68.13,-5.656],[131.7,43.826]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":193,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[18.514,-6.941],[-33.276,21.927],[93.386,-0.562]],"c":true}]},{"t":203,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-6.915,-14.251],[-9.38,40.839],[47.51,-30.24]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":-7,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-33.276,21.927],[5.299,-10.555],[-29.451,-26.172]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":3,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-9.38,40.839],[-24.162,-11.06],[-91.62,-22.853]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":12,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[113.019,32.241],[-1.135,-26.615],[-113.019,-32.241]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":30,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[129.556,-5.673],[7.207,-4.426],[12.17,72.534]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":48,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[20.033,-35.22],[24.82,-6.359],[108.512,9]],"c":true}]},{"i":{"x":0.32,"y":1},"o":{"x":0.167,"y":0.167},"t":61,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-40.935,-18.354],[69.258,0.624],[114.118,-27.203]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":70,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-110.008,-19.184],[15.525,-1.402],[54.092,-19.43]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":84,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-68.13,-5.656],[63.129,-26.565],[63.443,-50.053]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-33.276,21.927],[5.299,-10.555],[-29.451,-26.172]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":103,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-9.38,40.839],[-24.162,-11.06],[-91.62,-22.853]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":112,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[113.019,32.241],[-1.135,-26.615],[-113.019,-32.241]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":130,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[129.556,-5.673],[7.207,-4.426],[12.17,72.534]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":148,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[20.033,-35.22],[24.82,-6.359],[108.512,9]],"c":true}]},{"i":{"x":0.32,"y":1},"o":{"x":0.167,"y":0.167},"t":161,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-40.935,-18.354],[69.258,0.624],[114.118,-27.203]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":170,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-110.008,-19.184],[15.525,-1.402],[54.092,-19.43]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":184,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-68.13,-5.656],[63.129,-26.565],[63.443,-50.053]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":193,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-33.276,21.927],[5.299,-10.555],[-29.451,-26.172]],"c":true}]},{"t":203,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-9.38,40.839],[-24.162,-11.06],[-91.62,-22.853]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":-7,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-14.241,3.304],[-30.454,20.957],[19.514,-1.564],[11.823,5.95],[3.437,-9.631]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":3,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-21.862,17.885],[-9.38,40.839],[-6.915,-14.251],[-10.368,5.64],[-25.224,-7.275]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":12,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-24.159,12.674],[113.019,32.241],[21.986,-29.805],[17.357,-9.915],[-16.004,-3.872]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":30,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[55.35,-4.914],[129.556,-5.673],[-3.271,-18.353],[-13.529,7.902],[42.148,1]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":48,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[34.167,-10.201],[20.033,-35.22],[10.099,-7.209],[13.95,35.083],[26.183,-5.636]],"c":true}]},{"i":{"x":0.32,"y":1},"o":{"x":0.167,"y":0.167},"t":61,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[75.86,-3.345],[-40.935,-18.354],[42.881,12.14],[74.348,24.549],[70.369,1.013]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":70,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[12.51,-7.277],[-110.008,-19.184],[-19.192,3.494],[20.236,23.254],[16.22,-0.587]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":84,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-3.126,-17.964],[-61.192,-8.042],[72.921,0.195],[59.046,-10.343],[60.098,-29.814]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-14.241,3.304],[-30.454,20.957],[19.514,-1.564],[11.823,5.95],[3.437,-9.631]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":103,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-21.861,17.885],[-9.38,40.839],[-6.915,-14.251],[-10.368,5.64],[-25.224,-7.275]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":112,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-24.159,12.674],[113.019,32.241],[21.986,-29.805],[17.357,-9.915],[-16.004,-3.872]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":130,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[55.35,-4.914],[129.556,-5.673],[-3.271,-18.353],[-13.529,7.902],[42.148,1]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":148,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[34.167,-10.201],[20.033,-35.22],[10.099,-7.209],[13.95,35.083],[26.183,-5.636]],"c":true}]},{"i":{"x":0.32,"y":1},"o":{"x":0.167,"y":0.167},"t":161,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[75.86,-3.345],[-40.935,-18.354],[42.881,12.14],[74.348,24.549],[70.369,1.013]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":170,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[12.51,-7.277],[-110.008,-19.184],[-19.192,3.494],[20.236,23.254],[16.22,-0.587]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":184,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-3.126,-17.964],[-61.192,-8.042],[72.921,0.195],[59.046,-10.343],[60.098,-29.814]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":193,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-14.241,3.304],[-30.454,20.957],[19.514,-1.564],[11.823,5.95],[3.437,-9.631]],"c":true}]},{"t":203,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-21.862,17.885],[-9.38,40.839],[-6.915,-14.251],[-10.368,5.64],[-25.224,-7.275]],"c":true}]}],"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":20,"ix":5},"r":1,"bm":0,"nm":"Fill 2","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[790.902,773.678],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-2,"op":201,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 9","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[141.25,25,0],"to":[-3.73,-1.383,0],"ti":[-8.37,-1.955,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":38,"s":[146.62,14.455,0],"to":[5.12,2.58,0],"ti":[5.195,1.594,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":75,"s":[150.18,5.281,0],"to":[-5.195,-1.594,0],"ti":[-0.953,-5.614,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":106,"s":[134.453,14.614,0],"to":[0.953,5.614,0],"ti":[-3.875,4.525,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":137,"s":[149.75,10.975,0],"to":[3.875,-4.525,0],"ti":[1.75,-5.25,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":170,"s":[140.625,8.625,0],"to":[-1.75,5.25,0],"ti":[11.125,-4.375,0]},{"t":199,"s":[141.25,25,0]}],"ix":2},"a":{"a":0,"k":[197.25,-284,0],"ix":1},"s":{"a":0,"k":[82,82,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[192.5,-319.5],[250.5,-319.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294133425,0.509803950787,0.945098102093,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[192.5,-298],[313,-298]],"c":false},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"rp","c":{"a":0,"k":3,"ix":1},"o":{"a":0,"k":0,"ix":2},"m":1,"ix":2,"tr":{"ty":"tr","p":{"a":0,"k":[0,21],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":4},"so":{"a":0,"k":100,"ix":5},"eo":{"a":0,"k":100,"ix":6},"nm":"Transform"},"nm":"Repeater 1","mn":"ADBE Vector Filter - Repeater","hd":false},{"ty":"st","c":{"a":0,"k":[0.874463677406,0.896885812283,0.952941179276,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-10.631,0],[0,-10.631],[8.016,-3.698],[-1.065,-13.634],[13.375,0],[4.627,5.177],[1.051,0.57],[0,8.437]],"o":[[10.631,0],[0,8.766],[-0.831,0.384],[-4.815,6.616],[-14.376,0],[0.627,-13.698],[-7.554,-4.095],[0,-10.631]],"v":[[-74,-32],[-54.75,-12.75],[-68.625,11.021],[-43.935,27.259],[-74,40.25],[-105.002,26.948],[-80.268,10.573],[-93.25,-12.75]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 3","mn":"ADBE Vector Graphic - Fill","hd":false},{"d":1,"ty":"el","s":{"a":0,"k":[93.5,93.5],"ix":2},"p":{"a":0,"k":[-74,0],"ix":3},"nm":"Ellipse Path 2","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.874509871006,0.898039281368,0.95294123888,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 2","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"rc","d":1,"s":{"a":0,"k":[267.5,111],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":10,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"rc","d":1,"s":{"a":0,"k":[267.5,111],"ix":2},"p":{"a":0,"k":[-6,6],"ix":3},"r":{"a":0,"k":10,"ix":4},"nm":"Rectangle Path 2","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":17,"ix":5},"r":1,"bm":0,"nm":"Fill 4","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[200.25,-287],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":8,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":200,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"mail 6","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":22,"s":[15.427]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":56,"s":[-12.946]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[28.456]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":126,"s":[-12.946]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":167,"s":[24]},{"t":199,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[-192.052,-110.008,0],"to":[2.552,4.383,0],"ti":[6.537,13.177,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":51,"s":[-171.912,-105.677,0],"to":[-6.537,-13.177,0],"ti":[6.357,-1.675,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":85,"s":[-191.107,-93.45,0],"to":[-6.357,1.675,0],"ti":[8.571,-10.521,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":124,"s":[-212.946,-117.604,0],"to":[-8.571,10.521,0],"ti":[9.927,9.883,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":163,"s":[-174.552,-122.008,0],"to":[-9.927,-9.883,0],"ti":[-4.323,-4.992,0]},{"t":199,"s":[-192.052,-110.008,0]}],"ix":2},"a":{"a":0,"k":[2153.478,680.843,0],"ix":1},"s":{"a":0,"k":[67,67,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[4.932,0],[0,5.066],[-8.798,0],[-1.066,-0.267]],"o":[[-1.2,7.732],[-4.398,0],[0,-10.264],[1.732,0],[0,0]],"v":[[6.604,-0.329],[-4.726,13.668],[-11.391,5.403],[4.339,-13.526],[8.47,-12.993]],"c":true},"ix":2},"nm":"@","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[6.798,0],[0,22.262],[-20.396,0],[0,-17.33],[5.73,0.205],[-1.333,7.865],[0,0],[5.865,0],[0,-16.263],[-8.665,0],[-4.133,6.799],[0,0],[-6.266,0],[0,19.462],[23.461,0],[0,-27.194],[-22.127,0],[-7.998,3.599]],"o":[[-5.333,2.799],[-19.862,0],[0,-25.461],[20.662,0],[0,15.33],[-3.732,-0.133],[0,0],[-3.333,-1.866],[-19.196,0],[0,10.931],[7.065,0],[0,0],[0.667,7.065],[14.396,0],[0,-22.395],[-30.127,0],[0,26.128],[9.465,0],[0,0]],"v":[[17.936,34.33],[-1.393,38.596],[-35.519,3.67],[2.74,-37.787],[34.598,-6.994],[21.668,15.534],[18.336,3.937],[22.335,-20.724],[6.472,-24.057],[-24.722,7.003],[-9.791,24.332],[7.405,14.068],[7.671,14.068],[19.136,24.332],[44.463,-7.394],[4.206,-45.919],[-45.65,4.87],[-4.06,46.861],[20.335,42.062]],"c":true},"ix":2},"nm":"@ 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.227450996637,0.509803950787,0.95294123888,0.988235354424],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 3","mn":"ADBE Vector Graphic - Fill","hd":false},{"d":1,"ty":"el","s":{"a":0,"k":[126.905,126.905],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.885428667068,0.920325279236,0.960784316063,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 2","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[2140.425,652.021],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[126.905,126.905],"ix":2},"p":{"a":0,"k":[-4,11],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":18,"ix":5},"r":1,"bm":0,"nm":"Fill 2","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[2140.425,652.021],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":200,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"mail 3","parent":1,"sr":1,"ks":{"o":{"a":0,"k":99,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[183.055,-315.211,0],"ix":2},"a":{"a":0,"k":[2153.478,680.843,0],"ix":1},"s":{"a":0,"k":[56,56,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":1,"y":0},"t":5,"s":[{"i":[[1.212,0.293],[-0.053,1.063],[-0.465,1.092],[-2.964,0.923],[0,0],[-2.408,-1.462],[-0.75,-0.938],[9.093,-10.048]],"o":[[-13.028,-3.146],[0.06,-1.209],[1.127,-2.65],[0,0],[2.9,-0.902],[1.008,0.612],[0.699,0.874],[-0.845,0.934]],"v":[[11.967,33.017],[-77.516,10.287],[-76.716,6.809],[-70.385,1.081],[66.005,-41.368],[74.313,-40.349],[76.976,-38.011],[15.15,32.025]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":10,"s":[{"i":[[1.113,-0.027],[12.953,-2.709],[-0.38,0.852],[-2.964,0.923],[0,0],[-2.227,-0.88],[0.429,-0.708],[10.164,-6.61]],"o":[[-11.959,0.286],[-0.893,-0.313],[0.756,-1.716],[0,0],[2.9,-0.903],[0.932,0.368],[-12.428,5.23],[-0.945,0.614]],"v":[[4.34,8.53],[-73.957,7.989],[-75.054,6.191],[-70.014,2.274],[66.374,-40.184],[72.789,-39.988],[73.406,-38.058],[7.523,7.538]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":11,"s":[{"i":[[1.022,-0.318],[22.981,-7.154],[-0.472,0.148],[-2.964,0.923],[0,0],[-1.781,0.553],[1.404,-0.438],[11.142,-3.471]],"o":[[-10.983,3.42],[-1.629,0.507],[0.69,-0.217],[0,0],[2.899,-0.903],[0.745,-0.231],[-23.438,7.303],[-1.036,0.323]],"v":[[-4.379,-19.464],[-72.465,1.734],[-74.732,2.437],[-70.385,1.081],[65.996,-41.397],[70.589,-42.826],[69.196,-42.389],[-1.196,-20.456]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[0,0],[0.003,-0.005],[-0.001,-0.001],[-0.001,0],[0,0],[0.001,0.003],[0,0],[0.002,0]],"o":[[-0.002,0.002],[0,0],[0.001,0.002],[0,0],[0.001,0],[0,-0.001],[-0.005,-0.003],[0,0]],"v":[[-73.926,5.759],[-73.934,5.774],[-73.933,5.778],[-73.932,5.781],[-73.908,5.773],[-73.908,5.77],[-73.909,5.767],[-73.925,5.759]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":87,"s":[{"i":[[0,0],[0.003,-0.005],[-0.001,-0.001],[0,0],[0,0],[0.001,0.003],[0,0],[0.002,0]],"o":[[-0.001,0.002],[0,0],[0.001,0.002],[0,0],[0,0],[0,-0.001],[-0.005,-0.003],[0,0]],"v":[[-73.926,5.759],[-73.934,5.774],[-73.933,5.778],[-73.932,5.781],[-73.908,5.773],[-73.908,5.77],[-73.909,5.767],[-73.925,5.759]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":88,"s":[{"i":[[1.022,-0.318],[22.981,-7.154],[-0.472,0.148],[-2.964,0.923],[0,0],[-1.781,0.552],[1.404,-0.438],[11.142,-3.471]],"o":[[-10.983,3.42],[-1.629,0.507],[0.69,-0.217],[0,0],[2.899,-0.903],[0.745,-0.231],[-23.438,7.303],[-1.036,0.323]],"v":[[-4.379,-19.464],[-72.465,1.734],[-74.732,2.437],[-70.385,1.081],[65.996,-41.397],[70.589,-42.826],[69.197,-42.389],[-1.196,-20.456]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"t":89,"s":[{"i":[[1.113,-0.027],[12.953,-2.709],[-0.38,0.852],[-2.964,0.923],[0,0],[-2.227,-0.88],[0.429,-0.708],[10.164,-6.61]],"o":[[-11.959,0.286],[-0.893,-0.313],[0.756,-1.716],[0,0],[2.9,-0.903],[0.932,0.368],[-12.428,5.23],[-0.945,0.614]],"v":[[4.34,8.53],[-73.957,7.989],[-75.054,6.191],[-70.014,2.274],[66.374,-40.184],[72.789,-39.988],[73.406,-38.058],[7.523,7.538]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":94,"s":[{"i":[[1.212,0.293],[-0.052,1.063],[-0.465,1.092],[-2.964,0.923],[0,0],[-2.408,-1.462],[-0.75,-0.938],[9.093,-10.048]],"o":[[-13.028,-3.146],[0.06,-1.209],[1.127,-2.65],[0,0],[2.9,-0.902],[1.008,0.612],[0.699,0.874],[-0.845,0.934]],"v":[[11.967,33.017],[-77.516,10.287],[-76.716,6.809],[-70.385,1.081],[66.005,-41.368],[74.313,-40.349],[76.976,-38.011],[15.15,32.025]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":1,"y":0},"t":106,"s":[{"i":[[1.212,0.293],[-0.052,1.063],[-0.465,1.092],[-2.964,0.923],[0,0],[-2.408,-1.462],[-0.75,-0.938],[9.093,-10.048]],"o":[[-13.028,-3.146],[0.06,-1.209],[1.127,-2.65],[0,0],[2.9,-0.902],[1.008,0.612],[0.699,0.874],[-0.845,0.934]],"v":[[11.967,33.017],[-77.516,10.287],[-76.716,6.809],[-70.385,1.081],[66.005,-41.368],[74.313,-40.349],[76.976,-38.011],[15.15,32.025]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":111,"s":[{"i":[[1.113,-0.027],[12.953,-2.709],[-0.38,0.852],[-2.964,0.923],[0,0],[-2.227,-0.88],[0.429,-0.708],[10.164,-6.61]],"o":[[-11.959,0.286],[-0.893,-0.313],[0.756,-1.716],[0,0],[2.9,-0.903],[0.932,0.368],[-12.428,5.23],[-0.945,0.614]],"v":[[4.34,8.53],[-73.957,7.989],[-75.054,6.191],[-70.014,2.274],[66.374,-40.184],[72.789,-39.988],[73.406,-38.058],[7.523,7.538]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[1.022,-0.318],[22.981,-7.154],[-0.472,0.148],[-2.964,0.923],[0,0],[-1.781,0.552],[1.404,-0.438],[11.142,-3.471]],"o":[[-10.983,3.42],[-1.629,0.507],[0.69,-0.217],[0,0],[2.899,-0.903],[0.745,-0.231],[-23.438,7.303],[-1.036,0.323]],"v":[[-4.379,-19.464],[-72.465,1.734],[-74.732,2.437],[-70.385,1.081],[65.996,-41.397],[70.589,-42.826],[69.197,-42.389],[-1.196,-20.456]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":113,"s":[{"i":[[0,0],[0.003,-0.005],[-0.001,-0.001],[0,0],[0,0],[0.001,0.003],[0,0],[0.002,0]],"o":[[-0.001,0.002],[0,0],[0.001,0.002],[0,0],[0,0],[0,-0.001],[-0.005,-0.003],[0,0]],"v":[[-73.926,5.759],[-73.934,5.774],[-73.933,5.778],[-73.932,5.781],[-73.908,5.773],[-73.908,5.77],[-73.909,5.767],[-73.925,5.759]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":188,"s":[{"i":[[0,0],[0.003,-0.005],[-0.001,-0.001],[0,0],[0,0],[0.001,0.003],[0,0],[0.002,0]],"o":[[-0.001,0.002],[0,0],[0.001,0.002],[0,0],[0,0],[0,-0.001],[-0.005,-0.003],[0,0]],"v":[[-73.926,5.759],[-73.934,5.774],[-73.933,5.778],[-73.932,5.781],[-73.908,5.773],[-73.908,5.77],[-73.909,5.767],[-73.925,5.759]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":189,"s":[{"i":[[1.022,-0.318],[22.981,-7.154],[-0.472,0.148],[-2.964,0.923],[0,0],[-1.781,0.552],[1.404,-0.438],[11.142,-3.471]],"o":[[-10.983,3.42],[-1.629,0.507],[0.69,-0.217],[0,0],[2.899,-0.903],[0.745,-0.231],[-23.438,7.303],[-1.036,0.323]],"v":[[-4.379,-19.464],[-72.465,1.734],[-74.732,2.437],[-70.385,1.081],[65.996,-41.397],[70.589,-42.826],[69.197,-42.389],[-1.196,-20.456]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"t":190,"s":[{"i":[[1.113,-0.027],[12.953,-2.709],[-0.38,0.852],[-2.964,0.923],[0,0],[-2.227,-0.88],[0.429,-0.708],[10.164,-6.61]],"o":[[-11.959,0.286],[-0.893,-0.313],[0.756,-1.716],[0,0],[2.9,-0.903],[0.932,0.368],[-12.428,5.23],[-0.945,0.614]],"v":[[4.34,8.53],[-73.957,7.989],[-75.054,6.191],[-70.014,2.274],[66.374,-40.184],[72.789,-39.988],[73.406,-38.058],[7.523,7.538]],"c":true}]},{"t":195,"s":[{"i":[[1.212,0.293],[-0.052,1.063],[-0.465,1.092],[-2.964,0.923],[0,0],[-2.408,-1.462],[-0.75,-0.938],[9.093,-10.048]],"o":[[-13.028,-3.146],[0.06,-1.209],[1.127,-2.65],[0,0],[2.9,-0.902],[1.008,0.612],[0.699,0.874],[-0.845,0.934]],"v":[[11.967,33.017],[-77.516,10.287],[-76.716,6.809],[-70.385,1.081],[66.005,-41.368],[74.313,-40.349],[76.976,-38.011],[15.15,32.025]],"c":true}]}],"ix":2},"nm":"Path 6","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.401014983654,0.635570943356,0.964705884457,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":11,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":87,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":88,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":111,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":112,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":188,"s":[0]},{"t":189,"s":[100]}],"ix":5},"r":1,"bm":0,"nm":"Fill 6","mn":"ADBE Vector Graphic - Fill","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[4.2,-1.308],[0,0],[2.5,3.352],[0,0],[-2.717,0.813],[0,0]],"o":[[-0.18,4.162],[0,0],[-4.22,1.315],[0,0],[0,0],[2.717,-0.813],[0,0]],"v":[[103.625,47.302],[96.485,56.565],[-39.905,99.014],[-51.065,95.387],[5.902,26.402],[11.27,22.465],[17.541,22.927]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.349019616842,0.592156887054,0.933333396912,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 5","mn":"ADBE Vector Graphic - Fill","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[0,0],[4.2,-1.308],[0,0],[2.53,3.45],[0,0],[-2.717,0.812],[0,0]],"o":[[-0.149,4.26],[0,0],[-4.22,1.315],[0,0],[0,0],[2.717,-0.812],[0,0]],"v":[[103.573,47.134],[96.485,56.565],[-39.905,99.013],[-51.118,95.217],[5.469,25.011],[10.82,21.02],[17.108,21.54]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.1254902035,0.1254902035,0.1254902035,1],"ix":4},"o":{"a":0,"k":30,"ix":5},"r":1,"bm":0,"nm":"Fill 2","mn":"ADBE Vector Graphic - Fill","hd":false},{"ind":6,"ty":"sh","ix":7,"ks":{"a":0,"k":{"i":[[-1.69,-5.354],[0,0],[0.05,-1.142],[4.2,-1.308],[0,0],[2.5,3.352],[0.36,1.136],[0,0],[-6.374,-1.622],[0,0],[0,0]],"o":[[0,0],[0.36,1.157],[-0.18,4.162],[0,0],[-4.22,1.315],[-0.68,-0.903],[0,0],[-1.67,-5.372],[0,0],[0,0],[4.139,-4.613]],"v":[[78.958,-33.99],[103.175,43.824],[103.625,47.302],[96.485,56.565],[-39.905,99.014],[-51.065,95.387],[-52.635,92.318],[-76.841,14.537],[-68.329,7.683],[12.317,29.181],[68.061,-34.766]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.227450996637,0.509803950787,0.95294123888,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 4","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1801.139,934.164],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[594,594],"ix":3},"r":{"a":0,"k":17.3,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"front","np":8,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[1741.752,1155.556],[1787.515,1141.378]],"c":false},"ix":2},"nm":"Path 6","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[1746.435,1170.589],[1844.124,1140.151]],"c":false},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"rp","c":{"a":0,"k":4,"ix":1},"o":{"a":0,"k":0,"ix":2},"m":1,"ix":3,"tr":{"ty":"tr","p":{"a":0,"k":[5,15],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":4},"so":{"a":0,"k":100,"ix":5},"eo":{"a":0,"k":100,"ix":6},"nm":"Transform"},"nm":"Repeater 1","mn":"ADBE Vector Filter - Repeater","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":17,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":46,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":105,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":106,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":118,"s":[0]},{"t":147,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":2,"ix":4,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[0.750726640224,0.811723232269,0.886274516582,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-1792,-1153],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.152,-3.69],[0,0],[3.69,-1.152],[0,0],[1.152,3.69],[0,0],[-3.69,1.152],[0,0]],"o":[[0,0],[1.152,3.69],[0,0],[-3.69,1.152],[0,0],[-1.152,-3.69],[0,0],[3.69,-1.152]],"v":[[1861.208,1111.749],[1886.121,1191.558],[1881.524,1200.325],[1753.446,1240.409],[1744.678,1235.813],[1719.765,1156.005],[1724.362,1147.237],[1852.441,1107.153]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.926412940025,0.952468276024,0.984313726425,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 3","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-1792,-1153],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":14,"s":[1801.139,977.164],"to":[0,-35.5],"ti":[0,35.5]},{"t":29,"s":[1801.139,764.164],"h":1},{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":72,"s":[1801.139,764.164],"to":[0,35.5],"ti":[0,-35.5]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":87,"s":[1801.139,977.164],"to":[0,35.5],"ti":[0,0]},{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":115,"s":[1801.139,977.164],"to":[0,-35.5],"ti":[0,35.5]},{"t":130,"s":[1801.139,764.164],"h":1},{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":173,"s":[1801.139,764.164],"to":[0,35.5],"ti":[0,-35.5]},{"t":188,"s":[1801.139,977.164]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[594,594],"ix":3},"r":{"a":0,"k":17.3,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":10,"s":[{"i":[[-0.758,-2.403],[0,0],[0.05,-1.142],[4.2,-1.308],[0,0],[2.5,3.352],[0.36,1.136],[0,0],[-0.788,2.059],[-14.49,5.196],[-2.265,0.603],[-2.109,-1.321]],"o":[[0,0],[0.36,1.157],[-0.18,4.162],[0,0],[-4.22,1.315],[-0.68,-0.903],[0,0],[-0.707,-2.273],[0.933,-2.439],[2.197,-0.788],[14.919,-3.974],[1.978,1.239]],"v":[[78.735,-34.708],[103.175,43.824],[103.625,47.302],[96.485,56.565],[-39.905,99.014],[-51.065,95.387],[-52.635,92.318],[-77.065,13.819],[-76.632,7.874],[-6.935,-15.232],[0.09,-17.423],[74.435,-40.273]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"t":11,"s":[{"i":[[-0.758,-2.403],[0,0],[0.05,-1.142],[4.2,-1.308],[0,0],[2.5,3.352],[0.36,1.136],[0,0],[-0.788,2.059],[-13.999,6.772],[-2.338,0.367],[-2.109,-1.321]],"o":[[0,0],[0.36,1.157],[-0.18,4.162],[0,0],[-4.22,1.315],[-0.68,-0.903],[0,0],[-0.707,-2.273],[0.933,-2.439],[2.122,-1.027],[15.402,-2.421],[1.978,1.239]],"v":[[78.735,-34.708],[103.175,43.824],[103.625,47.302],[96.485,56.565],[-39.905,99.014],[-51.065,95.387],[-52.635,92.318],[-77.065,13.819],[-76.632,7.874],[-11.418,-32.357],[-4.394,-34.553],[74.435,-40.273]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":18,"s":[{"i":[[-0.758,-2.403],[0,0],[0.05,-1.142],[4.2,-1.308],[0,0],[2.5,3.352],[0.36,1.136],[0,0],[-0.788,2.059],[-11.355,15.263],[-2.734,-0.902],[-2.109,-1.321]],"o":[[0,0],[0.36,1.157],[-0.18,4.162],[0,0],[-4.22,1.315],[-0.68,-0.903],[0,0],[-0.707,-2.273],[0.933,-2.439],[1.721,-2.314],[18.008,5.945],[1.978,1.239]],"v":[[78.735,-34.708],[103.175,43.824],[103.625,47.302],[96.485,56.565],[-39.905,99.014],[-51.065,95.387],[-52.635,92.318],[-77.065,13.819],[-76.632,7.874],[-21.154,-67.958],[-14.138,-70.18],[74.435,-40.273]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":1,"y":0},"t":81,"s":[{"i":[[-0.758,-2.403],[0,0],[0.05,-1.142],[4.2,-1.308],[0,0],[2.5,3.352],[0.36,1.136],[0,0],[-0.788,2.059],[-11.355,15.263],[-2.734,-0.902],[-2.109,-1.321]],"o":[[0,0],[0.36,1.157],[-0.18,4.162],[0,0],[-4.22,1.315],[-0.68,-0.903],[0,0],[-0.707,-2.273],[0.933,-2.439],[1.721,-2.314],[18.008,5.945],[1.978,1.239]],"v":[[78.735,-34.708],[103.175,43.824],[103.625,47.302],[96.485,56.565],[-39.905,99.014],[-51.065,95.387],[-52.635,92.318],[-77.065,13.819],[-76.632,7.874],[-21.154,-67.958],[-14.138,-70.18],[74.435,-40.273]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":88,"s":[{"i":[[-0.758,-2.403],[0,0],[0.05,-1.142],[4.2,-1.308],[0,0],[2.5,3.352],[0.36,1.136],[0,0],[-0.788,2.059],[-13.999,6.772],[-2.338,0.367],[-2.109,-1.321]],"o":[[0,0],[0.36,1.157],[-0.18,4.162],[0,0],[-4.22,1.315],[-0.68,-0.903],[0,0],[-0.707,-2.273],[0.933,-2.439],[2.122,-1.027],[15.402,-2.421],[1.978,1.239]],"v":[[78.735,-34.708],[103.175,43.824],[103.625,47.302],[96.485,56.565],[-39.905,99.014],[-51.065,95.387],[-52.635,92.318],[-77.065,13.819],[-76.632,7.874],[-11.418,-32.357],[-4.394,-34.553],[74.435,-40.273]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":89,"s":[{"i":[[-0.758,-2.403],[0,0],[0.05,-1.142],[4.2,-1.308],[0,0],[2.5,3.352],[0.36,1.136],[0,0],[-0.788,2.059],[-14.49,5.196],[-2.265,0.603],[-2.109,-1.321]],"o":[[0,0],[0.36,1.157],[-0.18,4.162],[0,0],[-4.22,1.315],[-0.68,-0.903],[0,0],[-0.707,-2.273],[0.933,-2.439],[2.197,-0.788],[14.919,-3.974],[1.978,1.239]],"v":[[78.735,-34.708],[103.175,43.824],[103.625,47.302],[96.485,56.565],[-39.905,99.014],[-51.065,95.387],[-52.635,92.318],[-77.065,13.819],[-76.632,7.874],[-6.935,-15.232],[0.09,-17.423],[74.435,-40.273]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":111,"s":[{"i":[[-0.758,-2.403],[0,0],[0.05,-1.142],[4.2,-1.308],[0,0],[2.5,3.352],[0.36,1.136],[0,0],[-0.788,2.059],[-14.49,5.196],[-2.265,0.603],[-2.109,-1.321]],"o":[[0,0],[0.36,1.157],[-0.18,4.162],[0,0],[-4.22,1.315],[-0.68,-0.903],[0,0],[-0.707,-2.273],[0.933,-2.439],[2.197,-0.788],[14.919,-3.974],[1.978,1.239]],"v":[[78.735,-34.708],[103.175,43.824],[103.625,47.302],[96.485,56.565],[-39.905,99.014],[-51.065,95.387],[-52.635,92.318],[-77.065,13.819],[-76.632,7.874],[-6.935,-15.232],[0.09,-17.423],[74.435,-40.273]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"t":112,"s":[{"i":[[-0.758,-2.403],[0,0],[0.05,-1.142],[4.2,-1.308],[0,0],[2.5,3.352],[0.36,1.136],[0,0],[-0.788,2.059],[-13.999,6.772],[-2.338,0.367],[-2.109,-1.321]],"o":[[0,0],[0.36,1.157],[-0.18,4.162],[0,0],[-4.22,1.315],[-0.68,-0.903],[0,0],[-0.707,-2.273],[0.933,-2.439],[2.122,-1.027],[15.402,-2.421],[1.978,1.239]],"v":[[78.735,-34.708],[103.175,43.824],[103.625,47.302],[96.485,56.565],[-39.905,99.014],[-51.065,95.387],[-52.635,92.318],[-77.065,13.819],[-76.632,7.874],[-11.418,-32.357],[-4.394,-34.553],[74.435,-40.273]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":119,"s":[{"i":[[-0.758,-2.403],[0,0],[0.05,-1.142],[4.2,-1.308],[0,0],[2.5,3.352],[0.36,1.136],[0,0],[-0.788,2.059],[-11.355,15.263],[-2.734,-0.902],[-2.109,-1.321]],"o":[[0,0],[0.36,1.157],[-0.18,4.162],[0,0],[-4.22,1.315],[-0.68,-0.903],[0,0],[-0.707,-2.273],[0.933,-2.439],[1.721,-2.314],[18.008,5.945],[1.978,1.239]],"v":[[78.735,-34.708],[103.175,43.824],[103.625,47.302],[96.485,56.565],[-39.905,99.014],[-51.065,95.387],[-52.635,92.318],[-77.065,13.819],[-76.632,7.874],[-21.154,-67.958],[-14.138,-70.18],[74.435,-40.273]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":1,"y":0},"t":182,"s":[{"i":[[-0.758,-2.403],[0,0],[0.05,-1.142],[4.2,-1.308],[0,0],[2.5,3.352],[0.36,1.136],[0,0],[-0.788,2.059],[-11.355,15.263],[-2.734,-0.902],[-2.109,-1.321]],"o":[[0,0],[0.36,1.157],[-0.18,4.162],[0,0],[-4.22,1.315],[-0.68,-0.903],[0,0],[-0.707,-2.273],[0.933,-2.439],[1.721,-2.314],[18.008,5.945],[1.978,1.239]],"v":[[78.735,-34.708],[103.175,43.824],[103.625,47.302],[96.485,56.565],[-39.905,99.014],[-51.065,95.387],[-52.635,92.318],[-77.065,13.819],[-76.632,7.874],[-21.154,-67.958],[-14.138,-70.18],[74.435,-40.273]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":189,"s":[{"i":[[-0.758,-2.403],[0,0],[0.05,-1.142],[4.2,-1.308],[0,0],[2.5,3.352],[0.36,1.136],[0,0],[-0.788,2.059],[-13.999,6.772],[-2.338,0.367],[-2.109,-1.321]],"o":[[0,0],[0.36,1.157],[-0.18,4.162],[0,0],[-4.22,1.315],[-0.68,-0.903],[0,0],[-0.707,-2.273],[0.933,-2.439],[2.122,-1.027],[15.402,-2.421],[1.978,1.239]],"v":[[78.735,-34.708],[103.175,43.824],[103.625,47.302],[96.485,56.565],[-39.905,99.014],[-51.065,95.387],[-52.635,92.318],[-77.065,13.819],[-76.632,7.874],[-11.418,-32.357],[-4.394,-34.553],[74.435,-40.273]],"c":true}]},{"t":190,"s":[{"i":[[-0.758,-2.403],[0,0],[0.05,-1.142],[4.2,-1.308],[0,0],[2.5,3.352],[0.36,1.136],[0,0],[-0.788,2.059],[-14.49,5.196],[-2.265,0.603],[-2.109,-1.321]],"o":[[0,0],[0.36,1.157],[-0.18,4.162],[0,0],[-4.22,1.315],[-0.68,-0.903],[0,0],[-0.707,-2.273],[0.933,-2.439],[2.197,-0.788],[14.919,-3.974],[1.978,1.239]],"v":[[78.735,-34.708],[103.175,43.824],[103.625,47.302],[96.485,56.565],[-39.905,99.014],[-51.065,95.387],[-52.635,92.318],[-77.065,13.819],[-76.632,7.874],[-6.935,-15.232],[0.09,-17.423],[74.435,-40.273]],"c":true}]}],"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.174548238516,0.452203959227,0.890196084976,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 3","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1801.139,934.164],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[594,594],"ix":3},"r":{"a":0,"k":17.3,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"back 2","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.758,-2.403],[0,0],[0.05,-1.142],[4.2,-1.308],[0,0],[2.5,3.352],[0.36,1.136],[0,0],[-0.788,2.059],[-14.49,5.196],[-2.265,0.603],[-2.109,-1.321]],"o":[[0,0],[0.36,1.157],[-0.18,4.162],[0,0],[-4.22,1.315],[-0.68,-0.903],[0,0],[-0.707,-2.273],[0.933,-2.439],[2.197,-0.788],[14.919,-3.974],[1.978,1.239]],"v":[[78.735,-34.708],[103.175,43.824],[103.625,47.302],[96.485,56.565],[-39.905,99.014],[-51.065,95.387],[-52.635,92.318],[-77.065,13.819],[-76.632,7.874],[-6.935,-15.232],[0.09,-17.423],[74.435,-40.273]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":20,"ix":5},"r":1,"bm":0,"nm":"Fill 4","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1785.139,947.164],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[594,594],"ix":3},"r":{"a":0,"k":17.3,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"back","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":204,"st":-23,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"leaf 3","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[196,-240,0],"ix":2},"a":{"a":0,"k":[1500,1000.5,0],"ix":1},"s":{"a":0,"k":[56,56,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.52,-0.05],[15.722,26.95],[21.544,0],[35.341,11.01],[18.56,8.32],[-0.503,0.85],[-32.295,-10.05],[-43.131,0],[-18.804,6.14],[53.395,57.16],[53.175,-22.35],[0.078,1.07],[-71.736,2.18],[38.007,34.2],[6.59,0],[35.162,-3.87],[48.565,-16.86],[-0.019,0.91],[-0.004,0.17],[-36.694,4.03],[-15.873,0],[-2.179,-0.05],[16.272,13.78],[46.573,31.822],[-0.864,0.642],[-96.288,-81.53],[-30.176,-28.64],[6.164,41.47],[-7.044,39.89],[-0.121,0],[-0.907,-0.082],[-5.287,-35.58],[-1.283,-4.23],[-31.301,-36.06],[-0.128,-0.15],[-21.362,32.62],[-1.781,2.47],[-0.853,-0.58],[1.847,-2.83],[1.964,-100.57],[-22.107,-33.25],[-15.101,23.19],[0,0],[18.79,-15.47],[3.888,-2.83],[-14.087,-36.96],[0.026,-0.05],[0,0],[0,-0.01],[0,0],[0,0],[0,0]],"o":[[-10.195,-26.92],[-19.289,6.4],[-43.533,0],[-32.442,-10.1],[0.365,-0.95],[18.478,8.28],[35.105,10.92],[21.011,0],[-36.858,-62.52],[-71.572,1.17],[-0.162,-0.99],[52.999,-22.24],[-37.629,-40.07],[-1.487,-0.05],[-15.789,0],[-36.753,4.04],[-0.049,-0.86],[0.005,-0.17],[48.538,-16.74],[35.271,-3.88],[3.726,0],[-17.173,-15.39],[-96.765,-81.94],[0.811,-0.642],[46.879,32.06],[34.528,29.24],[-3.716,-13],[-5.304,-35.69],[0.12,-0.001],[0.865,0],[-7.072,39.563],[7.363,49.53],[39.468,37.69],[0.128,0.14],[2.483,-99.44],[1.801,-2.75],[0.83,0.52],[-1.835,2.53],[-21.321,32.64],[30.334,35.22],[25.708,-18.68],[0,0],[-13.962,21.17],[-3.711,3.06],[26.711,40.49],[-0.569,1.13],[0,0],[-0.001,0],[0,0],[0,0],[0,0],[-0.521,0.05]],"v":[[255.766,316.768],[216.528,235.818],[154.584,244.798],[30.443,223.238],[-48.814,193.138],[-47.513,190.428],[31.384,220.388],[154.559,241.798],[214.959,233.168],[75.055,51.768],[-160.378,118.009],[-160.74,114.908],[72.293,48.818],[-42.731,-63.242],[-55.102,-63.412],[-135.027,-58.872],[-269.658,-29.702],[-269.711,-32.362],[-269.694,-32.862],[-135.302,-61.862],[-55.074,-66.412],[-46.17,-66.332],[-96.486,-110.152],[-330.557,-288.331],[-328.049,-290.257],[-94.545,-112.452],[2.575,-25.562],[-16.736,-115.122],[-18.595,-236.622],[-18.232,-236.624],[-15.577,-236.505],[-13.763,-115.562],[6.917,-21.432],[113.245,89.358],[113.624,89.799],[163.293,-101.922],[168.667,-109.731],[171.191,-108.082],[165.664,-100.052],[116.551,93.188],[195.269,195.978],[255.786,131.648],[257.595,134.588],[208.343,189.678],[196.939,198.499],[258.235,314.828],[257.327,316.628],[257.327,316.628],[257.326,316.638],[257.326,316.638],[257.324,316.638],[257.324,316.638]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.038554400206,0.285618126392,0.427450984716,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 2","mn":"ADBE Vector Graphic - Fill","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[-2.571,34.45],[3.084,43.56],[43.327,-9.15],[-2.839,43.58],[-8.23,67.7],[47.117,-4.25],[-0.732,34.35],[63,43.63],[-107.885,59.634],[-44.46,-49.284],[-10.216,5.71],[-45.98,-14.077],[-28.6,19.15],[-50.281,-35.21],[-9.916,-48.08],[0,0],[0,0]],"o":[[-165.658,16.23],[2.57,-34.44],[-1.788,-25.24],[-50.433,10.65],[3.265,-50.13],[4.104,-33.77],[-47.371,4.27],[1.46,-68.54],[-62.999,-43.63],[59.009,-32.618],[36.825,40.819],[22.549,-12.62],[45.98,14.074],[28.598,-19.16],[50.281,35.21],[9.916,48.09],[52.841,-105.53],[101.227,31.71]],"v":[[257.324,316.638],[-50.066,198.838],[26.462,137.818],[-59.895,130.878],[-160.749,108.598],[-85.562,18.719],[-174.718,-6.552],[-269.711,-32.362],[-213.42,-133.032],[-312.32,-300.251],[-150.486,-234.301],[-76.158,-158.372],[-7.843,-234.946],[82.178,-44.552],[171.887,-107.612],[174.944,60.078],[224.503,87.928],[298.275,6.368]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.086274512112,0.355340272188,0.509803950787,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[776.13,1559.822],"ix":2},"a":{"a":0,"k":[252.778,308.333],"ix":1},"s":{"a":0,"k":[79,79],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[8]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":32,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":77,"s":[8]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":136,"s":[3]},{"t":199,"s":[8]}],"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 62","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[241.821,-10.2],[0,0],[0,0],[95.49,-34.36],[-51.858,-9.43],[0,0],[0,0],[-116.191,13.01]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[116.191,-13.01]],"v":[[315.451,8.94],[-55.948,-125.96],[-13.934,-68.12],[-81.586,-121.09],[-317.278,-74.91],[-59.935,42.4],[9.245,21.74],[-28.17,73.51],[201.087,123.15]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.363921552896,0.909803926945,0.864848911762,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[818.171,1522.597],"ix":2},"a":{"a":0,"k":[277.778,30.556],"ix":1},"s":{"a":0,"k":[79,79],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[-24]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":47,"s":[-21]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":99,"s":[-24]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":155,"s":[-21]},{"t":199,"s":[-24]}],"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 59","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-17.327,35.044],[0,0],[13.781,7.041],[0,0],[0,0],[11.484,9.404],[0,0],[0,0],[0,0],[38.997,-12.255],[0,0],[10.845,-4.755],[0,0],[-1.813,0.784],[0,0],[0,0],[-2.051,0.78],[0,0],[0,0],[-2.342,0.994],[0,0],[-8.098,-1.219],[-0.749,1.903],[0.27,-1.086],[-35.396,-15.316],[6.324,21.338],[6.24,10.822],[-19.384,-14.548],[-30.872,-23.95],[0,0],[-4.168,6.938],[-11.2,-4.394]],"o":[[17.328,-35.045],[0,0],[-13.781,-7.041],[-22.754,-17.704],[0,0],[-11.484,-9.404],[-28.863,-10.099],[-60.399,15.696],[0,0],[0,0],[0,0],[0,0],[1.79,-0.952],[0,0],[0,0],[1.17,-0.457],[0,0],[0,0],[4.779,-1.609],[0,0],[14.735,-5.227],[0,0],[-0.248,0.993],[-6.196,24.92],[35.396,15.316],[-6.326,-21.344],[-6.235,-10.813],[19.375,14.541],[30.871,23.95],[-28.077,-9.588],[4.167,-6.937],[11.2,4.394]],"v":[[206.56,28.825],[151.299,-38.985],[88.847,-36.229],[118.427,-55.556],[11.44,-91.41],[-27.295,-61.107],[-2.416,-91.742],[-73.512,-95.551],[-98.836,-16.496],[-156.585,16.364],[-156.585,16.364],[-175.312,22.938],[-168.851,27.142],[-163.456,24.528],[-163.419,24.516],[-163.339,24.482],[-158.445,22.598],[-158.442,22.593],[-158.427,22.592],[-147.889,18.725],[-147.868,18.715],[-105.019,8.428],[-104.254,5.309],[-105.019,8.428],[-23.419,87.593],[-1.44,66.332],[-30.523,33.292],[-7.472,36.239],[26.276,84.231],[127.822,77.943],[103.376,52.768],[147.656,62.865]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.086274512112,0.35686275363,0.509803950787,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1548.444,1508.903],"ix":2},"a":{"a":0,"k":[-158.915,-25.046],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[5.188]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":29,"s":[-2.812]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":61,"s":[5.188]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":97,"s":[-2.812]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":138,"s":[5.188]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":172,"s":[-2.812]},{"t":199,"s":[5.188]}],"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 23","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-72.4,84.95],[0,0],[0,0],[-45.06,19.7],[0,0],[0,0],[0,0],[0,0]],"o":[[27.07,8.84],[0,0],[39.11,-38.04],[21.97,25.45],[0,0],[122.11,-40.8],[-139.9,286.28],[-19.88,-196.75]],"v":[[-156.955,-120.915],[-89.775,-98.475],[-132.365,-147.195],[-3.555,-232.345],[44.065,-178.565],[40.695,-249.335],[275.615,-280.815],[-255.735,290.135]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.161906957626,0.703410863876,0.737254917622,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[7.46,89.64],[0,0],[-141.07,232.92],[0,0],[-40.31,-0.18]],"o":[[-139.9,286.28],[0,0],[0,0],[0,0],[29.92,-64.87]],"v":[[275.615,-280.815],[-255.735,290.135],[214.515,-6.555],[149.255,-49.445],[237.575,-49.925]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.113725498319,0.600000023842,0.674509823322,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 2","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1601.536,1460.812],"ix":2},"a":{"a":0,"k":[-258.333,261.111],"ix":1},"s":{"a":0,"k":[67,67],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[-14]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":43,"s":[-22]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":113,"s":[-14]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":158,"s":[-22]},{"t":199,"s":[-14]}],"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 65","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":200,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"leaf","parent":1,"sr":1,"ks":{"o":{"a":0,"k":85,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[196,-64,0],"ix":2},"a":{"a":0,"k":[1500,1000.5,0],"ix":1},"s":{"a":0,"k":[56,56,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[14.25,30.88],[0,0],[-9.27,5.98],[0,0],[0,0],[-7.51,8.07],[0,0],[0,0],[0,0],[-28.13,-11.24],[0,0],[-7.9,-4.3],[0,0],[1.32,0.71],[0,0],[0,0],[1.49,0.71],[0,0],[1.71,0.9],[0,0],[5.61,-0.95],[0.64,1.67],[-0.26,-0.95],[23.97,-12.92],[-3.18,18.58],[-3.75,9.38],[12.76,-12.46],[20.28,-20.53],[0,0],[3.34,6.12],[7.61,-3.69]],"o":[[-14.25,-30.89],[0,0],[9.27,-5.97],[14.94,-15.18],[0,0],[7.52,-8.07],[19.69,-8.44],[43.38,14.54],[0,0],[0,0],[0,0],[0,0],[-1.31,-0.86],[0,0],[0,0],[-0.85,-0.41],[0,0],[-3.46,-1.47],[0,0],[-10.67,-4.77],[0,0],[0.23,0.87],[5.82,21.89],[-23.97,12.92],[3.18,-18.59],[3.74,-9.37],[-12.76,12.46],[-20.27,20.53],[19.17,-8],[-3.34,-6.13],[-7.61,3.7]],"v":[[-126.89,19.835],[-92.06,-38.735],[-17.07,-24.785],[-69.93,-52.795],[3.14,-82.705],[51.04,-37.175],[12.86,-82.815],[62.6,-85.185],[85.06,-15.695],[127.59,13.825],[127.6,13.825],[141.14,19.825],[136.85,23.415],[132.9,21.065],[132.88,21.045],[132.82,21.015],[129.27,19.305],[129.26,19.295],[121.62,15.775],[121.61,15.765],[90.89,6.185],[90.16,3.455],[90.89,6.185],[38.21,74.335],[21.51,55.445],[53.59,10.635],[31.53,18.385],[3.08,70.725],[-68.66,63.855],[-32.57,18.515],[-83.48,50.395]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.364705890417,0.909803986549,0.866666734219,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1214.31,722.068],"ix":2},"a":{"a":0,"k":[119.643,-16.071],"ix":1},"s":{"a":0,"k":[-136,136],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[-53]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":56,"s":[-50]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":98,"s":[-53]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":157,"s":[-50]},{"t":199,"s":[-53]}],"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 15","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[81.51,-75.711],[-128.3,56.065],[-2.22,0],[-2.69,-5.596],[5.2,-10.51]],"o":[[0,0],[2.13,-0.931],[5.93,0],[2.42,5.01],[-13.86,28.028]],"v":[[-86.345,139.385],[136.205,-73.643],[142.805,-75.019],[157.135,-66.244],[154.665,-43.433]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[45.26,-73.28],[-81,69.392],[-3.32,0],[1.78,-10.112],[0.05,-0.238]],"o":[[0,0],[2.96,-2.541],[8.7,0],[-0.04,0.233],[-4.57,23.769]],"v":[[-72.085,102.304],[45.575,-98.64],[55.255,-102.304],[70.305,-84.442],[70.175,-83.736]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.086274512112,0.35686275363,0.509803950787,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[904.419,751.634],"ix":2},"a":{"a":0,"k":[-71.429,132.143],"ix":1},"s":{"a":0,"k":[-100,100],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":36,"s":[-4]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":117,"s":[1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":174,"s":[-4]},{"t":199,"s":[1]}],"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 22","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-26.95,51.06],[0,0],[-17.61,-6.33],[0,0],[0,0],[-18.63,-1.8],[0,0],[0,0],[0,0],[-13.85,-49.51],[0,0],[-2.34,-15.09],[0,0],[0.4,2.51],[0,0],[0,0],[0.57,2.74],[0,0],[0,0],[0.54,3.23],[0,0],[7.08,6.58],[-1.59,2.59],[1.03,-1.33],[42.13,18.99],[-28.33,14.87],[-16.51,4.62],[29.96,4.35],[48.58,6.17],[0,0],[-4.81,10.82],[12.83,6.46]],"o":[[26.94,-51.05],[0,0],[17.61,6.34],[35.87,4.49],[0,0],[18.63,1.81],[31.68,17.83],[25.13,73.47],[0,0],[0,0],[0,0],[0,0],[-0.2,-2.65],[0,0],[0,0],[-0.31,-1.57],[0,0],[0,0],[-1.58,-6.18],[0,0],[-4.57,-19.29],[0,0],[-0.93,1.21],[-23.49,30.41],[-42.13,-18.99],[28.33,-14.87],[16.5,-4.62],[-29.95,-4.36],[-48.58,-6.16],[30.55,17.57],[4.81,-10.81],[-12.82,-6.45]],"v":[[-167.555,-155.115],[-52.705,-168.555],[5.815,-53.085],[-10.935,-153.215],[104.725,-85.575],[92.745,25.945],[114.895,-72.575],[169.375,-7.985],[98.875,93.955],[102.935,181.715],[102.935,181.715],[108.815,206.165],[99.555,204.085],[98.655,196.335],[98.645,196.285],[98.625,196.175],[97.285,189.625],[97.275,189.615],[97.275,189.605],[94.155,175.675],[94.155,175.645],[75.375,124.365],[78.315,120.565],[75.375,124.365],[-70.795,123.625],[-62.545,81.635],[30.925,78.675],[-2.265,56.945],[-102.145,72.555],[-166.855,-31.215],[-68.525,-29.345],[-164.005,-65.085]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.086274512112,0.35686275363,0.509803950787,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1619.554,1158.989],"ix":2},"a":{"a":0,"k":[100,194.643],"ix":1},"s":{"a":0,"k":[-100,100],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[25]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":34,"s":[33]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":71,"s":[22.806]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":124,"s":[29.894]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":167,"s":[20.914]},{"t":199,"s":[25]}],"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 16","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[12.16,44.9],[0,0],[14.97,-1.87],[0,0],[0,0],[14.96,1.87],[0,0],[0,0],[0,0],[19.64,-36.49],[0,0],[4.5,-11.45],[0,0],[-0.76,1.9],[0,0],[0,0],[-0.94,2.04],[0,0],[0,0],[-1,2.44],[0,0],[-6.73,3.93],[0.79,2.32],[-0.57,-1.22],[-36.49,7.48],[19.65,16.7],[12.16,6.55],[-24.32,-1.87],[-39.28,-3.74],[0,0],[1.87,9.36],[-11.22,2.8]],"o":[[-12.16,-44.9],[0,0],[-14.97,1.87],[-29,-2.8],[0,0],[-14.97,-1.87],[-28.07,8.41],[-32.74,53.32],[0,0],[0,0],[0,0],[0,0],[0.62,-2.05],[0,0],[0,0],[0.53,-1.18],[0,0],[0,0],[2.34,-4.58],[0,0],[7.01,-14.37],[0,0],[0.52,1.12],[13.1,28.07],[36.48,-7.48],[-19.64,-16.71],[-12.16,-6.55],[24.32,1.87],[39.3,3.74],[-27.13,8.42],[-1.88,-9.35],[11.23,-2.81]],"v":[[155.755,-95.155],[67.825,-126.025],[1.405,-45.575],[32.275,-121.355],[-70.625,-88.605],[-80.915,1.195],[-80.915,-80.185],[-135.175,-39.025],[-97.755,53.585],[-116.465,121.875],[-116.465,121.875],[-125.405,140.055],[-117.755,140.055],[-115.685,134.125],[-115.665,134.085],[-115.635,134.005],[-113.415,129.095],[-113.415,129.085],[-113.405,129.075],[-108.495,118.675],[-108.485,118.655],[-84.665,81.645],[-86.295,78.135],[-84.665,81.645],[30.405,106.905],[31.335,72.435],[-41.625,53.585],[-11.695,42.355],[64.075,72.295],[133.305,2.135],[55.665,-13.775],[137.045,-24.995]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.160784319043,0.701960802078,0.737254917622,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[764.819,817.631],"ix":2},"a":{"a":0,"k":[-144.643,121.429],"ix":1},"s":{"a":0,"k":[-100,100],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[-2]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":45,"s":[-7]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":104,"s":[-2]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":164,"s":[-7]},{"t":199,"s":[-2]}],"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 17","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-24.431,75.331],[0,0],[-25.3,-4.431],[0,0],[0,0],[-25.61,1.932],[0,0],[0,0],[0,0],[-30.35,-63.672],[0,0],[-6.71,-19.844],[0,0],[1.14,3.301],[0,0],[0,0],[1.43,3.563],[0,0],[0,0],[1.5,4.233],[0,0],[11.12,7.237],[-1.54,3.876],[1.08,-2.032],[61.4,15.771],[-34.8,26.756],[-21.22,10.119],[41.51,-1.15],[67.11,-3.082],[0,0],[-3.96,15.75],[18.85,5.709]],"o":[[24.42,-75.331],[0,0],[25.29,4.431],[49.54,-2.35],[0,0],[25.6,-1.931],[47.02,16.658],[51.22,93.396],[0,0],[0,0],[0,0],[0,0],[-0.89,-3.541],[0,0],[0,0],[-0.79,-2.054],[0,0],[0,0],[-3.59,-7.976],[0,0],[-10.71,-25.008],[0,0],[-0.98,1.859],[-24.61,46.623],[-61.41,-15.771],[34.79,-26.755],[21.23,-10.118],[-41.51,1.15],[-67.12,3.081],[45.42,16.58],[3.96,-15.749],[-18.85,-5.709]],"v":[[-258.38,-174.038],[-106.3,-219.183],[-0.079,-76.85],[-46.239,-208.262],[125.98,-144],[135.98,9.551],[142.771,-128.826],[231.59,-54.312],[160.231,100.028],[186.341,217.7],[186.341,217.702],[200.031,249.369],[187.021,248.73],[183.98,238.459],[183.96,238.399],[183.91,238.256],[180.551,229.716],[180.551,229.703],[180.54,229.686],[173.051,211.598],[173.04,211.559],[135.62,146.651],[138.701,140.821],[135.62,146.651],[-62.12,179.988],[-60.829,121.293],[64.8,95.341],[14.84,73.755],[-116.49,118.326],[-228.33,-6.746],[-94.989,-27.302],[-232.429,-53.184]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.364705890417,0.909803986549,0.866666734219,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1129.909,779.904],"ix":2},"a":{"a":0,"k":[225,232.143],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[13]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":43,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":92,"s":[13]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":144,"s":[5]},{"t":199,"s":[13]}],"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 18","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[16.94,0],[0,0],[-43.77,0],[-1.63,-21.67]],"o":[[-53.5,0],[0,0],[51.94,0],[0.73,9.6]],"v":[[46.76,70.935],[-120.69,34.595],[-36.86,31.075],[73.86,57.695]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[-46.77,0],[-3.84,-3.7]],"o":[[0,0],[8.15,0],[25.89,24.98]],"v":[[-97.42,26.005],[53.12,-26.005],[71.53,-20.725]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.113725498319,0.600000023842,0.674509823322,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1571.15,766.592],"ix":2},"a":{"a":0,"k":[-109.821,33.036],"ix":1},"s":{"a":0,"k":[145,145],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[-49.641]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":52,"s":[-46.641]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":99,"s":[-49.641]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":153,"s":[-46.641]},{"t":199,"s":[-49.641]}],"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 20","np":3,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":200,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Shape Layer 10","sr":1,"ks":{"o":{"a":0,"k":36,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[512,530,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[905,66],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.04705881979,0.077508642159,0.176470588235,1],"ix":4},"o":{"a":0,"k":20,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-3,249],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":200,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/src/Artemis.UI/Assets/Animations/empty.json b/src/Artemis.UI/Assets/Animations/empty.json new file mode 100644 index 000000000..f79bf38aa --- /dev/null +++ b/src/Artemis.UI/Assets/Animations/empty.json @@ -0,0 +1 @@ +{"v":"4.7.0","fr":25,"ip":0,"op":50,"w":120,"h":120,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"ruoi","ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.967]},"o":{"x":[0.167],"y":[0.033]},"n":["0p833_0p967_0p167_0p033"],"t":35,"s":[100],"e":[0]},{"t":49}]},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0,"y":0},"n":"0p833_0p833_0_0","t":0,"s":[57.361,61.016,0],"e":[57.699,41.796,0],"to":[-4.67500305175781,-4.12800598144531,0],"ti":[-13.9099960327148,5.27300262451172,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10.219,"s":[57.699,41.796,0],"e":[79.084,33.982,0],"to":[12.8159942626953,-4.85800170898438,0],"ti":[-4.54498291015625,3.73400115966797,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.445,"s":[79.084,33.982,0],"e":[59.691,9.121,0],"to":[6.61601257324219,-5.43799591064453,0],"ti":[20.0290069580078,1.20700073242188,0]},{"t":35}]},"a":{"a":0,"k":[60.531,10.945,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.994,0],[0,-0.994],[0.995,0],[0,0.994]],"o":[[0.995,0],[0,0.994],[-0.994,0],[0,-0.994]],"v":[[-0.001,-1.801],[1.801,-0.001],[-0.001,1.801],[-1.801,-0.001]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.529,0.529,0.529,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[62.4,13.144],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.422,0],[0,-1.422],[1.421,0],[0,1.422]],"o":[[1.421,0],[0,1.422],[-1.422,0],[0,-1.422]],"v":[[0.001,-2.574],[2.574,0],[0.001,2.574],[-2.574,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.529,0.529,0.529,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0.7},"lc":1,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[64.145,9.606],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.996,0],[0,-1.996],[1.996,0],[0,1.996]],"o":[[1.996,0],[0,1.996],[-1.996,0],[0,-1.996]],"v":[[0,-3.614],[3.614,0],[0,3.614],[-3.614,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.529,0.529,0.529,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0.7},"lc":1,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[57.957,10.552],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":3,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"tr","p":{"a":0,"k":[60.531,10.941],"ix":2},"a":{"a":0,"k":[60.531,10.941],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"ruoi","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":50,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 2","ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.967]},"o":{"x":[0.167],"y":[0.033]},"n":["0p833_0p967_0p167_0p033"],"t":35,"s":[100],"e":[0]},{"t":49}]},"r":{"a":0,"k":0},"p":{"a":0,"k":[-0.75,-0.75,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-13.91,5.273],[-4.545,3.734],[20.029,1.207]],"o":[[-4.675,-4.128],[12.816,-4.858],[6.616,-5.438],[0,0]],"v":[[-7.383,24.76],[-7.046,5.54],[14.34,-2.273],[-3.178,-24.76]],"c":false}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.627,0.627,0.627,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":1},"lc":2,"lj":2,"d":[{"n":"d","nm":"dash","v":{"a":0,"k":2.028}},{"n":"g","nm":"gap","v":{"a":0,"k":2.028}},{"n":"o","nm":"offset","v":{"a":0,"k":0}}],"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"tr","p":{"a":0,"k":[67.87,37.631],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.953]},"o":{"x":[0.167],"y":[0.033]},"n":["0p833_0p953_0p167_0p033"],"t":0,"s":[0],"e":[100]},{"t":35}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim"}],"ip":0,"op":50,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":3,"ty":4,"nm":"im_emptyBox Outlines","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[60,60,0]},"a":{"a":0,"k":[60,60,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-0.001,-16.607],[-32.143,-0.002],[-0.001,16.607],[32.144,-0.002]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.8,0.82,0.851,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[60,55.75],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[12.856,-23.249],[0,-16.605],[-12.857,-23.249],[-45,-6.641],[-32.144,0.001],[-45,6.645],[-12.857,23.249],[0,16.609],[12.856,23.249],[45,6.645],[32.143,0.001],[45,-6.641]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.957,0.957,0.957,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[60,55.748],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-16.072,24.171],[16.072,11.312],[16.072,-24.171],[-16.072,-24.171]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.902,0.914,0.929,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[76.072,83.33],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-32.143,-24.171],[-32.143,11.311],[-0.001,24.171],[32.144,11.311],[32.144,-24.171]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.8,0.82,0.851,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[60,83.33],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"tr","p":{"a":0,"k":[60,60.186],"ix":2},"a":{"a":0,"k":[60,60.186],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"box","np":4,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":50,"st":0,"bm":0,"sr":1}]} \ No newline at end of file diff --git a/src/Artemis.UI/Assets/Animations/login-pending.json b/src/Artemis.UI/Assets/Animations/login-pending.json new file mode 100644 index 000000000..7e5d7187a --- /dev/null +++ b/src/Artemis.UI/Assets/Animations/login-pending.json @@ -0,0 +1 @@ +{"v":"5.8.1","fr":30,"ip":0,"op":101,"w":500,"h":500,"nm":"Login_and_Sign_up ","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Group 1 :M","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[218.999,313.27,0],"ix":2,"l":2},"a":{"a":0,"k":[218.999,313.27,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[2.603,-3.021],[0.567,-0.343],[0.567,-0.3],[3.803,-0.729],[3.803,0.729],[0.567,0.343],[0.567,0.386],[2.624,2.956],[1.274,3.728],[-0.011,0.729],[-0.054,0.729],[-1.446,3.749],[-2.667,2.978],[-0.632,0.364],[-0.632,0.321],[-3.803,0.729],[-3.803,-0.729],[-0.653,-0.321],[-0.653,-0.364],[-2.667,-2.978],[-1.36,-3.728],[-0.032,-0.75],[0.011,-0.75],[1.317,-3.749]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.337254901961,0.666666666667,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[250.124,313.27],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[250.124,313.27],"ix":2},"a":{"a":0,"k":[250.124,313.27],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":63,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":64,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":84,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":364,"s":[100]},{"t":365,"s":[0]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[2.603,-3.021],[0.568,-0.343],[0.568,-0.3],[3.802,-0.729],[3.802,0.729],[0.568,0.343],[0.568,0.386],[2.625,2.956],[1.275,3.728],[-0.01,0.729],[-0.053,0.729],[-1.446,3.749],[-2.667,2.978],[-0.632,0.364],[-0.632,0.321],[-3.802,0.729],[-3.802,-0.729],[-0.653,-0.321],[-0.653,-0.364],[-2.667,-2.978],[-1.36,-3.728],[-0.032,-0.75],[0.011,-0.75],[1.318,-3.749]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.337254901961,0.666666666667,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[241.231,313.27],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[241.231,313.27],"ix":2},"a":{"a":0,"k":[241.231,313.27],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":61,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":62,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":82,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":362,"s":[100]},{"t":363,"s":[0]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[2.603,-3.021],[0.568,-0.343],[0.568,-0.3],[3.803,-0.729],[3.803,0.729],[0.568,0.343],[0.568,0.386],[2.625,2.956],[1.275,3.728],[-0.011,0.729],[-0.054,0.729],[-1.446,3.749],[-2.667,2.978],[-0.632,0.364],[-0.632,0.321],[-3.803,0.729],[-3.803,-0.729],[-0.653,-0.321],[-0.653,-0.364],[-2.667,-2.978],[-1.36,-3.728],[-0.032,-0.75],[0.011,-0.75],[1.317,-3.749]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.337254901961,0.666666666667,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[232.338,313.27],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[232.338,313.27],"ix":2},"a":{"a":0,"k":[232.338,313.27],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":59,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":80,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":360,"s":[100]},{"t":361,"s":[0]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[2.603,-3.021],[0.568,-0.343],[0.568,-0.3],[3.803,-0.729],[3.803,0.729],[0.568,0.343],[0.568,0.386],[2.625,2.956],[1.275,3.728],[-0.011,0.729],[-0.054,0.729],[-1.446,3.749],[-2.667,2.978],[-0.632,0.364],[-0.632,0.321],[-3.803,0.729],[-3.803,-0.729],[-0.653,-0.321],[-0.653,-0.364],[-2.667,-2.978],[-1.36,-3.728],[-0.032,-0.75],[0.011,-0.75],[1.317,-3.749]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.337254901961,0.666666666667,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[223.445,313.27],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[223.445,313.27],"ix":2},"a":{"a":0,"k":[223.445,313.27],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":57,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":58,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":78,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":358,"s":[100]},{"t":359,"s":[0]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[2.603,-3.021],[0.568,-0.343],[0.568,-0.3],[3.803,-0.729],[3.803,0.729],[0.568,0.343],[0.568,0.386],[2.625,2.956],[1.275,3.728],[-0.011,0.729],[-0.054,0.729],[-1.446,3.749],[-2.667,2.978],[-0.632,0.364],[-0.632,0.321],[-3.803,0.729],[-3.803,-0.729],[-0.653,-0.321],[-0.653,-0.364],[-2.667,-2.978],[-1.36,-3.728],[-0.032,-0.75],[0.011,-0.75],[1.317,-3.749]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.337254901961,0.666666666667,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[214.553,313.27],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[214.553,313.27],"ix":2},"a":{"a":0,"k":[214.553,313.27],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":55,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":56,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":76,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":356,"s":[100]},{"t":357,"s":[0]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":1,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[2.603,-3.021],[0.568,-0.343],[0.568,-0.3],[3.803,-0.729],[3.803,0.729],[0.568,0.343],[0.568,0.386],[2.625,2.956],[1.275,3.728],[-0.011,0.729],[-0.054,0.729],[-1.446,3.749],[-2.667,2.978],[-0.632,0.364],[-0.632,0.321],[-3.803,0.729],[-3.803,-0.729],[-0.653,-0.321],[-0.653,-0.364],[-2.667,-2.978],[-1.36,-3.728],[-0.032,-0.75],[0.011,-0.75],[1.317,-3.749]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.337254901961,0.666666666667,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[205.66,313.27],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[205.66,313.27],"ix":2},"a":{"a":0,"k":[205.66,313.27],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":53,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":54,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":74,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":354,"s":[100]},{"t":355,"s":[0]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":1,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[2.603,-3.021],[0.568,-0.343],[0.568,-0.3],[3.803,-0.729],[3.803,0.729],[0.568,0.343],[0.568,0.386],[2.625,2.956],[1.275,3.728],[-0.011,0.729],[-0.054,0.729],[-1.446,3.749],[-2.667,2.978],[-0.632,0.364],[-0.632,0.321],[-3.803,0.729],[-3.803,-0.729],[-0.653,-0.321],[-0.653,-0.364],[-2.667,-2.978],[-1.36,-3.728],[-0.032,-0.75],[0.011,-0.75],[1.317,-3.749]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.337254901961,0.666666666667,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[196.767,313.27],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[196.767,313.27],"ix":2},"a":{"a":0,"k":[196.767,313.27],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":51,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":52,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":72,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":352,"s":[100]},{"t":353,"s":[0]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":1,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[2.603,-3.021],[0.568,-0.343],[0.568,-0.3],[3.803,-0.729],[3.803,0.729],[0.568,0.343],[0.568,0.386],[2.625,2.956],[1.275,3.728],[-0.011,0.729],[-0.054,0.729],[-1.446,3.749],[-2.667,2.978],[-0.632,0.364],[-0.632,0.321],[-3.803,0.729],[-3.803,-0.729],[-0.653,-0.321],[-0.653,-0.364],[-2.667,-2.978],[-1.36,-3.728],[-0.032,-0.75],[0.011,-0.75],[1.317,-3.749]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.337254901961,0.666666666667,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[187.874,313.27],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[187.874,313.27],"ix":2},"a":{"a":0,"k":[187.874,313.27],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":49,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":50,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":70,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":350,"s":[100]},{"t":351,"s":[0]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":1,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false}],"ip":50,"op":364,"st":50,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"User name","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":20,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[183.429,270.817,0],"ix":2,"l":2},"a":{"a":0,"k":[-55.929,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":30,"s":[0,100,100]},{"t":60,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[111.857,9.6],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.337254901961,0.666666666667,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"User name","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":30,"op":300,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Login & Sign up Button","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":12,"s":[0]},{"t":29,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":9,"s":[250,461.026,0],"to":[0,-16.667,0],"ti":[0,16.667,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":29,"s":[250,361.026,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":69,"s":[250,361.026,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":74,"s":[250,366.026,0],"to":[0,0,0],"ti":[0,0,0]},{"t":79,"s":[250,361.026,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":69,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":74,"s":[95,95,100]},{"t":79,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[7.633,0],[0,0],[0,7.633],[0,0],[-7.633,0],[0,0],[0,-7.633],[0,0]],"o":[[0,0],[-7.633,0],[0,0],[0,-7.633],[0,0],[7.633,0],[0,0],[0,7.633]],"v":[[34.696,13.878],[-34.696,13.878],[-48.574,0],[-48.574,0],[-34.696,-13.878],[34.696,-13.878],[48.574,0],[48.574,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.337254911661,0.666666686535,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Login & Sign up Button","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":9,"op":309,"st":9,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Password Box","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":7,"s":[0]},{"t":27,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":7,"s":[250,412.452,0],"to":[0,-16.667,0],"ti":[0,16.667,0]},{"t":27,"s":[250,312.452,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-76.33,-13.878],[76.33,-13.878],[76.33,13.878],[-76.33,13.878]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Password Box","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":7,"op":307,"st":7,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"User name Box","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":5,"s":[0]},{"t":25,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":5,"s":[250,370.817,0],"to":[0,-16.667,0],"ti":[0,16.667,0]},{"t":25,"s":[250,270.817,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[152.661,27.757],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"User name Box","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":5,"op":305,"st":5,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Use icon","parent":8,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":20,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,-55.513,0],"ix":2,"l":2},"a":{"a":0,"k":[250,194.487,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-10.409,0],[-7.633,6.939],[13.184,0],[2.776,-11.103]],"o":[[10.409,0],[-2.776,-11.103],[-13.184,0],[6.939,6.939]],"v":[[0,12.837],[27.063,2.429],[0,-12.837],[-27.063,2.429]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.015686275437,0.470588237047,0.929411768913,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[250,223.284],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-9.198,0],[0,-9.198],[9.198,0],[0,9.198]],"o":[[9.198,0],[0,9.198],[-9.198,0],[0,-9.198]],"v":[[0,-16.654],[16.654,0],[0,16.654],[-16.654,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[250,188.936],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.899,0],[0,-22.899],[-22.899,0],[0,22.899]],"o":[[-22.899,0],[0,22.899],[22.899,0],[0,-23.593]],"v":[[0,-41.635],[-41.635,0],[0,41.635],[41.635,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.337254911661,0.666666686535,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[250,194.487],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Top Button","parent":8,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":20,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-97.148,-124.904,0],"ix":2,"l":2},"a":{"a":0,"k":[152.852,125.096,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[13.878,13.878],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[125.096,125.096],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[13.878,13.878],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[152.852,125.096],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[13.878,13.878],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[180.609,125.096],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Tab","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":20,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[250,450,0],"to":[0,-33.333,0],"ti":[0,33.333,0]},{"t":20,"s":[250,250,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[7.633,0],[0,0],[0,-7.633],[0,0],[-7.633,0],[0,0],[0,7.633],[0,0]],"o":[[0,0],[-7.633,0],[0,0],[0,7.633],[0,0],[7.633,0],[0,0],[0,-7.633]],"v":[[145.722,-159.6],[-145.722,-159.6],[-159.6,-145.722],[-159.6,145.722],[-145.722,159.6],[145.722,159.6],[159.6,145.722],[159.6,-145.722]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.850980401039,0.86274510622,0.882352948189,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Tab","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":300,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/src/Artemis.UI/Assets/Animations/password.json b/src/Artemis.UI/Assets/Animations/password.json new file mode 100644 index 000000000..33d3a9b4a --- /dev/null +++ b/src/Artemis.UI/Assets/Animations/password.json @@ -0,0 +1 @@ +{"v":"5.7.8","fr":30,"ip":0,"op":301,"w":300,"h":300,"nm":"free 04","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 9","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[191,191,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":301,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shapes on screen 2","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-26,94.218,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0.762],[0.762,0],[0,-0.762],[-0.762,0]],"o":[[0,-0.762],[-0.762,0],[0,0.762],[0.762,0]],"v":[[40.188,-146.941],[38.809,-148.32],[37.429,-146.941],[38.809,-145.561]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0.762],[-0.762,0],[0,-0.762],[0.762,0]],"o":[[0,-0.762],[0.762,0],[0,0.762],[-0.762,0]],"v":[[15.077,-146.941],[16.457,-148.32],[17.836,-146.941],[16.457,-145.561]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843148708,0.827450990677,0.972549021244,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[11.008,-159.04],[6.02,-164.027]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[9.345,-152.39],[2.695,-152.39]],"c":false},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":103,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":107,"s":[0]},{"t":113,"s":[100],"h":1},{"t":130,"s":[0],"h":1},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":250,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":254,"s":[0]},{"t":260,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":103,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":107,"s":[100]},{"t":113,"s":[100],"h":1},{"t":130,"s":[0],"h":1},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":250,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":254,"s":[100]},{"t":260,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[0.988235294819,0.729411780834,0.023529412225,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[27.633,-136.939],[27.633,-133.004]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.258823543787,0.243137255311,0.686274528503,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-1.894],[1.894,0],[0,1.894],[-1.894,0]],"o":[[0,1.894],[-1.894,0],[0,-1.894],[1.894,0]],"v":[[31.062,-139.433],[27.633,-136.003],[24.203,-139.433],[27.633,-142.862]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.258823543787,0.243137255311,0.686274528503,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":94,"s":[{"i":[[0,0],[0,4.507],[-4.507,0],[0,-4.507],[0,0]],"o":[[0,0],[0,-4.507],[4.507,0],[0,0],[0,0]],"v":[[19.482,-150.336],[19.453,-155.153],[27.614,-163.315],[35.776,-155.153],[35.776,-150.501]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":113,"s":[{"i":[[0,0],[0,0.341],[-4.507,0],[0,-4.507],[0,0]],"o":[[0,0],[0,-4.507],[4.507,0],[0,0],[0,0]],"v":[[19.5,-155.992],[19.471,-159.403],[27.633,-167.565],[35.794,-159.403],[35.794,-150.727]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":147,"s":[{"i":[[0,0],[0,0.341],[-4.507,0],[0,-4.507],[0,0]],"o":[[0,0],[0,-4.507],[4.507,0],[0,0],[0,0]],"v":[[19.5,-155.992],[19.471,-159.403],[27.633,-167.565],[35.794,-159.403],[35.794,-150.727]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":151,"s":[{"i":[[0,0],[0,4.507],[-4.507,0],[0,-4.507],[0,0]],"o":[[0,0],[0,-4.507],[4.507,0],[0,0],[0,0]],"v":[[19.482,-150.336],[19.453,-155.153],[27.614,-163.315],[35.776,-155.153],[35.776,-150.501]],"c":false}]},{"i":{"x":0,"y":1},"o":{"x":1,"y":0},"t":241,"s":[{"i":[[0,0],[0,4.507],[-4.507,0],[0,-4.507],[0,0]],"o":[[0,0],[0,-4.507],[4.507,0],[0,0],[0,0]],"v":[[19.482,-150.336],[19.453,-155.153],[27.614,-163.315],[35.776,-155.153],[35.776,-150.501]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":260,"s":[{"i":[[0,0],[0,0.341],[-4.507,0],[0,-4.507],[0,0]],"o":[[0,0],[0,-4.507],[4.507,0],[0,0],[0,0]],"v":[[19.5,-155.992],[19.471,-159.403],[27.633,-167.565],[35.794,-159.403],[35.794,-150.727]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":296,"s":[{"i":[[0,0],[0,0.341],[-4.507,0],[0,-4.507],[0,0]],"o":[[0,0],[0,-4.507],[4.507,0],[0,0],[0,0]],"v":[[19.5,-155.992],[19.471,-159.403],[27.633,-167.565],[35.794,-159.403],[35.794,-150.727]],"c":false}]},{"t":300,"s":[{"i":[[0,0],[0,4.507],[-4.507,0],[0,-4.507],[0,0]],"o":[[0,0],[0,-4.507],[4.507,0],[0,0],[0,0]],"v":[[19.482,-150.336],[19.453,-155.153],[27.614,-163.315],[35.776,-155.153],[35.776,-150.501]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.258823543787,0.243137255311,0.686274528503,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[8.264,0],[0,8.264],[0,0],[0,0]],"o":[[0,8.264],[-8.264,0],[0,0],[0,0],[0,0]],"v":[[42.595,-136.003],[27.633,-121.041],[12.67,-136.003],[12.67,-150.727],[42.595,-150.727]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.490196079016,0.984313726425,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":301,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shapes on screen","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-26,-105.782,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.521,99.321],[6.883,104.75]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[6.883,99.321],[-2.521,104.75]],"c":false},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[2.181,107.465],[2.181,96.606]],"c":false},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.988235294819,0.729411780834,0.023529412225,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":4,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":9,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":18,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":50,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":55,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":64,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":104,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":109,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":143,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":145,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":154,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":159,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":168,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":200,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":205,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":214,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":254,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":259,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":293,"s":[100]},{"t":295,"s":[0]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.521,99.321],[6.883,104.75]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[6.883,99.321],[-2.521,104.75]],"c":false},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[2.181,107.465],[2.181,96.606]],"c":false},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.988235294819,0.729411780834,0.023529412225,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[17,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":14,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":19,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":28,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":65,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":74,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":106,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":111,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":143,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":145,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":164,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":169,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":178,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":210,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":215,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":224,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":256,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":261,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":293,"s":[100]},{"t":295,"s":[0]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.521,99.321],[6.883,104.75]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[6.883,99.321],[-2.521,104.75]],"c":false},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[2.181,107.465],[2.181,96.606]],"c":false},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.988235294819,0.729411780834,0.023529412225,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[33.5,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":24,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":29,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":38,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":70,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":75,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":84,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":109,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":114,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":143,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":145,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":174,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":179,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":188,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":220,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":225,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":234,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":259,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":264,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":293,"s":[100]},{"t":295,"s":[0]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.521,99.321],[6.883,104.75]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[6.883,99.321],[-2.521,104.75]],"c":false},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[2.181,107.465],[2.181,96.606]],"c":false},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.988235294819,0.729411780834,0.023529412225,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[50.5,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":36,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":41,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":50,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":82,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":87,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":96,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":112,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":117,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":143,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":145,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":186,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":191,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":200,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":232,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":237,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":246,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":262,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":267,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":293,"s":[100]},{"t":295,"s":[0]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.521,99.321],[6.883,104.75]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[6.883,99.321],[-2.521,104.75]],"c":false},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[2.181,107.465],[2.181,96.606]],"c":false},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[14.479,99.321],[23.883,104.75]],"c":false},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[23.883,99.321],[14.479,104.75]],"c":false},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ind":5,"ty":"sh","ix":6,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.181,107.465],[19.181,96.606]],"c":false},"ix":2},"nm":"Path 6","mn":"ADBE Vector Shape - Group","hd":false},{"ind":6,"ty":"sh","ix":7,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[30.979,99.321],[40.383,104.75]],"c":false},"ix":2},"nm":"Path 7","mn":"ADBE Vector Shape - Group","hd":false},{"ind":7,"ty":"sh","ix":8,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[40.383,99.321],[30.979,104.75]],"c":false},"ix":2},"nm":"Path 8","mn":"ADBE Vector Shape - Group","hd":false},{"ind":8,"ty":"sh","ix":9,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[35.681,107.465],[35.681,96.606]],"c":false},"ix":2},"nm":"Path 9","mn":"ADBE Vector Shape - Group","hd":false},{"ind":9,"ty":"sh","ix":10,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[47.979,99.321],[57.383,104.75]],"c":false},"ix":2},"nm":"Path 10","mn":"ADBE Vector Shape - Group","hd":false},{"ind":10,"ty":"sh","ix":11,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[57.383,99.321],[47.979,104.75]],"c":false},"ix":2},"nm":"Path 11","mn":"ADBE Vector Shape - Group","hd":false},{"ind":11,"ty":"sh","ix":12,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[52.681,107.465],[52.681,96.606]],"c":false},"ix":2},"nm":"Path 12","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450990677,0.827450990677,0.827450990677,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 12","np":13,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.587,0],[0,0]],"o":[[0,0],[1.587,0]],"v":[[-19.753,127.51],[74.55,127.51]],"c":false},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[-1.587,0],[0,0]],"o":[[0,0],[0.412,0.115]],"v":[[-19.716,141.635],[27.75,141.519]],"c":false},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[-1.587,0],[0,0]],"o":[[0,0],[1.587,0]],"v":[[46.534,141.519],[74.588,141.635]],"c":false},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[-1.587,0],[0,0]],"o":[[0,0],[1.587,0]],"v":[[-19.716,155.635],[74.588,155.635]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":86,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":148,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":149,"s":[0]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":235,"s":[0]},{"t":297,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":86,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":148,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":149,"s":[0]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":235,"s":[100]},{"t":297,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":2,"ix":5,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[0.2901960784313726,0.39215686274509803,0.8,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6.5,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":6,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.587,0],[0,0]],"o":[[0,0],[1.587,0]],"v":[[-19.753,127.51],[74.55,127.51]],"c":false},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[-1.587,0],[0,0]],"o":[[0,0],[0.412,0.115]],"v":[[-19.716,141.635],[27.75,141.519]],"c":false},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[-1.587,0],[0,0]],"o":[[0,0],[1.587,0]],"v":[[46.534,141.519],[74.588,141.635]],"c":false},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[-1.587,0],[0,0]],"o":[[0,0],[1.587,0]],"v":[[-19.716,155.635],[74.588,155.635]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.831372618675,0.831372618675,0.831372618675,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6.5,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":5,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":301,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/src/Artemis.UI/Assets/Animations/success.json b/src/Artemis.UI/Assets/Animations/success.json new file mode 100644 index 000000000..f274c145e --- /dev/null +++ b/src/Artemis.UI/Assets/Animations/success.json @@ -0,0 +1 @@ +{"v":"5.0.1","fr":29.9700012207031,"ip":0,"op":45.0000018328876,"w":512,"h":512,"nm":"Comp 1","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.572],"y":[0.556]},"o":{"x":[0.167],"y":[0.167]},"n":["0p572_0p556_0p167_0p167"],"t":7,"s":[100],"e":[92.154]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.641],"y":[0.056]},"n":["0p833_0p833_0p641_0p056"],"t":13,"s":[92.154],"e":[30]},{"t":17.0000006924242}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256,256,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-230,4],[214,4]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.23137254902,0.741176470588,0.36862745098,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":70,"ix":5},"lc":2,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.588],"y":[-51709.363]},"o":{"x":[0.167],"y":[0.167]},"n":["0p588_-51709p363_0p167_0p167"],"t":7,"s":[0],"e":[0]},{"i":{"x":[0.696],"y":[0.999]},"o":{"x":[0.509],"y":[0.003]},"n":["0p696_0p999_0p509_0p003"],"t":10,"s":[0],"e":[100]},{"t":16.0000006516934}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.566],"y":[0.999]},"o":{"x":[0.457],"y":[0.063]},"n":["0p566_0p999_0p457_0p063"],"t":7,"s":[0],"e":[100]},{"t":16.0000006516934}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":150.000006109625,"st":0,"bm":0}]},{"id":"comp_1","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256,256,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0,0],"y":[0.997,0.997]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0_0p997_0p167_0p167","0_0p997_0p167_0p167"],"t":24,"s":[40,40],"e":[90,90]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.574,0.574],"y":[-0.004,-0.004]},"n":["0p833_0p833_0p574_-0p004","0p833_0p833_0p574_-0p004"],"t":27,"s":[90,90],"e":[18.394,18.394]},{"t":38.0000015477717}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":24,"s":[-181.074,-5.414],"e":[200,-5.414],"to":[34.0465698242188,0],"ti":[-26.72825050354,0]},{"t":38.0000015477717}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":24,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":25,"s":[100],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":29,"s":[100],"e":[0]},{"t":38.0000015477717}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150.000006109625,"st":0,"bm":0}]},{"id":"comp_2","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.572],"y":[0.556]},"o":{"x":[0.167],"y":[0.167]},"n":["0p572_0p556_0p167_0p167"],"t":10,"s":[100],"e":[92.154]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.641],"y":[0.056]},"n":["0p833_0p833_0p641_0p056"],"t":16,"s":[92.154],"e":[30]},{"t":20.0000008146167}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256,256,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-230,4],[214,4]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.23137254902,0.741176470588,0.36862745098,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":70,"ix":5},"lc":2,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.588],"y":[-51709.363]},"o":{"x":[0.167],"y":[0.167]},"n":["0p588_-51709p363_0p167_0p167"],"t":10,"s":[0],"e":[0]},{"i":{"x":[0.696],"y":[0.999]},"o":{"x":[0.509],"y":[0.003]},"n":["0p696_0p999_0p509_0p003"],"t":13,"s":[0],"e":[100]},{"t":19.0000007738859}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.566],"y":[0.999]},"o":{"x":[0.457],"y":[0.063]},"n":["0p566_0p999_0p457_0p063"],"t":10,"s":[0],"e":[100]},{"t":19.0000007738859}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":150.000006109625,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"trait","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[263.334,471.109,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":0,"k":[15,15,100],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":150.000006109625,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"trait","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-180,"ix":10},"p":{"a":0,"k":[51.641,253.275,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":0,"k":[15,15,100],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":150.000006109625,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"trait","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[266.322,44.315,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":0,"k":[15,15,100],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":150.000006109625,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"trait","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[469.91,258.792,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":0,"k":[15,15,100],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":150.000006109625,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"firefly","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-18.097,"ix":10},"p":{"a":0,"k":[400.635,189.708,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":0,"k":[20,20,100],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":150.000006109625,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":0,"nm":"firefly","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-72.471,"ix":10},"p":{"a":0,"k":[359.413,150.912,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":0,"k":[20,20,100],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":150.000006109625,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"firefly","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-45.707,"ix":10},"p":{"a":0,"k":[396.894,150.961,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":0,"k":[30,30,100],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":150.000006109625,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":0,"nm":"trait 2","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-135.205,"ix":10},"p":{"a":0,"k":[410.865,406.53,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":0,"k":[-19.512,19.512,100],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":150.000006109625,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":0,"nm":"trait 2","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-45.606,"ix":10},"p":{"a":0,"k":[105.535,402.598,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":0,"k":[-19.512,19.512,100],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":150.000006109625,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":0,"nm":"trait 2","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-135.205,"ix":10},"p":{"a":0,"k":[104.864,111.71,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":0,"k":[19.512,19.512,100],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":150.000006109625,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":0,"nm":"trait 2","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-45.606,"ix":10},"p":{"a":0,"k":[416.722,113.206,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":0,"k":[19.512,19.512,100],"ix":6}},"ao":0,"w":512,"h":512,"ip":0,"op":150.000006109625,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[236.888,240.258,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[69.59,69.59,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-76.426,37.999],[12.056,114.074],[169.991,-68.635]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":35,"ix":5},"lc":2,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-7,11],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[-2.986]},"o":{"x":[0.167],"y":[0]},"n":["0p833_-2p986_0p167_0"],"t":0,"s":[0],"e":[0]},{"i":{"x":[0],"y":[0.973]},"o":{"x":[0.167],"y":[0.042]},"n":["0_0p973_0p167_0p042"],"t":14.791,"s":[0],"e":[32]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.828],"y":[0.011]},"n":["0p833_0p833_0p828_0p011"],"t":19.791,"s":[32],"e":[100]},{"t":24.7912510097683}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":150.000006109625,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256,256,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[80,80,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.976,0.976],"y":[0.968,0.968]},"o":{"x":[0.654,0.654],"y":[0.007,0.007]},"n":["0p976_0p968_0p654_0p007","0p976_0p968_0p654_0p007"],"t":0,"s":[0,0],"e":[401.025,401.025]},{"i":{"x":[0.468,0.468],"y":[1.057,1.057]},"o":{"x":[0.346,0.346],"y":[-4.83,-4.83]},"n":["0p468_1p057_0p346_-4p83","0p468_1p057_0p346_-4p83"],"t":7,"s":[401.025,401.025],"e":[372.7,372.7]},{"i":{"x":[0.375,0.375],"y":[1.543,1.543]},"o":{"x":[0.364,0.364],"y":[0.031,0.031]},"n":["0p375_1p543_0p364_0p031","0p375_1p543_0p364_0p031"],"t":12,"s":[372.7,372.7],"e":[401.025,401.025]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.327,0.327],"y":[-8.038,-8.038]},"n":["0p833_1_0p327_-8p038","0p833_1_0p327_-8p038"],"t":16,"s":[401.025,401.025],"e":[401.025,401.025]},{"t":20.0000008146167}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.229886716955,0.739552696078,0.369435897528,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[5.992,3.49],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150.000006109625,"st":0,"bm":0}]} \ No newline at end of file diff --git a/src/Artemis.UI/Assets/Animations/workshop-wizard-welcome.json b/src/Artemis.UI/Assets/Animations/workshop-wizard-welcome.json new file mode 100644 index 000000000..02a22bcc3 --- /dev/null +++ b/src/Artemis.UI/Assets/Animations/workshop-wizard-welcome.json @@ -0,0 +1 @@ +{"v": "5.5.7", "meta": {"g": "LottieFiles AE 0.1.20", "a": "", "k": "", "d": "", "tc": ""}, "fr": 24, "ip": 0, "op": 36, "w": 1600, "h": 1200, "nm": "graphic", "ddd": 0, "assets": [{"id": "image_0", "w": 163, "h": 319, "u": "", "p": "data:image/png;base64,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", "e": 1}, {"id": "image_1", "w": 372, "h": 216, "u": "", "p": "data:image/png;base64,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", "e": 1}, {"id": "image_2", "w": 149, "h": 87, "u": "", "p": "data:image/png;base64,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", "e": 1}, {"id": "image_3", "w": 222, "h": 159, "u": "", "p": "data:image/png;base64,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", "e": 1}, {"id": "image_4", "w": 245, "h": 74, "u": "", "p": "data:image/png;base64,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", "e": 1}, {"id": "image_5", "w": 586, "h": 145, "u": "", "p": "data:image/png;base64,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", "e": 1}, {"id": "image_6", "w": 444, "h": 288, "u": "", "p": "data:image/png;base64,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", "e": 1}, {"id": "image_7", "w": 706, "h": 410, "u": "", "p": "data:image/png;base64,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", "e": 1}, {"id": "image_8", "w": 771, "h": 376, "u": "", "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAwMAAAF4CAYAAAAIWCUIAAAgAElEQVR4Xux9i5LcuI7l7s7///LMRva0+tJonBdIZWXa2oiNcYkgSIHEeajs2//3/zz/790V+L83LXgi74kcN73eOO3/jGf+Z+KJHN027sp74JWfFE8Fngo8FXgq8FTgqcCfUIHfUfx96rndWeud3Dtzr1qfyKHO7YRw3s2xOx+94115VU2f8acCTwWeCjwVeCrwVOAPr8A7RNwfXuK/Xv+OOu/knM6dzrvzDkyF9HTe61125rJa3JX3zvo/uZ8KPBV4KvBU4KnAU4EvrsAnirsvLue/tn5Hfac5J/Mmc376/CaCejLnLlMw3ctP1/1Z/6nAU4GnAk8Fngo8FfjCCnyj2PuGMt9R12nOZF4S253D7vwu5644Tuen8Y8p+IaOfPb4VOCpwFOBpwJPBZ4KtBW4Q7z96aU+XdNJvmROEvs62zT+zvuQCvckPom93nEyR9XnjpxqzWf8qcBTgacCTwWeCjwV+EMq8EnC7ptLfrqOk3zuHDduV/gn69Sz3xXA7nw3bvL1P8nt3P3T+Zw1n5inAk8Fngo8FXgq8FTgN6/AjmD7zUtjvd7p+k3yuXOcOCdmLUwabxXVCEqEsRt7Ou6u3xa4+zTK+IQ8FXgq8FTgqcBTgacCf3oFfkrM/Q51P127JJ8b68Q5Mbu/JUAG4pSwdfM4cU7M85uC36GDn3d4KvBU4KnAU4GnAk8FPurvf3/Lcbji2X2fJJ8bq+LU+ET8OzndmnRxrkh3hbrKp8anX/7dvE6tTuZy1ntingo8FXgq8FTgqcBTgd+sAncLuN+sXEfNU1J7J/ZEzIkcEyMxFf+uGFZxu+OuAZkaCNVHav9q/jP+VOCpwFOBpwJPBZ4K/KEVcMTfH1qaX177ZJ2SXG4si1M5puNq3p33BolfJYrvHn9MwZ2n/uR+KvBU4KnAU4GnAk8FjlfgJwXd8Ze5IeHJ+qS5VPzO+MQ8qPVq+dP4Ol8J9zV+Yg5YfrW2Gn9MwQ3N+KR8KvBU4KnAU4GnAk8FzldgV7Cd39FnZDxdlySfip0I+VdV03lqHyrnnSepxHg3PhX/03nX+6u9OqZmUstk3Un+Z85TgacCTwWeCjwVeCrwG1TAEXy/wWtGr3CyJkkuFTsdR/O656lh6Aqr9pkchitoVVwdnwj8yZzHECSn/cQ+FXgq8FTgqcBTgacCb6/ASeH29s0fXvBkLZJcKnY67poAN24tt9rT4aNp003EefIbg9N/9ej1Esq0PL8leMfNedZ4KvBU4KnAU4GnAk8F/qnAJ4i6TziOk3Vwc6m4yVd6V9i7cdfZqL2+4pyYnbNWQjo1B+5vCx5TsHNqz9ynAk8Fngo8FXgq8FTgoytwt4D76Jc/LGCTWqrYE2K95kj+WlC6fmIa0jtxtwm49rOuc+I3COo3Aeq97votgdpXej5P/FOBpwJPBZ4KPBV4KvDFFVCi9ItfDW795DsnuVRsKsAdce/EsK/66Z5q0dU7d4fkiuTd3wR0JuAuY6DeSY3fZQySdX9HLHje6anAU4GnAk8Fngr88RWYiLVvLtrJ901yTf7KDxLpSuCr8ev83LiJWbjzjqR/bcf9yq/i1DgzF87YKyYR50msOo+TudRaz/hTgacCTwWeCjwVeCrwQRVIBO0HbTveysn3THJ9gwlwTYHz3k5MfHhCJCfmwBH0KkaNO8JfiW817qyR1tldM837xD8VeCrwVOCpwFOBpwIfXIG7xNunvPLp93Pzqbjkr984Yl39+4BJjp3fCKj3d+6HEqc7JsAR9CpGjSvBPn2/rnYql1Nvtd8kxxP7VOCpwFOBpwJPBZ4KfEkFToi2T33Vk+/m5lJxJ03AROAr04AMQLJvdB9YbRIxm5iA115q/O7PNedjCj4VAZ59PRV4KvBU4KnAU4GnArICSrzKBB8YcPKdklwqNhHUTLTfYQKmJuE6fvXup65JYgRS0T8R+esaaj315Z0ZosQsdQZoWv903ek6z7ynAk8Fngo8FXgq8FTghyrwLhH3rtc79T5JHhW7YwLWL/W7JkAJfic/+s3B3aZgxwTs/nbA+fJ/xTixSqyfMgUnhfzJXO/CgmedpwJPBZ4KPBV4KvBUwKiAErJGio8IOfkebi4Vd8oEdAI8+c1BEuuspQyBM+5emlQYO2KcfcFXX/fduc4+3mEKTov40/nce/DEPRV4KvBU4HepgNIOJ97zweoTVfyDcrzjUt5ZzpP7T3Kx2MQEKPGdfM1PRH+SF4l7VS81zu6FArKJ2E6EfhJbRT37q0PIACS/+Vjrpup0xbpxbq+ezueu+8Q9FXgq8FTgGyqww393v9+D33dX+Avzf/KFVeU8uXc3l4pLjMBd4n3Ne9ca19lM64HO1gGpdxqBxBS4vzVgAn1iCpya3WEKknVVLz/jTwWeCjwV+OYKKC789Hd78PzTT+jm/X3jBT65ZzeXitsxAeuX950v9sgE/LQhQL9ZqFfbAaOJEWBf7t2v+neZAvd90G8UJr8lcHIlsOOcW5LviX0q8FTgqcAnV0DpgU/eu7u3B9fdSv0mcd90qU/uNcl16q8EnRLljuh310rMR2J43N8cdG2kQMgR0O5X+kkc+mtApwyDEviT+kzqnECc2lOS64l9KvBU4KnAp1Ug0Qyftvfd/Tz4vlvBL5j/DRf85B7dXCouEcauMH9dl8lf8UnNwWSNujck9lXdJi2xK/7rl3BHzDsxbt4at/6sDMRVr+evD01uzjPnqcBTgacCeQXu4LF8F5894zEIn30+8e4+/dKf2p+bR8W9wwQwU3BK+Dt5EnOyXjxVw/SSOkL45Bd+JNYdg+DugxmJzjygZ+y5MhL1HE6D++l86b154p8KPBV4KuBW4DRvuev+DnEP1v8Gp/ipDXBqX0keFduNu+bgipv+tRxHvN8Zs/Puu23i/GYACXjnORLmqfh34jvxjuadNAUJWCex6mxP5lJrPeNPBZ4KPBVIK6B4P833p8c/mP+lN+DTGuHkfpJcLNYV/K8rcPqvBJ0Q+CdyqHdbr39Sd6dtHDOAvsg7Al3FqHFkJthzZgqc90VGgT1XY/UsToL6yVzOnXlingo8FXgqgCpwmqOeSv+7Ag/mf9mt+KSmOLkXN9ddJmAVz7u/DUjE/G7s1Mx8qhlYBXAn6hOhn8SeMAjOvydw/gpVB0kuULtxDuydzOWs98Q8FXgq8FTgTm46XV1Xt6zrfgOufsMeT5/l1+WbXL7TL3lyD26uiQlYBT4DGEeQ11xqjhpH5qOb5z5je0S1YM+n98b5Uu78VZsrJhH1Jw2EaxBYXB27avqYgunteuY9FXgq8LtXwNUFd9bhJ/fwKWL8U/Zx5zl/be6fvKAnhWPyHhMj0M2ZfkVPhP2dIn+6j+uyozomZ+E0zmkzsApqZhCUadgd74Q9+20AMzw7piAB6CRWne3JXGqtZ/ypwFOBP6sCp3koqd5Pru3u8yfx9yfXduvzx8X91KU9ua6bS8U5gr8TwkhUV7MzFd/JvCuWff1nMe6ekZFTNV7r5wLCjhlwBTv7DYCbozMZVfCrXEjUd6alMxPMFKh6q/EVHJNYBaonc6m1nvGnAk8Ffu8KuBx0sgo/sebJ/TMuOb3OXTxy5z7/iNw/cYlPrenmUXHJF2702wD2WwJXYDtCHuVy5taYxGR04j8xT52JYsK1Nh/7Yj4R3Og3AidMgSP4HXHv/pYAAfnkrw4lwjyJVWB6Mpda6xl/KvBU4PergOL5k2/8zrVO7jvJ9U5MfudaSQ3+qNh3XupTa7l5VNwJE6BE8lRwsy/765oTE+DOZyZGvXfXROw8FBicNANM8F/CGpkFZDycnNX8OKahE/rISLDY7jxYzdV5rPmSWAWuJ3OptZ7xpwJPBb6/AornT73hu9Y5td+Ted6Jy+9c62SNvj7Xuy74qXXcPCxuxwR0Qvq6BEj4ozmp4Fd5VmOQ5p6alrUBJjVPRKX7pVyJbFe4v+LS3xQwE7GKdbVHJezR/G4eesaeV+OigO40gJ/Op/b/jD8VeCrwXRVwtcDOW929xl3578TPO3OnvLNzts/cUoG7LqMrEpMDcfc6EaV1DvsrMCwWjSmxfUK8v3LU3xSwvO6aqwmpf+5+7sxRcs6JeE1EdWICOuFehX7Np/birl/f3xX+6rcnSV3rebkE4MY59+FkLme9J+apwFOB76iAqwWmb3M6/+l80/c6jamn8015Z1qPZ95Sgbsu6am8bp4TBgAJ2yqwO7GrxP6aW8V26yGRnz7v9jE1Ba4xcM8QidUOcJTwRoKafblHYh+JfscMqH26v0noaoPEv2MKklqvgJmAfxKrQPlkLrXWM/5U4KnA51Ug4ZF09ydyn8iR7vtU/Cl8PZWne687c5+q41fnueMCn8rp5rnLCCjRrsSwI+qVSUjF/uQ3A1MzgOrTmaWkSVjTT8Wz+qq/iuOpKXCMRreOeoaMjTIIjilAtVbAq8av83bjnPtxMpez3hPzVOCpwM9XwNUB6U5P5D2RA+1b5b4TD3dz785nZ3ln7vQO/Vbx6sKlL3sin5tDxXXjzjMmclODMDUEp0wAE/qOcVBmpTNEu2agE7mduOzEtxLWjmBXZkD9piBZQ+3XGWemoANO9xk7BzVWceMkgJ/MleLbE/9U4KnAeyqg+H26i528O3NP8OLknXfx8qfnd++8u6dJHX/7OScu98lL7uxHxTiCv9uzawJSgeyIble0pyah26vKUQX+Kz6pDTMISUM5orUK8ypSlbDvxLaaszvO1lT7R+PMLDGzsJ6H8xuZHWA+DeCn8yV384l9KvBU4J4KKH6frjrN++550/dL5k2xczqv46Bkvyh2Zz8n1v+tckwv+lqEd+Zga6Exxxx0X/A7UctEeyeiq+lwflPQiXXXUEzzo72zfPXd0M87DaMMQWcGEoGfxDomIPmtQGpkmBGodVJ16cwDe+aAuQvMbpx7b07nc9d94p4KPBU4W4ETWqLuaJoznZfGn63cXrYJhk7mODwyeZPpXiZr/bZzdi/w7vxOcKNip0bAMQHr+jUefQ1Xz52v/N26zATcFe/kdUzOembqTqzjThNPhG4VwxOR7oh/ZCbQ3Cv+LiOATEC3z/XMlOlSscpIdD3tnL0LvCdzuWs+cU8FngqcqYDijMkqk5zpnDQ+4cnJO7s4rXIneJrEntrf3Xyi6vNbjv/kZXbXTk0AMhgTsY+E8AlDoEwD+m0Ae65yIvGvfgPQjXd1npzVKlRRk6WGAIltJsLvEP9uTiTWlanoRHhaKybkEdArAlDjd5BCsuZvCebPSz0V+LIKuBogea1JzmROEou0SPI+p2NTnEzik1jGOzvvPNnDznq/zdz0Yl8vPp2XOuOJuGSiH4l7JWyZyO4ENhLdtX7stwETM8DWTdZKTRADveSuuOITfQG/S+xXsa5+8+CaAEfss99qVCPl1IXNQcbMPZcKjC4wu3EO8J7M5az3xDwVeCqQVyDhBSd7mi+Jd2PduN33OYlxSS431o1b6zCZw+p4Op9zZl8dM7m8kzk/YQKYwJ/8luCkIXCEvhODxD+ae8Wr3MrgKPNUTU/SJI7wdESvEuSX8FVx63gSmxqIGo9E++Tdr/rX2qJcjylIbuwT+1TgqYBbgV39UNdJ87nxp+NSDeTW86QgdgW0G4d45OSeVZ2Svapcv/W4e+E78TcpjLNe+tuALt4V+/W9OsGvhDEzCUp0s/G75zr7Vu/ORL9z1ugOdQ3sCln0JV391sAR+k4ME/Wv+W4O1xx0cchIKFPAaryelXM+9WwTUE5iFQ6dzKXWesafCjwV6CuwwwddxjSfG+/EOTGnNNPp+5TgoRN7Kkbxy04dnD3u5P8t5r7zUjtr3WkEXIPgGoL0NwWduE8EvxPrxFwgVWOV8Ed1QaDnnDdrIiU41RdyJf6R2GZi3RXyneiv6yW5mLhH5qcT/u5vAhxTgACWAW8CykmsAuOTudRaz/hTgacCv1ZglwvWbGkuJ/6dMTvv4tyrCdY5c1SMGq8cdte7pJrC2ccfEXOqCVixdtfo5jvPOrFbhasS/q5Adr6yr/txRLsTg4T9a64zPzU0rH7XHVDnXccViDBhqgwBEvzqeSfmT5mEa+0TZoAZHsdA7BiGbu6KA48p+CMo5HnJpwKwAooL0tIl+ZxYFbM7XvkSva9ax61TyqVdXpVDifrd+dM9uTVS+0/y/Fax6hKq8ccE/G8FXDPgCPSpwE/NRmd0XHPgmAIXCOsdcr4432UCqknoBPspUzA1A64BSGrUAaT7W4QdU5AAs0MyLjifzOWu+cQ9FfhTKrCjG2qNklxOrIph49O5at477sX044zCyrvHXX0wqaHa+yTn187Zufi/qxFwhD0T0p3gT0zAjhmYrLNrClxjMGkSV5BWYV1FZvqln5mCTzEDzBTsGAH3NzFIyDtmrrsLLjC7cc59O5nLWe+JeSrwO1fgpOhNcjmxU62jcnfjas51B9y45M4kmNbF3mEanD05MWsd0nhWw5O5krP6qFh0GXcuqTM3XbfGs587Mc8EaxXQnThOxT+KT8S6ayqmvxGYmh5UHxfg1nWdJkTiVAneOu6IZ2UaViPQmQJmFJjBSMY6o7P7rBP2Tt2RIUiNwnV3nPswiVWgm6yrcj3jTwX+tAo4nO/WJMnlxN5hApQe6d7V2atbo0mcwrjEGNxhGCa4rt4pqdPJXMm6HxO742qnFz4xAs7+OjF/h/hPDQET/o4pUGZAjav97pqgWuPu53pH0Nkn4MJEvRLFu2L9hBnY3UM1DhVEa34Vj2qmDAIyC+uZo3NVwKvGnTVSkE3WTHM/8U8FftcKnBK5aR4Vf9oEJAZA7c3hyp374mJZgs9JrBL2zv6cGLXOpIbJupP8HzsnueDqJXYaIBH91z6mvwFARsERx1MRj4R5ahjUbwGc/V17QbHKRKz3ILk/7H4kZsAV/J0IPiXEkSlg+adj13s4It+JUfXrANb9LUFnINAz9lyNVSw6CeAncynMfMafCnxrBRy+d98tyaViJybA/UDpxtX3Vnvu6qTmTHAq5dkEz0/lnmL7pB7sfp7O5/bCj8UhQZ1uSF3ctEGVyOyEOxL5nbh1DUFXHyXI7xD+q4DvRLxjApyY69xfsezd1zhmDlBcd78SMOl+O7Ar/uv8VLy/4idz3H0rI8PydGPqWUcEqu7XuXZnmZzvej9cUHbjXGw7nc9d94l7KvDJFVBcn+w9yaViU41RNQDisdQAqH2ydZPaObEKw9Kv/eijkIPXU/zveIi9u3pnp27O+6R5Pj7+hBlQl3+3mZAxYIahMwtK2NcmdcXzKpzZnHQMmY7UDCTvsdZAmYHuXNOzdpuOgVAnUOszJaS7cWfOGvPTZgDtNxH9E7GP5iAQTwmIGYwOYB8y+HjaeTb4hRVQPJ++kptPxZ0yAUxPXO824Te1/5PmwMG+FH+deCfGwXG1fzXu6on0ribrprk/Jr4Tzcnm1EVPGlWJS2Rc1HN3HInmTiBfBiAR2hMz4Ap/N469SwW81AxMgLLeNRdUHNE6FfiXiJ2YATb3HfvphH9dt4p0dxzN60D+p74gPWSQoPcT+1TAq4DieS/L/0YluRL9sO4h4SJlAnZyOXtyanftYSpK06/yLg8rTmAGIN3TFNunNevO5WQu59zfGnOJ2smiqql3m0iJ0QosKl6JfTY/Fdun4tc8EzOBxP/1XNXEqXE1EfUuqXviNDkTl8oY3CnC628GqhhPxtlcJPIdw1IBuauX+ywR/o4hqGTCyMO5J3cD+G9NBhMSeOb81hVIsFsVIsmlYhNtgQxIx/dKvHfrpntB+1H1S8cVVnXj7rMOtxXeJwbjNA+oWiS1PZkrWff22KkZONmsrjNHzauepyJfCWglpJGAd8X8yfnoXdheqrhX9f1GM5CIa0dwv2JYHBpXc9A+J8ahAjj7jYAyWChXYhYcca+AV427pJIArbtmkvOJfSrwaRVQHJ/s182l4lLhrcS7GneMxAn+U+/t1trBJlfwn4pTJkFh9PSdupo5uU7W2s31EXETM6AubtKw7zICVfy6gr/GIaHuiG5lBlTubr6aw/bPatCNVWBUZ6dAMmlWBihKuDpi3hHXrnDv4hIz4K6jjEJXF8cAqHoyI+CeU82xSwguyLtxDjifzOWs98Q8FXhHBRS/J3tIcrHYdEyJfDXemQBnDjIP7HlXT6duCf6wWEesT2IYTyD8nzxX3JHojORuT9ad5H/bnNQMqEvqGgHVWEy8M1GKBDcTvkykX/OUEK/5VbwS8eu5qFyn9shqxGp+CgBVc7lC0xHBruB24y4QW+PV3CR2BUlkLFRMHe9+Vs/QeAL8U2JhRKHGKqAmRKrA+GQutdYz/lTgrgoobk/XdfOpOFdTIB7qtMT1LuqDlhrv1kyNS62rqsca72IPiuueK3xW4x0Wow9MjPOTPZ+sSXrPU+6Z5H/LnMQMqEuqBH7agGs+9edu3BH5azO7ovua48Yj4e8YglNrqffsxtUzdJ7quXuxU6CamIC1kavIVmI+nVvz/fffhejWcZ/VPVw/s72jORXUWD2d2JQUnPNm5OGM1bvnkqlzZ0/mctZ7Yp4KnKiA4vVkjSTXRDRPNMauoJ/MX7mz1s+tEYtLsCYR1Uronxx38Z6963Ts4YGmq10zoC7wpEm7hulcPBP6TLCmBsEV97sC3V0nMQvrnk6YoCroFSC65+8SiwNgDJhcMeyIaVeYr3HJnCTW2S8zKUjEo3p166lnnShHZ7VLCA8ZuB31xD0V+LUCitOTeiW5JiYAiWvGSylnnY4/YQiSM3AF7hRzu49DHdZXjlE/T/ezvu8JHkgMljqXk7nUWsfGHTOgGh2NT5urE/FM9DuGIBHILHYq0JVYRwbBNQ6v/P/v71uRvGtXO1X/DuTUWU8vrCP4kcBFwtkRxEqgT8avdZFpmJoJ5z1fuV2DhEDfMQzOWSRm4QTgu8Dsxjl3+WQuZ70n5qlAUgHF6XfkUmu6OkLxj/owpbgK8Z9atxtHz676qpok5+BgpSO805hTJoFx/fTdnHm1xiex+2Su6V2w5+2aAbeB3QZUQrQKXSZmJ6J4rYcyBWr82lvN6Qp8tJfEOEzq082poMYAUwGgezlRI1VR6ghQR8gqMb6KeWUGOuHfPXOMgZq3vr/7DmhO95zFOrVnMcnYdW/UvUD3ywVmN865xydzOes9MU8FWAVOik83l4pzNQTilU4TXDWYCvvpPLXH7mxUfZIbnX4hVwLc/RhXcTzF9cRQ7PBAgsdJrDqjk7nUWuNxZQbURVUuvGsOJfjrHCS617iJ8L/mKwOgxLszvsY48eve6nuiXDs1QDVnNe4Ad72I6u6wS+sKPtcYnDYDF9gp8a1MAxqfzFsB+DUfvfM61r1HBVtWYwTi3fOEeBg5PGQwhvtn4h9agR0sriVLcrHYxAQkOiKJrXtwTQCb91OG4FOMwLsMRGdAFDe44+udPyXkT+W5DcKYGVBNf7cR6Bqz+wrARLAjkJVQ74S5mlMNRiLgndxqTztGSZkxBba7hiA1AhPxqgSuI6Sr4FYCfmIgkNlg+0MC391fNRVJfdXcDsAReSjzwIBdAa8av4MMGHndBvBP4j++AorH3QIleVSsox2ufU0FO+IxxV/faAh2jUDFJoW9yUegBPMR1yg8djWDyoN6IeEL1U8nc6m1ovGpGXCb2WksJvodUYtidoxANzcV9E58ss71ntVorM+deqG6sLkMWBForxdRkYMSSl0DKUBiX6cdMd0J22oArhj2nOVxBbpjPNa9oDWTd3JyIBJRZ5OQjyImdndSkvyjySBijif40yvgYK77DkkuFovGUj3BDALjKtdYOLplyomT+rBzmmAcw1SFt92HNIbniAs63HZ4A+H9pA5Kd6x1Py3iT+dzexnGITMwubCTBt01Ao7g78SyEuFqTir0nfjpmt28FajcGnVz0LMKhNcFc0njFec2gzICDhDtiP8qilGuyf9U6LvMgPP+KoaZg25MPVNkgOZfd02Rlgvk7j1MiMMB5mRdJ98T81QA4fK0Mi6eq3VPmYC6jivuXR5DJmBiDlhNlFaanpeDiSrGFe+OcHdiGH8nY4gX1HN3PI1zzvCjOOCUGVCXOxX9XfO6ohYJ7ysnMgJTg+AIfSem2996PpP3cupY12WAq85ZkYLTIErEuV81KhB1wKQEsCvWL9B6xbtz0li1xjre/XkFVvbeaU26vAjEd8lBEVldV92lZPwOMmD7TXvlif+zK5AId6dSbr7Jh0PEExNx3+Vy9cZVBxW/w4nMSHTrO2fTxSBhqTDzJCY7uZyYDhddk6JwmgnwRJwnsepMT+ZSa8Hxzgykza0Eomq0KsLXxpsYgGv+VPQrU1BFuSP0p6I+mcfeu4JOt2cX8NR5nwC4u4AtFbqusFdCXOVJxtfYZJ4yA7u1UabAIQEX8BXBfZsp+AgyGLPIM/GnK+AKd2efbi4Vh8a753eagE5P3GUgGIciA8SeO+c1Eb8V67scO3h9ai4zBQ4HIB5QeKvG13NJYtl5nsqT3JlfYqsZ+B2NABLUnXh2xPdVo+5/158ZA2Uy1v2gPBXYTpglByyVAUjvDbqwiWtnYNCBEXvmCOFpzGveRLQj0X/aDLD36kije59dI+CeJVonFf8KeNX4HWTA3mEM8M/E37oCSpAnL5/kUrGO4L/2hrgl4Zw1Vv1ZjTNBr+aqPSPhr+rpnCPCLCWaEcYjjFPxp4zAn/hhKOEd505EMXeaga5x0meJ2GVCvBP+O2agmgYl3ll8YgJYPVStUA0eM5D/B7kSQX6JvDpHGQQ0rwriqdno8nRie83f7amKWEYWCVG4JNaJ6A5U3WdToX8KyE/liYjgCf66CpwQkEiQo2KoNV0TwESzEtRKkCMxn8w7HYtMAHs+vZAOzjkfXxRWq/GOSxBXTJ5f9en4puME9Iw9r2uoMzmF3afyqP3+Ml5FagICbkNXkarE51Tw1nnqy61RPwMAACAASURBVP21D1fYd3GOAUnXQfFd3ZQJUXMqGSAQRAC73hdFFNHFLMEpwCmg6saVwO/AzZ2D4tR8Z961L8dsdLHsGXpnR/CrGndAy/IiYEZkcJIQEnBOYlVPnMyl1nrGP78CJzE2ycVi0VhqDCYm4LRod7SKs+YJvmQ1V7jwTr6sOKsw3B1HeVMecGrhin5VdzePizTuem4+GncJ3LTZXSMwFaOdIUhNQn03R7grY1BzODm/yQwwEHPBvebYuaioGZwvG7UxmTitorcClvMzi+nGXs+mZkCJ+prbeT/nHV3joIwTMwLd3E7YozvA7oYD1gyAXXB249zeOJ3PXfeJ+4wKJMLd2bGbT8XtGIFdUd3NVzkn48wgdPrmqj/7sOZwpKp9ilMuZ3Y8uYPnLu8y8a/2pPik4w/0jD1XY2vvncTsk7kgPigz4ApAt8lYAzOxvwrq2oDIODBh3+Xr4lNzwPamcqm5HfAgM4JACtW4gpM6z3qhGHApUEsaSLl8RyA64JQI4wsgPskMrHtCRqQC/Ol37ghk8oyRhEsgJ8ngtyYER0k+MW+tQIKfamNuLhX3aSZA8R3jTsR9K187/FhrsmMGVP2vc3Y/lnWY5QhsxpWVLybYrvaAxl1OUHphUkc1p/bgKSF/Kg/EiNelu/46TRfkmAElHHcNwNWISPTXRq8GxxXhyAx066s13DmTd2PAVt/hOtPTJiAhA0VQatwFPOfLhws+p4SxaxDWOCTeJ6L+NWcyrwN2Nxeaq8giGf8mMkjMg+qF07mc9Z6Yn6mAKwid3SW5Jh92HJ3Q8VblpzWGjTFNUXM43Ffz7eRX79C913qGyVkxgcj4kOGn87GMYXw6hvaiuNrlgA4zXZPg4K0r0t041c+n8vxrHWYGnAZn7hc5a9SczvM1BpmDGoPmdHHJXDfvBQ6dgVjHKlhO69GBLgM3dYYMvCbEoS67akCnkRMgcb9+oC8hruCvIIkMwGkzcK3rGA4E5I45cmKus0e17NZ3iWsaV/fU3c+EdNn9PgXkp/I4vfjEvL8CiSBUu3NzqbjkA1CNRRwziau82PHd+qxyLIuf5u7WW8+FvSeLU2fLuFLx5B0ciTDYwfsd7EfvwjgB1Q5h6wkOOIXbp/L8cr/uMgNIyDKh6gj92thKvDPB7sxN5nd7U2vUeqgaoPop48DqXoEsBbbrQikycYANxbgNyr6GKPBDYraClCt6X3GuUUiE+jT2eg+0L2RCOpDucqz50RwF+MyYMWD/aTJgpFzv9EkgP5lrpz+fuWcqcBJD3Vwq7g4TwDjGMQ6paFd6xPlYpvblflTr+BY9c2/VhB8VH7pYrfiQcYG7hoP9jPvROgy3lZnqzsbFYzeOnf+JHL/kT8xA6uKTBuuaVT1TQluNXw34ilv///oc/fmKd2NVnDu+gkbdQx27DjoFzjoP/awATJGMArrUiZ8wAgy4Kni6Qh/lVOIbiX4171qPif4kR7J/N9YlgSlhdSDvGobrXroEW++xC9JunOoTRmjO3Cfm5yuwi5XrGyS5WGxiAioXTISxEttoDYffUEwyd8KvHUemdXVvpyNep3ha+cLhyYlJULyQjHc4/g4OcHHdjWPnfyLHP/mRGegubGIGmBG4GgS59Sriu/iJ0Ed5rlzr/xSpEvtqfF3LeZ8KNMoIdcCk6qnA9LoU7Jw7cEPPXBBz41xxdsIUdKCxK/4rkCGx38WpWCTuleif5L32p8AemREF6Ix41Nx1vCMDNL+bh+azWDYH3fOTgH4yl9uXT9xeBRLxzlZK8qhYh/8VXyQ84uiFup4j5BFPOnOdmC4/4llUL8WftY6sx5UhQNzI+E5hrsMDXQ6HYyvWutyA5lV8VvVSeO5qEta3JzD7RI6/voh3/4A4aWTUcKgpkDh2GrcT4UxsK9G+GgGV59pfZ0SYOVnnuSKfCXsl+l1gZWeszl8BmDOuKHQH9DrBhr4KpKCkBDYDPiS+ldGYiHYkxqfGob5XQgJubEoaDPTRebtEsd7PCegnAJ3E7vSNmvuMv68CSpAnO0lysVg05piDjnc6AYziXN46qTecXO6+nPfq1kPnrM7U5UdkAJTQdngxiVEcsIP9Dre7XNFpB/SMPVdjDr8kGLDNIZ0ZmDa+46RTkctEtiP01fxXsbvfCCTGwFnj2uvu+1dwnRiDKtRdEGcCXwFXcqlRbCLIUgB0gVGBnwK8qRm49pcK/HVeBdu6l9TknIi/zlrVrSMKdWY1dwfOdV0F0Mkd7NZXfbAN6MsCJ3OpfT/jfgVOYmWSa2ICOsxn+mD6gcnRDutenPiOG5mwV1zqro/4ldVmvT3JmU4MgRLOiuMUFjMs7/D2LuyffAxiukHhuXsWqb7xkeU//0YxmfNPrGMG1CVWTYQakDWrEuOOAK8i/2rS1UQ4RuDEXphxqSDj1sUFJyT2d02AAi01zi6sEjLduHqWGoQJcCVAiIzBRLR3ol/ld4yJK/gVoKu9dMJ+h7SQUVAGYYcMOrOhzEXXA+rup0B/Ol+6/hP/vxXYwcOuhm4+FYfGmei/9uNwCxLHSjSr3K7uOBWX8q2rm6ZGIBWnTOTvCHyEtQkXdus7/Kv2zXgAYb3SEQzndw2B4hAXS0eYX83AFABQw7EGqgL5ik3F9zqvMwnoWfIc7e16B7Zn9V61RihXV0tV3wS0FXgxQmOEo8hoveDTZlIiLjUCCmQS8YuAzhXa13xHvK+xbn4nr5ur22vy/m7dGXm4BMBAX92nKSEkYD8CdMAWJ3O5hPTE/acCCQaquiW5JricaAAVqwQ946/KNydEfbef3byV39G+Oy5mz9Q96MYVbrkfWBwhfpIDGZ4ne5lg/0QbXLVHuDrVMSpvcidizFdmgAnE2lhpo3VNmBqBTtCvzVkNxyrep2bAMRwVIDrTUIFQ1aMDzgmYpmClAP80oDkgl4ixSbOnX1EQMF77TMV0Ou+EoHdydPtySIHFILB3SKAjEfWsuzvojihyZeCtwFiNr32QxCrCOJlLrfWnjyfCndUqyaNiXTyvPIH4h8UhrmFaIeW55OPZrvBPNE/Ks+v5qzNUonGH8xSeM27qsFflm44rnFfGp/LADgf8FqZgNQMKJJQxqI3GhCoTx44hcE1AIviRcbjeIzEW65zuz+kzVcsLHNgZpOCk7kNHAojQHHBLRIoj0lTMFCyYUUiAzYl1TYQj5FUulEMZgETon4hlhKMIghGAS6A1R0rMtUd27v1UbCdrTtf4k+c5eOfWx82l4tB4ivNKB1QumhgCZhbYRzPFk6fMAMrDOJbVrauZez8cIepgG/r44j53+Mw1CyiXwne014rRiPun/MA4gGGtg8NOjLorVg5mBtKmTxpNuflExLtivTMg6zPHYNS1OoPQCX31vmqOAlQGni44M0Dq8u8If3V5lcBC492ld4Cwy8dEPwM1BXgJaCqBfq112gx0eddnk32xnKhmjvFyz8IFenRfnLtV11jv+S4puD3h9hbba5Ljif1PBZQgT2qV5GKxOyZg5R1XD6A5iqOUfqh5VTwzDTtzu/dT74b4e70PyXnXe+RgExLATECf+HiT8F3KERPsV3XocLGrEcJPx5w55zeJQfjyVjNQmws1DBLFqHETU6Bi3X8s3Al8lbszGlcNnHeegNN18Kz2DIQYuNfcNU+9dDtAlhCkK6h2wLEDmNr4jkhVMSnQTuK7OejZNNbdV0IKKtYlAQX8aPwuQlAC3ALt5b9snfQOi3XXPbXe75bnNP65+VTcjhFAH4BcU+BoglRYIy5lee6a4+69406He9MeUZw3wUIX2xkeKyx3ecdZQ3E342SG+Yz/1bz1HCdGwZnv3hWK869L+RLJHWggMHAbT8V1ohsJ6E5sI9HOYqdj677WHI7Qr3NrXU4aAefMKjilZ39dPEVE6wV1Y11R4poCp1EVSE6MgANcr3UToEyBGeU/YQau91PvsK6VvOua363ldd/qOuj8nHN3zr6u64C3uudqnK3pEkMX5667s8bvNtfFNue9k1ws9lNNQKcJlE5A4xPeTOaoWLZvxrGKb517gmJq/7KfGU4irHZxX2F2wgWTfbqi3+EAVENV6057oGcJnu9iNJw/MQOd4FSNw0SzI6irAK9zHGPgxlyN7MSvscmfu9gKLrWmLpC6QKRAKSGUFZwSQnOAT11+1207wNg1ZQIYCkQRSDrgODEDK3h3f1bgjoyDmueuu1MPRTjsLJMz7QAczU8JgN1tde/X3kliVc+dzKXW+ubxkziX5LrLBCB+mfAJ465uHaUfJnzZ5VTrVM539spiau2cn3d7wuU5JpjV2MoLDncx7nFw/LVGsk7FftccVPxOeUJxhYPZDv46MewetfORGaiA0xkAp0FRo3RCu8tXTcAa44j1dX43F5kKllvtAb2Hej4FHgTi7hkysF8v1ISEdoGtzp+IJybc3OZ34ipYuSC3Alcq+BnIIiHvCPy6dwT+ihTUeEISymi5gO/GVUJhQM8IeJcAEuBPYlVvnsyl1vq28US8q3dzc6m45OPNCW7oNMGJZ1MR7+gRZgYco5BydOVWl2uvO9OdqerLd5iBlHcSnJ/EMq5Nxxyur9zg4H93bugs1Rl3XKRwRmopxwwwI+A0RxXcXdMqc+CYAiXs3Rwsz7p3tWfnPdP6dSBRQUwBjjrPemkSknEv5JrTufjyIpcA1XiqeZ0vAh3IuM/Srxyv+NQo3GUGVrBOjEW6fwTiae3cM3FJwCVbBNhTAnD7xI1zevVkLme9T49RgjzZv5tLxSX4fJcJ6HjMfXaXQHdNxSkT4PAqq7/Lu1WIdncO8RfCuIqpCHvrc4X/TvwJnFcfiibvPeEDVveUD1D8et67+PzL/Nfl/K/mNiUXe9rMnZhGQvwCliroTxoAlavbw/rM+fMu8LgAex0pOsc1T/1zN3e9Ioqc1HyHMJNLzmJ3TIEr+joAcJ6xGCX+L6BIBfYa7/yZrYP2uJvXeTeXrN5FAow4UhJQd1+NO2LB6cGTpJOu92nxLuY5+05ysdjEBDC8VwI1+diE+K3jrcpNCTc6scoMTHKw9+i4dmq+nHvE+jPlLsVFCm9dU5B8yHFinZhdDkACH9WY1T7lAhRf74fLCXTerhlwGqo2UGcCrhhkEFYTUGPR2PoPoycm4rVO979A1K2/Puv+XHM5oOIAa5enAj/7uSOUlGTWC5YQ3S7gJQ3xTlOgwEMBWAVeJK5PArRaQ4E9Gp/kvd5L1ckxTKpG1x1yz6wD5ykpdGszgnfHkr443YNpvk+PP4lnSS4Vu4PbnbhXnKGELht3xtY9JZqCxd5hBpgxYmO1vswkTHuCcZzCNwcnp3isOIDxnbuvjgvcuRWHVa1So9VxRvIMxZ7C+X/epzMDXfNeCyeNWoVqbXgEAK7w7/J1oj/Jx3Je71PXWJ93f67zal2Sn7tYBjQMdFxAmhDTFNCceY4LVuIfCSsEBLUhHQHY5aqA6gKWA8QOqDqi/cqjQDwdV4bC2T+ql1sfVu9ujJ07IwWU6zQJOL3gkonTe5U4kznfFqtwL3mfJBeLRWOOOXB43eWSqShOxbvixjTfxd07eVGNnJrUudcdSu4Hu3cpJjkc5WKrwwdOrpQnOr5KcZ7xcsoLdT8MM6c6Bd0Blw/q/L/mJWagAxPlvmvTTQyBK+avtV7x128FlGFY5zAj0cWtz5w/7xgpB6Rd4e8QhwNSpwAsIdX2EpMEqDlUE7ruPwUKBIYMvBTIorkMeKemYAU6F7Tr/t19OcRR3z2dk5xfR5zr/A700ZxuHnrGnquxtF/SXpyST7rOO+NP45qb73cxAZXz3Z8TfpzojskctnfnvRhv17HujqM7wfrONQQu56g4B3MRh7lckOC8s5+Kmwkvo7kqZ8cPKQ84eD/F5P/ZMQPVHLguXRmC6t6RSL+aiYn43bndGupZBQn0NQLVa81/XSD21SEBHGYY6loJOCGydomwm59e6gQgUWOyRp+Osa8OnVhMwcw1Cy7wvuKmQp+BdkII7vqIqNIaKiB3jAAj4VOmQJGB2zNuHOrr+vx0PnfdU3E7OLWDk2pdNO580Kn8vO4Tjann3Th75mqCypkdhzrPKnd2WmKylprTjSe87HAvuuuo91I8WnEf4SrDdweLFVepcWeNK2aHA+40B0h7dOfonu0RPJ6YgcTBo+ashmCNWwU8el5Ffo1zfzOw7gP9F4o788JAhr3bBFROGAGHPCp41QumiGsH0BxSdwXHaVOgmjQViifNgQN4aYwC5KmoPzEvIQOX0Na4bo56hubX5yyui0XP2HNENKmQcPqxi3F7dJr/9DwX09x1k3wsNjEBFbfvMAGMt05wWuVTlBNxa41H+U6Zk07XdPznnsUudyqOcjDK4YmKhc6ck3yyu/41v+PsxACc4HzFDwrLFdaq8X9hWjUD6stA2vhK9HdNVYW+Ev4qfmIuOrGPTAF7hw6k0hpWoHDOqFtjPfxKNhNiYvlc8pzEJZc8ddbu1xTVyAos3HEXoLo4B6grOL7mqFwnRX26XiWDbv+IMNzniDjVmTmE2wE8yrv2RnqPu/vJei3pKadnT+dz1kxiEtHu5E3yqdjECCAcV/iuOKQbT591wntXjCszkIx3vI342uVxxrvMGFSOd+6cwgeXyxTHMB45zTHKODC8P7XPitGqPi7u1zwdFyDcnuB/ygH/+jcDCiS6y64asGs6JrbZF/odYb9jKtZ3UKaAxar6ITCpILrGuX+ucQ4ATYkrBbNpvCs60mZygZQBgQMSnRBkz6bgu+4lEft1XhXvSa5prPPOp2IUEaAzdYxCB84uQSDicADf7REnV9qnydpp7km8wrM7c6q1T5iADuMTTnf5hxmD1AR0+gDxJNIa7ppuXLInxL/MkCVn7dzJrs9cDnPF7q7YVkK/jqfrpRxwgmd3+ABxBsLhVMMwzmjv1OtSrv+dARc4EBioZuuE9Np4E7HfzU//mtAar8Q+MxUdiLhmqYpzZgAcoGExyggo4upIxwGtu2Ic0cFiHDBl4p6NOULRMQUpeKXgeL2DAuEE1NecygygWLWftfbTd2Y5ujH1zL0PKA8D8gkpOP2x9mYa7/T1HTmdde/CKgcjFc6yvXX52TOHExDH1H043KNiLp7s1ux0Qsed677WfJ1OULFsvI45e0FzujN3uHjnnjr8pXjI5ZcpHie88YpN1zkZ3+F3za84wBH7ToyDywpb1fhfa5wyA25z7wjtKsInP69N7szv4p1nE+CZggsyZuslconFAaSEBF2yPhXnXPo7TUHNrQC4Ax31zAElBabXGq5A7+LRGiinu1bNewfIK9PQAT0jS3VmdZz9nBJ77Z30fqPec3pp0rd35a17uROn3NwqDo07eN3hfoffKk7xB+J2xldVuKPYLneiJdz5btwp3q7n8DuZgVPcgTD2wof//ruhE95ge6vrKQ7ozEvKC47Yd2JWbEP4uY37qRlgjeo0UmoGrnj1HxBzhH2NqaI+/QfEdf76s/ozA1J3jAGOAp+EhNaLqMhNiQN3/q5gcOYnTaUEmmsCOjC5auaIfAZGFVQ6MEuFNQPQ1Ax0QK2AXpma9B13CME5J3S+LuC7cXUvXd9tk0MhY9Xbk3GnT9O8LsakeSvesvlqDwn+Mix3x1zB33EP4yNXuKscVReg+GoyXJHv5kecfp21q3+6u4JM2Ql+Vfy04hL6M/vYkfKGwvWOCxA/THI5Ql9xi8O1KWcntWcY75x3xSeJte8yA6gZV4FeG5EJ/CRWGYUrl/qrRd2a6zMGJBXEFDhWMKkgVMEJgTgisI6MpgS2Q4oOIctLTJI4c3/CFCDRp5474OOCZwU7F0ARaCcA76xdwVq9l7N/tscE/LtY9cwh5I4A6v1MiEDdfzXOCMnp3UmMuyeEbZM11RyFjet8FrtjAlyMRwZhxxC4IjgV3Yg/ET/ebQac/Tvc3d1NZtw6Pld3UvUmww0m/BMcXDEX/dnlhYRXEBfcYVpczmB1c7AfcX+dy85dYScdX82A85UhAQVlAFYguGLdfzzcgUKdu/vbhLq/+j7dHtSXClU/BjQVYBS4I7L8JiNQAVFddgSgal5iCFRzKvGmBD8CDgbgdQzFpmD5TiCvYHqHGUjev9tPBeKUVLu745CAawDSe4zu8rSPXAHzLXGnTADCYhejO6zvBCSKY1yheERxlvrQlc5PONQR7ycMBOJe9G7duTpmgN2TrmcYr/2kGVDC3uUVx2zcYUIQ9lf+YAaAxSYcj8T/cax3zIADJKopOyHdiW0kuK+G7v7vlWcV//UfBE/yuuKfmZ71HZnQd0CFgUmd3xFFSkgohyLyhEBVLjauBH4KnkwYuY3nCDsEBF3TO+CTAFIihndB1gHyu0jBBfOuHqxGCYhPyKC7g+6dQqShnrvjaz9Nem+n1989N8EwFYvGnY8yd5gAxkMpRzlC3+FAh0O7PKnuqO/H9p9wMjon9/wYNzt3X32AYpzjcIyLiewDjou1Dm84MS63dHHJ+zr828UkXIIw2tUlFnb/pBlgAn1tfGYE0rFJ3jqny4FiHCB0ALiCBTNo18E7ZOOAkCK79aIlsQ7IOTETYaLmJE3WxboCDsUlz6dgngDeXUDuAjZaXxkWN78D6KpeLIdDxiwmGUPEoZ674xaxOI37gTEJfqnYxAQ4+I5wvfsQpMQpm4O45Q7h3/HjxemVF7v1p2bAeZc7zUB6N1SrnOCgjnMU5ileUPh8Yv7UGLB3U/ua8EU3B+G6qx/qfBebW31z0gy4LnsV8FVEVyBIxb4b3627+w+IJ2CFSGAH4E+aAUV4P20E3MvfgenUEKAGPAHIO6KxAkgK7g7wpyD5ip8SgruWswYzBXWsgrZTlwTUE6PX3bWEKI6SBVEkqpeUmPmE8ZNYt/MhpsP+yhOKN5JxxxgggZ4KdhZ/lwmoXF/3sI6jMfa8G6scXO+Dez/cvkD9V59XLKtYd62n4hJMrPjMsNgR9ogX0nVcM+DyUFdLxsGT2tfzQT8z3Idjn2oGquN3RX4St4LA5B8Pd3tUYOeAjQs8KeBMAMglSDfOBbfduFScqHgXbFGjuQJuRygicGMgpYQ6musC6Qr8ai0Fus64imFEpOrkEuAOKdT7g8g8iWOEsTvW9anqpd3ePjU/xSwVn3ztZVjMhCMaW593f2bPuo9YiIN2Y9H8+iGO8ejK292f1fjkHVxOVh/xKmevd1ndL3Xvu75L8UOZAIWRDF9Tsd7lco2A4oGEi1SsW5MubvIMYXaiUVqd8iebgbVxT5uBDnBcEHKBZ41jf54CUAJOSawCtZPjqTBR8UnDKXC+2yBMzYEjeidmIAH3aawiAUZWaGx9vkOWFYBZLhTbgbh7jxCJqOfueO1b1Usn+zzJlWKVimfjTNh3uIxEvYP1UxPA+Ob6uIZiGKe5HFjXSOZd+1Jz1nGXh9d9OZw8MXH13qq71t3zKSd1uLGDb0jsKyxXmK3EeF3XMR1OzIq16X/zYJ2r+LSLVc8QJivNQTH6TzYDK5CcNgMdSLkg5ADPeqh3fY1IgCmJTYj7VGwqTFh8Ar6deEONngg9JAAnBqADawVmCsDrfAToKo9DBLtkw/aK6qAAnhGtAnp1tooIXEJI7zFa1+nRtP+cnGlMilEqPjEBK6Zf+94R/jUf4wBmElIxj7hJiXHFh0qso/xq/yov41rF1/Wd0Jl0593dh3qf1f1TPVXHnY8GE/5QGM34xeEFlV+ZAcQxTt517wzzXT5I6qt4QmmL9T5ZeuZPNQNrI79qoP5nSGt8BZn6dUOBXwdCDJhQvPMcgdEJQGK5U7J+R7wCULeBUCNOG9QF7gTQFZg4AObEMLDvxlIQnpCJAnFlQrraraTjvLNbfxVX75RzB7p76JoEdreT/kD9nPTgLiYoQYXyq3lovHs+/WKMzIJ6PhX/jH8Qv9U5SnxPeTIxA2gPStxPx10Odu7G7n13+Ud9cKj4qPDQ4QmFuTvGgM3dyYv4613GIOUG9/xbHP9UM3A12AUeJ/8vyo3+ATGKr8/Xn9WfVwBRIHwdXEICNX+Xgz1zxtYLpcjzBMidzJEIEhWLxh3x5Qq72uQKzBWI1PldPiXaO6BMSCMFabbeKtRrXkVCzns4ZFffndUU1em648n5dgSQ3CtEIOx5SyaDBlW9NUj5f6ZY5MxLTECHwVVwIpxNsL7L6TxDAhvxkSOW32EGErGfvqPDxcxsIV5XfOrcPacXUs5RPFGx0cHKOzkg5YzKCyk3pOvt1AdxPDNmHV8g3GZY+9fYSTNw5VMNuAr7dY7zfNcUoPVY3jqny4FiWE2mwIMApwKK+yWCAZELUm6cA2jvikmEiIpNDEHXrK54q+so0eiOK7HbgZya4wBpJQ4G3gxomRlw987ex3lXJ6aCtwJ6d9whBXZ30Hz1fO1V1SNJXzu5TmKOynXKBFTsRljuPHdFaSriES+leVLRrnRDx6UXbyd7dt7D4WbnjLrzRs/Yc9U7Lv84/ME4w8W4Li555nDHJKbOmeQ4wSeV97qfWUzVEN35O3j/C77/pBlYm3vHCFx5fuo/OlbfA4GWAzAuwCMgegyBgs1/jzvCwxVFLijXZu7yO8Dd5XEFZAf6CdhPY5XoRgDdgfD6bEo2LK8zVkHbrYsL9oyc0b1Ed8cliOQe145K+inv1rMzpiYgEXlVfF5v0GF9HUMxXU4lciv/qHgktNm8agASgZ/EIs5N3hG9R8ffiG87Tu/uhvthrt5udD+dHlO9nuBKjXUx7gSWnxTsUzOwsweG813eLl49YzpgvVPs3vyPYwa6C58CCQOJFXTY/9b/ahi6fHVc/TuAGu/kryCUgp+qG6t1CkgTwkJUq0izI7iztH1/NgdgkfhyBZHj4GtjI9B24xToI2BXIJYQgiKFay0G1l0Mmlf3Xvfa/a9DKJOicjrvqGpa75d7dt29ZGJACYWOXFxScXvk/o7uV3CwjMW4wk4J+Q4zuzkqjxK1iFMUEZmCJAAAIABJREFUF1VuW7nPyZmYiZ1Y5z2cmPpOdU73zg4nK2507mPSKw7HOB8LOuxJMN/Byy7f3YL9lX8i7idzEN6rOnbzGHcgzHVw/p+5qxlwLnbSVA6YrAJ8BZuJUFdz0Pi17uR/UagDyATYEKg6Z4FiKrhMyKuCjwtYblwCbu+OPWUKqAtvXmoq3tx5DrgrwHEEbwVbhxSuGMcMoNjuuXqm3keRFauXqkMF8LqWSwhrXP0z+9kRDd389eq6veLG3dnrDjZ9owlwOKTj7RNcXteu3KfWRRqh49WqD1hMty+3TidNgMu9lcvTPki4JuULxRvuuMJahwOYIE/E+voxKDEfiA+ctRkXJbzL8N7BdHhXUjOw24C1+TvwqKL9tebuV/4uZ32W/APiCkyu8XEAicVU0FjBBv25AxpEeikZdqDlkG4Kdu+OT8SLikXjTuMmQq8DZRc4OpC7ao7GXHBPQHAKqmovStQj4a7yMhB3zEBS924t93yTuBpb70HXi6oH1jlJ7E7fpziUYiL76OKOKfx2x5Ww73hbzXE4rRPdyby7Yrt9OdyrajLh3/Re1Ttf57v94/BLwhkT0V8xi3FJitGJiF856JrHDEHHWRXP1frqfRR3IMxmnNFht3MP/rpzu2agAxnWiKkZWPNX8T75Oc1X49F8BbYKZNR4CkKMjC6w6UDqhBmoe90h9J+e6wIvElCOCHKbtYIAEmkJwHeAxEBKAVgK9owsFJhOjYMD9ChGvX83z53j1l2dGSIRRRT1HqK7z3oi6Rd0f6c9n4p/B6ccjHQ/wqQGoXJC5dWK44xDFL9cXNqtUce6XI6of8c8tP+On1Us4lxl0BC/7poCpy+Snt3liY6P1AcQlx8cbFdifMViFZsKfYdDUC3cGlR8rOeFzk/hPNQqUzPggEaNucsIrI2+GgT33x9c89lfE0JrdCCDgNUBZAZQCJzc5x35TQDKJV03zgG5n4xJBI6KTYWUMgouICTA38UyAOtAKwE8JfoR8KrnahytO9nPCrCKEGts3Wc3jubU2legd86dkU6Xf+3F9D7/ZB+va08+erhiXuFsJyZPPFNim/Gxw+cqv2MIOr6s3Kpi2LjzHoxjEUc7HJsax9oLu3w5NQIOZiSc0OEue+bGO4IeYb4z14mZ5p++P8JmZMQQXisd8de802YgaeTOHFRgWMX9+mc3rpufzO1i1bOuBrtGwPka4cQootolzApw3XpdzLc8U2J/fQ8VuwPeDMAdcE9jkLhf87giGs1x51fQRgBd10HzFBmpeWq+qlGdz+K7MfUsuSso13Wvkztbe1r1w10Y4IosR8xVPGMGAcUqnGbGQI0lPKPE/br/+oHL+eCFzIHiRzWvm8+esfe47pyqGzt3dJ4193q/3TtZ1629zHrG7VXng4FjBnZxfYrj9eOLEvXrOutc9e8IGO90ayreUOMK19e9d/cCnSvEctcM1IZyf0aAkxiBay31pX+NqyZgBQtkMJTZ6HLUZx3wuODW1VQ9m4KUS3wdGE1ALQE/BnCfMpYIm+nXU8fNs4afjDHQR2BfgcgV9R341zXcXJUQpsTSre+CtrvXhDQrcNc1FGGgcUUebF43FxIMaNikfyY97+INilP4ODEBCZZX3tzhWzR3YgYUl6FxtZZjLjpunbwbq6U7xngXcWZy1yZ3Pu3L2oOJKXDMgYubDPNVjgv3lSFY+aCLdcS8M0+twziv4w+Hc51zQ3fjlztQzQC75NUBo5+dxr/WQV8c1HN3nAn/ugcU6+x1jWHxLqijc0BfIdLnJwHLJV605hT4fnpeImhULBp3DEFtdBfk0TwHXFZgdAErATsWi0S3K8YRwaj5yHB0AJ+8KyOIrras3umZ7twdJj7UWNe7qkdQvyf4c+VIhBnC1g7PEhxWsR2PdvyB+EZxjeLpdf76IQ5xXV0vNQ7JfpB5QO+saslqhbhYnT/jO/fOoji3V3b5Q3FBxTnFBS6uO1i84qYyA67YRznVbw3qvNfPzj9QTrhD1bbDXHR+Fw4eMwOs+Z2mRIK+glsn0lnMa2z9+//rfDd391sINLcDRwTQCpTQOCOBjuAqiNS83Rz2jAGbmneNp3F13qf+7AJz16z1ne4yBa5BUODvAJKKcYSySxoKTFNSqXvvSAS9HzIZqh7dO7hzKqir81PjLUks/7vc6A6rHlDj7+htJsC6sbtMgMLyDqsZbzic4gptFJcIe8R9HU9O8jK+rbVVtXHPovIf4tc7eDXpDdZnyhikHNFhCTIHCocV7qrxzgww7L7i3ZhT+Sd8NeWCDqvpHXhd6v8qt019segayAWr2vwIDDoBz/6aUAUg93+KtM5zjEc3xwE6BUxqXAGXC1gKyCaAxuYgMHO/jiRg+FOxqdhJQRuJMCXOGMDXuY5QRCKdAVYFwA4QGdg7Y4hsFAkl40rsq3HnvVWMQwzoXJPzvfrIFQhr36leUOOnetjBl9QEuBiL4pjQ3+FVd24ivhk31/UcE+FwpJO3y+O+P4tTZ1bH1V3o4q+77dzNLjbtHWUAuj53ep4ZAQejqrjucC/F5k6wr3k74c9Efv2yv2MIEDe4nOHWtGI/4oIWrxMzsNtwO0agE+ldPhR3PV+BJM3Zza3PGJjVPUzqmQIWE/6OKUCgpcBMjU9Acb3An/rnBKxVLBp3nyPxxwDiXUSgwA2ZDodEEAFMCGeaK90/qgfLg87RJerpPVCE0wkM1q+qD9xe38Uc9BGswyoXV5n479ZTH4TYuDP328zAyq+KL533T/iT3Qf3/Ne7y+6ne3d3+sgxBilnMKypY0rcVwxUQrkT968c6V/pmRgCtPaVC+V8hylQBgByfGcGUMN0z9MGXAV41+iOaO9EeWcM1G8HUJ51D+5fF0Lvstas+3uXCuDuAK8E5Or6LrixeR2gnQBDVzS8Iy4ROCrWFf+dSEuAARGBeu6Kz12BnM53yMQlKMeEOOtVwrt+dkW/G4fOXZ1Vcl+uPmICoot5R//VNVwh1sW5wg/hqmMIXGPwDjPQrXHaRKg1EC9O3r9yc5fb4VmmixDfoXvn3kfVK4w7dnhDYf4EXyb4rfB5R5S7c1eBv+I1MxHVFLgmwMX3de3KIZ0OUBj91/iuGXDFLGp+BDLINKzPHeNQ41dgqGskfw3plafGV9Dp9tfFuDW8gIGRCwMsRGoOASKwY8/VWELYChQ/dVwJ/XXfE2DvGj8FAwYUihTccQRy6147cK3j6GdFGhUwO4DvYtC8bt/vNgP1nbvaTJ6p++PcOXXv1fiJfk4El4OBSuw72JsYAyXAK28wobzLTYyn2T4qB6pYlwtZbZwcXYxzfh2nMbO43mPnjp24911vucYg5YJd/HdEcoLLSKB3wj8V88wUrHusRqCO7XKRw4kVo20zsH5Bvy5jAnwOCKVgVJs9EfWdYXDnK4Oxvkcq9ln8CQBzzswFvA700DP2vLtPCvAYiau5nzieCB8V64L6RLApYL9qy0RoB1QOeLliHuVy53ekUHOqXM64inHWTN7VrbuKYyTS3SlHeKg7Xe/VpIddzFDCTQk2B2O7GPYMGYSVLxA/dNzL+Ljj1Zob5XTXctZQesDhQ2U0ENeheifap+M8dXcmXFjXcXuJ9VTaszV+iv8dv1RBfmEMMglonOE6E/ET86DyrXtkxsB5F5cDaq4Rjr8usDIDqKm6hp40MQMPR8Sv+2BGAMWx+d2YesbqUt9V1cshkS6HAiuH1Bh4IfJlpOwSdrf3iUD4tDkJkKvYu0wBAn4GLspEdMK4klUqnitIpvM7EmA5E3KqZNCBvrN/RAROPnReLpGnZFLj6/min+/u0R2BhjDSwVsHt1UME/V1Dy6vOEL9hBmY7kfxIePWyhuqfiiePVe8ijhTcZ8ad/ok5QyG9V0/K5zv8EphGBpPTQIS9RWLO9PgiPvXv0OYGge1hwlfOHVF5wGxGpmBtFFU4yFwYM874FrF/goM9SvBxBSg9dx1GFDV/TmgpsiiAo8j8B2CmwLeCliPKcDwrUB7ncli07EuvhOHu0TAgCoZQyZiIszrut9gBqbvf92fxITVM3eIH5IKuPrs/jlix41xDYCDczUXw2TEmZUb1zjGmyc4ta7V8WQXo+YlXDd9R+f9T3Ckc8a7d6W7uycMAOqJhBumpsDBCAfDECfcaQiYsFeGYTr39Z7JP27uOIvx5/RDzz98cZmB9LLXJnQal4GOMgvoHwOvoHTCECT5amwCkC4Ad8TByAQRkvucxXV35LpICNgU4KnxFeySWFc4/FRcYghWAOj2i3Ilzz/RFCREwmK7MfRMxSZGZBrLyFGNnSYLRPjdnUzFftoDSa+meDT5SKI+vjhCFfEew3jFlR0XMxOA4l2+TnhQcaT73k7clCdTDmR3Z5e/unuc9o1rDFT/JuI/wSEXuxGeduL9Wl8JdzVe81zx9f+yODTG9riOpbV0zqnF71NmwGlOB8RYzAVoNab72TEGFcTYnApinTnpgM55ZwaQTl27GAZoFfwvwHK/kNTcaL567o7vAuo6/xP/nIC7ip0YgKsmU+HngA/7aoHGurwVvCtQOgZiKtKn8xDod4Dv7H+HKCoJsHNBsS2RlMZK7uGdPZmYgtQQnDIDzoe0NMbhHWUCnHG2r9ToqPUqX6iaIA5Mz9nhu+Se3c1nE45g2O/iAMLryi8OxqVYy4xCZxY6UV9xeuWa668JvWLQf3/AWadbA/FDVyendg7Gdxj+1/+aUP2fvHTEYddoqjlVsysAc/5nPq99rcZhYhZqnu5ntZ+1Rp2R6cadZwrkFEmh+ercO8BznyFAnQIjAt87hcWduRWAr2ur2FSI1XjXFLjzHCOwglMKeMog1NyKaBxwdoGakdS6TvdnVZOkTilRTwRASzDlv15ce0jd5UnPpcJsRxx2c9mzVCAnfNDxHJuv9uKM320G6v7Zz92YetZxHrsPijtP89zk/l9zVG914xPsR3MY5jjYpXC6E98Mu6/4nb//n5iINbbuCxmHlBMQtyZn8s8dW81Ad5ErsDKh6YLgtY4DNmtsJ6ivZzXOnYfmM2BlRkO9m3rnbn4CiIkRcM9WAeAO+VawS0R+ErsDqu+cqwB83YuKTUzBTxDDKh5PEkeXFxkGRkp1zkkDgEA/JUn0rl1+t95r3OTPSoyoe3uy31xsussQMLGscL2bm4hvNV9xERpX8xiHOfVQMTV/V0fGWQ5HKi3U3SvGR1OuqvOmvcPm1bGJIUA4cRLXFf4i8b1iYSfmkTCv+M9+I1DXXn+TUNdE+0Gc4GK54o56Rv/6eccMKDBjTaoAhQHRrgFYwYQJe8cQvHI5/72BuiaqnaqLU1MEhA4IugbBBUOXjKsASMAziT0pNO7MlYB+AvTrnpUB6ETdhCjUV4qEMDpBi4R+jVVkwuITM1HJhYF5R0ToHXdIISEKdV6KVNx71d2v3Z5KBJmLdQmedhg7wfTKcSt/MO5QazkCv1truh+H59S7OTqD8eJ1pxD/ofN15nUx6x12ucmNQ/3h8gWKUz3rGgaG5QrXHGxn2JqMIVOgjMHuvBXDK6coMzPF/66uLfYqM1AbhTXOChhOAzsA0wlyZRRWcEmNgzIAaW4ErLU+67oKHLtYBYapEXCJ8jEFu/KFz3dBfm34LmNiGE4RQ92TSxQJaXQAqYQvIo26riPUlcFQazlrMBKYvCurLyIOxyB0dzARH6c7yf0QMRGJCIMR77mYnYj5da3uv26vOCVZy+Fqh9N268N0hdImiZZhua576t4vdK93DQDK63CG25eo7x1sV1jiYFeKrwxPp0L+9R7dXy1yf1PADMaK7Z05OIH97ln98m8G0CVnwpA1ZwUjBywcAHME/rXWFatE/hqXmg22Vh1zarDO6f7c1bzGsZh6zhMyVGDpmgQFrB2AIxBMY1meTxpzwP3ar4p1SaACSJe/5nIEYxJTiaAjF0UWaE5KREjUq/XVeCWDFPyd96g1YKaM1dwmFfDvBKZ30+lFJqwcLHIwsIthz5TYVtypuBBxSzKP8UvHs1P+Qu/qmiRWK8ZF6FxTTVPvoHOnunt7lwHo1lL95mC8wv0Jnp/A8U44M4zu4nf+IbAyFuyvCbnmoOMC9I4dNidn89c5vy7n9VXhOnjnorMmcwHSAZaTwjwxBA7QukajA1wGgrsk0gEnAkwHLB2irPmTu8RiV5BLgDSJdcTGJ8Q44N6Bt0sUE6PADEEHUC65OIJVkQoTyumYEvVoXM1bAV8BvZtL1aUjmXouiSlg58zuY3Kf0/5zOAxhYvrcFbRVXHc4rbCf8WHHM+qZMg7Jfhw+V+/sjCf8xs6y4yzGdYjj2HM1lt7raTzrtW5MPUuFJsJbhFUKnxnedmK74mwn5p2Ydd4rXon+uo5ao8Pmk7hPsbozA6pJ2DgCRtXkiThWon4FQPZ1oxtDAr/mZD+7Yw54KrBmdXXHUvJT90N9dbkADQl2JeTV+AqYSewUaN85LxFQKjYR/xVEKKiUL8OIOFiOlDwQqUzJps5TgHzCDCgiUHtQNUAGiwl/ZQqSe3D1ibqX3V3rekz1tosv0w8iiQlAWOzyHuKU9Xn3Z/VM8YsyAyy/w2+Mo7pzcZ91HMOE/qeYAHWnkx6qPZMaggTzE3PgYrvCO0f0r5jaxau/6rPOV7GdwajmwTUhEy5Q+I/uzj9n55qBtWmdRnOa1gFT90sIi3PNA/uHwEl+BNzVfDhAmpIFA1d3rJ61C6JsXnd/unvEnlVwc4GTrd2JjG945ggqlzgSU9DF7oj9SjiKVBLhWsHfAcsLrGtsQkyIgDqAV6A/yYXeU5GwGu/ukzqvtZcmYiTpRVf8p1xWMcnhLYa1SoAzXnA4JMmvxL4ar+854av6vl3t1DOXs+od+WkTkHAY64VTfKDwvcMWFxfQx4hdXHZMQReDxHvFXCXy1TjK93qODEbCC279kB6QZkABptN8zBA4gKpATYn8HQFfQXe61gp0DpArIlAkU2um4ivROeea3I0O7Nxn3ToVEBMwTWITEfKTsXeSAAKPFXwUEdTYul9HTE4MAAJIJHiRCehA2X2mzAgaT4wHe59aAxXL3kudMzOE3X1Bz071koMxjjBEYhFhuYO3itc6DlCinHFd3RPjMhXrvh/br5uDcRM7l/UOMbE/MQKMQ1x+ceOmveByAop7hyFwjYHCa8cIrLhWhftrLP2rPmuO6Xy1p7pGwhWI+xCfj8xAJ85UU07EqSOaEaAq0Y6AthP/ykw4AOzup9sXe8ZAm4GtO1bPujtHFMNAHAF1N0fFqjkdmN4NxFMA35nngv8KEmi9HYKo+V3hj+ZNjEIieFVsIuYrAFdzsSvwd8ggec+VMBwT1t0pdu6IkOp9VHfa6ePUELhcpnAZYWzHWQr3E+OQxK7ruvticZN3VhyTngfii3oPflcTsL6/6h/Vh1NDgHrfFf8VRztcRVi7awyqUaj5dkxDJ+679RycV7zUYTjjZssM1GZF4os1bTqmAE0Blyu+nTjnvx/QmYgO4Nl6Kl6RDzIlHUAj0EbAjHKweCcXAm50x1S8M68KDkdQ1Dmf/LNLABUYundKTEGXDwl5BkoOYDGDMCWcRCyzWEZG17slpkDNcUghiUFEzOqanOd6z5y7ymKc3r3LDExEccXRlMcQbjsfpBC/KK5N9jyNZXzk8Egi9H/CBDj39E5O2ekzZeoZFl/v5GKHi6sVoy5BvWIletbFKAOABPv0udpDHU84oMPi6IwuMYsu7Q6gVhByG1+BVAqkTj4GqkrwKzHezVd76gCcPUvB2DkbBMYuALtxF3A4d43FrqCagHASeydwn8ztkEAH2HUPu6aggjcShIx4FKBVIunWrDl2DYAzvyOljsw6wHfJsa7B8rO6OO/TkU29Q0pA1BzufUO9wXrXwRMkEJXgZ1ym+IlhtcMlp+artRK+mcRWLO/OQp1PxwcJ7yS6p/Lh5E6exPgkl+IDF+dP4DTiBPfDRYdVVZwjTEXif/cfBytzsO6HxSoucGvkcOC/+F+ZAdQAbsNVYHRAlIGdAzr1nZjQX/MpQ9CtzYyCm5u9kwvYTl0mtXcAu7sjCMRrLLtHK9g5xN6BYyL0k9gEiH8qVhHAui8V65LFCkIo/w6hVADrjEJiDqbg6ojnHTPQkUJCFGw+Iwr1XjVvPW9lBpJ7lPaNixEIc5gYdcaUgahcgfjE5YNkfre3k9zivLvDJY74d2IUz3SchZ6x54qj0jtca4TwdJKXYXzSl6jHOyxG+ODgdvKhYxXYK0ZVfF9/PmUAXuvV/yhZ9x8pU0ak7meC9w62Q8zuAKpetAnIui7fBREWh4DOMQEroDrxnfhXoLprGBg5rEDlkM0KNg7B1fwdWE3AWYG1e+ccoE5EfhI7AeSfmKOE/ronFXuCNDqC2zUIjgFwgDIhIJSvE9TIdCgzkuRS5OG+vxPHYq77pIzBSaHT4ZL7bIqDE+5yuKrD+4mYR3zg5t/hlo436jsgDnD4pOI0+1nFKg5RnKDGFeYn8xU+s7XU3Cm2d9iLBKdrAlJs7T68MCPQCfPJs2uf3b8ncP6NwYrZdX2F5x03pNj9C1Y7ZgA1i2qyTwNZB1DTGCb0HXOxArNjKhDIOsTkxFQCdQEcATt7rsbce8dIfwXHBHSTWAX2nzCuiGDdoxPbxbhk0hFCJyBTg4DypqCpQFgBrhL4KL8S/um+0n3U92LE3ZG9Ev9q/FSfOB8SGDd1GItw133u8ErNlfBBYjJWzun+vMMxrB5uXRUvILOQzHN4QXGAGmf3eWduh5Vu7zBsd/G7632F351hSHG5Cv4VD+80A6911i/9ncnofsugfvPQ7X81BArvJ/VDd+evXKuYrc1UL9gUZK88Soy6wKriKogqIF7r4AKw+4+LXeBle1Z16wwdeoYIJwVxBMgngLreMwSc6XN1v5377oLup8Y5Qt8lmyl5KOJwyWaNc41AN8cBVSdGgXdduyMVFtONsX29ywwo01DP071fOz2kMOQnzUDCRx1/KE5RHObmRJyg+Ejxc9UDFZdPcwvC/Ql/pByy3uETBqD2RILnTt+5H3mQsVc4zPA3xb4VbzszoMZX4Y3+vOZwvvQ7OZFxqXMVnyScxDj1n7FdM8AaGY2lQKzAR4GrAkc07syrohvtxcm1grSK/x0A3SWBjjzYMwewE2BOYncEzDvnJiSiYu8yBYhwGLApMkIAykgKfZFCc1IRzoisIwRFEu64+85dnHpmkQ+58OrOqR7verZic8UQJUInPIQwneF3N+ZwnIpZa1Z5yxnr6ufWpObv8FvVP5kz4Qx1p5zx7krfzR9Or6z7YvEuljtmQGEE+4igMLf7kIJw1xXfTIy/xtSX/sQIoP2vORSO324G1IVnIIsaMBX/HXC4oKNEtDPuguoFqGnOnfwMtE/VSAE3IwU0t96reo9cIkD3EwGuAmI1voJoEkt0zkcNJUQyIZEqCq+Xd4V+IipdI9CRlDIJDHhPjiES7NbYNR2qDoqs61myM1Xn6IqV2jysJxGmICxSGDTB12stJL5ZzmROErvuyeVa991ZPsYBHadMOcPRIck9UpoIAfq7+CLBcITHCJcdvO5whGGDwtorn4urjoB2xPdjBv7+q0JJc/xOhqADRiXWkfhngOwYhgqkndnoYnbBnYl7RQJTYu0A2zUICJxdYZDc9Z1YRBKf9jwhExWLxrvn6tnEMChD0BGXI3pd4V3zu4S2EqAS/h1ZTtZhtVhNSVqzTkCos1ZihPXMnXxU8Tb9eYr7DNMZ/zB+SMZcTnHqgTjCfZ7EpdygBLsa/xR+ULi87nPyUcc1+ifx18U01wzsGoI/7q8JdSLNvfBMzCWisftCo0RpMr4Lpu82AxNiQCCtvkR18+r6LMYFbvUVrruHDukjMmDPnTvv9gATLZ8+dopQXu95yhS4JFTXVKTkGIA1pyvQrzmMyFgMMh3u+i6BOvuc1ui65+gMunHWG2seV5xNuMjFNYdrkg9Kdd3EQKhYlzsQXyTPWeyEFzrMRr9BmOC+uktq/JM44RR2T0y7wtoORxW2onGEg+vHC2QOJmbgmvNH/gPi9YKnX1odscaE/hSMEQiloD0BVsdY1BhFFCuAq9jJnnfq5Z4RijtBCs49m5DDdfcTEkhimeD5lLFTpLKCeX031ygwMclMwoScHOHrCHxHZLMYJfqRWXDWnRoFRtyI6Ov5K1OH7n93V5ye+ykz4H5s2Yl7zVW8UPHX4cKVd3ZNgOKJDmvRByLGGROcV/dHjX+SCbj24uI2i3NxmfW2wt4pzirscs3A1BCsBqMzG/W3Bsl/Z0DlRpif8JGFxyuwpJfcEWUuKCMgUCCmQEvNr8DqgnQHnBNjwADYAX1lBtL3UfVk4+6Yawg6oHcJY73LCNwV6KtxZ41PEfnpPlxyqSDTrZOQTJfPNQVpHCMmJoAdEJ7G/JQZuN7X2TciFtegOXdGxajedHnHEa0ph9ScrnBXcTtYz3hGjdVxVTPF5VP8d/RGxxkXJqV3RmGmyqfmnxo/hdVdHudZxQyEDx2mKpxVJmDFLdcQXHNO/4PgdX31m4Qa+9rTR/1Hx7rLqS78tEE7wFAgwubUMQfAGWi7IloB+Aqkjriv8S6xKKJw8ihScGt6giwYYSRj651+TEFOP6eIhok7h3AYwTjkc725S1zTL1grOSmiY7GKBJVpqGujr0toj6xOzlitNzr/5H65t3diBFzMSnGWYeqEY9w5CZajnF1NaqyqG8NqxPcK3+v4dS+YVpmOdXdOaSL3np6IS/qHxbofbJDhdz4EOJjq4CfCsktg1/Hu5xp7+t8DrPmRSXFiXI5Ate2eQ75cBSq6nOryv9MQKPBxBSsS8cl8RQx1PI1PiaSajZQ4FPjXu+LWCoE7IgNG5slYShqnCEP1ywkSeHeOU6SDRGEiFhHAQZD7u1iMjNjcFcyReO7mVxJQc5UBqPNV/tQwoP254r+L686VCYede+3wkMKcbrw+c3DuNeeAAAAgAElEQVQP8QvC2AkfpWvUtdV7KD7oRLiqb4fJzhwm+BHeKhxW4/UupvE7d9md6+KyiuvG1bNIaC7/jswxBQm2IbG9CmllCKowr3M74T555uRdY5I/Iw667pI8ryrw0CVUjeAAsQsESPA5QO0AmALBKqoZiLqCe41D+WvMta4L+jWvu7eEJFBOp+5dTL0TLjG4cd2dQ88Y4Thj30AeLsmgOEUq6zwVi8YVCdng9negBMHyD55dsqr72BXfn2oGKiGtpKMMViWo7mf0LL2rDgcp3GAc4+IwwkIXjxEPODjtcBvilQfD+xuntE96T0/FK3x1sXiCtwoDEDZ28xju1XiEsa4hSE3BFe/+GwDHIKx42sVXvO3erYupOLrO68b+xaOuGViBAl1mB4y7PAqgO5CqeVwQVICXAv4uwCvgn44n8xA5pLXozsQ1cOg83ecs7rqv7v2c3vWkL04Rwk/luZOIKnApUqsE8S+Q+/vB1BR0+RGBIbJzCG9iBhQpVCJx4ieEbZFNcw7orNJ77fR2jXGwqWJg5Q+Xd+qHmg5zp3jr7MGJUTzr1AthLeJ4hdtIiKfPHUyvd+5TTQDDx65vGFafNAIOBiRY6mBXJ+5XjEvEf53nCvuJUWBrsf1XbHZ4hZ3LL2N3mwHUhAyYFSi54wy8EnB0BX8H8Ar0FQEkoh7FJmt0tVV7UHMQ4CfkwkjDIXlEUtPnal4Hyp9MLqn4OklILBcisvocCX2HoK53V1+5UyKrwK1+3jEDK4EkhLFDJo4hQmfrihD3Xp42Awk/uPg3wWFnH6diKqYl+IzE/tQEuLrBxeEUe9N4956eiLvzQ4zblwwLEeYyfE2xb8W77su5YxKY2O/yO+agi0G5Xs/RP2Lu8Lyr0Q5+/4v3EjOAGnS94IljP2UIOjB2ALrGOKB6zdkxCAkpKCHuGIBkPVS35H1rjdhZqLOrd84lFzbvJ4nmk0lmSlSnyAkJx6mgdA0DMhJ3mYMEwHdIMjEFbmyNWwnFNWTpOat76XKOwo6KcQ6H7HJGgu9qPwrnrzq6e0YYuiv8PxWbHX2j7uKd43fj7J1GoMMN9TFBiV9H8F/rriJ9fab+F4VqbLemaxK6vThGZp3X/XlS2/We/nPuqRlwGsYF5y4XMggpACHAU4CqxhNR7Aj1ut56HuzP17xkjSS229dObRJimZ61uk/dvXSf7dz7jiAeU8BpExGfQ1iuKE3NgjINSuRX0J4K/YQQKnklxLESFZunxtbx69SZsElED+sjJf4nmOQK6YnId8T8lH8Udl/n4hiiBGcRn6scKzokesKZ9414nPRE12+t+Fse7uCqwkWFD0r0d7iJ5jjiGon3FVddgY9MBpvP1umwXWF4V39ltFocnpiBHWHkiC/HEEyAnAHiNdYRCALphBgUOazrJ6Jd5XX2vkswSR26M5g8U2TyUySUiPwktiOwT3yWkJaK3TEElRBT4V/BUhFeAsg1VoE9IlNlPmreJJ4ROHtXVnd2BvUuq7uhesftfwfvHSHtCnk3rvJRgrEq1nkfxK+T52zOde6OLmCx6/1Rd6PetTT+3biremHdz8Rkf5oR6ARxxSNX9K+5Kh6y3wrUeRNz0OEv2nf3vKuDwxV1no3JUzPQiTG3ydzGZ0DdAYOKd756KCBV4hsBrTuvxrnksZ6jWqvGpmbAqRGKSYmoO1OXkJI4dJ8ZUUzH3D55N+mcXO8UgVUgU8SniA2JehcwXVNQhXcls47cVMzOnEo26VpdvHqGzq6rzcm7hzCj6/GEEyp2OTh4zUkxdrLWT2Gui7MT3k+wMhX1afzJO+rmOoWjOx9WFOY52Dn5WIIwCwniVbBfe1Lim81BBuDKrf6KkZO77pO92xT/EU7/C587MHQvKhJQ6/xEMCmw2BGGCegzU6GEtgPiLjHsCHxGQo7h6OYn5OeQ4HVPVF5ENvW+uCKAxaE7je6xIhQ17vZK0pOfFHs3mSnBudbCITWH2FBMQngdQKeCvYpq9rPzRcnNh8gFifx6B5Rhm9xfxR0VaxxMUeJa4dYJrkB84vBMjVF4i2qC8rB4NfbgLL/lp3AT4WP3nPUl62GFq+mHkWtvHR4pI7DOrbHrz0rI1zzIGDiCX8V0a7k1QDzicNS/7oASRg4wK8GTCikm8lJgUgbCFf4duN0J9tUIqLVS43C9D5q3jnd/7s6hI8c1vzsnJaWJCXjIyunsczGnyA3lcQUmIi4EnlcFlNBlRsABbFeIT0W9IlZnj12MeobEiHtezg10+cX5eDDhA/fjjsK/xFykmMzWdvBW4SWq7cSkrWc+1RbdvVG5nLv2jphPwMoJTt6BgUz8V+xhovuKZaIexbye1/9CsTIT1zpdzitfHVt/Vn+u4yl+V1776+cTZqDmQQ3jgnaXzwHyFNQc4FcAXsd3ieGE6EeivCMQZ72UeBJjct0VZRq6c3DPW91z10yse52QTUJGSew7COrEGqdIbgW+ui9XZCpx34Gl+gLWAbL77CfMgCIURu4u8bekU/4jb84ZppyiOOSOj0Tqw4rLJY4pQNzFOI2t72Ip4+EEZ9fzTHSBM2+CzSfwbTfHp+DjjhFQGJngnPrwUcfdn53/LsCKjcxAMNHPzAmaVzG5xnXjlQ/XOd0YwuRfzIASO+qyOwKGxThfEdwvEArsXWB0DIMS32gt1zio/EjQJ/OuPSZCPiGtbo8uOdZ7Wdd9iEx15ueMnyS8CnTrW6amoMuliM0BWlc0JySpCGGSS+Vc37UzUo65cs9k97ZOBSvDFQfrFJ7dkUOt6WBjwpVII6QfVOq+1jNXOkKN1/uTxu/ev3T+SUxEuZze2zEBHT4wzEgwyhHEjrjeFe7VFKyYiQxDjXn9XH+r0MV0e53UE51Ly3dTV44uvNt4ybqJSXBByRH5HdAm4IuEdc3hmoJrniP+EyOAYlWObj/Ju6FYVmN3zCFBRWzOvUM51HNGhru9lZLRT8V/CglWYKz7ckwBynHKDKyEMSEFRKhs34iwFfGrenZEhJ45d9PlEmYSHCOwg20pbzjYWjEG8YjiMYaVp8Z28dDVFc46zp16R8wn4t8E+xQ+JsK/w7lu/vrMMQKvvOqv9qxrr+J+fT79XyDqctdn7rsjLqjPFQ7/66xZk6UNuDaQM9cFcdTgDrgzMGOGQAFoArzIFDhfihJBjkxCRyx3xU4IU9XBIdL0nGu8O5+RTXqfJ8Tl9NU7iOzkGqdIkeVxvowx8DxFkswcOGOVBK9zcAhXxazv767Tzal1dH5e75N7H1QvuPwwxXqFWyfGHZPicBHCt44DO1xKatlhK3rGnv/O+Oje8a53Kva62Kb6cAfj7jIEjhG43ouZglTE15yrOUBGocagHOtztveKrQq/63jCZ3/F3mUGnCZXMe6XWQRUKdCh+B1AVqK7IyI1BxmEZF4Se+1xYmoSQnRjWc0e0jsp09+b6xRBJqZAEalLkA7wTglTiXRGAp2od+PRuuhdk1o5Imfn9jHxijCiw5UV+6o4dfFqJ67jpISPnHdlMe78Wpv17J6PJP+pximMY/2jMO3ajcKjbg1XcKYfNjrhq7Crjjs/KyFfxXliAtDc7vn6rI53Yw4WO7jenf0/z9KvKylAq/wVbGr+k4bABTYGwB1hOICtxHfNywgEmYGVuJwYZ826b5W3kufOe6Tky8i8IysmGKZjjBR3x5zeSPvz0+K/gSwrSaakyoiSgT4aU1+MFLkkRFNzubWocYyUdu+kwxl3YzzjiR1z4GLiDtcprHTqO+F1Bx+7u+FojN07tTs/wTXUK07POEbAwSu3r10BeolqhTWJAVixqObvjAF61s2tz+r/mhAzFa99od9EdFjM9q6wu57l5Gz/OROnkZwY1izOfBaTfFnoQL4DJidu+gUGzUtIYEdEv+ZORLuagwyNmnfV/9T7v4sQE0OAyC+5u2sPOT0zJc9dYnvH/IQ8VaxDkIxoO8LrCNsBYhXjkKsS/+m4IuhaG5eAVI0ccZPeNUeoor528H7t8wTP2DwXH7scTt4OJxJsQ1yJMG/ynM1BdyDByPQenYxX+LSupWLRuItxCn9Uzzr45OBJh1GJEeiE/bVuagTWecwYrAZAra/MAlqne4dJPes5onP/BYPdhnLjWBM5OVJTkIC/C4ATo9DNccjCiXHIYirU0bxuTST6T5qBpB4uOao4RZbuvZmQoOoJNb72WxJ7kuzuyqWI8S4SdQnxFyD9+wcGuoqIu3H2LBX9KN4hmy6mI5x6ZurnrobT++RwQe3RqQHoMAVhF8Jv9Zyt4WBawmMddjETgLAOYZDCJjVe70QaP71TO/N+J/xKscnBFCT+d01BJ7Sv/ShBj4yEK+6v+d1vBuoeao3qvrvxFS/rmUy45xf8TZoqiUVN5ORIDYECMkQA1x6noDklElc8I7JQ85PxbzADyGg5BuwUaao7xgzD2guuYNkhP6fHdkju3XN/ilS7dSeA68xJyfakSXCIu4tZn7l/rnHrXUrO2e0P18gzLFEYokxAxXH0c7fOzr4Y7ym8YkYgwTAHi5yYjqvfjUPueuk9VvFoXOET68muD+vHgl+E4t8/TD4oXGt1c9kHDccsrLkTwd6JfpbLEffMSHQ1SN7PwWjEM/WewJ+TRjzVkO6a6VcGB6RS4Y8AlRkBBuqIOJSAVzmVqF8JSMWicbXHJG99H6cuTky9oy6ZniBO5/7VdVaCUX2hxpNcLrF9UpwizURYvoNgGQg7wN2R84SMGeEiwcDW7ohpKjzq/UrOmPUS6+du3hTPGS6jMYZJ6Vi3RvLurlma4JbCKzX+bXiW3l0Vv4NRST8mWMREaSJYL+Fe5yCBfMUxAV1zuj+7Iv6k2VDv041f/ZDguboHv4wnDXm6OZ21WYxrFphIc8FwIiodYGcC1xW/rzglxC8wd2KR6FdmIFmjktj0XSdkfN3jTgAgct0hWESk7v2d9p3TX1WMffrPikDX/avYnyBbBs4dKSuiPmkOXKJH72B/gVoOKTmDejeT/tnB+VMY43IIwkKGQQrLPgW/EBYy3PkGHFNYU9+Pxac94X50SLHHiXfxR4n8ij1M9HexSKivohqJ/i7G+QfAXb6aqzMk7rsyPHbqXs9P/rzTaDtzqyBTIiQBfld8deDczVVxU5BnJFNFO4p1Bfo1v5oGdz7aj2McHKHv7qN7D0R0Dqmqs53cB/f+KWJk/ZX0XhKr+vBTxhPyVbEJ+XaxSrBfNUNxHehPiFjlWYnJiXX2gPJI4vm7KOps0vvW3XVmBBB2KExh2K1w/VTudO8d5yL8Y/w8xaUUh9L49K6ciE/vr4r/aSxSWFZFaNf/SKhWYXzN7eKVeUiEPTIKnVBPnnX7X9eaGBqnnjXG4ZUOj//1bLfhducrQbQ2bApCroFIv6p0YL8D8N36l/hmRiMR6Nf+dswAylHrUdfo5qXPEMEqo+EQ84RUmcA4SbCqv9S42z8niPEncihyXffEYtOxO0yBIuKOKHaeJcReiSPZqzqD5AzZHUvxPhHHCKMV7k8/SLD1XLxicWoM8bJb43pOvyNOJfdWxd5lAnb7tutzJvbRep0gr9iVGoBrPhL7dVzFIyOg5iXrrLHs/TtcV3VnZ13Hrv785d4lTToB4kQguHtJTYELbI4pWHMh0acEfCUhFK+ELhLddY9dnqlgV2s6edl7qb129UemCNU5JXaXfF2D0IkQ9swZQ3cc9Z/ba0n//mSsItt1b6nwb4Hz74fMFNQx9rMjrjuCOPGMET4jmHTPrI7OWHe/Ui5we1Rh+xTj2bwpt3S9j/bPsIxhyDtMQIphP4E3Cc7U3qn7TXEo+QCx27fJhwIlUqvIrpjVzUfGgD3vxPy11lTo1/XUGnU9ZXDW+A7L1TkgDGbnD7H2pCg4lcvJo2IS8EIEcYo4FMgjcZqYgWuNE0IbiWtH6Hf7mBqIrm5M+Dum4CfIeELAyf1dSUb1xTT2J4h3smZC1ioWjStS7sB2YgQcQleCPBX6afx6Ri4xTYW/ex+6HlDPlPhHPZx+WHDxh2GGs9cdg+BghMIZNe6s4Z73O+IUViRCn5kEF3PcXlP4gDDGwQFXqJ42A8oQdAJ7agZcca9MgyP6lamqZsHllO6+tfcsaVqn6U7lc/OwuERQucJ/B6RdIjhtAphR6NZKzcBJA5CamYlhmBD7zrlffYNIvBtnzzqir73p9o+Ty+n7T4pJiNuJdcW/Al0G3oiUWc6E6B1yv84QkRLbYzK23hWn/undUsJf9aMjtj/JBDBsUmOo/xPuXM8nwZ1vwZ7kjqpYV+zXXux+dsWgE+figxKsE+F/YQcT+U5MJ/jRvCvWXTPNrfa74iWrWY1b74GD/x1/oGf//K/QpICr4lNQQPncPO82Ba55YAbghDlIjAMS/isoVyOwzkF/vubfFdvlZ8/q+9RYNF5FAiN8RbJM+LtjDslO7v1ur6ne/5RxRczrPlXsT5B4BW0H/FXMZFzNSYVKUvfJXTppBlCfu9jgYjzDkwnXKHyq4xX7urr/aVijMKHWSMUnGMI+QJz4qHBS/HeCFYnsK7YzFUyYO/F1vsqnxte9JqbBfcdaN3Ym7ljlDOfnf+6xK7ZPgfKdeaZgxcAWCcQOPB3QdslBifwqaFl8OoZMw9QMXHt1zMKJvSa1Qefrkv0dJJ4StephNb72ZBI76eWfmKNIOhGnpwhdgTQjfEecu2Rf96Fyq/GrlkqwoLjd+4HurzIIU+yuWMN4AX0EQGs7e0Iinn1wePBF37JvxwynT12B2QlxJGRZrDIIE/E9mfPax/X/O+GemARn/W6NWj/2szumOEVi7jvI/9Qabp6JKVBkwUSfKwinRqAjHCTY3dgrzs3zikvMQJdfrVXXYHt0xmotlMFi5+MQeRqj7tRD2pq0k4hTBM/ysC96614dslbg7uRIYpLYujcl/hMTlZxpjT1tBhyhnvQ9E+lJnm8zAQjLds76jrkJRnT9iXq87jXFCffjAOvLKtQ7kZmI1Cqo1dzOKLBn6//W/5V7KtTX+XcbgW6v7Bmrmzt23a8pDv+1jiuwdxvv1DpJntQUuERSRWUCzAngd+s4gtaJYWLaEe3u/MRAvMMMTGvanTHL1ZHfRAg4d8sVRCkhJ722iw/vmp+QvYpNBK4i/xTETwn3O/J0Iik1UNP74GJ47YVJbyZYvq6HDAbb084Y6vuUHxEWqbP6BhxRvV7fUcXfhQ2uKVB93Y13wryKTCTGHbGbmAFkNH7SDCBD4r4XqlF93hkAZQpczKU4/O5GPbWem2cCeN0cF8CZCEzIwxGtlWB2TcBdAn83L3svZVw6Ekamo5IdWhcRe3K+qVn4SUJ3e02Jgk8aV2S+7lXF3kX8CuBPCYO6jhISVSAgweDUUNU2vTMnzIArvJ1+R1jhrqFwguVHmDF5zuagM/oW3EjuoIp9FxagHlVCko0nBgGJ9Su/K5BR3Gkz4JqIbv9sL8hAqfp055CYMYbZCp+7fv1r7Z9o2FNrunlU3JRApoCuSKQbZ88SsXztOZmDxDN73q2jhDsaV/MqIabv1hHq1Ai4phHdgeROrU2d3GFnXgcYqo9S4fbT8YrYHTGLgHfy3CH4Lu9JU4DEQiWf9OdEJO3cC3ZH3Z7reFFhdtK37j4Ylqj1ELe/Ayd+Slek9ybp/+6+u/jQreP2rBJ9yri740zUrpiDRHWHG1UQK4NQc+/EM/F/7ZXtj5mUdX59b1XHdBzhMbs/6K6y+/5jZuC6XKfEhZtHxSVAORF9DMCr+FxjT5gDJpCvtVIRvcY7f2br7BgOZ/9JTFd753xOCgZF9slddchZ9cZKfElsStA/EZ+IAhWbit5EFCTCgMW6psON68jHEUBKYE3vghLRrlCeiPbJnLTX2RruuyUcnPR7Ejs93915qodrfhWf9LzqCxcPlMhXIrLO7/Ip4e8I2yTHSTPgCv4dw3GXEejOzr0XYyPgiITdxlPzT4FHksf9eqQEUJenE40M7JWAdMeV2O/EsJqDBH4i6rs10DMVO9lPFfap4UFn55iDybl3PYnu1GniP9VDquc/dVyR/rpvFZsIBCWmdwSEawqmcQn5TGvm3Bd1dxlWI2GsTIXC5i4vyzldTwl7VJtJzdBZqFzOGd4do+7fnSYg7XFH7KOeZcKeCU0ljNFcZgp+ygygddPn1zu/5k3rk9Q8OVN1pxy++qUnPqGJT+7BzaXiEgB1AT6NU2TTje8K/CqelfBnYvu1FyXw1/x3xLL9J+/axaL5SgQgcY/Oe12n/pkJgeQOr8ChemMaezfZn8qfiAYWm46dFP2IVK4aTb80qT12BIWeOWSVnCm7t24v7Ahyt39VPyd7+On+R3iUnNs7YpOeVvd11+h34jDtS2UWqnDt1qw5nC/9V55UGFcx7ZgEtQYT9qnoV4ZG7ZfVV9UV3Qd2hgnO2jyUEP87mvbkftxcJ0ikA0WXHJToV0KUiVJmDhLjcK1xh2Bfc6I/d+sjs5HuFdVP1cepOyN+59zd+RNRoIjc7R+V5x24cXqNRDyoWBuM/36JieBm4r4Sx8nYjpRSsYSEUHKm6q52486zRJgnsYovWN+zXle9OOE6dA6q5sn53RWrenNdV8We7OMTZtwR/KlIVcLVFcVIyKv5OyJ+Yjiu+iTGg81h9e7GJs8QXjq8Qe/7Jzb0yT0luSZA6RBKJxo7QHfEYRWoKLcSskx0XzmnRqLmfoeBSPfq1MeJWc+xO7/kTBPhj/JOTIHqETW+AkwSe5cAOJ1XiYQTgiIR0GtsIuwd4b6br1sjEftJrZXwde6lEvBKtKfzd+PZO6PeUz2pxp06nu653XzpPUqFPrvTJ4R+7aOu5xEOuIK+CtEqppWRUAJ6Fc2nTYCTe7rmmrv7s6oLG+/GVPwEtxkOw7EECHYbNJ1/cm9uLhWXAC4DfibmEgHJBKgzxkyBK+JXgnrNQTnVWtPx6by6b/YeKrYbnzzbER+O0JiIiatvVW98o2hwMemTxEUnRHZFvJrvEBIjIFU/Na7OybmbLnZ3caq3dsdrXzp7UH2paqLGa83TeHVmd4yn9+hOE1D7wTUJSuSngpIZCWQAHEPxTWagE/XsHZWRmBiC9Nw6nN/FYZTzr+ff0OCn9pjkUbE7YF1FNgL1Lk4ZBccAXOeO8ncmAM1RhgGNT+d1+3inGWBnwurWnfHkfNVdUWbinQJC9dAdYuDunInYULHJbwOQ0FYiXo075NLt08nLzAElpc1DZPfONQTTPkpNwU+YgJT3v6WPVb+t10rF7vYmEvTMIDhmgQn7VKA6gr8T0e4zJKiV0E7nOfGuGZjUJKm7On+Fq2rcwVV497+l0U/u082l4k4RCyMQJf5XYGdGoItT4lUJdpRzKs5PzJuYhfoeTl2cmCq83fNhAgHdh6moSO7wSqaqN6axmzrwbdOVmHin8LhL0DsmgAl+VqOkfpNDVfezG58+c+apGDXu9tPkvVl9Vb7J2Zyek9wlJ9a996rvlHBDhiEV/IkYZWI3HeviX8/Q84kgr0I/ye2aFhbnjFUBjur40UagCojTTXo632lgcvNNvjSh2k6EfyoOXdHpCFonphPg7jNkAJQRUePr+spksL06Y+v5qHp1sepZd5empiAV/9O73/W+22+nceOufI6wWNeeimM0zxEtSpAgMe/Mc+e6NbjrnNI77ApzJ07FJP2Yvsdaz7T30vi7zo7lPdl/6C4nd9wR90oQVmG5xjOT4IwhoX6tcbcZUEK+28c7zAB7767+jtivMc65o/vT3cGEE7o71fbVNzR93fjJPSe5JmCsyOB6tyoi63NXEO4aASRslch9jScCva7jzFf50fiOGZi+NzrX7pzZs3ruExOQ3sFUyJ/qoZ8QFCfWTESJip0YhokpcEWOk9shG/XeE8OQ3LsOP5VYdoX6pL/c3JN9q/didz6t6Yn+meQ4eZ8SYaX6gZloxyyoGCYyUzFfha4jiqs4VwJ+HZ+aAbSmuzYzO84732UIuryu8Ff3sOsp2TPf0vypQEkBJqnDXaZgV+i5RgAJfvXcEcadyHefKbF/5UHiXs1HhqPLy56hOqn6qPpedxbdA+d5FQ/sTiGhkQiVqfBI+i3t5Z+Kl2C7bEzFnjIFlVxcEnHjOvK6XlO9I5u7c4bqbqX4nfSDMga7uTqMQLVSdajz0vidM5rOde7UmnvSR+hesp5gJoD14B3i/1rPFd8sft37K18V5u4ada6zx//++yBPmYHuXZQZQPusudAZq/NV+OzisOoLNf5Xqb8BABRwnHqHJI+KVaTARFQVlYgAlDh0x5mJUAJ7vUNurIpDYv9a65PNQFrL2oPumXW9y4T/YwoUipwbt4C3EB1afSJmHAJBeZ25SCxd76DeX42fOgmF0Yz/dkV7nZ/kU7ys3kuN1/qm8afOJ8mT3hkVf/L+I8G3YwKY2OzWc0U5E/dMoHdjqcBXe5waDbQ3VENlANzxLr96hsY7TD2BxS4m/xX3DUDggMbJ90hysdgdAnCFXSfGHYHpiNaauxPx3fqJmL/mI4OQGIcu19Q4sH3tjKl6XXe9M4TKKNS5XX8n90rhw+Tud72c9JuDBZ8Qo8RI3aOKP2UKdkinm+uQjXq3d52XumcJXruxblzXu7Uu0/2j+qp87zoXtU5yf1TsXSag9kZdhwl4NNcV/ev8KqjRWH3uzqsGIBX417rOPBXD3sGpCRL9bs0q9iFTqM7+Lkx2sPmX3vsWQFCA4YCpmyPNpWqYEAL7ouSOOaIRCftVAE7E/zWfzVUCf82hYtX4XbncOrk1ZPnWsd0/s/ns3id3eO0z1RvT2LSXfypeiZN1X07su01BR1QOyTjvwnJPz8u9b1Mj6/ZBF3d6zZ3eces0PYcT89w7tHsfnS+wSOjVO+yYgHWOEpDqK3XN5Yr66TxmBpR4V3ur4+zd1Vrs/br67xgDdAfQXWB3BGEi6gXVI2r8lz79BlCYAMup90ryqFiXSKpgUwIuEf+u6OxypulFBQYAACAASURBVAIfrZUI+CsHmpPkUrFqnO3FGWO1r2u755TcFddMdjmvHkzu8FSsqD6a4MFPz0lA2Yk9aQo6ApqQz+6+7zoj5z5N7jXrp/ouJ/J39XHebdqHd52HyuvcozWHik/usjIGqdhHQrETpO6zO4RwKtSvvd4576QZqLWtubvaOwYBnZk6y+v+KmPQYTN6VvtK9cW/+jAFE9XInzZ+8v2SXJOvQM7XJEf4VzGn5jDhnwjYVdAy41BzuvNecSpWCfpkfl0P1WL6rqy26djVd+qs691gd6WL7dZJxMapHvo0nHH2k4KzEz8xBYpMHII6Icacmp2Mce6eirnbALCeS/qs1k2918k6T3M59x2JqEQIKcHfrbHOOWUIupypSE0F89X7rqF4xanYOw0B2++KY2if7vyaq2IkOxcU2+VE99e9kwq7nXHYn98AElNwUcJlmtetmYpLvhYxEkICsBKLK/rXeWwOE8GJQL7WU0J+jUtEPZqn1nX3w/J0tXRNRr2/dT/p+bJ4NVbHVW9N737XkyrXtI9/cl4ifFyAf4cxcPaSvpuT0zmr9J6o+G6czZnkU320vrfKX2uUxjs1viMmvS8qHo27gqsTft0dRQYhee58fVZifN1bIszrvCqo1brJWig2WQO95/WcGSM1t56vcy5oztUjykDUuLW3kjtce1L1B+rh//kWwDgBQqff1c03JRCHjDqB2Am3u4zAulYqnutcd341AtN51/povpuX5VFrdPVTNa0CAplB9Lzej3rP3HmOkJne/W8VNilOpcDtxE9NQSd4ThGUyp3WLY13sBrFqLk7d1zl7rDceXcnr5Pn7hjnPjPRNL2fyhjUcSTw13u9YwK6PEooqznp/LvNgLsfN66+v2sGrnndebnPKp6peQj/1D107rfbH6yX/9rHt4DGSVA6+c5JrglpOIYACUom+hIB2RmOTiiv4hCNuwKbzT9tBq461bzqea07mt+dTxKr5q91P/Fndm+6/OyZgzGneugkRrw7VyKKELHUPaucO6aB7UGtK0kpLH5yf2rqOwzAqTs/ea/JnLDcR8LTOzK9q47YcoR+d9+V+HfHkYhd17yEuit4q7C/cqH56n/TXwl0Z1zFdO/rPFPvVnN0P0+esTvBzCTCzukdd/kANe4/634LeBxBoJLk5Lu7uVRcQk41Fgl8Ju6UKejG2TNXxK97cg3CNccR7Sdj11zu+zlmyIlhderG1LOrBdS5qzgmeJI7vLak6o1p7B3YcUfOkwJp3Z/Kq8ZdstkhszvqmdwX5+6pmN3xrufcuqi13Tx3xzl37cTddUxAvddMwClhj3KxL8ZVHK851jFmANIxJMjVes68a/8o1wkzUGuUmKPrXrnmC8XX5+weTe5h7UHVM2qc9fQvc78FRO4CqZPvn+RSsd24K7KqyEQkowRhagSYcEUCvs5xBLLK5ZgFZUDQ+N1mYGq0mHhX59wJ+3rXUI7UFEzuPet9le8u3Lgz7wTcnTnvjOkI06mZs8eaJ70DbrwT58SwHkkMS1c/d32n9nfHJGerYtG4+xyJ+0TYMaHfCXsk9tVzR/C6QtsR6kkuFTsxGZ2pmJoAVVsm7NEdqXes1oBhn2sOXPxUfWIbARek7gaJT8h/ElSTXCzWFf9KzLnCTolGd9wR9Mg4OHOVGbhyv+IcY7DG13058939sNzJWD3vWrOutmgOe+7Oufq3u6/JHZ4Ko6TfPgFr3D1MgN6d48Q5MVU83flubu4pryX3yIl1Yt6x16Rud8S698i9S67g7/K5JqDOVcLQHXeE/bq2EtNXrBLlXZxjDFR+tO5kP/W9d2rV1RDV9brz6gzdO6Hu3dpjyV2uvZn0lTXXBaw7QOLTcp6uhZtPxSWCaiL8XdGXis5U2K/7YHNd8c3MwLVWt45jALr5dT30Pk5d2P5Ynbox9Cw996tfkSnsxtmzun7FA9UXu/Gfhj9oPxPQd+ecjuuI8FPrnNyvO2KTnGsNp/PefQ7u3erEWLfXRDipL7Do664r+DrhmD5zBfO1J0ccK/PwGlfrJuO7hmL6bus5obp0MZNn3f2sa673ld0tFuf2wS7Gwr78FmB5J5CdrEmSi8UmY+oLLRNzaGzXCDABuyOiE9OghH8nwJXxqOOO0Hf3UWvmnEF3fmyeawg64d7lnRiCk6Yg6bd3YsqJtVJxlZJGkj+JdQjwRH1QjumdSObdFfuNJiC9dyo+MQFdLvTFdyL8XTHJjIES20jo7pgBxyR0wlzt1TEXu4I/EfudSE+f7d4LhXcMOx1cdWIQFtK5CYjdCdifmPtkbZJcifBPxRcScI5B2DEKSCSvAlyJ3VREO0Jd5TxpBtRau4ZJze/uijpTZgKYkUjvpTIEzvi3CqcU+yZkkM65Oz5953fEJxid3sdJ/HTOO2o1EhvNpKkw6uaxZ+prLTIM6rkjNJExYOL+xFgq1JXwR2ZhMg8ZnsQ4sBzdmHpWTQAyBc7d2zWwp/przSMxPQXAnwSan1r7VI2SPCoWjXfP6zNHADKhx74+M0HqiNVXbmQcUjGN4lOBX/d9Iu+V89S7pnVH53v6rjym4D7UkuAOlk7npfHXstN591XsP5kVvqI9pPPS+HXdnbnvqGEkNMqG1N1IxJQSZ0jQI7GXPkfC/YTgdYV2J6LvNAPrvtw9MoNTa+XGnjIE7MyRiejMQ/IswUnVL6rfrfnfBDjqhe8cP1mnJBeLTQxBFX+deETCrQpWJCSVwGR5VhNw5XGEMotR5kEZDzT+CWZA1bI7X2UC1Xh3P1zz0N0/9Azdw6lQSvrtTgy5K7cF9M3i7563Ix4ntTtx7tMc03mqJyZ1uHtOco9U7F0mwBV7SPihr/tV0LkiFgl1JG6V+L7m1byJUJ/Gsnd2c9b3nhgsdXbIFE7MYiL62Z1X/YDWSXvaWeeP/I+OpYWs8TtAP82l1kyMARJwTNg5BqATk+kzJeCRyE2Nwxrv/JkZFDbfNSvp/pnYV7m6uepZJ1KQeWB3hYmd5A4/xuDfKGYBPgC/n5q7i8Wn5yucZevtzP02E5DeFxWfmIBOIE0EXV0zFfxIuDuCXs11RTQyCco8oPxq3Une1aio2qjYieC/2wSkd9cV+KpnHOyLcuwCmLOh3zXmVO2SPCw2HZt+1XW+ICNBqkSnK56VGHZNhWMEklwqFq1X30flUe/vjLOYRNA/puAzES4igvIKO3PXVKfynKxwgreP+P+1Aul5qvhUSDkC/trxjghkxsAZU6K5itpOhLOY0yagE+GvNdi+1LjzjjU/MgOfaAKYqE/vdcUZ1TcOHsY5TgGjs7nfMeZk/ZJcqfCv4u46iy5PFaJdrGMkOpHInrkGYmoYXIH9ilOiHeVSa6i81zmpPEjIs9rUc3TqzUyBawKQAXTuYMUM1SNqfM2XxH4zdsWk0LzsiRxdDU/nvfNMT+U+lefddzI5KxWbiqWpCaiCLTEISKh2wtQR80jousahxnVrOiaB7cNZAxkHVZekRqfEv3tv0L1Agj+9v8w4rH2s+sbp+XGObwUmpyjvjDlZRzeXikPjzAAo4e+YACQgT5kDV1BXEeoK7B0z4Ir5ugab54w574pE+V2mwL0rjyl4D1KNSeKN5uA9lfBWUfjqZfnfqJO5knVPxSZ3R8UmQqqL7UR6J7YS4V/nK+F6QvgqMV/XcIT61Awk86ZmoJun6njdX2bMuhzoPNk9YXet7qP2Fbvzqh9U7qSH3bXanN8OUkmh7o49XUs3n4o7YQqYsKtkV8UlGu/EKTMMrphHedP5qSlQJqWOT/bDaqbyu3OvPnHNWyd2urks79qb6q6xWHesYoHqobux4935t0ij2ezpfO+uR3eHT+zh2+9Vcq4q9pQJYILOFXvKKDDxyYyCMhFIdF/7VrmT+Wnsjjlx97+eT3cG6P3defX8651T586EeXJ/U4GvesfBou0c3w5WTpHeHXOypkkuFrtjCDoR2Qk7JPqRMHS+SCtzgHK4QpvNv9sMXPVSJqKLY8/qeSV1ZkZOnSM6f2UCurvpPkP38DEFPuptkwhZ6s7c/hv+Gplg6mSNu/NP9pTOSc9t+mXU+RrLBB4Sd84cJQyVsK8C9RWv5iQCfc3/338fYDI/jT1hBjrRntZlenau8EfGoq679ox7T3/CBLB9R33/OwBX9MJvDD5ZWzeXitsxBZOvvUpAul+fHdHvxLhCuTMCymAoUe+MK3My3X+d5/zcxahnqfB375Qj7qd3v4MEleuNMPLWpVIRuLu50+v91Ln91Lq79a/z0/NQ8cnXVCW4XLGnRD4Sg0rI7wjdHaGNxHQq9pV52dnjTm2qgK77UOflmIdOpLP7pET91Pwqg5H2s+q/KN/vAmLRS78x+GR9k1wq9oQpqDnYz6noV6IzFc2JiL5ikXh3nqscaNx9L8f4ODF3mgL3Pqx7qH/ufu4Mh2MW1LzHFPxagaNE80bMfddSCmPftY9T6yTnrWITE1DFHBN3u8KvMwrsmTIISpBf+3WFNsqn1kH51bqTvOydOuHemRkUV0X41NixO3WXCejW7HpT9c7/b+fcdqXHcWQN7Pd/5sFG9pQbGhbJiKAop52LFw2s36IoKXTwF3JWs/u5K89/2/u1A40V8u64Tp2VXFlshyFA8Bbd/LLmgIFVC70eaGfPojbUm3wPvtGzTmNhx8EaC2/8me4o3q6JaA1ka8dbm+wzL6/d71176O5z5Jvttb98vjmYQtvKmimk/1oVdV5RvGIEMjBD0FYFxR34V+HeQq8C34wxQP250wxkfVHhX5lbC+HsmtpZp3azoj1xxbNx6DDoyvN/2vnVAw6J+Y3ybq3ZfCjuDaYgMw/MDTgTk8E0A/UoxjMkjOFA9RgzsxNz7ZVIQxb+GWOY5bL9WPewsoaZet75gPbRN86Ub7Z55IX0zQEtbf+FuVbnD8XvwlUEgBnsKdCYmYAMVhHAKxCMcjEGAAH+2p9qe5mJibTy+uXFss+UubVrRDEICNSzdY/2BMqtHndse2re/8T/hUOvJMzBSt2as/myOLXMxu+CngVND14joEWw+smtmIEq1FfrXePK+mjHgGIjrZR6Vb3tuRKtjSxOKbPz721ddX1H25/dawePj0enPvqyOjTyvzin6jxVgIg1BxUTkMGehVIVPlnY3gVmBvyvNqpQ/6mXQTrKy4A/o3fUB3ZuqrDvrUH7rLK2vf5Ex5O6107nCY/Rv3gQHnqnyGk7tVdyVcDIq5M9Y80Cgn5UztxWrzEKDCMTYXP9v39WAGpPKV+NAqrnmYpdExRBOaM7awrYtaKuQbsh0R5B5Ws+JVY+GH60QtdLsSLPzNf/qqbOQScoITCrmAJ0e6yA6i7ce+Ce5YxAHZkRBPC2/IQZYMZaAX00n3YNZ2DPQD9rWNczh91DbBxznnXmGjPAKP6lmM4XlZILxe7Al4XFS1oG/NYY7+/sGSrbhWPWTERGIgJ6L2/0TIn1zJRqcqIcrFFjTQEbt7Muo3WoGocxBl86LKfZkgIKTKBY1SBUTQALehnwe0CawfEl7gXqKFYB87Uv6P8qVDEEHpgrRqMC9oouEcAj8GfnPzId61zaTYPWpLfJ0L7I2qtsWra9Sm63DgLCtoYmEVSgcy6UXFlsVMY8j6DeQh+CyggSEfhb8Fsh+MrJwn0ExBHcr/kRvKPyKBeq1218Ig2U+UNGz85ZtlZQmZdr3YRoj6ByJRfc/BMwChxQQAUKFfQV4Irgb4U5+3dW9hQTcPVRMQYKrEd5FcOQwbsC9kqsXRvsfDFz7q27zDxk69Rbc+tWVPaQEptt96480pGivPCkxBNcVqBzTthcKI6B/wi+WFPAgGLFACgQi+De5kLxUblSLzID63P0d6QBYxiYGDv32TxZiFfnPasfrUFbZ92c1bXvbXCUq3woTMVRQFBAhQkUH5WzN6wVI4BujleI82LtsyxGgXOvXVufAXUUg0yGaj6Yfu/EWOBGenuAzsy5hfdTJsC2cwe8o30oHAF66Ly8dM3uqtE5N2yuLE4ts/EnTAELnQzQMjEedLPPGGNQyRWZhWw81bLIVHjPK888mK+smwr8oz2CyhWD0X2GZH376gume6CTDyqgzDeKVUyAB0+7JiACPwb+I7C1z5Xb7iw2gvMI+jvMQKU/CvBHOtt2vZyVZ8ggRDkjcFfXr9f+HSZAMR7wAKgGKC+4ahtTr65A5/wouVTwj+DLy2NBFAGgze3VZ56xMYwp8GKUZyi2Wh4ZDgvmKH8E/UibqJ6d4wjwmefeWovWVLcp6NpD9RPBr6n06xEvnm4BJp/0HwcjE9ABVx4wenmZ22D1llkB/AocI5BnvjQwOTLjErVx1UFfDrLckSbZ8wjUM+Ng10PFPHas1ev4YPZFJTY7npQ2jx5z6kvkaGcmeahA5zwpuU6ZgsptLwJFthwBLQvUO4C9+/88hGD+U56NE9XPoB7lRuYNzVNUPzMBWR1rRNZNFq1vtEdQOdNG93Gn9Mlr+zEvpW5h/kA+Ze5QrHKb6sWeNgEMqKIYxiwgWK+Auvr1AIF955cBr60M8DODFkE+Y/yqBgFBenXd2+MD5VGOm85cSrtu7O4LZLsDk4BWoHuu2HwoTgEqGxvd6EZxCDRRuQeiKjRHoKwCtoVqVB+ZFFvfMxxX31FbjBlQtWQh31sT7Hp4qilAe4g+BEBgdzuPell1ifRDeZT5QbFZuS3LTICFuQzuMtj04C6CXwT/LOiyt+mRUUD1d8zAjjlhxr+jLZrHbhOA1pgC8GhfIJNROU7YNiu5y3W6Xx7ljkxFWoHOOVNyZbGKIbDA5oHnJQYDgeimmYFWBfCVWNZoWGPgQbtqBq6cLPizfbXjj+ohQ2HnGM1jtm52yqK1tm7Iytr3NrSy3+gDwQTe0cYjX2ZVwV5YT9VfAf1VDgT9HihF4GcBjgFE7ysDc6tv+/Wpg0DdAi17637VY9r4thmwY1z7HpVlz6M5VebW5vDaq6xJLy/KEx0F6n7LjpTOXK1H1x0vjtYOT7L/KtA5d2wuFKeYAgb0PVBToXEHVjNAXgGUgfksnqlfgfrIQFRy2f4z4/fqZHnWst2/s/reusqe2VzeMYT2xlpHia0ceafzv/JlVxHyYXVUkEDxUfmuCYggced59eaaMQ87t+7WBFxjRDmROVHNhYXo6rhtnmsLMPqjunb+s3/bNciuSS+n3cZoX9gxdxwDbJsdbZVyfPOlUerwVPqXAl1zqORBsU8zBRZ+VUhFt/IR4LK37Qy0VwCeyXv1nc2fxUc6ZM/ZufCAnDGGtl5mQhlgr6597+hCuXaOu5O5d/q11r3rBbmrxV39zHRV+oBiFROAAC6DtuiG2Oa0oImgkgFdm4OpgwD9ypmBOjIBaw7vb6aNrB5ThrTx9PfmMppfFKusKWWtVte9t+9QLvYM7MrDtleO2z0kyw1PxVYFOudRyZXF7hiCCBAVsKsagKsNVJ8FfW8sn7rIYNhyFtYZA1DJZcehjN9qGmlybYpM+2wNIND38to27cb01jHaI6h8bUOJrRwap/NX+vTWOt94sattovgduGLh3sIegka2nLmdtqCuwDEyA1G5Ui+Cfa+fKK8ytkrstU8Z3dU5t7mRQfDi13Okuu7tWYTyKGdXZy6l3VLsvChKsj22Uud8srlQ3I4pWOtmoBfFec/VZxn0KoCcxSI4t+bBwjVjALw6Sr3KWFntWHPAGoHKuslMgbKGq6CP9tHOoXMy906/3lb3zpe72haK3zEBGehVIBDdHFv4XNuIwDQyAQoEI/g+aQa8caH+VMeW6emVsfHsWlDW05iAm07JeUncJPTNzXTPK5svi1OAigX/DA49wIziM4MQAa0HxzZPBsNqmTUEjIFQTEOlPxnER0YDzQujd8UUsHUqpsDmttud3T8oz84xovRhp51frouAu2PsahtZvFrmxaNbew/WmDqZIVDNQGYQMmBmjQXztQGBe9VIeP1nxqsYhQjO0TyicmVt2D7smABlDymxaH935kJttZfPC6Jd0kcl7JxfJdcpUxCB5DdMgWcGEBwjgM9ynvo6sBoGFuDZOFUjpJ8H6tFXgMrXAW/dss8YkO/aQzuHjNKHnXZ+re4dL3qlDRR76kuAzcsAIYqJ4HYFRHRzHsWq9Sy0s/UZw7ACumIeKmDPGoZM46pJGBPwwtNvXgwvnLRClzvnmc2F4u7+UoCgkfk6wMBqBO1RXfZGHgF4VM4aENvvSr+QPlnOrG5kArM5U4wDMpMR6CtreN22aG9UY9mjQWmfzfnrcQi+d8av5Eaxp0xABIYZ+KkmAMF/BYq9OuiLgALqSuwTzAAL/+zc2XWR/Tszkuv+8dZwdd17+xLlYvdyVx62vaNx81I4Ku+jknfOtZILxe7cvFq49AAwAz2vfvUZC91Xfxgw7jAAbL9sW5V6iuFhdI40iuYUGT5kEJApUOC/su6jAwPlqh40p/JW+/PUeidf+kruLFYtY2/4KybAA84oD7rBtrkQfEewy9azN/yoXrUc1asYH6SlLWeNQbYGItOgrJtr3ytGFpmHkybAMzxPPbvofs3LgJbqZwI755zNheJ2ICsCQMYEMDE70JoBf4cZWI1FZBwqUM/kYvrPGB82j2c00DNmfpFBYM2qsobXwwTtjWose2Ap7bM5fylOgXVl3EpeFKtAFLp1ZU0CujlGhsDW9/J1AjPKZcs9sEbPojaUeoyZyQwSC/hIbw/QmTkfE6CcAg+KnRfBgybj5q50zj2bC8UpQGVjT5gCL2f2jIF/BpC9GJQ7AvisPQb6o74wEM/EKHpEcI/miTUFypqyOT1ToYA82htKrspRorRfyf+2OgjAq+NR8qJYxQRYSFOgTb39zUAzg9XsZpu59WbrM8YAAfw1DsYAoFy7Y4vMwY4xiMwcu24yU7nuHWROvX2G9gXKX9m7SpuV/F+vMy+Ar0/BVzvQOf9KrixWKUO3tjsGAQFmBLorJHoxDCCr9RioRzkVM/GJRebE6sCMO6qTacqWsYbAg3zbdwbMo3WsrO/scFD2G3vInMjJtv2kuFMvfiUvilUgKotF0MbcBqu3zAz8ItOAADsC5E+9639RG1E5atMag4o5yfqENNmB/+o8X/uWNYxePAvvaE+wedSzRmlXzf2Y+Dn8HzMVX+1I5zpQclXACBmAS8gI4CKDgJ6z5axJWIH6AlAVsLN6FtjfZAaQcUCGy64B1gjYtYXmHJmCiiHwzMiYgvuOxxMvfiUnio3KWXPAQN8KlTt/RzCMoJYxCyxoX20xoG5jkKHwylEOrz/Zs6wPno42VxZjwbxzbdh1s2MColzeqYD2j3KSdOZS2v1KrAJuX+ngNHqrAp3rgc2F4hSgqsIcA32euWDBP4JXBL1ruWoUdsyAZzIiM4FMhpcr0sM+Z/XJ8lm4zubx2mzReohyrZuUNas2l7fR0d7w+tt1YLBtd7X37TynXvxK3ixWKUPGwJYzt7pRHa+uBXUPSNEtO6pTMQMI1KNy1NdPOYqx46n0H4G9Yr5QLg/eWbPgwbuyftezgN0/bBx7znTnY9v9WtxfO/C/JvSLGu5cE0quLFYxBB5keQCYxXlwmYEgglYEv6i+BXsGmq2RQNCOyq821bxePUUPxYQh0GfLd02BYgiQKejaQ5UjSGm7kv8pdU68+JWcnaCkGAHWFCAIZAwBirkDpt9iBhTjYMG7agiiPBnYo7XmGQoW9Lv2j3rGKO2quR8d/1cO+0dPwkM717k22FwoTjEFNrZy2xvV8Z7vQOsdZiCD8shsIINgjQFqIzIBO+O3bSIjp8xpZgBRWQT5yhpejwa0N6qxzPGjtM3ke1JM98tfyYdio/IKhHWBPwufCP6vPNkNeRbD3qxHBgCZD8Y4MDEW7HfH7eWL2vBg3I47MwGKEWDXpJfTngdoXyCTUTlf2DYruV9R55cP+VdMwAs62blG2FwoTgGqO0xBZg4iAN4B4wy6vbII2tdYBP4o724uqwdjEBhtvRj07NqWjHFYc9m/vX97uddjoLr27VGC8lSOnhM5K/3oqHPi5a/krHwNYM1BdJOvgF8G82seFvq9OgimbR02/hOHYjvKUY6r/8h4qNqo+mfz7pkDG8/Ut3tSMQdX3a79o54PSrtq7tfE/9Lh/hrRX9rRzrWi5Mpif9kU7MBxB/wjc8C0cY0BxVbGypoFD/wZyFdjkCmIjIGyhhXTUI1ljidl/zL57ozpfvEr+VAsC/sRPFVMgG1TNQGqGfDAOILhLDYC8Qi8WSDP8lb6o4wt0tID9o5n3jqK1kO2Ttb9e9IEoP2jnCOduZR2Hxv75kP9saL+eMc61wybC8UpQMV+KajEWUD1QDSD0wxwWfj9xCGQjyC9Wi+D+cgInByrqnsG8r9iCtAeqhxbJ3JW+sHUOfHyZ3OiuG+bAAYAIxCOYNc+Z0yAGqMagqtPUb2ovGIkKiZANVYW5lkjt2MC1nFFphSZA6Yem4PZ+zYG7cdKztfXedNh/nqxf2gA3euGzYfinmAKEDwyhoGF8shYqPUvA8ECegT4nslYn6F6WX1mrJ72yERFRgDN47Wdo7jMYHh1bbw9LrK1j/bFmkuJZY+sEznZtlHciRe/khPFKjepWSy6ufVA0YIdA6MR5K6Ap0K9zancwCugrsReffrUqdTLdIpyojoWohX4Z+Y/Ww+2zPZFAW60J9ZcSuw3zgLU5mvKn3yIv0bEP9zRzvWj5KqAkVcne2bLsn9ngO9BbAS2FhJZeLb5qmbgyoPqo35F9VE9tv1Ivwj8M70zA2EBfdcgqGvQO1oqa1/NUznSlP1byV+p0wkSCH4UGIrASgGuXbhj6iOoR/CK6iugfbVlb/UVUK/GKvWQJt44sjpsmRdn11NmGKP1oKzJbF137x/lPDhxDijtvyL2iQf4K4SbTv4fBTrXEZsLxUXlDJBVbnsRKLLQGQEtC9IqKH/yXv9jYRz1hTET2ThR/soYM0PglUVGgDGFtm6Ua91Ehp9gxgAAIABJREFUzLq84qtr3zu2UK7KUXcip9KPEy9/JWcWG5Vlt/7r2FloY8APGQILwd2ga8GeAWVrIBRQr8ZmpobNabWraKsAP7tOopwZ2CtrWDUBjKH49lmgtP+a2G8f2q8RajoKFehcS0ouFLsDWRZYIxjrNgIZuKqgrJqLKD9qVy0/bQYy8xW1jUwBmmdvfbDmwTMQCP4ra/8uQ5CNBx4mhQAF1pX0St6KCYjgh4F5D7TYehmMstBv22dAPcodGQMPolGsYjKYWNUMMGNkNEbwj8ycXVvs2mDXJAv67B5i45j925mLae/1Mehl8voBzgBuV6BzTSm5stiojHkeAaCFHQYUM0DNDMBVxoD9bqzXxudZ9Dxr75SxsFqxxmKFa8YseHNSmXcPjNl1tfbZ28xoj6DyNacSqx4sp3KfeukreVGscpPqxbK3vFU49OrZZ1mMNQEewCP4VQHfA3T0LCqv1FPGmJmJCNiR3h6IM/OvGAQE+9V1b88OlEc5azpzKe2+PvbUAf16YWYA2wp0ri02F4pj4D+CLxbeFFNQNQeMKWBiPJC/2wygPjDj6Iqxc2/zVoxAZd1kBkBZw1XQR/to+3BYzKWa646XPdsGilNMgIU0BdpUs8DAP4L3qDwDX7aMMQYI4K/+RbmYNrwclXFHxiHT2CvL1oRqBOzaVNZqdd17ex3lYs+Hrjxsez8Xd8eh/3OizYBoBbrXF5svi1PLbDwD+ww0skbAwvKaOwJ3FOMBOPtsbTP6ewfwPzlR3qyvTJmiaaYlM8/XZqmaAhX+1fUdbWZ2r9GHARFo27z7Ba+0h2J34crC7iVfBnEMEHp5I0iPYJiBZBb8vVwMqD/VDDDaINBnzRprDrI4WxatM/Q8yhNte7R/iOPivyGduZR2fyr2Gwf+Twk4g6EU6FxnSq4KGHl1smesWfCgMoLJzChkt9U7EO0ZiwysGWhH/YnMDKrn9Svrv9UexWYGgDGDTIxiJGysZzDsRqysfW8zK/uNOgweGKTABIrtMgEeXCmwz4CiYgwQoFvAPWEGUB+QQfiUo5gM5rMxZfWiuWD0t7p6UF4xiBG8K+t33cpoX3j93j0K2DZ32/kT9f/CQf8nJvIlg+xcb0quChgxpqBy24tAkTECDKxaWEd1ds2AYhxQ7FrO9gsBfmQ8kC4WvDMz5uXywJ01kMwajIxC9pwxE4q5eMnx869uqjCRxatlLMBlUB+BIgJIBkJZaPbaiqAbgbYC+0rsp93/+Wf22XEx4L+Op6qphWRk+CrrxlubWR67UdS17Z0H6l5DZ0p3PtTez5crQPXzYswAb1Ggc80puVAsC14eZHmAmMXZMhUwGcPA3q5nYJ6VRfkj6GZh3OY9YQYybRhzUDF0ynqI1geC+GiNV9Z+dBigXLccIpuNqCBRhSEGwjLYZ8FPAUgEuQrcZ7nUMmsgELQrZqBqTiIt7HOkqTc/jHlg1wa7Tmw+a0ROmICozeoWVvdutZ0/V+8XDvY/N2k/NODO9cfmQnEKUEU3vMhYIJjMgBQZCRaeEfSyeVRTsGswKqYiGms2RqSPBfPMoClGIFpTKMd6LChrmKn3C8ZAhQgUH5UrzxHEeyCF6rDlCGCvthF0M+YBGYOoDcUQoP6y40C6sHk8XTJzUQH/Eyaguu69MwLlYlGmKw/b3p+MQ2D0J0WZQd+uQOc6ZHOhOAWoqgD3F0zBCv8VkI/qVHJZwN81A6wBiOY5MnYI/LP1xsB9de1nBwPKefuh8k+DKkgw8V4MawIiWM9gkAHFt5gABvwVE9AZa2E9utFXDMO17qM6zNxW14ZnJqNn2XNUZvc2s4fY86AzF9vmn4x76gH+Jyfjjw+6cy0qubLYHUNgwTOCNMZIVKEzq/cpY2//vbHY+gjO1/Lo79U4eH/vGgvFDFjt7PgiTa55zuKrJiBbU56BsH2xRwzaJ6jcO7IqdU4cfSpEMPEs8DMQxt7qIsi3ABvBpxeHQNrWYSAY3ZyfNANoPFn/1bFlerJzosytt6ZYY2nXhArvzN6I1nx1b7NtVvNPPaPAUw7umZhRAIFLRSFlfZ8yBbu3wqwRyOCUuQFnYjKYRsaiagCqJmM1DpE2zJiZmMgARHOvPlfMQ2QKKut7Z08qe6+yt706VYBA9Z5kAljQZOH/iuuC4W7Y9/pn22Ahnxlj1p6qqYXw6EtDBOsM7HtrMzOaihFA+2LNpcSi/d6ZC7U15f8o8I0De8QfBZAC3euSzYfionLvuX3GACADfSiPcoONAB0ZDLb+Jw7FRuXIDKzQr8SisWXGJ6trTcjOnGZ1UZlqCtDaj/KhvbxTj8m9Aw6ormICVlD0IAkBWvWW2AJuBqwe6CLARbfttj4D6ihnZCi8/n9iT5sBpJGde2ZOojrZc6XsWoPqGo7WcbQX0R5i9jDqq5JjYosKMC+AYuqpNgpsK9C5PpVclVtU1ih4sO4Bkwf9rBFY87HmgL0Bt2B/tZXVt6CPoF0xDmv7KK/aV6tjNMZM78o8suvh2mDRuvDKs2deu94mVvZSd/0O+EA5snLmJpYFPTYOGYUIhtf8CMCVWAW+2XYjqI/qI8NwjYeNs+PPxmjhldHf0zebf3Zt2DjbN7v/dtb+mgvlUV7+nbmUdid2UWD3UB8xR4E7FOhcp2wuFMfCfxfYISOQASlT9lQzcPUdgX7Hl4VMJ2RQ7DwjPaP4yvOszrU/vfVaMb3rfkd7RDkbvFzdkIDynTQBFfBTTQACeg+QK3WQGUAAzgB+1ldrHFB/7BgR6HvGhNHJi4nmPZpbD+5tf6vAr67vaP+ifaTs+85cSrsTaxToPMxH3FHgtAJd61XJg2KfZgqYLwFd0MsCMgPqCux7BoFpgzUWkT4I8FG5lxc982A++xLQ+ZXAmoxsf6N9cvps2AEXFZLQ1wFbzoKfF6caAg8cIzhnoBhBuQfaihnoiGXG0RWjwD2auyiXB/vZmqqaA1TP7qlOcO/M9a2z5afafeoB/lMiz2BaFehcs0ouFKvcvNpYD+AtiDF1PBBUnkWxGeQiAP6UI9PAgLxiFpT2MoNgQR31YQX3THd2TrI1EK0HZB4ywM/WOFr/XrutG19MxsJGFKc834H9DAgR2K8wlxkJ76bbg+MMmFE8YziUHKsJqdTzTIp9lhkdL7brmZ1zZg1k4K6s1XUb7e4RcUv+J5xts5J76mwowB7wG01M1VHgiAKda5fNheKicsYoZDe6URl6zkInA/QMGNuY698KnDPG4HTeylhZDT2N0LO1PPvblkV5rw2prFdUx25ytFdOHAoKaKgA5cXvmoAIAjOw94CUufW+6qnA79VjbvMRwKO8aznKxYyfiVG09WKj+WSfRzlt/XXvoHXp7bOOfaLuX6VNNffENyjwjQO7oduTYhT4jwLd65fNh+IUyMpueHcMwo5RyMCWhV4F6q+5/NTpMA5rPgvETBteHQ+sUV9RHQvYyLx5+WwOb19k6yjbR9k6R3vAHlFqPHvEKZCRxSrmgDUBLARW4X8FZq+tDvD32rjDDDBtWHhWgF+JvdairRPBe7Q+2HVj16IC/JU1vmsY0F5V9ijKNeWHFDh1QB/q7qQdBVwFOtexkqsKS5kByABRAT0L7RFIRnCPQJYxBV4MazQstCuAr8Sy/clyWq2qmjLmwK4B1kyielVTkNXLjitln615KmCB6lRgCwGbCoSZIWDKEDwr4KzcxEexKEdkMir1IlPE5vKMFAJ91sDZ3FFbKO7aA4pprewbtFdUBOnOp7Y/8aQC1QOZTD9ho8DtCnStaTWPagy8+OwZMhDoVjm6Hd4B1wjYWThmgJ+J8UAdGZFqXsUkMYaM0d9rE8F9NN+onjUkdgOjfYHK7zgQGABRoIq90WVBDxkFdGvtgeqnDqoXxWT1rMlgAVtpy8Yq/Ym0UMxPxQwgs4DgXllTXi5kDrI63h5k9gy7dztzsW1O3KYCTzi4N4cw1UeBfynQua6VXCiWNQAW2CIYzOIi6HuzKfCgf32GDIBX/9dMQQb7iqHcNQXe2jx9VCEIUQxABvbVMvY2OYLht5iAq5/oawVjAljzsaONBWvbJjILynrw+pmBvbpmxwScPmV+ND+Clx8d9gzrjyjQub7ZXCguKmeMQuW2F8G/ZzSYrwzRjXb2XC2L4F59bse41mf+zkxIlpsts/kj85d9achMgFIWQXy2rtGaR8aiehwh+M8giwUw20b2b3Tjr0Alc8vvQXcExSygr3EMzLN5I6hX2rBj29Eo0ykCdjS/HWtl3Qve+kZrHpWj/Kf3YjX/1DusAHuIH+7GpB8FjirQuc7ZXCjuaaaAMQAepGa38bsQXYV+9IUgMgBef1GsMkY1NtM7A3zGAHrQn5lNBujRmrebXIlXIMdCt3e4INBSyhmDwIIkAlwWviPYVeA7ikW39R1tdII/q2nVBNj1xqyHa02idabAO7tH2DjmpdyZi2lvYg4poBzGh7owaUeBWxToXOtKruqNqq3n5alAnwr9HpCqpkD9IpBBM3OTf6cZqI7NapjNS2XOWLNwwhR4OW/Z5OD/x5z5yQWCMxb0PPhXnyHorgBzB6ijfnWYCMbMVMZvITybE2TgxgTctaunneMKKFBzvDPTwChwgwKda17JVTEFyABcclkgtc9ZMPTyMJCa1fuUXf9b+5VBNGsG1jh0g8+YCK9dJW8E+DuGITNeyKhl845MAKq7blW0D1D5zrZnbiY7TEAGfgo0WpCOoLcKup/82U14B6irZqDSH6QLuu1ny712orlmjWCU0xqRdd0za9TuE2btZ21W953SbrWNqXezAicP6ZuHMs2NArQC3euezYfionLGFJz8SqACKbqZz/JV4Hs1G/ZvBPhKuTouxvB47Vf1zgA+Wh+qKfDir42H1rdiIKLNzIJIFpdBnQXBbhOQQe5VxoJsBP4KfCOw9/qE6ljDofQn0wd91WDqRqCemTR2DWRx3rqKnmXPUZndN+x+YV6enbmY9ibmRgWUw/vGbk1To8AtCnSufyVXFqsYggzkbJ7s39nNfgSYEehmIBuBelSHhW9rIKr1bD+qea88qhnI5kHRO5qz7Dkqy9aat1mV/dC52dkbVi+ucvMbAaD3tUD9KlA1BQp8I7BfzUA1VukPA/SRCUJzwQK/N3cehFfirrXOrtMq3HeCe2euzr0+uRoV+NaB3TiESTUKbCvQuQ/YXChOMQUM6F8iRTfEynMFWqtgXDUIFuAR4Gf9i3IpbWTtK2O088eYAy8/Wgcs9COzaTclWu/VTYxABX0FQJAXASbzXIX/FbxZKM7qRPCObtiZeqhd1Aaqj8Zf0dbLGc1jBPrZemEMplf/WvvZWkbrfN0/Sizad525UFtT/kUFTh3QXxzSND0KlBXo3A9sLhT3NFPgmYbsWXY7rt6cM/CsgHo19urHp743BvaZHY+ih4X2zKBFpkAxkZ5JYI1DtCHR2rf1WDBhDMAdJgABrYVAe+Nd/TKAQBuBetUMRHmZcXTFKHDP3OyzpoBZc/M1oPxqnoqnFVAP49P9mfyjwLcV6NwTSi4U65WzRsEDxQgmL/1V6EfAuWsK2PoIxCMDoNR7mhnYNQKZKVCAX1mj3fucgTHPACBTEOVFIGnLvXgE5dZMZMAcAbxnDFC7CtRbA4PaiwySOjYvT9cztCaidtj1ZU1gtBeq5ndnb7Ft7rQxdR+oAAKQB3Z5ujQK3KJA595QcmWxLPwjgGNvhD1DgKDfK6/ceCt1IsC3ffnEodjIFChmAcVGGjGGZzUi1rhlpgDNJVozXnn0rPJc2dSVn1N4ddhbXwt5FlxZCN0FXrW+CuqKoVihv1LPasZ8GYiMBJofZNyi+sgUZOsnA34E3Kh83StKLNpjnblQW1P+MAUUSHlY16c7o8AtCnTvETbfKVMQwbwFOMYwqF8PGFi1wO4BvQLTDNyz8M4YCRRjYZ6Nj3SItFCMQsUIVL4CsGuf3dgdpiD7ooAgMrvtR+DKwK8ao97or0CfwbnNy5oSpv9eHzJdUU7WmCmgH+WMgD9alwi2UXlmMNg9Y+PYNqv5p95LFOg+nF8y7OnmKCAr0LlXlFwVU8DAHWsKIpOAbpozo9BhCqpQbeFbMQLV2OzGf3ccmRlgzVo0x+o6sptKWefyhjQVFADLDICFxCrwR2YAwWx0m6/AehXyURvoC0DWbpYb1Yu0jOaKnTMPrqO14a0vtI7WJVoxrqfBfYzA7qnzQ/XvPKx/SLYZyh9WoHPPKLkqpoC5vY2gngVEFjgVc1C9Lc/A2iuLvkIwXxNYiK986WDMQ9S+ag7Yed41BteRoaz57JhBIKPCm/qFwIIxAlbGBDDA7IFzZCAQvEdfEjrbQLogIxDp7AG/11ZkGLLnSplnKLpNgO3P7usX7Z3d/FP/hQp0HcwvHPp0eRQoK9C5b5RcKJaB/wjKvNt6BICsEcgAlYFXBNQZmNv8kdFABoSp5/UD9Z392pCNo6qvnd/IGNp1xa4ztF7LG9Cp2PVlgIVM5qcsDOhmJoEtO2kGFMNgYZwxQEyMBe7MiKmGwANtL38E5Mq6Y01CJY7ZS2MCGJX+aMydh/UflXiG/cMKdO4fJVfXVwIWBtk4BJPM1wEF7CuAzEA/AnSlnGmvMmbl60E0f2i+snm/tjVjFNYjQFnn0dGBoEb9KmBBj/2ZCfo6wIKuAvOrwVBAXflKoLSRGZ6d8SOoZw1BlCczAdl6YEA9W59o7TL5K69Upd1K/qnzcgU6DuaXSzDdHwW2FejcR2wuFBeVM7e6ESTumAL2K0IFcpU6DJwrsO+BPNMGqmeNTsX4ZDm8MnZ+bZz378gsbG82J4FyO2tj2S8BHlRGpkGBYBWmIwNwyhigvFn/I81UfVjtM4iP5hmBP2MsryWJgBuVs3mUPcS2qeSc2B9UAAHFDw55hjQKHFGgey+x+SpfCSJ4y255uwyCBe0IQBnAZ2I86GafRVC/axbW9pFxiICeGXtmwFhzlhmEDPir6xJtTgQ3DLxFhgAZgwxKM8Bl4Bfd3HvQzRiDU/UqoM/oYIE4MlwV8GeNoM2NIL2yJr11jvKgvbGWd+ZS2p3YlyrAAsdLhzfdHgVuV6BzTym5KvDFfCXwYNSDQMZIsAAagW4FjDNoRlCvQDvKFZWrZoAxAVanzICxc+IZyGzO7cZT1rKyaatfBRTwr5oAD8RRrm7Av9sMVMacaRJBf3X+MrORQb+yzpB5GCOg7PCJvUWBUwf0LZ2fRkaBByvQubeUXKdMgQeNyBREdTI4XQHc5lfBPjIPtg0E5J9yBPteTiZvZDgqxkcdrxePnnlzvtZZtySzbpkYC4TRtle/CiCgZG6l2dvuTxwTa83A7hcDxgywXzWY/u+aAc8Y7BiCqK63ppj1w4C+ciuvxKLXXWcu1NaU/5gC7EH8Y8Oe4YwCtyjQub+UXCiW/SLgQZ4H8lmcLWOMAALSLlNwB+CzxiMyHFl9pgwZBAv3yMChuY6MQWQiqhsxA5/s5yAMHGYmYAd2GZjuNgORmYi+QFgYZ80IUw9BPaM7M38esEfGzzMF0bPsOWMS1rXeCe6duar7ceq9XAEEDS8f3nR/FHiEAp37jM2F4qJyxiiwXwkQ1COj4LUTPcsMQgTEFTOwAjiqr34ZYI2DHU9l7GhuGFPAGANkDnY3KPvzDQYGGRhlgN6CsWIg7BcEFsajLw8nzEA0nvV55auKpxsyEAj8o5wZvLNrqgr3nfDemWt3L079FyuAgOHFQ5uujwKPU6Bzv7G5UNwdpoABywz8mbIMzBV4RoBfNQMI9JV2s1yR8VGeR0bBgn1mCq/NV11/dvMi6GF+4hEZAsUEKGBvQTQzEtFNfacZUNpQ+q5qEpklC+jKfFnTEJmIbhPgtRu9eNAaVl5YnbmUdif2RxVAB/WPDnuGNQp8VYHOfafkymKfZgqUrwIK6KLb+sw4IGCPcqN6HtyjfipfA1Bsph9rALz1U1lvaGNmEGTLsn8zBiCDVuULAQL6znIlF2tOkA6KFhHw74A/O88RuDNGUjWna3wXuHflQXtsyv+gAgpI/EF5ZsijwFEFOvefkqsCaQzsZTfFu18HIihFoJuVK3URnK9Aj2Ijc8D2FeWP4D4zWLasOl/rhqmsM7Th7jADlZ+4RLfuFqRRnFJ+5f7U2TUBDNBbXZg6FsBtHc9oRHWy50qZNSQK6CtArsTurHtUd8pHAaiAAhAw2QSMAqOArED3HmTzobiofMcU2LoIOCvlDOAzMRaoWQD/xKHYyAyshoJtXxmLjY1Mg/c8MmPXgs/mljUIyuaJQKtySxxBrQeqCgBHYM/eyCvGQGmLbT8aP6sBAv3MGChwH31VsDl2TECUy1uzYwKUnTyxj1AAAcEjOjmdGAX+gAKde1HJVb29ZeDPg08LlRFkdhgBBLtVkFZu8BH4ewZAqVMdg4X4KE+HMfDmvGNLM4aAMQfMbTULwAyUszCumgH0deAC2upYdnRijYEH3Qzse2shm3u7/jKAZ+GejWPXfnc+tt2J+4MKKNDwB+WZIY8CtyvQuSeVXBVTwHwliGAyMgHq853bbgakWTCPoF4xDl4Oq5/96sCMIcqLzBIyDLY8gv7KOmRBSIVABmg9cFUAGkE5KvegHdX5lKOYXTPA6JLFIENgjQBjApB5uNYoYxwVg7ATi14q7NpHeaZ8FKAVUA5pOukEjgKjwLYCXXtTyYNio3LGFEQ3/Sr8ewCbQS0DvJ++7UC1BXQPvpGpQOUoJ9N/5fY/M1nRHFTMAFpzHuwxIOaBZHRTzBiEqhmoALpSR/l6YGGcGRMTY4E701M1BBnsszf/jGFk1lR0qHfBe1ee7ZfPJPh7CjAH8d9TZUY8CjxDgc79qeRCsQz8XwraWA8yPYj0zENkKJivAxZgo/zsTX5kMiJjUIF5ZBBQeTRmRi/WDGTGIDIH0dpAu075KYcHpBYsI9D1gJWFYntDj2D9aiuKy9rN2mLAvzKmTBu2DM2DNRfev7OvBlF99NwzHtma7IT3zlxoH035KPAvBdBLfyQbBUaB7yvQuU/ZXCguKmeMQgT1Fh4R/EcgWoHdnZv1yAAgY6EYhwzsWVMQ9ScyNjvz0W0EEMhVflJy8osAgnyvvFKnYjaQ2VFMgp0X9EUmmqfK/EXwHoE1Am5UjtZg5U3BtlnJPXVGAVoB9MKnE03gKDAKHFWge6+y+VDcCVMQfU1g4JT9otAF/yqkX/Gf9k+agbUd7+9IS8YwMPOwboZsPiubhvl5iAKdGcAqYIzA3MuFnik5mb6iLw3IKFThn5kPC/esQUCQjoAblaP8HWu4kmPqjAJtCqAXfVtDk2gUGAVaFOjcs0quLFYpy74cIGhEXwqqRsACfQb4USx7Ox9BOvqKUDUdyAgwpuhauN4Xl8wY2DK7AZT1lwGbV8bAZ9eXAQT0F+RW4j51WIBnzEDWF8YIZJp59VnAjwwemlsE6uq6iQ5p1jAwh3xnLqa9iRkFoALKYQyTTcAoMArcpkDn3lVyKeBvIXIVh739z2CzYg4Q+Cuwj3JVAJ81FWzcU82AsuYQ8FngVAG0agpYuPcAXAF8JVYFesVA2HlAhguVe/N6x9cABcaVWHT4d+ZCbU35KCApUDmQpQYmeBQYBY4p0Ll/lVwoNrv9t2JEpuDEV4IM3hHYV6D6bjOQ9ZH9AhDFefp4Zg/NW2YQ0UZRbnkZEI1AGAH1jgnwjIFtz34NYM0Ak5uNyTTwytAza9Dsv+8wAV4fojXXDe7d+dBemfJRQFIAvdSlZBM8CowCX1Ogcy+zuVBcVM6YhejWf4VS9W8vZ/ZMhXlkKNh8axz7BYDNbfto61lDEZkAdn7sHHkbJFtHCKLQz0iYn5+ot+MW1j2YZ555YL72pcN0KP2IAD37crJrAqL6EbhH60ExitkhjdabcsB35lLandhRQFYAvczlhFNhFBgFvqpA555mc6G4v2AKEGQjqGdhHhmFSj+sAYgMAmu+IgOA1om6cU4aAQ/UK2DNAn1kAhij0hVz6c98Mdk1Ab/8JWBMgLqTJ/7rCnQfzl8f0HRgFBgF/qNA195W8mSxapmNj26iK3EReFuQvpZSBuoIpJEJYOpHBoDpF5MfGQiki7fevPlW1hKzjRUzgH42xAD1rhnYNQYegKOvFKhOVB4ZgzW+8ndkImyudf7RPHtrRQFyJTZbl115mLU/MaNAqwLdh3Nr5ybZKDAKbCnQub+VXCr4R+YlA8odE6DALQJuBNLsTT5q51N+/U9ps2IGbB07P54xy+bjWsTKGkILn/m5CDIACO4RSGcGAoE/W1cxKXa8Sl0G/hU9PbifrwFoVU/5KPAlBToP5y8NYZodBUaBRIHuPc7mQ3FROXOj3PWVAOXJoJeFd894sF8LMuhnTcaOGaiYJgT+aF2wm5m5LUbwysIyMg0I/K/67C0+m2/HrCjwj3RUwN/OGzOPtq/RGmFv5tm4nbXI1p24UeARCnQdzI8YzHRiFBgFQgW69zqbr/KVYIXQdUDR7TO6lUY32awpsBCPQJ8xDAqsIxORtcf2xfYnG6OdJzQP0bxWti2CyAw6VyiPgLr6HN34MwYE5WBNgDIGLxY98yA90h3NFwL+DOAVuFdi0brszIXamvJR4KgC7Av9aCcm+SgwCtymQOeeV3JVTAHzlcCD1UtMBPkZzEbwHLWHQL3DOKA2dswA6p/VNDNGnv7rAlfWjbcxIghDN9hsOQPsFpRZgGdyMzFK+2tsZhAY+EcaKgZhnVtmTu1aUGBciUWHcWcu1NaUjwK3KLB7KN/SyWlkFBgF2hXo3PtsLhQXlTOmIAJ/BvijGPaLAnPrnuX6lCk5dkwBA/2MEVI0s4sXrYNssbPQaIF6B4hZ0M8AXQH8ztgM/hmwRzpaXSND4cV5xiF7xpgHb+10wXtXnvbDfBKOArsK7BzKu21P/VFgFPiuAp37X8mFYhn4v5Szsd6NtQVXxiCoRoCFbAb6o1zqzf9OWyrsR2YSFWJ/AAAPfUlEQVRMMXhoN7A/FUGQ65Vn0OvBuWoQOgE/608G/2wZMk4RsEe6R0aANXbfNgGZkUFrdspHgVcogF7KrxjEdHIUGAW2FOg8B5RcWawCkZEhqJiAKgQj8LaAj+LXciZWNQqsefFMl2e4sjnw5iF6Fi1kDxzRM2QKMjhGhqHDIKD2I4OiGAsL7tm4IhOQPVfKIhOBnrPlahxzaM7XAEaliXm9AsqL+/WDnQGMAqNAqED3WcDmQ3EnTAFrHk59HYhAnIF+BPFejmpery3GLHXAP9qqzK1yhxmI4HkFcgbOmRjVHEQ5vTyVZx5cM5pag4AgHQE3Kkf50Vryytk2K7mnzijwOAXQi/hxHZ4OjQKjwFEFus8ENl/lKwELnexPWFCcag6yePXmH5kAW14xBUwbkRnw5sKbU3Y9oEWufBWwcKr+JCiCdAXwlVjb3k5/lbFHsR7ce33KoJwxb3bOFSBXYitrC9WZ8lHg1Qp0HcyvFmE6PwqMAq4CneeDkqtiDBjw9H7egiCWNQAZSDOQ/Wkn+/lNt3lgvxZE8B8ZJ6SnXWjsushgz5Yxt9foZ0AWbNUvAQjoGXOAYiKTEvXdi89Af9cEVAyA12Z0PI8BmBfXKNCkAHsQNzU3aUaBUeBlCnSeEUouFMvA/yW1jX26KWDNAxvHgn8UFxkCr/1Ic88k7G4F5esAMgjo9h2BeWc5yrVjAiqGIKpjTUf073WeFVN3hwlQzMfuep36o8BjFUAv3Md2fDo2CowCtyrQeVYoubq+EjBAq5iH6Gacud1XIT6KZ9ryvjhEXzuYfDs6dhoCxQhY4EPgn8E2AvWOcqV/CO6RCYq0sWCP9EZGoMMEdIN755eFWw/jaWwU6FZAeSl3tz35RoFR4H0KdJ4ZbC4UF5UzXw/Yn7sg+I8gWQVs73ZevdnvMg9oTJkxyMAfzWe2K9ifnlQh+FOP+QlRB/RXTEdWRzE9HlhHP7fKfoa1YwIUuO8E985c7zvBp8ejgKPAzqE8go4Co8DfVaDz7GBzVb4SRFAa/XTIi981Ah6cR8CeAfiuKYi+CKh9yUxApuu6W9g5X+uwt8sZvCqgX4H1UybB6wt6FpmD7DlbB80LAm5UjvJXT16l3WobU28UeJ0ClQP5dYOcDo8Co8ARBTrPDyVXxRQwXwkiaM/gN4P3S/Ts6wAD4hbiWVNgczNmgOmPYgZsrF2IzLwjgGPh3wNdxhzsmIKrrm0nMg1ZWwj+q19DrjmJ6lvdvHgF3tF8ovyVw4xts5J76owCr1eAOYhfP8gZwCgwChxVoPMcUXKdMgUnfjqEvi4wPydaYxiwj0xDBvxqmQf7rPFaF6VXhwE49Fv2DPYrcM3e/EdQb+szRqPST8/4RMDeZQIi06DCPTPvyoHWnU9pe2JHgVcooLx4XzGg6eQoMAp8RYHus4TNh+KicgZYPUBH8MtCv81TAfdPnYop2AX+rE1Pn2tBorlSFy4yAgiiUTnz1YCFezYug3gmhwfkDOwzWmawz/6EC81xJ7h35kL9nvJR4NUKdB/OrxZjOj8KjALbCnSeKUquU18JPHCO4FaBZDaW/WKgmIITZiAyN+uCUuYTLcQI9Dxg7gTsys97PnXULxToJz+oPBuzUnbNA9Lbmy8FxpXY6tpA9aZ8FPizCnQezn9WxBn4KDAK/EuBzrOFzYXiOr4SWOjNIBh9JYiMBmsArClhvxScMgNIm8hEqduHucVmbsNXKK7CeuXrgdpWBO+MIbB1ozF7cZkRQPCOytc5V2KztdKVR12PEz8KvF4B9PJ8/QBnAKPAKPBVBbrOGCUPiv0LpiADfvWrRGZ4UJlnEOyCRPOFIM+WZ/9mAJr5Oc43TQBjDjITgMoyE5CZBlRm5x3Nq3JwdeZS2p3YUeAnFECH8E8McgYxCowCX1Wg85xRcn37p0O2ffSloFKufEVgYj0TgYA/6ve66Nh5u+JYuNv5SoCMAQP8KwBHPyFivwR4uSLwZ59ncRG8V34SpBgBdm6ZQ6szF9PexIwCP6kAe0D/5OBnUKPAKHCrAt3nDZsPxbFfCrw4D7AtPGcwnQG6Uo+57WdimDbR+LzyijGIFicLq+wXA2QKOoEftYXKn2YCFBhXYrODqSvPrYffNDYKPFkB9JJ8ct+nb6PAKPBOBTrPHSVX5UtBBLbqrf81U+j2P4JxVI8tV78OZOYAlSFTwJRb+GUNAmsEPNBHwM3e9LNxUXuRMcj6p5RdWrLmatVeAXIlFp1onblQW1M+CvwZBZQX6Z8RZQY6CowCtyjQef4ouSqmIPsqsIrV9aVgBWUE+kps9nVAacczN6xxsosrmw8G/tSfCqnwHf38R8nTdeOfmRzWPOyYANacKXHMYcOsAybPxIwCo4CjgPICHQFHgVFgFDihQNc5pORBsexPhzwAjqDaxjJxKqDv/BRIbQuNPTIM0RqymrMA2GUGPLhHEI/K15xKbGQ0IpC3hmXVGH0lyWLZskoce5aw64DNN3GjwChgFEAvxBFsFBgFRoE7FOg8i5RcKJb9IoDAuPKzIhXOUTwqX8fAxKIxq2agss4YI2DBOgNtD6pP/dxHNQfZOKo6ROaiCved4N6Zq7K2ps4o8GcUQC/CPyPEDHQUGAUeoUDnmcTmQnHKV4IMkDNDYOsxMK7EqGbkilf67I39tCGoQvAu4DOGYo1hwD+KV8yMFxs9y54zJsEeGF3w3pXnEQfadGIUeIMC6CX4hjFMH0eBUeD3FOg8m9hcKE4xBSx8ZybgtEHYzZ8ZH7sikbbVFcz+x6/RT2XY39kj88CYg522PDhnf/7DGqZ1DhQgV2LRPHfmQm1N+SgwCvyjwKkDegQeBUaBUWBXgc7zScmVxaplbzEFrDFQzMs6/4r+yrqpmIEMopkbfBXq1XgP/FezwcI9q43VmwVyNo6Zz85cTHsTMwqMAosCpw7oEXkUGAVGgS4FOs8pJZcK/haUr/F7eZif+Hj5mHpMDAv/6GdCa56KXrtrhAFedINegXW1DmtAVuj3TAEai1d/1TiDbhbI2Th2brvzse1O3CgwCvyjgPJiHNFGgVFgFPiWAt1nFZsPxe38dCgDaQThDPBHMZkRUMpY84M03FlT1VvyKpwzXw4skFfqZDki4K+CvgLjSiya185cqK0pHwVGgUSBk4f0CD8KjAKjQLcCnWeWkgvFotv/VYfqT4cUUGfbYOO6wB/pyK4XFXzRjXq3OWANAQL7qtm5dFR1ivTvBPfOXOx6mbhRYBQYMzBrYBQYBX5MgS6ojCDXkwu1qXwl8Nplb/JPmAKUE/X30uvOnwqpoHuHIXiDCYgMyGkjMCbgxw7hGc7vKIBebr8z0hnJKDAK/KoCXeeYkqcKvcwXhMwUIGjfuelX2o1MFNIQlTNrFEEl898ReECsmIW7YiNwZ8do9UTaXfFsXMd8MTkmZhQYBQ4q0HEwH+zepB4FRoFRgFKg8yxTcp00BTvg31n3mgD03zFEcd4EKhqv9RlIrf60hqkX/f4fmQuUG5kLBOlIF1SO8lOb0ASxbVZyT51RYBRoVKB6IDd2YVKNAqPAKNCiQPd5puR7iymwJqHyb68OawQUTbNFgUATwXcGvwjMO8t3+skAPNJJNVrMRlXaZPJNzCgwChxWoOtgPtzNST8KjAKjAK1A97nG5kNxqmHIflKk/tyIgf5qTGYOWJNAT64JVP+7gU91BsB3gd9rJ/uqwPaLhXcFyJVYNE+duVBbUz4KjAJNCqCXV1Mzk2YUGAVGgdsV6DzflFwoNipnn6u/7Wcgn/kJENu/daKRFl2LQjUFjCFAQM8C/J0mIOqTp3M3uHfn61obk2cUGAWAAncd1DMRo8AoMAp8S4HOc47NxcSpcI2AHZUzpoCN8eK+YQLsmlL/w1rGFHTEMDmusahjQPVYjar7c0xAVbmpNwo8RAHmhfWQrk43RoFRYBQoK9B51im5UKz60yEG1iumIIJ75udIFROAdPEmWoHO3S8FLLyjOFS+jvO0Cfi0pWiINltnLtTWlI8Co8BBBSoH8sHuTOpRYBQYBY4q0HnmKblQrGoKmK8KLMjvxF2ThcYXmY2dyWZgVAHs3djKz4EyQN8Zn9WVycXORWcuts2JGwVGgYMKMAf4weYn9SgwCowCX1Gg8+xTcqHYb5qCCNgZ4+FNIhpr98SrXwOu9tnbeyaOicnazczBqpcC5EosmpPOXKitKR8FRoGbFLj7sL5pWNPMKDAKjAJQge7zT8mHYlVTwII8+xUgypc9R2VoQmzfquCJ6ilfACI4R18BMqivmhbWKCCzgebBK0eaVnJOnVFgFHiIAuiF9JBuTjdGgVFgFDimQPc5qORDsXeagtMGAI1VnWAGUFGMYgxsrFIXgXy1n3eAO+qbOm8TPwqMAg9ToPtwftjwpjujwCgwCtAKdJ6HSi4mtssUeMBf+RnQbp/pSRECGWhVAd6DeOWnQGMChAmc0FFgFPiOAsyB/p2eTaujwCgwCnxHge5zUcnHxHbDu81XyZ99VWBmMWqTAfwoP6rLGgM2bu3HXT8FQmaD0Z7tt5pr4keBUeAlCjAvnpcMZbo5CowCo0CrAp3no5oLxe+Uq18ZdtqKJgTl9OohuO8yBaidijlgoR21fRLclbZbN9okGwVGge8qUDmQv9vjaX0UGAVGgXsV6Dwn1VxMPIpR4f9St/qFANU/NXsszKo/80Egj9pF5Si/1YvJp2jcnU9pe2JHgVHgAQqgl8gDujhdGAVGgVHg6wp0n5VqPiYexZwqR3mzyWPq7sDqqZ/rMH3qijn1NYDp39c33nRgFBgFzivAHMTnezEtjAKjwCjwDgW6z0w1HxOPYlD5ZyY6YpgcnbOO4BaVMzf0HTmYdk5+DWDG0Dkvk2sUGAUersDdh/XD5ZjujQKjwCgAFThxbqo52XgUh8pZY3CJxuRbBWbiVXjtjmfyMTHfNgGV9uFmmIBRYBR4vwLMQfz+Uc4IRoFRYBToV6D7/KzkY+swcUyMag5U8GdniYVvLx9Tl4lh4ZrNtfa1UifTrjsfO08TNwqMAi9QgD38XzCU6eIoMAqMAl9RoPscreRj63THXYKzee+eIAWC2Vg2jjULJ01ApQ93z9G0NwqMAl9W4KkH+JdlmeZHgVFgFJAV6D5Pq/nYemzcRwgldhWuWk8VXwH0KnyzbbBx1X6w2lT6weaeuFFgFPghBe46qH9IshnKKDAKjAKpAifO1UpOpY4Su2MOvr10FEBWYqs38GobjH4ncjLtTswoMAq8VAH1BfDSYU63R4FRYBQYBUQF/tL7YQBaXBwTPgqMAr+jwP8HCm5WgYkAQGAAAAAASUVORK5CYII=", "e": 1}], "layers": [{"ddd": 0, "ind": 1, "ty": 2, "nm": "pen 2", "refId": "image_0", "sr": 1, "ks": {"o": {"a": 0, "k": 100, "ix": 11}, "r": {"a": 1, "k": [{"i": {"x": [0.667], "y": [1]}, "o": {"x": [0.333], "y": [0]}, "t": 0, "s": [0]}, {"i": {"x": [0.667], "y": [1]}, "o": {"x": [0.333], "y": [0]}, "t": 5, "s": [-30]}, {"i": {"x": [0.667], "y": [1]}, "o": {"x": [0.333], "y": [0]}, "t": 10, "s": [-30]}, {"i": {"x": [0.667], "y": [1]}, "o": {"x": [0.333], "y": [0]}, "t": 14, "s": [-15]}, {"i": {"x": [0.667], "y": [1]}, "o": {"x": [0.333], "y": [0]}, "t": 18, "s": [-30]}, {"i": {"x": [0.667], "y": [1]}, "o": {"x": [0.333], "y": [0]}, "t": 22, "s": [-10]}, {"i": {"x": [0.667], "y": [1]}, "o": {"x": [0.333], "y": [0]}, "t": 26, "s": [-30]}, {"t": 30, "s": [0]}], "ix": 10}, "p": {"a": 1, "k": [{"i": {"x": 0.242, "y": 1}, "o": {"x": 0.333, "y": 0}, "t": 0, "s": [938.408, 323.652, 0], "to": [-84.752, -8.713, 0], "ti": [84.752, 8.713, 0]}, {"i": {"x": 0.667, "y": 0.667}, "o": {"x": 0.333, "y": 0.333}, "t": 5, "s": [429.893, 271.375, 0], "to": [0, 0, 0], "ti": [0, 0, 0]}, {"i": {"x": 0.667, "y": 0.569}, "o": {"x": 0.333, "y": 0}, "t": 10, "s": [429.893, 271.375, 0], "to": [21.151, 13.176, 0], "ti": [-44.46, -22.024, 0]}, {"i": {"x": 0.667, "y": 0.864}, "o": {"x": 0.333, "y": 0.237}, "t": 14, "s": [523.553, 301.389, 0], "to": [29.096, 14.413, 0], "ti": [-45.818, -50.49, 0]}, {"i": {"x": 0.667, "y": 0.893}, "o": {"x": 0.333, "y": 0.072}, "t": 18, "s": [663.591, 412.357, 0], "to": [1.634, 1.801, 0], "ti": [-48.996, 15.884, 0]}, {"i": {"x": 0.667, "y": 0.885}, "o": {"x": 0.333, "y": 0.189}, "t": 22, "s": [1002.192, 426.09, 0], "to": [49.726, -16.12, 0], "ti": [35.512, 24.795, 0]}, {"i": {"x": 0.667, "y": 1}, "o": {"x": 0.333, "y": 0.317}, "t": 26, "s": [946.246, 264.763, 0], "to": [-19.812, -13.833, 0], "ti": [-2.406, 1.06, 0]}, {"t": 30, "s": [938.408, 323.652, 0]}], "ix": 2}, "a": {"a": 0, "k": [81.222, 159.292, 0], "ix": 1}, "s": {"a": 0, "k": [100, 100, 100], "ix": 6}}, "ao": 0, "ip": 0, "op": 480, "st": 0, "bm": 0}, {"ddd": 0, "ind": 3, "ty": 4, "nm": "line", "sr": 1, "ks": {"o": {"a": 0, "k": 100, "ix": 11}, "r": {"a": 0, "k": 0, "ix": 10}, "p": {"a": 0, "k": [793.313, 548.688, 0], "ix": 2}, "a": {"a": 0, "k": [353.419, 144.6, 0], "ix": 1}, "s": {"a": 0, "k": [100, 100, 100], "ix": 6}}, "ao": 0, "shapes": [{"ty": "gr", "it": [{"ind": 0, "ty": "sh", "ix": 1, "ks": {"a": 0, "k": {"i": [[0, 0], [-116.849, -66.994], [-14.03, -0.479], [-4.382, 1.989], [-95.037, 54.53], [0.648, 5.836], [2.663, 2.088], [82.608, 45.053], [12.674, -7.604], [4.048, -15.548], [28.044, 0]], "o": [[116.849, 66.994], [4.046, 2.796], [10.696, 0.365], [95.037, -54.53], [2.35, -3.116], [-0.798, -7.183], [-11.764, -9.226], [-42.065, -9.348], [-23.37, 14.022], [-3.751, 14.41], [0, 0]], "v": [[-346.198, -77.303], [4.35, 123.678], [32.394, 133.026], [55.764, 128.352], [340.876, -35.238], [345.55, -49.26], [336.202, -63.281], [233.374, -124.043], [191.309, -91.325], [121.199, -91.325], [65.112, -58.607]], "c": false}, "ix": 2}, "nm": "Path 1", "mn": "ADBE Vector Shape - Group", "hd": false}, {"ty": "st", "c": {"a": 0, "k": [1, 1, 1, 1], "ix": 3}, "o": {"a": 0, "k": 100, "ix": 4}, "w": {"a": 0, "k": 3, "ix": 5}, "lc": 2, "lj": 2, "bm": 0, "nm": "Stroke 1", "mn": "ADBE Vector Graphic - Stroke", "hd": false}, {"ty": "tr", "p": {"a": 0, "k": [353.698, 140.891], "ix": 2}, "a": {"a": 0, "k": [0, 0], "ix": 1}, "s": {"a": 0, "k": [100, 100], "ix": 3}, "r": {"a": 0, "k": 0, "ix": 6}, "o": {"a": 0, "k": 100, "ix": 7}, "sk": {"a": 0, "k": 0, "ix": 4}, "sa": {"a": 0, "k": 0, "ix": 5}, "nm": "Transform"}], "nm": "Group 1", "np": 2, "cix": 2, "bm": 0, "ix": 1, "mn": "ADBE Vector Group", "hd": false}, {"ty": "tm", "s": {"a": 0, "k": 0, "ix": 1}, "e": {"a": 1, "k": [{"i": {"x": [0.667], "y": [1]}, "o": {"x": [0.333], "y": [0]}, "t": 0, "s": [100]}, {"i": {"x": [0.544], "y": [1]}, "o": {"x": [0.333], "y": [0]}, "t": 5, "s": [0]}, {"i": {"x": [0.561], "y": [1]}, "o": {"x": [0.644], "y": [0]}, "t": 10, "s": [0]}, {"t": 30, "s": [100]}], "ix": 2}, "o": {"a": 0, "k": 0, "ix": 3}, "m": 1, "ix": 2, "nm": "Trim Paths 1", "mn": "ADBE Vector Filter - Trim", "hd": false}], "ip": 0, "op": 480, "st": 0, "bm": 0}, {"ddd": 0, "ind": 4, "ty": 2, "nm": "rule", "refId": "image_1", "sr": 1, "ks": {"o": {"a": 0, "k": 100, "ix": 11}, "r": {"a": 0, "k": 0, "ix": 10}, "p": {"a": 1, "k": [{"i": {"x": 0.411, "y": 1}, "o": {"x": 0.536, "y": 0}, "t": 6, "s": [869.05, 575.269, 0], "to": [0, -12.161, 0], "ti": [0, 0, 0]}, {"i": {"x": 0.325, "y": 1}, "o": {"x": 0.603, "y": 0}, "t": 14, "s": [869.05, 502.3, 0], "to": [0, 0, 0], "ti": [0, -12.161, 0]}, {"t": 20, "s": [869.05, 575.269, 0]}], "ix": 2}, "a": {"a": 0, "k": [185.76, 107.761, 0], "ix": 1}, "s": {"a": 1, "k": [{"i": {"x": [0.411, 0.411, 0.667], "y": [1, 1, 1]}, "o": {"x": [0.536, 0.536, 0.333], "y": [0, 0, 0]}, "t": 6, "s": [100, 100, 100]}, {"i": {"x": [0.325, 0.325, 0.667], "y": [1, 1, 1]}, "o": {"x": [0.603, 0.603, 0.333], "y": [0, 0, 0]}, "t": 14, "s": [105, 105, 100]}, {"t": 20, "s": [100, 100, 100]}], "ix": 6}}, "ao": 0, "ip": 0, "op": 480, "st": 0, "bm": 0}, {"ddd": 0, "ind": 5, "ty": 2, "nm": "circle", "refId": "image_2", "sr": 1, "ks": {"o": {"a": 0, "k": 100, "ix": 11}, "r": {"a": 0, "k": 0, "ix": 10}, "p": {"a": 1, "k": [{"i": {"x": 0.356, "y": 1}, "o": {"x": 0.533, "y": 0}, "t": 4, "s": [829.036, 709.273, 0], "to": [0, -12.162, 0], "ti": [0, 0, 0]}, {"i": {"x": 0.252, "y": 1}, "o": {"x": 0.6, "y": 0}, "t": 12, "s": [829.036, 636.3, 0], "to": [0, 0, 0], "ti": [0, -12.162, 0]}, {"t": 18, "s": [829.036, 709.273, 0]}], "ix": 2}, "a": {"a": 0, "k": [74.402, 43.421, 0], "ix": 1}, "s": {"a": 1, "k": [{"i": {"x": [0.382, 0.382, 0.667], "y": [1, 1, 1]}, "o": {"x": [0.533, 0.533, 0.333], "y": [0, 0, 0]}, "t": 4, "s": [100, 100, 100]}, {"i": {"x": [0.287, 0.287, 0.667], "y": [1, 1, 1]}, "o": {"x": [0.6, 0.6, 0.333], "y": [0, 0, 0]}, "t": 12, "s": [105, 105, 100]}, {"t": 18, "s": [100, 100, 100]}], "ix": 6}}, "ao": 0, "ip": 0, "op": 480, "st": 0, "bm": 0}, {"ddd": 0, "ind": 6, "ty": 2, "nm": "circleshadow/graphic.ai", "cl": "ai", "refId": "image_3", "sr": 1, "ks": {"o": {"a": 1, "k": [{"i": {"x": [0.833], "y": [0.833]}, "o": {"x": [0.167], "y": [0.167]}, "t": 4, "s": [0]}, {"i": {"x": [0.833], "y": [0.833]}, "o": {"x": [0.167], "y": [0.167]}, "t": 12, "s": [25]}, {"t": 18, "s": [0]}], "ix": 11}, "r": {"a": 0, "k": 0, "ix": 10}, "p": {"a": 0, "k": [829.374, 702.742, 0], "ix": 2}, "a": {"a": 0, "k": [111, 79.5, 0], "ix": 1}, "s": {"a": 0, "k": [96.125, 96.125, 100], "ix": 6}}, "ao": 0, "ip": 0, "op": 480, "st": 0, "bm": 0}, {"ddd": 0, "ind": 7, "ty": 2, "nm": "trangle", "refId": "image_4", "sr": 1, "ks": {"o": {"a": 0, "k": 100, "ix": 11}, "r": {"a": 0, "k": 0, "ix": 10}, "p": {"a": 1, "k": [{"i": {"x": 0.38, "y": 1}, "o": {"x": 0.531, "y": 0}, "t": 2, "s": [658.173, 632.703, 0], "to": [0, -12.167, 0], "ti": [0, 0, 0]}, {"i": {"x": 0.284, "y": 1}, "o": {"x": 0.597, "y": 0}, "t": 10, "s": [658.173, 559.7, 0], "to": [0, 0, 0], "ti": [0, -12.167, 0]}, {"t": 16, "s": [658.173, 632.703, 0]}], "ix": 2}, "a": {"a": 0, "k": [122.162, 36.615, 0], "ix": 1}, "s": {"a": 1, "k": [{"i": {"x": [0.485, 0.485, 0.667], "y": [1, 1, 1]}, "o": {"x": [0.61, 0.61, 0.333], "y": [0, 0, 0]}, "t": 2, "s": [100, 100, 100]}, {"i": {"x": [0.425, 0.425, 0.667], "y": [1, 1, 1]}, "o": {"x": [0.703, 0.703, 0.333], "y": [0, 0, 0]}, "t": 10, "s": [105, 105, 100]}, {"t": 16, "s": [100, 100, 100]}], "ix": 6}}, "ao": 0, "ip": 0, "op": 480, "st": 0, "bm": 0}, {"ddd": 0, "ind": 8, "ty": 2, "nm": "trangleshadow/graphic.ai", "cl": "ai", "refId": "image_5", "sr": 1, "ks": {"o": {"a": 1, "k": [{"i": {"x": [0.833], "y": [0.833]}, "o": {"x": [0.167], "y": [0.167]}, "t": 2, "s": [0]}, {"i": {"x": [0.833], "y": [0.833]}, "o": {"x": [0.167], "y": [0.167]}, "t": 10, "s": [25]}, {"t": 16, "s": [0]}], "ix": 11}, "r": {"a": 0, "k": 0, "ix": 10}, "p": {"a": 0, "k": [520.816, 622.041, 0], "ix": 2}, "a": {"a": 0, "k": [293, 72.5, 0], "ix": 1}, "s": {"a": 0, "k": [100, 100, 100], "ix": 6}}, "ao": 0, "ip": 0, "op": 480, "st": 0, "bm": 0}, {"ddd": 0, "ind": 9, "ty": 2, "nm": "ruleshadow/graphic.ai", "cl": "ai", "refId": "image_6", "sr": 1, "ks": {"o": {"a": 1, "k": [{"i": {"x": [0.833], "y": [0.833]}, "o": {"x": [0.167], "y": [0.167]}, "t": 6, "s": [0]}, {"i": {"x": [0.833], "y": [0.833]}, "o": {"x": [0.167], "y": [0.167]}, "t": 14, "s": [25]}, {"t": 20, "s": [0]}], "ix": 11}, "r": {"a": 0, "k": 0, "ix": 10}, "p": {"a": 0, "k": [868.571, 577.959, 0], "ix": 2}, "a": {"a": 0, "k": [222, 144, 0], "ix": 1}, "s": {"a": 0, "k": [100, 100, 100], "ix": 6}}, "ao": 0, "ip": 0, "op": 480, "st": 0, "bm": 0}, {"ddd": 0, "ind": 10, "ty": 2, "nm": "board", "refId": "image_7", "sr": 1, "ks": {"o": {"a": 0, "k": 100, "ix": 11}, "r": {"a": 0, "k": 0, "ix": 10}, "p": {"a": 1, "k": [{"i": {"x": 0.536, "y": 1}, "o": {"x": 0.502, "y": 0}, "t": 0, "s": [804.165, 619.963, 0], "to": [0, -2.5, 0], "ti": [0, 0, 0]}, {"i": {"x": 0.493, "y": 1}, "o": {"x": 0.333, "y": 0}, "t": 8, "s": [804.165, 604.963, 0], "to": [0, 0, 0], "ti": [0, -2.5, 0]}, {"t": 14, "s": [804.165, 619.963, 0]}], "ix": 2}, "a": {"a": 0, "k": [352.643, 204.691, 0], "ix": 1}, "s": {"a": 1, "k": [{"i": {"x": [0.483, 0.483, 0.667], "y": [1, 1, 1]}, "o": {"x": [0.529, 0.529, 0.333], "y": [0, 0, 0]}, "t": 0, "s": [100, 100, 100]}, {"i": {"x": [0.422, 0.422, 0.667], "y": [1, 1, 1]}, "o": {"x": [0.594, 0.594, 0.333], "y": [0, 0, 0]}, "t": 8, "s": [105, 105, 100]}, {"t": 14, "s": [100, 100, 100]}], "ix": 6}}, "ao": 0, "ip": 0, "op": 480, "st": 0, "bm": 0}, {"ddd": 0, "ind": 11, "ty": 2, "nm": "shadow/graphic.ai", "cl": "ai", "parent": 10, "refId": "image_8", "sr": 1, "ks": {"o": {"a": 0, "k": 59, "ix": 11}, "r": {"a": 0, "k": 0, "ix": 10}, "p": {"a": 0, "k": [348.478, 435.728, 0], "ix": 2}, "a": {"a": 0, "k": [385.5, 188, 0], "ix": 1}, "s": {"a": 0, "k": [100, 100, 100], "ix": 6}}, "ao": 0, "ip": 0, "op": 480, "st": 0, "bm": 0}], "markers": []} \ No newline at end of file diff --git a/src/Artemis.UI/Assets/Animations/workshop-wizard.json b/src/Artemis.UI/Assets/Animations/workshop-wizard.json new file mode 100644 index 000000000..248ce1370 --- /dev/null +++ b/src/Artemis.UI/Assets/Animations/workshop-wizard.json @@ -0,0 +1 @@ +{"v":"5.7.6","fr":25,"ip":0,"op":150,"w":320,"h":200,"nm":"03_Expertise 02","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Line top","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":12,"s":[0]},{"t":13,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[160,26.042,0],"ix":2,"l":2},"a":{"a":0,"k":[150,176.042,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":12,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[149.984,176.037],[150.031,176.037]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":22,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[105,176.074],[195.028,176.085]],"c":false}]},{"t":32,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[149.984,176.037],[150.031,176.037]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125,0.113999998803,0.113999998803,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":12,"op":32,"st":12,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Picto check","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55,161,0],"ix":2,"l":2},"a":{"a":0,"k":[55,161,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[43.023,137.816],[50.776,145.569],[67.023,129.321]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":20,"op":150,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Right tube stroke","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55,161,0],"ix":2,"l":2},"a":{"a":0,"k":[55,161,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[7.72,3.989],[0,0],[0,0],[0,0],[0,-9.289],[-13.255,0],[0,13.255]],"o":[[0,0],[0,0],[0,0],[-7.719,3.989],[0,13.255],[13.255,0],[0,-9.289]],"v":[[11,-3.828],[11,-41.5],[-11,-41.5],[-11,-3.828],[-24,17.5],[0,41.5],[24,17.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125,0.113999998803,0.113999998803,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[55,119.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Glass stroke","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":40,"op":190,"st":40,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Liquid green mask","parent":6,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55,161,0],"ix":2,"l":2},"a":{"a":0,"k":[55,161,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[7.72,3.989],[0,0],[0,0],[0,0],[0,-9.289],[-13.255,0],[0,13.255]],"o":[[0,0],[0,0],[0,0],[-7.719,3.989],[0,13.255],[13.255,0],[0,-9.289]],"v":[[66,115.672],[66,78],[44,78],[44,115.672],[31,137],[55,161],[79,137]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.779999976065,0.922000002394,0.976000019148,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 2","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"fl","c":{"a":0,"k":[0.779999976065,0.922000002394,0.976000019148,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":70,"op":220,"st":70,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Liquid green","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[265,161,0],"ix":2,"l":2},"a":{"a":0,"k":[0.49,27.328,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.333,0.333],"y":[0,0]},"t":70,"s":[80,0]},{"t":100,"s":[80,74]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":70,"s":[0,27],"to":[0,-6.167],"ti":[0,6.167]},{"t":100,"s":[0,-10]}],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.113725490196,0.113725490196,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.525490196078,0.8,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0.49,0.328],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":220,"st":70,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Right tube","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":20,"s":[0]},{"i":{"x":[0.258],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":34,"s":[-20]},{"t":44,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.197,"y":1},"o":{"x":0.333,"y":0},"t":20,"s":[355,161,0],"to":[-15,0,0],"ti":[15,0,0]},{"t":34,"s":[265,161,0]}],"ix":2,"l":2},"a":{"a":0,"k":[55,161,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[2.761,0],[0,0],[0,2.761],[-2.761,0],[0,0],[0,-2.761]],"o":[[0,0],[-2.761,0],[0,-2.761],[0,0],[2.761,0],[0,2.761]],"v":[[10,5],[-10,5],[-15,0],[-10,-5],[10,-5],[15,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125,0.113999998803,0.113999998803,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[55,73],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Plug stoke","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,2.761],[-2.761,0],[0,0],[0,-2.761],[-2.761,0],[0,0]],"o":[[0,-2.761],[0,0],[-2.761,0],[0,2.761],[0,0],[-2.761,0]],"v":[[1.5,0],[6.5,-5],[-1.5,-5],[-6.5,0],[-1.5,5],[6.5,5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":30,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[46.5,73],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Plug light","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[2.761,0],[0,0],[0,2.761],[-2.761,0],[0,0],[0,-2.761]],"o":[[0,0],[-2.761,0],[0,-2.761],[0,0],[2.761,0],[0,2.761]],"v":[[10,5],[-10,5],[-15,0],[-10,-5],[10,-5],[15,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.779999976065,0.922000002394,0.976000019148,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[55,73],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Plug bg","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-11.977,0.816],[-4.224,8.569],[12.023,-7.679]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[55,137],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Cross","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[7.72,3.989],[0,0],[0,0],[0,0],[0,-9.289],[-13.255,0],[0,13.255]],"o":[[0,0],[0,0],[0,0],[-7.719,3.989],[0,13.255],[13.255,0],[0,-9.289]],"v":[[11,-3.828],[11,-41.5],[-11,-41.5],[-11,-3.828],[-24,17.5],[0,41.5],[24,17.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125,0.113999998803,0.113999998803,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[55,119.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Glass stroke","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-3.59],[5.523,0],[0,3.59],[-5.523,0]],"o":[[0,3.59],[-5.523,0],[0,-3.59],[5.523,0]],"v":[[10,0],[0,6.5],[-10,0],[0,-6.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":30,"ix":5},"r":1,"bm":3,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[55,127.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Glass light","np":2,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[7.72,3.989],[0,0],[0,0],[0,0],[0,-9.289],[-13.255,0],[0,13.255]],"o":[[0,0],[0,0],[0,0],[-7.719,3.989],[0,13.255],[13.255,0],[0,-9.289]],"v":[[11,-3.828],[11,-41.5],[-11,-41.5],[-11,-3.828],[-24,17.5],[0,41.5],[24,17.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.779999976065,0.922000002394,0.976000019148,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 2","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"fl","c":{"a":0,"k":[0.779999976065,0.922000002394,0.976000019148,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[55,119.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Glass bg","np":3,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false}],"ip":20,"op":150,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Picto cross","parent":11,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55,161,0],"ix":2,"l":2},"a":{"a":0,"k":[55,161,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[46.876,145.124],[63.124,128.876]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[46.876,128.876],[63.124,145.124]],"c":false},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":20,"op":170,"st":20,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Left tube stroke","parent":11,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55,161,0],"ix":2,"l":2},"a":{"a":0,"k":[55,161,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[7.72,3.989],[0,0],[0,0],[0,0],[0,-9.289],[-13.255,0],[0,13.255]],"o":[[0,0],[0,0],[0,0],[-7.719,3.989],[0,13.255],[13.255,0],[0,-9.289]],"v":[[66,115.672],[66,78],[44,78],[44,115.672],[31,137],[55,161],[79,137]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125,0.113999998803,0.113999998803,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":40,"op":190,"st":40,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Liquid red mask","parent":11,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55,161,0],"ix":2,"l":2},"a":{"a":0,"k":[55,161,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[7.72,3.989],[0,0],[0,0],[0,0],[0,-9.289],[-13.255,0],[0,13.255]],"o":[[0,0],[0,0],[0,0],[-7.719,3.989],[0,13.255],[13.255,0],[0,-9.289]],"v":[[66,115.672],[66,78],[44,78],[44,115.672],[31,137],[55,161],[79,137]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.779999976065,0.922000002394,0.976000019148,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 2","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"fl","c":{"a":0,"k":[0.779999976065,0.922000002394,0.976000019148,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":70,"op":220,"st":70,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Liquid red","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55,161,0],"ix":2,"l":2},"a":{"a":0,"k":[0.49,27.328,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.333,0.333],"y":[0,0]},"t":70,"s":[80,0]},{"t":100,"s":[80,28]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":70,"s":[0,27],"to":[0,-2.333],"ti":[0,2.333]},{"t":100,"s":[0,13]}],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.113725490196,0.113725490196,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.776470588235,0.035294117647,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0.49,0.328],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":220,"st":70,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Left tube","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":20,"s":[0]},{"i":{"x":[0.258],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":34,"s":[20]},{"t":44,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.197,"y":1},"o":{"x":0.333,"y":0},"t":20,"s":[-35,161,0],"to":[10.983,0,0],"ti":[-4.017,0,0]},{"t":34,"s":[55,161,0]}],"ix":2,"l":2},"a":{"a":0,"k":[55,161,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[2.761,0],[0,0],[0,2.761],[-2.761,0],[0,0],[0,-2.761]],"o":[[0,0],[-2.761,0],[0,-2.761],[0,0],[2.761,0],[0,2.761]],"v":[[10,5],[-10,5],[-15,0],[-10,-5],[10,-5],[15,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125,0.113999998803,0.113999998803,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[55,73],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Plug stoke","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,2.761],[-2.761,0],[0,0],[0,-2.761],[-2.761,0],[0,0]],"o":[[0,-2.761],[0,0],[-2.761,0],[0,2.761],[0,0],[-2.761,0]],"v":[[1.5,0],[6.5,-5],[-1.5,-5],[-6.5,0],[-1.5,5],[6.5,5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":30,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[46.5,73],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Plug light","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[2.761,0],[0,0],[0,2.761],[-2.761,0],[0,0],[0,-2.761]],"o":[[0,0],[-2.761,0],[0,-2.761],[0,0],[2.761,0],[0,2.761]],"v":[[10,5],[-10,5],[-15,0],[-10,-5],[10,-5],[15,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.779999976065,0.922000002394,0.976000019148,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[55,73],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Plug bg","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-8.124,8.124],[8.124,-8.124]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-8.124,-8.124],[8.124,8.124]],"c":false},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[55,137],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Cross","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[7.72,3.989],[0,0],[0,0],[0,0],[0,-9.289],[-13.255,0],[0,13.255]],"o":[[0,0],[0,0],[0,0],[-7.719,3.989],[0,13.255],[13.255,0],[0,-9.289]],"v":[[11,-3.828],[11,-41.5],[-11,-41.5],[-11,-3.828],[-24,17.5],[0,41.5],[24,17.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125,0.113999998803,0.113999998803,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[55,119.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Glass stroke","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-3.59],[5.523,0],[0,3.59],[-5.523,0]],"o":[[0,3.59],[-5.523,0],[0,-3.59],[5.523,0]],"v":[[10,0],[0,6.5],[-10,0],[0,-6.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":30,"ix":5},"r":1,"bm":3,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[55,127.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Glass light","np":2,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[7.72,3.989],[0,0],[0,0],[0,0],[0,-9.289],[-13.255,0],[0,13.255]],"o":[[0,0],[0,0],[0,0],[-7.719,3.989],[0,13.255],[13.255,0],[0,-9.289]],"v":[[11,-3.828],[11,-41.5],[-11,-41.5],[-11,-3.828],[-24,17.5],[0,41.5],[24,17.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.779999976065,0.922000002394,0.976000019148,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 2","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"fl","c":{"a":0,"k":[0.779999976065,0.922000002394,0.976000019148,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[55,119.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Glass bg","np":3,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false}],"ip":20,"op":170,"st":20,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"Liquid stroke","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[159.97,144.056,0],"ix":2,"l":2},"a":{"a":0,"k":[-0.03,44.056,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":20,"s":[{"i":[[0,2.065],[1.271,0],[0.492,0],[0,0],[0,0]],"o":[[-1.226,0],[0.689,0],[0,0.698],[0,0],[0,0]],"v":[[15.077,32.985],[15.008,33.017],[15.055,33.002],[14.982,33.223],[15.001,33.219]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":23,"s":[{"i":[[0,9.375],[14.825,0],[-0.638,0],[0,0],[0,0]],"o":[[-9.96,0.057],[-15.008,0],[0,11.582],[0,0],[0,0]],"v":[[38.877,32.984],[0.008,33.017],[-38.946,33.002],[-38.936,56.556],[38.883,56.551]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":33,"s":[{"i":[[0,9.375],[15.075,6.983],[10.029,-7.085],[0,0],[0,0]],"o":[[-9.793,7.099],[-15.011,-6.954],[0,11.625],[0,0],[0,0]],"v":[[38.877,32.984],[0.008,33.017],[-38.946,33.002],[-38.936,56.556],[38.883,56.551]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":43,"s":[{"i":[[0,9.375],[15.023,-6.995],[9.925,7.019],[0,0],[0,0]],"o":[[-9.877,-6.984],[-14.998,6.983],[0,11.625],[0,0],[0,0]],"v":[[38.877,32.984],[0.008,33.017],[-38.946,33.002],[-38.936,56.556],[38.883,56.551]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":53,"s":[{"i":[[0,9.375],[15.008,-4.233],[9.904,4.248],[0,0],[0,0]],"o":[[-9.752,-4.026],[-15.008,4.233],[0,11.625],[0,0],[0,0]],"v":[[38.877,32.984],[0.008,33.017],[-38.946,33.002],[-38.936,56.556],[38.883,56.551]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":63,"s":[{"i":[[0,9.375],[14.825,0],[-0.638,0],[0,0],[0,0]],"o":[[-9.96,0.057],[-15.008,0],[0,11.582],[0,0],[0,0]],"v":[[38.877,32.984],[0.008,33.017],[-38.946,33.002],[-38.936,56.556],[38.883,56.551]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":70,"s":[{"i":[[0,9.375],[14.825,0],[-0.638,0],[0,0],[0,0]],"o":[[-9.96,0.057],[-15.008,0],[0,11.582],[0,0],[0,0]],"v":[[38.877,32.984],[0.008,33.017],[-38.946,33.002],[-38.936,56.556],[38.883,56.551]],"c":true}]},{"t":79,"s":[{"i":[[0.085,0.165],[-0.035,-0.119],[0.027,0.022],[0,0],[0,0]],"o":[[0.045,0.084],[-0.096,-0.14],[-0.034,-0.04],[0,0],[0,0]],"v":[[-21.779,32.896],[-21.679,33.14],[-21.68,33.019],[-21.609,32.74],[-21.712,32.629]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":36,"ix":2},"o":{"a":0,"k":4,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[0.1254902035,0.113725490868,0.113725490868,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":20,"op":79,"st":20,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"Liquid","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[159.97,144.056,0],"ix":2,"l":2},"a":{"a":0,"k":[-0.03,44.056,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":20,"s":[{"i":[[0,2.065],[1.271,0],[0.492,0],[0,0],[0,0]],"o":[[-1.226,0],[0.689,0],[0,0.698],[0,0],[0,0]],"v":[[15.077,32.985],[15.008,33.017],[15.055,33.002],[15.065,56.556],[15.084,56.552]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":23,"s":[{"i":[[0,9.375],[14.825,0],[-0.638,0],[0,0],[0,0]],"o":[[-9.96,0.057],[-15.008,0],[0,11.582],[0,0],[0,0]],"v":[[38.877,32.984],[0.008,33.017],[-38.946,33.002],[-38.936,56.556],[38.883,56.551]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":33,"s":[{"i":[[0,9.375],[15.075,6.983],[10.029,-7.085],[0,0],[0,0]],"o":[[-9.793,7.099],[-15.011,-6.954],[0,11.625],[0,0],[0,0]],"v":[[38.877,32.984],[0.008,33.017],[-38.946,33.002],[-38.936,56.556],[38.883,56.551]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":43,"s":[{"i":[[0,9.375],[15.023,-6.995],[9.925,7.019],[0,0],[0,0]],"o":[[-9.877,-6.984],[-14.998,6.983],[0,11.625],[0,0],[0,0]],"v":[[38.877,32.984],[0.008,33.017],[-38.946,33.002],[-38.936,56.556],[38.883,56.551]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":53,"s":[{"i":[[0,9.375],[15.008,-4.233],[9.904,4.248],[0,0],[0,0]],"o":[[-9.752,-4.026],[-15.008,4.233],[0,11.625],[0,0],[0,0]],"v":[[38.877,32.984],[0.008,33.017],[-38.946,33.002],[-38.936,56.556],[38.883,56.551]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":63,"s":[{"i":[[0,9.375],[14.825,0],[-0.638,0],[0,0],[0,0]],"o":[[-9.96,0.057],[-15.008,0],[0,11.582],[0,0],[0,0]],"v":[[38.877,32.984],[0.008,33.017],[-38.946,33.002],[-38.936,56.556],[38.883,56.551]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":70,"s":[{"i":[[0,9.375],[14.825,0],[-0.638,0],[0,0],[0,0]],"o":[[-9.96,0.057],[-15.008,0],[0,11.582],[0,0],[0,0]],"v":[[38.877,32.984],[0.008,33.017],[-38.946,33.002],[-38.936,56.556],[38.883,56.551]],"c":true}]},{"t":79,"s":[{"i":[[0.085,0.165],[-0.035,-0.119],[0.027,0.022],[0,0],[0,0]],"o":[[0.045,0.084],[-0.096,-0.14],[-0.034,-0.04],[0,0],[0,0]],"v":[[-21.779,32.896],[-21.679,33.14],[-21.68,33.019],[-21.67,56.573],[-21.773,56.463]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":54,"s":[0.007843137719,0.835294127464,0.933333337307,1]},{"t":78,"s":[1,0.341176480055,0.180392161012,1]}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"gr","it":[{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":20,"op":79,"st":20,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"Pad mask","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[160,84,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[320,112],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":14,"op":164,"st":14,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"Pad","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.82],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":24,"s":[40]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":44,"s":[-10]},{"t":74,"s":[25]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":14,"s":[160,-10,0],"to":[0,23.5,0],"ti":[0,-21.667,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":24,"s":[160,131,0],"to":[0,21.667,0],"ti":[0,-0.167,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":34,"s":[160,120,0],"to":[0,0.167,0],"ti":[0,-1.167,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":44,"s":[160,132,0],"to":[0,1.167,0],"ti":[0,0.833,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":56,"s":[160,127,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":61,"s":[160,127,0],"to":[0,7.5,0],"ti":[0,-7.5,0]},{"t":81,"s":[160,172,0]}],"ix":2,"l":2},"a":{"a":0,"k":[160,134,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-1.657],[1.657,0],[0,1.657],[-1.657,0]],"o":[[0,1.657],[-1.657,0],[0,-1.657],[1.657,0]],"v":[[3,0],[0,3],[-3,0],[0,-3]],"c":true},"ix":2},"nm":"Button top","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[1.657,0],[0,1.657],[-1.657,0],[0,-1.657]],"o":[[-1.657,0],[0,-1.657],[1.657,0],[0,1.657]],"v":[[6,9],[3,6],[6,3],[9,6]],"c":true},"ix":2},"nm":"Button right","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,-1.657],[1.657,0],[0,1.657],[-1.657,0]],"o":[[0,1.657],[-1.657,0],[0,-1.657],[1.657,0]],"v":[[3,12],[0,15],[-3,12],[0,9]],"c":true},"ix":2},"nm":"Button bottom","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[1.657,0],[0,1.657],[-1.657,0],[0,-1.657]],"o":[[-1.657,0],[0,-1.657],[1.657,0],[0,1.657]],"v":[[-6,9],[-9,6],[-6,3],[-3,6]],"c":true},"ix":2},"nm":"Button left","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[176.5,128],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Pad buttons","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[4.4,0],[0,0],[0,4.4],[-4.4,0],[0,-4.4]],"o":[[0,0],[-4.4,0],[0,-4.4],[4.4,0],[0,4.4]],"v":[[0,8],[0,8],[-8,0],[0,-8],[8,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[143.5,134],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Pad joystick","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[3.85,0],[0,0],[0,3.85],[0,0],[-3.85,0],[0,0],[0,-3.85],[0,0]],"o":[[0,0],[-3.85,0],[0,0],[0,-3.85],[0,0],[3.85,0],[0,0],[0,3.85]],"v":[[26,17],[-26,17],[-33,10],[-33,-10],[-26,-17],[26,-17],[33,-10],[33,10]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125,0.113999998803,0.113999998803,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[160,134],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Pad stroke","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[160,117],[160,151]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125,0.113999998803,0.113999998803,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Pad central line","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,3.85],[0,0],[-3.85,0],[0,0]],"o":[[0,0],[-3.85,0],[0,0],[0,-3.85],[0,0],[0,0]],"v":[[16.5,17],[-9.5,17],[-16.5,10],[-16.5,-10],[-9.5,-17],[16.5,-17]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.004000000393,0.263000009574,0.395999983245,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[143.5,134],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Pad left side bg","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[3.85,0],[0,0],[0,0],[0,0],[0,-3.85],[0,0]],"o":[[0,0],[0,0],[0,0],[3.85,0],[0,0],[0,3.85]],"v":[[9.5,17],[-16.5,17],[-16.5,-17],[9.5,-17],[16.5,-10],[16.5,10]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.340999977261,0.180000005984,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[176.5,134],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Pad right side bg","np":2,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false}],"ip":14,"op":164,"st":14,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"Cup liquid mask","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[160,140,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[320,120],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":4,"op":154,"st":4,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"Cup liquid","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.178,"y":1},"o":{"x":0.333,"y":0},"t":4,"s":[160,10,0],"to":[0,15,0],"ti":[0,-15,0]},{"t":14,"s":[160,100,0]}],"ix":2,"l":2},"a":{"a":0,"k":[160,100,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":22,"s":[{"i":[[5.522,0],[0,0],[0,5.522],[0,0],[-20.597,0],[-14.083,0],[0,0]],"o":[[0,0],[-5.523,0],[0,0],[15.999,0],[21.879,0],[0,0],[0,5.522]],"v":[[200,161],[120,161],[110,151],[110.001,120.006],[160.013,120.025],[209.999,120.024],[210,151]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":30,"s":[{"i":[[5.522,0],[0,0],[0,5.522],[0,0],[-20.705,-7.069],[-12.005,4.802],[0,0]],"o":[[0,0],[-5.523,0],[0,0],[14.304,-5.722],[20.705,7.069],[0,0],[0,5.522]],"v":[[200,161],[120,161],[110,151],[110.001,120.006],[160.013,120.025],[209.999,120.024],[210,151]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":46,"s":[{"i":[[5.522,0],[0,0],[0,5.522],[0,0],[-20.763,10.059],[-11.499,-5.94],[0,0]],"o":[[0,0],[-5.523,0],[0,0],[14.082,5.994],[19.69,-9.539],[0,0],[0,5.522]],"v":[[200,161],[120,161],[110,151],[110.001,120.006],[160.013,120.025],[209.999,120.024],[210,151]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[5.522,0],[0,0],[0,5.522],[0,0],[-20.597,0],[-14.083,0],[0,0]],"o":[[0,0],[-5.523,0],[0,0],[15.999,0],[21.879,0],[0,0],[0,5.522]],"v":[[200,161],[120,161],[110,151],[110.001,120.006],[160.013,120.025],[209.999,120.024],[210,151]],"c":true}]},{"t":90,"s":[{"i":[[5.522,0],[0,0],[0,5.522],[0,0],[-20.597,0],[-14.083,0],[0,0]],"o":[[0,0],[-5.523,0],[0,0],[15.999,0],[21.879,0],[0,0],[0,5.522]],"v":[[200,161],[120,161],[110,151],[110.001,138.006],[160.013,138.025],[209.999,138.024],[210,151]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.1254902035,0.113725490868,0.113725490868,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":54,"s":[0.007843137719,0.835294127464,0.933333337307,1]},{"t":78,"s":[1,0.341176480055,0.180392161012,1]}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Liquid","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":4,"op":154,"st":4,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"Straw right","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[160,100,0],"ix":2,"l":2},"a":{"a":0,"k":[160,100,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-4.694,0],[0,-4.694],[0,0],[-4.694,0],[0,4.694],[0,0],[-4.694,0],[0,-4.694],[0,0],[-4.694,0],[0,4.694],[0,0],[-4.697,-0.004],[0,-4.692],[0,0]],"o":[[0,0],[0,-4.694],[4.694,0],[0,0],[0,4.694],[4.694,0],[0,0],[0,-4.694],[4.694,0],[0,0],[0,4.694],[4.694,0],[0,0],[0,-4.697],[4.691,0.004],[0,0],[0,0]],"v":[[-42.5,74],[-42.5,-48],[-34,-56.5],[-25.5,-48],[-25.5,-33],[-17,-24.5],[-8.5,-33],[-8.5,-48],[0,-56.5],[8.5,-48],[8.5,-33],[17,-24.5],[25.5,-33],[25.5,-47.993],[34.007,-56.493],[42.5,-47.993],[42.5,12.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":75,"s":[0]},{"t":110,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":45,"s":[0]},{"t":75,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[0.525,0.8,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 2","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[222.5,75.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Straw color","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-4.694,0],[0,-4.694],[0,0],[-4.694,0],[0,4.694],[0,0],[-4.694,0],[0,-4.694],[0,0],[-4.694,0],[0,4.694],[0,0],[-4.697,-0.004],[0,-4.692],[0,0]],"o":[[0,0],[0,-4.694],[4.694,0],[0,0],[0,4.694],[4.694,0],[0,0],[0,-4.694],[4.694,0],[0,0],[0,4.694],[4.694,0],[0,0],[0,-4.697],[4.691,0.004],[0,0],[0,0]],"v":[[-42.5,74],[-42.5,-48],[-34,-56.5],[-25.5,-48],[-25.5,-33],[-17,-24.5],[-8.5,-33],[-8.5,-48],[0,-56.5],[8.5,-48],[8.5,-33],[17,-24.5],[25.5,-33],[25.5,-47.993],[34.007,-56.493],[42.5,-47.993],[42.5,12.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":43,"s":[0]},{"t":73,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[0.780392169952,0.921568632126,0.976470589638,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 2","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"st","c":{"a":0,"k":[0.125,0.113999998803,0.113999998803,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[222.5,75.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Straw bg","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":43,"op":193,"st":43,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"Straw left","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[160,100,0],"ix":2,"l":2},"a":{"a":0,"k":[160,100,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[4.418,0],[0,0],[0,-4.418],[-4.418,0],[0,0],[0,-4.418],[0,0],[4.418,0],[0,0],[0,-4.419],[0,0]],"o":[[0,0],[0,-4.418],[0,0],[-4.418,0],[0,4.418],[0,0],[4.418,0],[0,0],[0,4.418],[0,0],[-4.418,0],[0,0],[0,0]],"v":[[42.5,74],[42.5,-48.5],[34.5,-56.5],[-34.5,-56.5],[-42.5,-48.5],[-34.5,-40.5],[18.5,-40.5],[26.5,-32.5],[26.5,-32.321],[18.5,-24.321],[-34.5,-24.321],[-42.5,-16.321],[-42.5,12.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":65,"s":[0]},{"t":100,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":45,"s":[0]},{"t":75,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[0.776000019148,0.035000000748,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 2","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[97.5,75.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Straw color","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[4.418,0],[0,0],[0,-4.418],[-4.418,0],[0,0],[0,-4.418],[0,0],[4.418,0],[0,0],[0,-4.419],[0,0]],"o":[[0,0],[0,-4.418],[0,0],[-4.418,0],[0,4.418],[0,0],[4.418,0],[0,0],[0,4.418],[0,0],[-4.418,0],[0,0],[0,0]],"v":[[42.5,74],[42.5,-48.5],[34.5,-56.5],[-34.5,-56.5],[-42.5,-48.5],[-34.5,-40.5],[18.5,-40.5],[26.5,-32.5],[26.5,-32.321],[18.5,-24.321],[-34.5,-24.321],[-42.5,-16.321],[-42.5,12.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":43,"s":[0]},{"t":73,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[0.780392169952,0.921568632126,0.976470589638,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 2","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"st","c":{"a":0,"k":[0.125,0.113999998803,0.113999998803,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[97.5,75.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Straw bg","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":43,"op":193,"st":43,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"Top line","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":1,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[160,100,0],"ix":2,"l":2},"a":{"a":0,"k":[160,100,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[159,78],[161,78]],"c":false}]},{"t":8,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[104,78],[216,78]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125,0.113999998803,0.113999998803,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":0,"op":150,"st":0,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"Cup mask","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[160,140,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[320,120],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":4,"op":154,"st":4,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"Cup","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.178,"y":1},"o":{"x":0.333,"y":0},"t":4,"s":[160,10,0],"to":[0,15,0],"ti":[0,-15,0]},{"t":14,"s":[160,100,0]}],"ix":2,"l":2},"a":{"a":0,"k":[160,100,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[200,85.569],[200,99.569]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[200,107.791],[200,111.791]],"c":false},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Reflect","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.522,0],[0,0],[0,5.522],[0,0],[0,0],[0,0]],"o":[[0,0],[-5.523,0],[0,0],[0,0],[0,0],[0,5.522]],"v":[[40,41.5],[-40,41.5],[-50,31.5],[-50,-41.5],[50,-41.5],[50,31.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125,0.113999998803,0.113999998803,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[160,119.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Glass stroke","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,5.522],[0,0],[0,0],[0,0],[-5.523,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,5.522],[0,0],[-5.523,0]],"v":[[2,31.5],[2,-41.5],[-12,-41.5],[-12,31.5],[-2,41.5],[12,41.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":20,"ix":5},"r":1,"bm":3,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[122,119.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Light bg","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.522,0],[0,0],[0,5.522],[0,0],[0,0],[0,0]],"o":[[0,0],[-5.523,0],[0,0],[0,0],[0,0],[0,5.522]],"v":[[40,41.5],[-40,41.5],[-50,31.5],[-50,-41.5],[50,-41.5],[50,31.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.779999976065,0.922000002394,0.976000019148,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[160,119.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Glass bg","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":4,"op":154,"st":4,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":"Shadow","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[0]},{"t":5,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[160,176.042,0],"ix":2,"l":2},"a":{"a":0,"k":[150,176.042,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":4,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[149.25,176.042],[150.75,176.042]],"c":false}]},{"t":14,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[113,176.042],[187,176.042]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.917647063732,0.917647063732,0.917647063732,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":4,"op":149,"st":4,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/src/Artemis.UI/Assets/Fonts/RobotoMono-Bold.ttf b/src/Artemis.UI/Assets/Fonts/RobotoMono-Bold.ttf new file mode 100644 index 000000000..8eff26c1e Binary files /dev/null and b/src/Artemis.UI/Assets/Fonts/RobotoMono-Bold.ttf differ diff --git a/src/Artemis.UI/Assets/Fonts/RobotoMono-BoldItalic.ttf b/src/Artemis.UI/Assets/Fonts/RobotoMono-BoldItalic.ttf new file mode 100644 index 000000000..99299640b Binary files /dev/null and b/src/Artemis.UI/Assets/Fonts/RobotoMono-BoldItalic.ttf differ diff --git a/src/Artemis.UI/Assets/Fonts/RobotoMono-Italic.ttf b/src/Artemis.UI/Assets/Fonts/RobotoMono-Italic.ttf new file mode 100644 index 000000000..cf2b5b39c Binary files /dev/null and b/src/Artemis.UI/Assets/Fonts/RobotoMono-Italic.ttf differ diff --git a/src/Artemis.UI/Assets/Fonts/RobotoMono-Regular.ttf b/src/Artemis.UI/Assets/Fonts/RobotoMono-Regular.ttf new file mode 100644 index 000000000..d9371a1bd Binary files /dev/null and b/src/Artemis.UI/Assets/Fonts/RobotoMono-Regular.ttf differ diff --git a/src/Artemis.UI/Assets/Fonts/RobotoMono-SemiBold.ttf b/src/Artemis.UI/Assets/Fonts/RobotoMono-SemiBold.ttf new file mode 100644 index 000000000..06aea97f3 Binary files /dev/null and b/src/Artemis.UI/Assets/Fonts/RobotoMono-SemiBold.ttf differ diff --git a/src/Artemis.UI/Assets/Fonts/RobotoMono-SemiBoldItalic.ttf b/src/Artemis.UI/Assets/Fonts/RobotoMono-SemiBoldItalic.ttf new file mode 100644 index 000000000..72b0fc6d9 Binary files /dev/null and b/src/Artemis.UI/Assets/Fonts/RobotoMono-SemiBoldItalic.ttf differ diff --git a/src/Artemis.UI/Converters/DateTimeConverter.cs b/src/Artemis.UI/Converters/DateTimeConverter.cs new file mode 100644 index 000000000..7baf68ebb --- /dev/null +++ b/src/Artemis.UI/Converters/DateTimeConverter.cs @@ -0,0 +1,34 @@ +using System; +using System.Globalization; +using Artemis.WebClient.Workshop; +using Avalonia.Data.Converters; +using Humanizer; + +namespace Artemis.UI.Converters; + +public class DateTimeConverter : IValueConverter +{ + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + if (value is DateTimeOffset dateTimeOffset) + { + return parameter?.ToString() == "humanize" + ? dateTimeOffset.ToLocalTime().Humanize() + : dateTimeOffset.ToLocalTime().ToString(parameter?.ToString() ?? "g"); + } + + if (value is DateTime dateTime) + { + return parameter?.ToString() == "humanize" + ? dateTime.ToLocalTime().Humanize() + : dateTime.ToLocalTime().ToString(parameter?.ToString() ?? "g"); + } + + return value; + } + + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + return value; + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Converters/EntryIconUriConverter.cs b/src/Artemis.UI/Converters/EntryIconUriConverter.cs new file mode 100644 index 000000000..fdd185fec --- /dev/null +++ b/src/Artemis.UI/Converters/EntryIconUriConverter.cs @@ -0,0 +1,19 @@ +using System; +using System.Globalization; +using Artemis.WebClient.Workshop; +using Avalonia.Data.Converters; + +namespace Artemis.UI.Converters; + +public class EntryIconUriConverter : IValueConverter +{ + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + return $"{WorkshopConstants.WORKSHOP_URL}/entries/{value}/icon"; + } + + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + return value; + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Extensions/Bitmap.cs b/src/Artemis.UI/Extensions/Bitmap.cs new file mode 100644 index 000000000..e30bc754f --- /dev/null +++ b/src/Artemis.UI/Extensions/Bitmap.cs @@ -0,0 +1,48 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Avalonia.Media.Imaging; +using SkiaSharp; + +namespace Artemis.UI.Extensions; + +public class BitmapExtensions +{ + public static Bitmap LoadAndResize(string file, int size) + { + using SKBitmap source = SKBitmap.Decode(file); + return Resize(source, size); + } + + public static Bitmap LoadAndResize(Stream stream, int size) + { + stream.Seek(0, SeekOrigin.Begin); + using MemoryStream copy = new(); + stream.CopyTo(copy); + copy.Seek(0, SeekOrigin.Begin); + using SKBitmap source = SKBitmap.Decode(copy); + return Resize(source, size); + } + + private static Bitmap Resize(SKBitmap source, int size) + { + // Get smaller dimension. + int minDim = Math.Min(source.Width, source.Height); + + // Calculate crop rectangle position for center crop. + int deltaX = (source.Width - minDim) / 2; + int deltaY = (source.Height - minDim) / 2; + + // Create crop rectangle. + SKRectI rect = new(deltaX, deltaY, deltaX + minDim, deltaY + minDim); + + // Do the actual cropping of the bitmap. + using SKBitmap croppedBitmap = new(minDim, minDim); + source.ExtractSubset(croppedBitmap, rect); + + // Resize to the desired size after cropping. + using SKBitmap resizedBitmap = croppedBitmap.Resize(new SKImageInfo(size, size), SKFilterQuality.High); + + return new Bitmap(resizedBitmap.Encode(SKEncodedImageFormat.Png, 100).AsStream()); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Extensions/IActivatableViewModelExtensions.cs b/src/Artemis.UI/Extensions/IActivatableViewModelExtensions.cs new file mode 100644 index 000000000..8186b0222 --- /dev/null +++ b/src/Artemis.UI/Extensions/IActivatableViewModelExtensions.cs @@ -0,0 +1,15 @@ +using System; +using System.Reactive.Disposables; +using System.Threading.Tasks; +using Avalonia.Threading; +using ReactiveUI; + +namespace Artemis.UI.Extensions; + +public static class ActivatableViewModelExtensions +{ + public static void WhenActivatedAsync(this IActivatableViewModel item, Func block) + { + item.WhenActivated(d => Dispatcher.UIThread.InvokeAsync(async () => await block(d))); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Extensions/MaterialIconKindExtensions.cs b/src/Artemis.UI/Extensions/MaterialIconKindExtensions.cs new file mode 100644 index 000000000..c594ce7bc --- /dev/null +++ b/src/Artemis.UI/Extensions/MaterialIconKindExtensions.cs @@ -0,0 +1,35 @@ +using System; +using System.IO; +using Material.Icons; +using SkiaSharp; + +namespace Artemis.UI.Extensions; + +public static class MaterialIconKindExtensions +{ + public static Stream EncodeToBitmap(this MaterialIconKind icon, int size, int margin, SKColor color) + { + string geometrySource = MaterialIconDataProvider.GetData(icon); + + SKBitmap bitmap = new(size, size); + using (SKCanvas canvas = new(bitmap)) + { + canvas.Clear(SKColors.Transparent); + + // Parse and render the geometry data using SkiaSharp's SKPath + using SKPath path = SKPath.ParseSvgPathData(geometrySource); + using SKPaint paint = new() {Color = color, IsAntialias = true,}; + + // Calculate scaling and translation to fit the icon in the 100x100 area with 14 pixels margin + float scale = Math.Min(size / path.Bounds.Width, size / path.Bounds.Height); + path.Transform(SKMatrix.CreateTranslation(path.Bounds.Left * -1, path.Bounds.Top * -1)); + path.Transform(SKMatrix.CreateScale(scale, scale)); + canvas.Scale((size - margin * 2) / (float) size, (size - margin * 2) / (float) size, size / 2f, size / 2f); + canvas.DrawPath(path, paint); + } + + MemoryStream stream = new(); + bitmap.Encode(stream, SKEncodedImageFormat.Png, 100); + return stream; + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Extensions/ZipArchiveExtensions.cs b/src/Artemis.UI/Extensions/ZipArchiveExtensions.cs index 0d1fc507d..ad1900caa 100644 --- a/src/Artemis.UI/Extensions/ZipArchiveExtensions.cs +++ b/src/Artemis.UI/Extensions/ZipArchiveExtensions.cs @@ -2,6 +2,7 @@ using System; using System.IO; using System.IO.Compression; using System.Threading; +using Artemis.UI.Shared.Utilities; namespace Artemis.UI.Extensions; @@ -16,7 +17,7 @@ public static class ZipArchiveExtensions /// A boolean indicating whether to override existing files /// The progress to report to. /// A cancellation token - public static void ExtractToDirectory(this ZipArchive source, string destinationDirectoryName, bool overwriteFiles, IProgress progress, CancellationToken cancellationToken) + public static void ExtractToDirectory(this ZipArchive source, string destinationDirectoryName, bool overwriteFiles, IProgress progress, CancellationToken cancellationToken) { if (source == null) throw new ArgumentNullException(nameof(source)); @@ -28,7 +29,7 @@ public static class ZipArchiveExtensions { ZipArchiveEntry entry = source.Entries[index]; entry.ExtractRelativeToDirectory(destinationDirectoryName, overwriteFiles); - progress.Report((index + 1f) / source.Entries.Count * 100f); + progress.Report(new StreamProgress(index + 1, source.Entries.Count)); cancellationToken.ThrowIfCancellationRequested(); } } diff --git a/src/Artemis.UI/MainWindow.axaml b/src/Artemis.UI/MainWindow.axaml index f91d7815a..70f2b258b 100644 --- a/src/Artemis.UI/MainWindow.axaml +++ b/src/Artemis.UI/MainWindow.axaml @@ -12,6 +12,9 @@ MinWidth="600" MinHeight="400" PointerReleased="InputElement_OnPointerReleased"> + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/SettingsView.axaml.cs b/src/Artemis.UI/Screens/Settings/SettingsView.axaml.cs index 75d3d5b12..6e04c8c28 100644 --- a/src/Artemis.UI/Screens/Settings/SettingsView.axaml.cs +++ b/src/Artemis.UI/Screens/Settings/SettingsView.axaml.cs @@ -3,8 +3,7 @@ using System.Reactive.Disposables; using Artemis.UI.Shared; using Avalonia.ReactiveUI; using Avalonia.Threading; -using FluentAvalonia.UI.Media.Animation; -using FluentAvalonia.UI.Navigation; +using FluentAvalonia.UI.Controls; using ReactiveUI; namespace Artemis.UI.Screens.Settings; @@ -19,6 +18,11 @@ public partial class SettingsView : ReactiveUserControl private void Navigate(ViewModelBase viewModel) { - Dispatcher.UIThread.Invoke(() => TabFrame.NavigateFromObject(viewModel, new FrameNavigationOptions {TransitionInfoOverride = new SlideNavigationTransitionInfo()})); + Dispatcher.UIThread.Invoke(() => TabFrame.NavigateFromObject(viewModel)); + } + + private void NavigationView_OnBackRequested(object? sender, NavigationViewBackRequestedEventArgs e) + { + ViewModel?.GoBack(); } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs b/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs index 2a747e5f9..3391aeab8 100644 --- a/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs @@ -4,39 +4,40 @@ using System.Linq; using System.Reactive.Disposables; using System.Threading; using System.Threading.Tasks; +using Artemis.UI.Routing; using Artemis.UI.Shared; using Artemis.UI.Shared.Routing; using ReactiveUI; namespace Artemis.UI.Screens.Settings; -public class SettingsViewModel : RoutableScreen, IMainScreenViewModel +public class SettingsViewModel : RoutableHostScreen, IMainScreenViewModel { private readonly IRouter _router; - private SettingsTab? _selectedTab; + private RouteViewModel? _selectedTab; public SettingsViewModel(IRouter router) { _router = router; - SettingTabs = new ObservableCollection + SettingTabs = new ObservableCollection { - new("general", "General"), - new("plugins", "Plugins"), - new("devices", "Devices"), - new("releases", "Releases"), - new("about", "About"), + new("General", "settings/general"), + new("Plugins", "settings/plugins"), + new("Devices", "settings/devices"), + new("Releases", "settings/releases"), + new("About", "settings/about"), }; // Navigate on tab change this.WhenActivated(d => this.WhenAnyValue(vm => vm.SelectedTab) .WhereNotNull() - .Subscribe(s => _router.Navigate($"settings/{s.Path}", new RouterNavigationOptions {IgnoreOnPartialMatch = true})) + .Subscribe(s => _router.Navigate(s.Path, new RouterNavigationOptions {IgnoreOnPartialMatch = true})) .DisposeWith(d)); } - public ObservableCollection SettingTabs { get; } + public ObservableCollection SettingTabs { get; } - public SettingsTab? SelectedTab + public RouteViewModel? SelectedTab { get => _selectedTab; set => RaiseAndSetIfChanged(ref _selectedTab, value); @@ -52,6 +53,11 @@ public class SettingsViewModel : RoutableScreen, IMain // Always show a tab, if there is none forward to the first if (SelectedTab == null) - await _router.Navigate($"settings/{SettingTabs.First().Path}"); + await _router.Navigate(SettingTabs.First().Path); + } + + public void GoBack() + { + _router.Navigate("workshop"); } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/Tabs/AboutTabView.axaml b/src/Artemis.UI/Screens/Settings/Tabs/AboutTabView.axaml index 8016a6b79..506c960d7 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/AboutTabView.axaml +++ b/src/Artemis.UI/Screens/Settings/Tabs/AboutTabView.axaml @@ -5,20 +5,21 @@ xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" xmlns:vm="clr-namespace:Artemis.UI.Screens.Settings;assembly=Artemis.UI" + xmlns:il="clr-namespace:AsyncImageLoader;assembly=AsyncImageLoader.Avalonia" x:DataType="vm:AboutTabViewModel" mc:Ignorable="d" d:DesignWidth="1000" d:DesignHeight="1400" x:Class="Artemis.UI.Screens.Settings.AboutTabView"> - + RenderOptions.BitmapInterpolationMode="HighQuality" /> Artemis 2 @@ -52,17 +53,9 @@ - + - + @@ -81,17 +74,9 @@ - + - + @@ -110,17 +95,9 @@ - + - + @@ -139,17 +116,9 @@ - + - + diff --git a/src/Artemis.UI/Screens/Settings/Tabs/AboutTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/AboutTabViewModel.cs index 8fa53983e..984187e6f 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/AboutTabViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/AboutTabViewModel.cs @@ -1,75 +1,15 @@ -using System; -using System.Reactive.Disposables; -using System.Reflection; -using System.Threading.Tasks; -using Artemis.Core; -using Artemis.UI.Shared; -using Avalonia.Media.Imaging; -using Flurl.Http; -using ReactiveUI; +using Artemis.Core; +using Artemis.UI.Shared.Routing; namespace Artemis.UI.Screens.Settings; -public class AboutTabViewModel : ActivatableViewModelBase +public class AboutTabViewModel : RoutableScreen { - private Bitmap? _darthAffeProfileImage; - private Bitmap? _drMeteorProfileImage; - private Bitmap? _kaiProfileImage; - private Bitmap? _robertProfileImage; - private string? _version; - public AboutTabViewModel() { DisplayName = "About"; - this.WhenActivated((CompositeDisposable _) => Task.Run(Activate)); - } - - public string? Version - { - get => _version; - set => RaiseAndSetIfChanged(ref _version, value); - } - - public Bitmap? RobertProfileImage - { - get => _robertProfileImage; - set => RaiseAndSetIfChanged(ref _robertProfileImage, value); - } - - public Bitmap? DarthAffeProfileImage - { - get => _darthAffeProfileImage; - set => RaiseAndSetIfChanged(ref _darthAffeProfileImage, value); - } - - public Bitmap? DrMeteorProfileImage - { - get => _drMeteorProfileImage; - set => RaiseAndSetIfChanged(ref _drMeteorProfileImage, value); - } - - public Bitmap? KaiProfileImage - { - get => _kaiProfileImage; - set => RaiseAndSetIfChanged(ref _kaiProfileImage, value); - } - - private async Task Activate() - { - AssemblyInformationalVersionAttribute? versionAttribute = typeof(AboutTabViewModel).Assembly.GetCustomAttribute(); Version = $"Version {Constants.CurrentVersion}"; - - try - { - RobertProfileImage = new Bitmap(await "https://avatars.githubusercontent.com/u/8858506".GetStreamAsync()); - RobertProfileImage = new Bitmap(await "https://avatars.githubusercontent.com/u/8858506".GetStreamAsync()); - DarthAffeProfileImage = new Bitmap(await "https://avatars.githubusercontent.com/u/1094841".GetStreamAsync()); - DrMeteorProfileImage = new Bitmap(await "https://avatars.githubusercontent.com/u/29486064".GetStreamAsync()); - KaiProfileImage = new Bitmap(await "https://i.imgur.com/8mPWY1j.png".GetStreamAsync()); - } - catch (Exception) - { - // ignored, unluckyyyy - } } + + public string Version { get; } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/Tabs/DevicesTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/DevicesTabViewModel.cs index 620da173e..e6c1366c1 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/DevicesTabViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/DevicesTabViewModel.cs @@ -8,7 +8,7 @@ using Artemis.Core; using Artemis.Core.Services; using Artemis.UI.DryIoc.Factories; using Artemis.UI.Screens.Device; -using Artemis.UI.Shared; +using Artemis.UI.Shared.Routing; using Artemis.UI.Shared.Services; using Avalonia.Threading; using DynamicData; @@ -16,7 +16,7 @@ using ReactiveUI; namespace Artemis.UI.Screens.Settings; -public class DevicesTabViewModel : ActivatableViewModelBase +public class DevicesTabViewModel : RoutableScreen { private readonly IDeviceVmFactory _deviceVmFactory; private readonly IRgbService _rgbService; diff --git a/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabViewModel.cs index 110c948e8..74adce108 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabViewModel.cs @@ -13,8 +13,8 @@ using Artemis.Core.Services; using Artemis.UI.Screens.StartupWizard; using Artemis.UI.Services.Interfaces; using Artemis.UI.Services.Updating; -using Artemis.UI.Shared; using Artemis.UI.Shared.Providers; +using Artemis.UI.Shared.Routing; using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services.Builders; using Avalonia.Threading; @@ -26,7 +26,7 @@ using Serilog.Events; namespace Artemis.UI.Screens.Settings; -public class GeneralTabViewModel : ActivatableViewModelBase +public class GeneralTabViewModel : RoutableScreen { private readonly IAutoRunProvider? _autoRunProvider; private readonly IDebugService _debugService; diff --git a/src/Artemis.UI/Screens/Settings/Tabs/PluginsTabView.axaml b/src/Artemis.UI/Screens/Settings/Tabs/PluginsTabView.axaml index 5e1b9c246..b9f28f4a6 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/PluginsTabView.axaml +++ b/src/Artemis.UI/Screens/Settings/Tabs/PluginsTabView.axaml @@ -25,14 +25,19 @@ - - + + + + + + + - + - - - + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/Tabs/PluginsTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/PluginsTabViewModel.cs index 217ca1383..6113a20b4 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/PluginsTabViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/PluginsTabViewModel.cs @@ -9,18 +9,17 @@ using Artemis.Core; using Artemis.Core.Services; using Artemis.UI.DryIoc.Factories; using Artemis.UI.Screens.Plugins; -using Artemis.UI.Shared; +using Artemis.UI.Shared.Routing; using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services.Builders; using Avalonia.ReactiveUI; -using Avalonia.Threading; using DynamicData; using DynamicData.Binding; using ReactiveUI; namespace Artemis.UI.Screens.Settings; -public class PluginsTabViewModel : ActivatableViewModelBase +public class PluginsTabViewModel : RoutableScreen { private readonly INotificationService _notificationService; private readonly IPluginManagementService _pluginManagementService; diff --git a/src/Artemis.UI/Screens/Settings/Tabs/ReleasesTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/ReleasesTabViewModel.cs index fe6a1a532..d316b62a8 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/ReleasesTabViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/ReleasesTabViewModel.cs @@ -22,7 +22,7 @@ using StrawberryShake; namespace Artemis.UI.Screens.Settings; -public class ReleasesTabViewModel : RoutableScreen +public class ReleasesTabViewModel : RoutableHostScreen { private readonly ILogger _logger; private readonly IUpdateService _updateService; diff --git a/src/Artemis.UI/Screens/Settings/Updating/ReleaseDetailsView.axaml b/src/Artemis.UI/Screens/Settings/Updating/ReleaseDetailsView.axaml index 61fe4a5c1..ef4b22704 100644 --- a/src/Artemis.UI/Screens/Settings/Updating/ReleaseDetailsView.axaml +++ b/src/Artemis.UI/Screens/Settings/Updating/ReleaseDetailsView.axaml @@ -3,22 +3,23 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:updating="clr-namespace:Artemis.UI.Screens.Settings.Updating" - xmlns:avalonia="clr-namespace:Markdown.Avalonia;assembly=Markdown.Avalonia" - xmlns:avalonia1="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" - xmlns:converters="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared" - xmlns:converters1="clr-namespace:Artemis.UI.Converters" + xmlns:shared="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared" + xmlns:converters="clr-namespace:Artemis.UI.Converters" + xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" + xmlns:mdxaml="https://github.com/whistyun/Markdown.Avalonia.Tight" mc:Ignorable="d" d:DesignWidth="1000" d:DesignHeight="1400" x:Class="Artemis.UI.Screens.Settings.Updating.ReleaseDetailsView" x:DataType="updating:ReleaseDetailsViewModel"> - - + + + - @@ -103,16 +104,16 @@ - + Release date + Text="{CompiledBinding Release.CreatedAt, Converter={StaticResource DateTimeConverter}, FallbackValue=Loading...}" /> - + Source - + File size Release notes - - + + - - + + diff --git a/src/Artemis.UI/Screens/Settings/Updating/ReleaseDetailsViewModel.cs b/src/Artemis.UI/Screens/Settings/Updating/ReleaseDetailsViewModel.cs index 2ea6be462..2d9a1a413 100644 --- a/src/Artemis.UI/Screens/Settings/Updating/ReleaseDetailsViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Updating/ReleaseDetailsViewModel.cs @@ -18,7 +18,7 @@ using StrawberryShake; namespace Artemis.UI.Screens.Settings.Updating; -public class ReleaseDetailsViewModel : RoutableScreen +public class ReleaseDetailsViewModel : RoutableScreen { private readonly ObservableAsPropertyHelper _fileSize; private readonly ILogger _logger; diff --git a/src/Artemis.UI/Screens/Settings/Updating/ReleaseView.axaml b/src/Artemis.UI/Screens/Settings/Updating/ReleaseView.axaml index 97e58bd65..47a02b961 100644 --- a/src/Artemis.UI/Screens/Settings/Updating/ReleaseView.axaml +++ b/src/Artemis.UI/Screens/Settings/Updating/ReleaseView.axaml @@ -4,13 +4,17 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:updating="clr-namespace:Artemis.UI.Screens.Settings.Updating" xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" + xmlns:converters="clr-namespace:Artemis.UI.Converters" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="Artemis.UI.Screens.Settings.Updating.ReleaseView" x:DataType="updating:ReleaseViewModel"> + + + - + - + diff --git a/src/Artemis.UI/Screens/Settings/Updating/ReleaseView.axaml.cs b/src/Artemis.UI/Screens/Settings/Updating/ReleaseView.axaml.cs index 29e385e8a..02cd2454c 100644 --- a/src/Artemis.UI/Screens/Settings/Updating/ReleaseView.axaml.cs +++ b/src/Artemis.UI/Screens/Settings/Updating/ReleaseView.axaml.cs @@ -1,6 +1,4 @@ -using Avalonia; using Avalonia.Controls; -using Avalonia.Markup.Xaml; namespace Artemis.UI.Screens.Settings.Updating; @@ -10,9 +8,4 @@ public partial class ReleaseView : UserControl { InitializeComponent(); } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs b/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs index 0e5e5e8d4..032f93cbe 100644 --- a/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs +++ b/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs @@ -9,6 +9,7 @@ using Artemis.Core; using Artemis.Core.Modules; using Artemis.Core.Services; using Artemis.UI.DryIoc.Factories; +using Artemis.UI.Extensions; using Artemis.UI.Screens.VisualScripting; using Artemis.UI.Shared; using Artemis.UI.Shared.Services; @@ -52,9 +53,9 @@ public class ProfileConfigurationEditViewModel : DialogViewModelBase().First().ToString()) + + _profileConfiguration = profileConfiguration == ProfileConfiguration.Empty + ? profileService.CreateProfileConfiguration(profileCategory, "New profile", Enum.GetValues().First().ToString()) : profileConfiguration; _profileName = _profileConfiguration.Name; _iconType = _profileConfiguration.Icon.IconType; @@ -140,7 +141,7 @@ public class ProfileConfigurationEditViewModel : DialogViewModelBase Confirm { get; } public ReactiveCommand Delete { get; } public ReactiveCommand Cancel { get; } - + private async Task ExecuteDelete() { if (IsNew) @@ -148,7 +149,7 @@ public class ProfileConfigurationEditViewModel : DialogViewModelBase _iconType; set => RaiseAndSetIfChanged(ref _iconType, value); } - + public ProfileIconViewModel? SelectedMaterialIcon { get => _selectedMaterialIcon; @@ -244,7 +245,7 @@ public class ProfileConfigurationEditViewModel : DialogViewModelBase? _isCollapsed; private ObservableAsPropertyHelper? _isSuspended; private SidebarProfileConfigurationViewModel? _selectedProfileConfiguration; @@ -69,9 +69,9 @@ public class SidebarCategoryViewModel : ActivatableViewModelBase .WhereNotNull() .Subscribe(s => _router.Navigate($"profile-editor/{s.ProfileConfiguration.ProfileId}", new RouterNavigationOptions {IgnoreOnPartialMatch = true, RecycleScreens = false})) .DisposeWith(d); - + _router.CurrentPath.WhereNotNull().Subscribe(r => SelectedProfileConfiguration = ProfileConfigurations.FirstOrDefault(c => c.Matches(r))).DisposeWith(d); - + // Update the list of profiles whenever the category fires events Observable.FromEventPattern(x => profileCategory.ProfileConfigurationAdded += x, x => profileCategory.ProfileConfigurationAdded -= x) .Subscribe(e => profileConfigurations.Add(e.EventArgs.ProfileConfiguration)) @@ -89,12 +89,6 @@ public class SidebarCategoryViewModel : ActivatableViewModelBase _isCollapsed = ProfileCategory.WhenAnyValue(vm => vm.IsCollapsed).ToProperty(this, vm => vm.IsCollapsed).DisposeWith(d); _isSuspended = ProfileCategory.WhenAnyValue(vm => vm.IsSuspended).ToProperty(this, vm => vm.IsSuspended).DisposeWith(d); }); - - profileConfigurations.Edit(updater => - { - foreach (ProfileConfiguration profileConfiguration in profileCategory.ProfileConfigurations) - updater.Add(profileConfiguration); - }); } public ReactiveCommand ImportProfile { get; } @@ -144,7 +138,7 @@ public class SidebarCategoryViewModel : ActivatableViewModelBase { if (await _windowService.ShowConfirmContentDialog($"Delete {ProfileCategory.Name}", "Do you want to delete this category and all its profiles?")) { - if (ProfileCategory.ProfileConfigurations.Any(c => c.IsBeingEdited)) + if (ProfileCategory.ProfileConfigurations.Any(c => _profileService.FocusProfile == c)) await _router.Navigate("home"); _profileService.DeleteProfileCategory(ProfileCategory); } @@ -161,7 +155,7 @@ public class SidebarCategoryViewModel : ActivatableViewModelBase } private async Task ExecuteImportProfile() - { + { string[]? result = await _windowService.CreateOpenFileDialog() .HavingFilter(f => f.WithExtension("zip").WithExtension("json").WithName("Artemis profile")) .ShowAsync(); diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationViewModel.cs b/src/Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationViewModel.cs index 2d7a7712e..bfc179095 100644 --- a/src/Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationViewModel.cs +++ b/src/Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationViewModel.cs @@ -104,7 +104,7 @@ public class SidebarProfileConfigurationViewModel : ActivatableViewModelBase if (!await _windowService.ShowConfirmContentDialog("Delete profile", "Are you sure you want to permanently delete this profile?")) return; - if (ProfileConfiguration.IsBeingEdited) + if (_profileService.FocusProfile == ProfileConfiguration) await _router.Navigate("home"); _profileService.RemoveProfileConfiguration(ProfileConfiguration); } diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs b/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs index 0e8f7141d..f49cc0ec3 100644 --- a/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs +++ b/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs @@ -38,13 +38,15 @@ public class SidebarViewModel : ActivatableViewModelBase SidebarScreen = new SidebarScreenViewModel(MaterialIconKind.Abacus, ROOT_SCREEN, "", null, new ObservableCollection() { new(MaterialIconKind.HomeOutline, "Home", "home"), - #if DEBUG new(MaterialIconKind.TestTube, "Workshop", "workshop", null, new ObservableCollection { - new(MaterialIconKind.FolderVideo, "Profiles", "workshop/profiles/1", "workshop/profiles"), - new(MaterialIconKind.KeyboardVariant, "Layouts", "workshop/layouts/1", "workshop/layouts"), + new(MaterialIconKind.FolderVideo, "Profiles", "workshop/entries/profiles/1", "workshop/entries/profiles"), +#if DEBUG + new(MaterialIconKind.KeyboardVariant, "Layouts", "workshop/entries/layouts/1", "workshop/entries/layouts"), +#endif + new(MaterialIconKind.Bookshelf, "Library", "workshop/library"), }), - #endif + new(MaterialIconKind.Devices, "Surface Editor", "surface-editor"), new(MaterialIconKind.SettingsOutline, "Settings", "settings") }); @@ -119,7 +121,7 @@ public class SidebarViewModel : ActivatableViewModelBase { if (_updating) return; - + Dispatcher.UIThread.Invoke(async () => { try diff --git a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs index a6e28ea39..fadaaaf0e 100644 --- a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs +++ b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs @@ -10,6 +10,7 @@ using Artemis.Core.Services; using Artemis.UI.DryIoc.Factories; using Artemis.UI.Extensions; using Artemis.UI.Shared; +using Artemis.UI.Shared.Routing; using Artemis.UI.Shared.Services; using Avalonia; using ReactiveUI; @@ -17,7 +18,7 @@ using SkiaSharp; namespace Artemis.UI.Screens.SurfaceEditor; -public class SurfaceEditorViewModel : ActivatableViewModelBase, IMainScreenViewModel +public class SurfaceEditorViewModel : RoutableScreen, IMainScreenViewModel { private readonly IDeviceService _deviceService; private readonly IDeviceVmFactory _deviceVmFactory; diff --git a/src/Artemis.UI/Screens/VisualScripting/CableView.axaml b/src/Artemis.UI/Screens/VisualScripting/CableView.axaml index a54997cc1..31fedf0fa 100644 --- a/src/Artemis.UI/Screens/VisualScripting/CableView.axaml +++ b/src/Artemis.UI/Screens/VisualScripting/CableView.axaml @@ -41,7 +41,8 @@ Text="{CompiledBinding Converter={StaticResource SKColorToStringConverter}, Mode=OneWay}" VerticalAlignment="Center" HorizontalAlignment="Stretch" - FontFamily="Consolas" /> + FontFamily="{StaticResource RobotoMono}" + FontSize="13"/> - + - + - + - + diff --git a/src/Artemis.UI/Screens/Workshop/Categories/CategoriesView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Categories/CategoriesView.axaml.cs index 15ac17ab5..8cb505ab9 100644 --- a/src/Artemis.UI/Screens/Workshop/Categories/CategoriesView.axaml.cs +++ b/src/Artemis.UI/Screens/Workshop/Categories/CategoriesView.axaml.cs @@ -1,6 +1,5 @@ using Avalonia; using Avalonia.Input; -using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; namespace Artemis.UI.Screens.Workshop.Categories; @@ -12,10 +11,6 @@ public partial class CategoriesView : ReactiveUserControl InitializeComponent(); } - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } private void InputElement_OnPointerReleased(object? sender, PointerReleasedEventArgs e) { diff --git a/src/Artemis.UI/Screens/Workshop/Categories/CategoriesViewModel.cs b/src/Artemis.UI/Screens/Workshop/Categories/CategoriesViewModel.cs index a72737141..74d0f629e 100644 --- a/src/Artemis.UI/Screens/Workshop/Categories/CategoriesViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Categories/CategoriesViewModel.cs @@ -46,16 +46,16 @@ public class CategoriesViewModel : ActivatableViewModelBase private IReadOnlyList? CreateFilter() { - List categories = Categories.Where(c => c.IsSelected).Select(c => (int?) c.Id).ToList(); + List categories = Categories.Where(c => c.IsSelected).Select(c => (long?) c.Id).ToList(); if (!categories.Any()) return null; List categoryFilters = new(); - foreach (int? category in categories) + foreach (long? category in categories) { categoryFilters.Add(new EntryFilterInput { - Categories = new ListFilterInputTypeOfCategoryFilterInput {Some = new CategoryFilterInput {Id = new IntOperationFilterInput {Eq = category}}} + Categories = new ListFilterInputTypeOfCategoryFilterInput {Some = new CategoryFilterInput {Id = new LongOperationFilterInput {Eq = category}}} }); } diff --git a/src/Artemis.UI/Screens/Workshop/Categories/CategoryViewModel.cs b/src/Artemis.UI/Screens/Workshop/Categories/CategoryViewModel.cs index 08d991009..328b43c2a 100644 --- a/src/Artemis.UI/Screens/Workshop/Categories/CategoryViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Categories/CategoryViewModel.cs @@ -17,7 +17,7 @@ public class CategoryViewModel : ViewModelBase Icon = icon as MaterialIconKind? ?? MaterialIconKind.QuestionMarkCircle; } - public int Id { get; } + public long Id { get; } public string Name { get; } public MaterialIconKind Icon { get; } diff --git a/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserView.axaml b/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserView.axaml index 2b28230f7..0c14c271f 100644 --- a/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserView.axaml +++ b/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserView.axaml @@ -9,9 +9,9 @@ x:Class="Artemis.UI.Screens.Workshop.CurrentUser.CurrentUserView" x:DataType="currentUser:CurrentUserViewModel"> - + - + @@ -27,7 +27,7 @@ - + @@ -39,6 +39,7 @@ - - \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserViewModel.cs b/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserViewModel.cs index c204c3165..5d4fc9b80 100644 --- a/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserViewModel.cs @@ -5,9 +5,11 @@ using System.Reactive.Disposables; using System.Threading; using System.Threading.Tasks; using Artemis.UI.Shared; +using Artemis.UI.Shared.Services; using Artemis.WebClient.Workshop; using Artemis.WebClient.Workshop.Services; using Avalonia.Media.Imaging; +using FluentAvalonia.UI.Controls; using Flurl.Http; using ReactiveUI; using Serilog; @@ -16,67 +18,91 @@ namespace Artemis.UI.Screens.Workshop.CurrentUser; public class CurrentUserViewModel : ActivatableViewModelBase { - private readonly ILogger _logger; private readonly IAuthenticationService _authenticationService; - private bool _loading = true; + private readonly ObservableAsPropertyHelper _isAnonymous; + private readonly ILogger _logger; + private readonly IWindowService _windowService; + private bool _allowLogout = true; private Bitmap? _avatar; private string? _email; + private bool _loading = true; private string? _name; private string? _userId; - public CurrentUserViewModel(ILogger logger, IAuthenticationService authenticationService) + public CurrentUserViewModel(ILogger logger, IAuthenticationService authenticationService, IWindowService windowService) { _logger = logger; _authenticationService = authenticationService; + _windowService = windowService; Login = ReactiveCommand.CreateFromTask(ExecuteLogin); - this.WhenActivated(d => ReactiveCommand.CreateFromTask(ExecuteAutoLogin).Execute().Subscribe().DisposeWith(d)); + _isAnonymous = this.WhenAnyValue(vm => vm.Loading, vm => vm.Name, (l, n) => l || n == null).ToProperty(this, vm => vm.IsAnonymous); + + this.WhenActivated(d => + { + Task.Run(AutoLogin); + _authenticationService.IsLoggedIn.Subscribe(_ => Task.Run(LoadCurrentUser)).DisposeWith(d); + }); + } + + public bool IsAnonymous => _isAnonymous.Value; + + public bool AllowLogout + { + get => _allowLogout; + set => RaiseAndSetIfChanged(ref _allowLogout, value); } public bool Loading { get => _loading; - set => RaiseAndSetIfChanged(ref _loading, value); + private set => RaiseAndSetIfChanged(ref _loading, value); } public string? UserId { get => _userId; - set => RaiseAndSetIfChanged(ref _userId, value); + private set => RaiseAndSetIfChanged(ref _userId, value); } public string? Name { get => _name; - set => RaiseAndSetIfChanged(ref _name, value); + private set => RaiseAndSetIfChanged(ref _name, value); } public string? Email { get => _email; - set => RaiseAndSetIfChanged(ref _email, value); + private set => RaiseAndSetIfChanged(ref _email, value); } public Bitmap? Avatar { get => _avatar; - set => RaiseAndSetIfChanged(ref _avatar, value); + private set => RaiseAndSetIfChanged(ref _avatar, value); } public ReactiveCommand Login { get; } public void Logout() { - _authenticationService.Logout(); + if (AllowLogout) + _authenticationService.Logout(); } private async Task ExecuteLogin(CancellationToken cancellationToken) { - await _authenticationService.Login(); - await LoadCurrentUser(); + ContentDialogResult result = await _windowService.CreateContentDialog() + .WithViewModel(out WorkshopLoginViewModel _) + .WithTitle("Workshop login") + .ShowAsync(); + + if (result == ContentDialogResult.Primary) + await LoadCurrentUser(); } - private async Task ExecuteAutoLogin(CancellationToken cancellationToken) + private async Task AutoLogin() { try { @@ -95,21 +121,26 @@ public class CurrentUserViewModel : ActivatableViewModelBase private async Task LoadCurrentUser() { - if (!_authenticationService.IsLoggedIn) - return; - UserId = _authenticationService.Claims.FirstOrDefault(c => c.Type == "sub")?.Value; Name = _authenticationService.Claims.FirstOrDefault(c => c.Type == "name")?.Value; Email = _authenticationService.Claims.FirstOrDefault(c => c.Type == "email")?.Value; if (UserId != null) + { await LoadAvatar(UserId); + } + else + { + Avatar?.Dispose(); + Avatar = null; + } } private async Task LoadAvatar(string userId) { try { + Avatar?.Dispose(); Avatar = new Bitmap(await $"{WorkshopConstants.AUTHORITY_URL}/user/avatar/{userId}".GetStreamAsync()); } catch (Exception) diff --git a/src/Artemis.UI/Screens/Workshop/CurrentUser/WorkshopLoginView.axaml b/src/Artemis.UI/Screens/Workshop/CurrentUser/WorkshopLoginView.axaml new file mode 100644 index 000000000..538f4cccc --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/CurrentUser/WorkshopLoginView.axaml @@ -0,0 +1,17 @@ + + + + A browser window has opened where you'll be able to create an account and/or log in. + + + Waiting for log in... + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/CurrentUser/WorkshopLoginView.axaml.cs b/src/Artemis.UI/Screens/Workshop/CurrentUser/WorkshopLoginView.axaml.cs new file mode 100644 index 000000000..9d6092a7f --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/CurrentUser/WorkshopLoginView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.CurrentUser; + +public partial class WorkshopLoginView : ReactiveUserControl +{ + public WorkshopLoginView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/CurrentUser/WorkshopLoginViewModel.cs b/src/Artemis.UI/Screens/Workshop/CurrentUser/WorkshopLoginViewModel.cs new file mode 100644 index 000000000..793fedc6d --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/CurrentUser/WorkshopLoginViewModel.cs @@ -0,0 +1,49 @@ +using System; +using System.Reactive.Disposables; +using System.Threading; +using System.Threading.Tasks; +using Artemis.UI.Shared; +using Artemis.UI.Shared.Services; +using Artemis.UI.Shared.Services.Builders; +using Artemis.WebClient.Workshop.Services; +using Avalonia.Threading; +using FluentAvalonia.UI.Controls; +using ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.CurrentUser; + +public class WorkshopLoginViewModel : ContentDialogViewModelBase +{ + private readonly IAuthenticationService _authenticationService; + private readonly CancellationTokenSource _cts; + private readonly INotificationService _notificationService; + + public WorkshopLoginViewModel(IAuthenticationService authenticationService, INotificationService notificationService) + { + _authenticationService = authenticationService; + _notificationService = notificationService; + _cts = new CancellationTokenSource(); + + this.WhenActivated(d => + { + Dispatcher.UIThread.InvokeAsync(Login); + Disposable.Create(_cts, cts => cts.Cancel()).DisposeWith(d); + }); + } + + private async Task Login() + { + try + { + await _authenticationService.Login(_cts.Token); + _notificationService.CreateNotification().WithTitle("Login succeeded").WithSeverity(NotificationSeverity.Success).Show(); + ContentDialog?.Hide(ContentDialogResult.Primary); + } + catch (Exception e) + { + if (e is not TaskCanceledException) + _notificationService.CreateNotification().WithTitle("Login failed").WithMessage(e.Message).WithSeverity(NotificationSeverity.Error).Show(); + ContentDialog?.Hide(ContentDialogResult.Secondary); + } + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Entries/EntriesView.axaml b/src/Artemis.UI/Screens/Workshop/Entries/EntriesView.axaml new file mode 100644 index 000000000..ecc131eb9 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Entries/EntriesView.axaml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + diff --git a/src/Artemis.UI/Screens/Workshop/Entries/EntriesView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Entries/EntriesView.axaml.cs new file mode 100644 index 000000000..3f2106645 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Entries/EntriesView.axaml.cs @@ -0,0 +1,28 @@ +using System.Reactive.Disposables; +using Artemis.UI.Shared; +using Avalonia.ReactiveUI; +using Avalonia.Threading; +using FluentAvalonia.UI.Controls; +using ReactiveUI; +using System; + +namespace Artemis.UI.Screens.Workshop.Entries; + +public partial class EntriesView : ReactiveUserControl +{ + public EntriesView() + { + InitializeComponent(); + this.WhenActivated(d => { ViewModel.WhenAnyValue(vm => vm.Screen).WhereNotNull().Subscribe(Navigate).DisposeWith(d); }); + } + + private void Navigate(ViewModelBase viewModel) + { + Dispatcher.UIThread.Invoke(() => TabFrame.NavigateFromObject(viewModel)); + } + + private void NavigationView_OnBackRequested(object? sender, NavigationViewBackRequestedEventArgs e) + { + ViewModel?.GoBack(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Entries/EntriesViewModel.cs b/src/Artemis.UI/Screens/Workshop/Entries/EntriesViewModel.cs new file mode 100644 index 000000000..4ebd77ecc --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Entries/EntriesViewModel.cs @@ -0,0 +1,67 @@ +using System.Collections.ObjectModel; +using System.Linq; +using System.Reactive.Disposables; +using System.Threading; +using System.Threading.Tasks; +using Artemis.UI.Routing; +using Artemis.UI.Shared.Routing; +using ReactiveUI; +using System; +using System.Reactive.Linq; + +namespace Artemis.UI.Screens.Workshop.Entries; + +public class EntriesViewModel : RoutableHostScreen +{ + private readonly IRouter _router; + private RouteViewModel? _selectedTab; + private ObservableAsPropertyHelper? _viewingDetails; + + public EntriesViewModel(IRouter router) + { + _router = router; + + Tabs = new ObservableCollection + { + new("Profiles", "workshop/entries/profiles/1", "workshop/entries/profiles"), +#if DEBUG + new("Layouts", "workshop/entries/layouts/1", "workshop/entries/layouts") +#endif + }; + + this.WhenActivated(d => + { + // Show back button on details page + _viewingDetails = _router.CurrentPath.Select(p => p != null && p.Contains("details")).ToProperty(this, vm => vm.ViewingDetails).DisposeWith(d); + // Navigate on tab change + this.WhenAnyValue(vm => vm.SelectedTab) + .WhereNotNull() + .Subscribe(s => router.Navigate(s.Path, new RouterNavigationOptions {IgnoreOnPartialMatch = true, PartialMatchOverride = s.MatchPath})) + .DisposeWith(d); + }); + } + + public bool ViewingDetails => _viewingDetails?.Value ?? false; + public ObservableCollection Tabs { get; } + + public RouteViewModel? SelectedTab + { + get => _selectedTab; + set => RaiseAndSetIfChanged(ref _selectedTab, value); + } + + public override async Task OnNavigating(NavigationArguments args, CancellationToken cancellationToken) + { + SelectedTab = Tabs.FirstOrDefault(t => t.Matches(args.Path)); + if (SelectedTab == null) + await args.Router.Navigate(Tabs.First().Path); + } + + public void GoBack() + { + if (ViewingDetails) + _router.GoBack(); + else + _router.Navigate("workshop"); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Entries/EntryInstallationDialogView.axaml b/src/Artemis.UI/Screens/Workshop/Entries/EntryInstallationDialogView.axaml new file mode 100644 index 000000000..af75201c2 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Entries/EntryInstallationDialogView.axaml @@ -0,0 +1,8 @@ + + Welcome to Avalonia! + diff --git a/src/Artemis.UI/Screens/Workshop/Entries/EntryInstallationDialogView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Entries/EntryInstallationDialogView.axaml.cs new file mode 100644 index 000000000..b228f4b0f --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Entries/EntryInstallationDialogView.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Artemis.UI.Screens.Workshop.Entries; + +public partial class EntryInstallationDialogView : UserControl +{ + public EntryInstallationDialogView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Entries/EntryInstallationDialogViewModel.cs b/src/Artemis.UI/Screens/Workshop/Entries/EntryInstallationDialogViewModel.cs new file mode 100644 index 000000000..7b7cbca67 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Entries/EntryInstallationDialogViewModel.cs @@ -0,0 +1,8 @@ +using Artemis.UI.Shared; + +namespace Artemis.UI.Screens.Workshop.Entries; + +public class EntryInstallationDialogViewModel : ContentDialogViewModelBase +{ + +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Entries/EntryListView.axaml b/src/Artemis.UI/Screens/Workshop/Entries/EntryListItemView.axaml similarity index 67% rename from src/Artemis.UI/Screens/Workshop/Entries/EntryListView.axaml rename to src/Artemis.UI/Screens/Workshop/Entries/EntryListItemView.axaml index 9af92602f..2831515f6 100644 --- a/src/Artemis.UI/Screens/Workshop/Entries/EntryListView.axaml +++ b/src/Artemis.UI/Screens/Workshop/Entries/EntryListItemView.axaml @@ -3,42 +3,48 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" - xmlns:entries="clr-namespace:Artemis.UI.Screens.Workshop.Profile" xmlns:entries1="clr-namespace:Artemis.UI.Screens.Workshop.Entries" + xmlns:il="clr-namespace:AsyncImageLoader;assembly=AsyncImageLoader.Avalonia" + xmlns:converters="clr-namespace:Artemis.UI.Converters" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="110" - x:Class="Artemis.UI.Screens.Workshop.Entries.EntryListView" - x:DataType="entries1:EntryListViewModel"> - + + + + + + + + + Icon required + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + At least one category is required + + + + + + + + + + + Synchronized scrolling + + + + + + + + + + + + + + + + + + + + + A description is required + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Entries/EntrySpecificationsView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Entries/EntrySpecificationsView.axaml.cs new file mode 100644 index 000000000..b3289a3bf --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Entries/EntrySpecificationsView.axaml.cs @@ -0,0 +1,100 @@ +using System.Linq; +using Artemis.UI.Shared.Extensions; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Media; +using Avalonia.Media.Immutable; +using Avalonia.ReactiveUI; +using AvaloniaEdit.TextMate; +using ReactiveUI; +using TextMateSharp.Grammars; + +namespace Artemis.UI.Screens.Workshop.Entries; + +public partial class EntrySpecificationsView : ReactiveUserControl +{ + private ScrollViewer? _editorScrollViewer; + private ScrollViewer? _previewScrollViewer; + private bool _updating; + + public EntrySpecificationsView() + { + InitializeComponent(); + + DescriptionEditor.Options.AllowScrollBelowDocument = false; + RegistryOptions options = new(ThemeName.Dark); + TextMate.Installation? install = DescriptionEditor.InstallTextMate(options); + + install.SetGrammar(options.GetScopeByExtension(".md")); + + this.WhenActivated(_ => SetupScrollSync()); + } + + protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) + { + if (this.TryFindResource("SystemAccentColorLight3", out object? resource) && resource is Color color) + DescriptionEditor.TextArea.TextView.LinkTextForegroundBrush = new ImmutableSolidColorBrush(color); + + base.OnAttachedToVisualTree(e); + } + + private void SetupScrollSync() + { + if (_editorScrollViewer != null) + _editorScrollViewer.PropertyChanged -= EditorScrollViewerOnPropertyChanged; + if (_previewScrollViewer != null) + _previewScrollViewer.PropertyChanged -= PreviewScrollViewerOnPropertyChanged; + + _editorScrollViewer = DescriptionEditor.GetVisualChildrenOfType().FirstOrDefault(); + _previewScrollViewer = DescriptionPreview.GetVisualChildrenOfType().FirstOrDefault(); + + if (_editorScrollViewer != null) + _editorScrollViewer.PropertyChanged += EditorScrollViewerOnPropertyChanged; + if (_previewScrollViewer != null) + _previewScrollViewer.PropertyChanged += PreviewScrollViewerOnPropertyChanged; + } + + private void EditorScrollViewerOnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) + { + if (e.Property.Name != nameof(ScrollViewer.Offset) || _updating || SynchronizedScrolling.IsChecked != true) + return; + + try + { + _updating = true; + SynchronizeScrollViewers(_editorScrollViewer, _previewScrollViewer); + } + finally + { + _updating = false; + } + } + + private void PreviewScrollViewerOnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) + { + if (e.Property.Name != nameof(ScrollViewer.Offset) || _updating || SynchronizedScrolling.IsChecked != true) + return; + + try + { + _updating = true; + SynchronizeScrollViewers(_previewScrollViewer, _editorScrollViewer); + } + finally + { + _updating = false; + } + } + + private void SynchronizeScrollViewers(ScrollViewer? source, ScrollViewer? target) + { + if (source == null || target == null) + return; + + double sourceScrollableHeight = source.Extent.Height - source.Viewport.Height; + double targetScrollableHeight = target.Extent.Height - target.Viewport.Height; + + if (sourceScrollableHeight != 0) + target.Offset = new Vector(target.Offset.X, targetScrollableHeight * (source.Offset.Y / sourceScrollableHeight)); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Entries/EntrySpecificationsViewModel.cs b/src/Artemis.UI/Screens/Workshop/Entries/EntrySpecificationsViewModel.cs new file mode 100644 index 000000000..cc9d289eb --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Entries/EntrySpecificationsViewModel.cs @@ -0,0 +1,164 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reactive; +using System.Reactive.Disposables; +using System.Reactive.Linq; +using System.Threading.Tasks; +using Artemis.UI.Extensions; +using Artemis.UI.Screens.Workshop.Categories; +using Artemis.UI.Shared; +using Artemis.UI.Shared.Services; +using Artemis.WebClient.Workshop; +using Avalonia.Media.Imaging; +using AvaloniaEdit.Document; +using DynamicData; +using DynamicData.Aggregation; +using DynamicData.Binding; +using ReactiveUI; +using ReactiveUI.Validation.Extensions; +using ReactiveUI.Validation.Helpers; +using StrawberryShake; + +namespace Artemis.UI.Screens.Workshop.Entries; + +public class EntrySpecificationsViewModel : ValidatableViewModelBase +{ + private readonly ObservableAsPropertyHelper _categoriesValid; + private readonly ObservableAsPropertyHelper _iconValid; + private readonly ObservableAsPropertyHelper _descriptionValid; + private readonly IWorkshopClient _workshopClient; + private readonly IWindowService _windowService; + + private string _description = string.Empty; + private Bitmap? _iconBitmap; + private TextDocument? _markdownDocument; + private string _name = string.Empty; + private string _summary = string.Empty; + private bool _iconChanged; + + public EntrySpecificationsViewModel(IWorkshopClient workshopClient, IWindowService windowService) + { + _workshopClient = workshopClient; + _windowService = windowService; + SelectIcon = ReactiveCommand.CreateFromTask(ExecuteSelectIcon); + + Categories.ToObservableChangeSet() + .AutoRefresh(c => c.IsSelected) + .Filter(c => c.IsSelected) + .Transform(c => c.Id) + .Bind(out ReadOnlyObservableCollection selectedCategories) + .Subscribe(); + SelectedCategories = selectedCategories; + + this.ValidationRule(vm => vm.Name, s => !string.IsNullOrWhiteSpace(s), "Name is required"); + this.ValidationRule(vm => vm.Summary, s => !string.IsNullOrWhiteSpace(s), "Summary is required"); + ValidationHelper descriptionRule = this.ValidationRule(vm => vm.Description, s => !string.IsNullOrWhiteSpace(s), "Description is required"); + + // These don't use inputs that support validation messages, do so manually + ValidationHelper iconRule = this.ValidationRule(vm => vm.IconBitmap, s => s != null, "Icon required"); + ValidationHelper categoriesRule = this.ValidationRule(vm => vm.Categories, Categories.ToObservableChangeSet().AutoRefresh(c => c.IsSelected).Filter(c => c.IsSelected).IsNotEmpty(), + "At least one category must be selected" + ); + _iconValid = iconRule.ValidationChanged.Select(c => c.IsValid).ToProperty(this, vm => vm.IconValid); + _categoriesValid = categoriesRule.ValidationChanged.Select(c => c.IsValid).ToProperty(this, vm => vm.CategoriesValid); + _descriptionValid = descriptionRule.ValidationChanged.Select(c => c.IsValid).ToProperty(this, vm => vm.DescriptionValid); + + this.WhenActivatedAsync(async d => + { + // Load categories + await PopulateCategories(); + + MarkdownDocument = new TextDocument(new StringTextSource(Description)); + MarkdownDocument.TextChanged += MarkdownDocumentOnTextChanged; + Disposable.Create(() => + { + MarkdownDocument.TextChanged -= MarkdownDocumentOnTextChanged; + MarkdownDocument = null; + ClearIcon(); + }).DisposeWith(d); + }); + } + + public ReactiveCommand SelectIcon { get; } + + public ObservableCollection Categories { get; } = new(); + public ObservableCollection Tags { get; } = new(); + public ReadOnlyObservableCollection SelectedCategories { get; } + + public bool CategoriesValid => _categoriesValid.Value ; + public bool IconValid => _iconValid.Value; + public bool DescriptionValid => _descriptionValid.Value; + + public string Name + { + get => _name; + set => RaiseAndSetIfChanged(ref _name, value); + } + + public string Summary + { + get => _summary; + set => RaiseAndSetIfChanged(ref _summary, value); + } + + public string Description + { + get => _description; + set => RaiseAndSetIfChanged(ref _description, value); + } + + public Bitmap? IconBitmap + { + get => _iconBitmap; + set => RaiseAndSetIfChanged(ref _iconBitmap, value); + } + + public TextDocument? MarkdownDocument + { + get => _markdownDocument; + set => RaiseAndSetIfChanged(ref _markdownDocument, value); + } + + public bool IconChanged + { + get => _iconChanged; + private set => RaiseAndSetIfChanged(ref _iconChanged, value); + } + + public List PreselectedCategories { get; set; } = new(); + + private void MarkdownDocumentOnTextChanged(object? sender, EventArgs e) + { + Description = MarkdownDocument?.Text ?? string.Empty; + } + + private async Task ExecuteSelectIcon() + { + string[]? result = await _windowService.CreateOpenFileDialog() + .HavingFilter(f => f.WithExtension("png").WithExtension("jpg").WithExtension("bmp").WithName("Bitmap image")) + .ShowAsync(); + + if (result == null) + return; + + IconBitmap?.Dispose(); + IconBitmap = BitmapExtensions.LoadAndResize(result[0], 128); + IconChanged = true; + } + + private void ClearIcon() + { + IconBitmap?.Dispose(); + IconBitmap = null; + } + + private async Task PopulateCategories() + { + IOperationResult categories = await _workshopClient.GetCategories.ExecuteAsync(); + Categories.Clear(); + if (categories.Data != null) + Categories.AddRange(categories.Data.Categories.Select(c => new CategoryViewModel(c) {IsSelected = PreselectedCategories.Contains(c.Id)})); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Entries/Tabs/LayoutListView.axaml b/src/Artemis.UI/Screens/Workshop/Entries/Tabs/LayoutListView.axaml new file mode 100644 index 000000000..575f24ffc --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Entries/Tabs/LayoutListView.axaml @@ -0,0 +1,41 @@ + + + + + + Categories + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Entries/Tabs/LayoutListView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Entries/Tabs/LayoutListView.axaml.cs new file mode 100644 index 000000000..6b574bb29 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Entries/Tabs/LayoutListView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.Entries.Tabs; + +public partial class LayoutListView : ReactiveUserControl +{ + public LayoutListView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Entries/Tabs/LayoutListViewModel.cs b/src/Artemis.UI/Screens/Workshop/Entries/Tabs/LayoutListViewModel.cs new file mode 100644 index 000000000..a32408d09 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Entries/Tabs/LayoutListViewModel.cs @@ -0,0 +1,43 @@ +using System; +using Artemis.UI.Screens.Workshop.Categories; +using Artemis.UI.Shared.Routing; +using Artemis.UI.Shared.Services; +using Artemis.WebClient.Workshop; + +namespace Artemis.UI.Screens.Workshop.Entries.Tabs; + +public class LayoutListViewModel : EntryListViewModel +{ + /// + public LayoutListViewModel(IWorkshopClient workshopClient, + IRouter router, + CategoriesViewModel categoriesViewModel, + INotificationService notificationService, + Func getEntryListViewModel) + : base(workshopClient, router, categoriesViewModel, notificationService, getEntryListViewModel) + { + } + + #region Overrides of EntryListBaseViewModel + + /// + protected override string GetPagePath(int page) + { + return $"workshop/entries/layouts/{page}"; + } + + /// + protected override EntryFilterInput GetFilter() + { + return new EntryFilterInput + { + And = new[] + { + new EntryFilterInput {EntryType = new EntryTypeOperationFilterInput {Eq = WebClient.Workshop.EntryType.Layout}}, + base.GetFilter() + } + }; + } + + #endregion +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Entries/Tabs/ProfileListView.axaml b/src/Artemis.UI/Screens/Workshop/Entries/Tabs/ProfileListView.axaml new file mode 100644 index 000000000..e7b733741 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Entries/Tabs/ProfileListView.axaml @@ -0,0 +1,42 @@ + + + + + + Categories + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Entries/Tabs/ProfileListView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Entries/Tabs/ProfileListView.axaml.cs new file mode 100644 index 000000000..62adad88b --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Entries/Tabs/ProfileListView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.Entries.Tabs; + +public partial class ProfileListView : ReactiveUserControl +{ + public ProfileListView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Entries/Tabs/ProfileListViewModel.cs b/src/Artemis.UI/Screens/Workshop/Entries/Tabs/ProfileListViewModel.cs new file mode 100644 index 000000000..49df897db --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Entries/Tabs/ProfileListViewModel.cs @@ -0,0 +1,43 @@ +using System; +using Artemis.UI.Screens.Workshop.Categories; +using Artemis.UI.Shared.Routing; +using Artemis.UI.Shared.Services; +using Artemis.WebClient.Workshop; + +namespace Artemis.UI.Screens.Workshop.Entries.Tabs; + +public class ProfileListViewModel : EntryListViewModel +{ + /// + public ProfileListViewModel(IWorkshopClient workshopClient, + IRouter router, + CategoriesViewModel categoriesViewModel, + INotificationService notificationService, + Func getEntryListViewModel) + : base(workshopClient, router, categoriesViewModel, notificationService, getEntryListViewModel) + { + } + + #region Overrides of EntryListBaseViewModel + + /// + protected override string GetPagePath(int page) + { + return $"workshop/entries/profiles/{page}"; + } + + /// + protected override EntryFilterInput GetFilter() + { + return new EntryFilterInput + { + And = new[] + { + new EntryFilterInput {EntryType = new EntryTypeOperationFilterInput {Eq = WebClient.Workshop.EntryType.Profile}}, + base.GetFilter() + } + }; + } + + #endregion +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml b/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml index d0717860f..c97d51ee0 100644 --- a/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml +++ b/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml @@ -9,6 +9,8 @@ x:DataType="home:WorkshopHomeViewModel"> + + - + - - - - - + + + + - + Featured submissions Not yet implemented, here we'll show submissions we think are worth some extra attention. - + Recently updated Not yet implemented, here we'll a few of the most recent uploads/updates to the workshop. - \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml.cs index e28f6659b..4a143850a 100644 --- a/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml.cs +++ b/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml.cs @@ -1,6 +1,3 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; namespace Artemis.UI.Screens.Workshop.Home; @@ -11,9 +8,4 @@ public partial class WorkshopHomeView : ReactiveUserControl(async r => await router.Navigate(r)); + + AddSubmission = ReactiveCommand.CreateFromTask(ExecuteAddSubmission, this.WhenAnyValue(vm => vm.WorkshopReachable)); + Navigate = ReactiveCommand.CreateFromTask(async r => await router.Navigate(r), this.WhenAnyValue(vm => vm.WorkshopReachable)); + + this.WhenActivatedAsync(async d => WorkshopReachable = await workshopService.ValidateWorkshopStatus(d.AsCancellationToken())); } +#if DEBUG + public bool ShowLayouts => true; +# else + public bool ShowLayouts => false; +#endif + public ReactiveCommand AddSubmission { get; } public ReactiveCommand Navigate { get; } + public bool WorkshopReachable + { + get => _workshopReachable; + private set => RaiseAndSetIfChanged(ref _workshopReachable, value); + } + private async Task ExecuteAddSubmission(CancellationToken arg) { await _windowService.ShowDialogAsync(); } - - public EntryType? EntryType => null; } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Home/WorkshopOfflineView.axaml b/src/Artemis.UI/Screens/Workshop/Home/WorkshopOfflineView.axaml new file mode 100644 index 000000000..b700c5375 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Home/WorkshopOfflineView.axaml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + Could not reach the workshop + + + + Please ensure you are connected to the internet. + If this keeps occuring, hit us up on Discord + + + + + + + diff --git a/src/Artemis.UI/Screens/Workshop/Home/WorkshopOfflineView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Home/WorkshopOfflineView.axaml.cs new file mode 100644 index 000000000..a7d5eebdb --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Home/WorkshopOfflineView.axaml.cs @@ -0,0 +1,14 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.Home; + +public partial class WorkshopOfflineView : ReactiveUserControl +{ + public WorkshopOfflineView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Home/WorkshopOfflineViewModel.cs b/src/Artemis.UI/Screens/Workshop/Home/WorkshopOfflineViewModel.cs new file mode 100644 index 000000000..8c72ea6bd --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Home/WorkshopOfflineViewModel.cs @@ -0,0 +1,55 @@ + +using System.Reactive; +using System.Threading; +using System.Threading.Tasks; +using Artemis.UI.Shared; +using Artemis.UI.Shared.Routing; +using Artemis.WebClient.Workshop; +using Artemis.WebClient.Workshop.Services; +using ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.Home; + +public class WorkshopOfflineViewModel : RoutableScreen +{ + private readonly IRouter _router; + private readonly IWorkshopService _workshopService; + private string _message; + + /// + public WorkshopOfflineViewModel(IWorkshopService workshopService, IRouter router) + { + _workshopService = workshopService; + _router = router; + + Retry = ReactiveCommand.CreateFromTask(ExecuteRetry); + } + + public ReactiveCommand Retry { get; } + + public string Message + { + get => _message; + set => RaiseAndSetIfChanged(ref _message, value); + } + + public override Task OnNavigating(WorkshopOfflineParameters parameters, NavigationArguments args, CancellationToken cancellationToken) + { + Message = parameters.Message; + return base.OnNavigating(parameters, args, cancellationToken); + } + + private async Task ExecuteRetry(CancellationToken cancellationToken) + { + IWorkshopService.WorkshopStatus status = await _workshopService.GetWorkshopStatus(cancellationToken); + if (status.IsReachable) + await _router.Navigate("workshop"); + + Message = status.Message; + } +} + +public class WorkshopOfflineParameters +{ + public string Message { get; set; } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsView.axaml b/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsView.axaml index 4e48f869c..5e953bd10 100644 --- a/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsView.axaml +++ b/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsView.axaml @@ -2,24 +2,132 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:layout="clr-namespace:Artemis.UI.Screens.Workshop.Layout" - mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" + xmlns:Layout="clr-namespace:Artemis.UI.Screens.Workshop.Layout" + xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" + xmlns:il="clr-namespace:AsyncImageLoader;assembly=AsyncImageLoader.Avalonia" + xmlns:converters="clr-namespace:Artemis.UI.Converters" + xmlns:mdxaml="https://github.com/whistyun/Markdown.Avalonia.Tight" + xmlns:mdsvg="https://github.com/whistyun/Markdown.Avalonia.Svg" + xmlns:ui="clr-namespace:Artemis.UI" + xmlns:converters1="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared" + mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="800" x:Class="Artemis.UI.Screens.Workshop.Layout.LayoutDetailsView" - x:DataType="layout:LayoutDetailsViewModel"> - - - - - - - - - Side panel + x:DataType="Layout:LayoutDetailsViewModel"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + downloads + + + + + Created + + + + + Updated + + + - - Layout details panel + + + Latest release + + + - - + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsView.axaml.cs index 3a529743e..57e93b1e1 100644 --- a/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsView.axaml.cs +++ b/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsView.axaml.cs @@ -1,4 +1,3 @@ -using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; namespace Artemis.UI.Screens.Workshop.Layout; @@ -9,9 +8,4 @@ public partial class LayoutDetailsView : ReactiveUserControl, IWorkshopViewModel +public class LayoutDetailsViewModel : RoutableScreen { private readonly IWorkshopClient _client; + private readonly INotificationService _notificationService; + private readonly IWindowService _windowService; + private readonly ObservableAsPropertyHelper _updatedAt; private IGetEntryById_Entry? _entry; - public LayoutDetailsViewModel(IWorkshopClient client) + public LayoutDetailsViewModel(IWorkshopClient client, INotificationService notificationService, IWindowService windowService) { _client = client; + _notificationService = notificationService; + _windowService = windowService; + _updatedAt = this.WhenAnyValue(vm => vm.Entry).Select(e => e?.LatestRelease?.CreatedAt ?? e?.CreatedAt).ToProperty(this, vm => vm.UpdatedAt); + + DownloadLatestRelease = ReactiveCommand.CreateFromTask(ExecuteDownloadLatestRelease); } - public EntryType? EntryType => null; + public ReactiveCommand DownloadLatestRelease { get; } + + public DateTimeOffset? UpdatedAt => _updatedAt.Value; public IGetEntryById_Entry? Entry { get => _entry; - set => RaiseAndSetIfChanged(ref _entry, value); + private set => RaiseAndSetIfChanged(ref _entry, value); } public override async Task OnNavigating(WorkshopDetailParameters parameters, NavigationArguments args, CancellationToken cancellationToken) @@ -32,7 +48,7 @@ public class LayoutDetailsViewModel : RoutableScreen result = await _client.GetEntryById.ExecuteAsync(entryId, cancellationToken); if (result.IsErrorResult()) @@ -40,4 +56,9 @@ public class LayoutDetailsViewModel : RoutableScreen - - - - - Categories - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Layout/LayoutListViewModel.cs b/src/Artemis.UI/Screens/Workshop/Layout/LayoutListViewModel.cs deleted file mode 100644 index 17ac0ca9e..000000000 --- a/src/Artemis.UI/Screens/Workshop/Layout/LayoutListViewModel.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using Artemis.UI.Screens.Workshop.Categories; -using Artemis.UI.Screens.Workshop.Parameters; -using Artemis.UI.Shared; -using Artemis.UI.Shared.Routing; -using Artemis.WebClient.Workshop; - -namespace Artemis.UI.Screens.Workshop.Layout; - -public class LayoutListViewModel : RoutableScreen, IWorkshopViewModel -{ - private int _page; - - public LayoutListViewModel(CategoriesViewModel categoriesViewModel) - { - CategoriesViewModel = categoriesViewModel; - } - - public CategoriesViewModel CategoriesViewModel { get; } - - public int Page - { - get => _page; - set => RaiseAndSetIfChanged(ref _page, value); - } - - public override Task OnNavigating(WorkshopListParameters parameters, NavigationArguments args, CancellationToken cancellationToken) - { - Page = Math.Max(1, parameters.Page); - return Task.CompletedTask; - } - - public EntryType? EntryType => WebClient.Workshop.EntryType.Layout; -} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/SubmissionDetailView.axaml b/src/Artemis.UI/Screens/Workshop/Library/SubmissionDetailView.axaml new file mode 100644 index 000000000..99365cb52 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Library/SubmissionDetailView.axaml @@ -0,0 +1,58 @@ + + + + + + + + + Management + + + + + + downloads + + + + + Created + + + + + + + + + + + + + View workshop page + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/SubmissionDetailView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Library/SubmissionDetailView.axaml.cs new file mode 100644 index 000000000..729f02a2b --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Library/SubmissionDetailView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.Library; + +public partial class SubmissionDetailView : ReactiveUserControl +{ + public SubmissionDetailView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/SubmissionDetailViewModel.cs b/src/Artemis.UI/Screens/Workshop/Library/SubmissionDetailViewModel.cs new file mode 100644 index 000000000..7d94935c0 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Library/SubmissionDetailViewModel.cs @@ -0,0 +1,228 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Reactive; +using System.Threading; +using System.Threading.Tasks; +using Artemis.UI.Screens.Workshop.Entries; +using Artemis.UI.Screens.Workshop.Parameters; +using Artemis.UI.Screens.Workshop.SubmissionWizard; +using Artemis.UI.Shared.Routing; +using Artemis.UI.Shared.Services; +using Artemis.UI.Shared.Utilities; +using Artemis.WebClient.Workshop; +using Artemis.WebClient.Workshop.Exceptions; +using Artemis.WebClient.Workshop.Handlers.UploadHandlers; +using Artemis.WebClient.Workshop.Services; +using Avalonia.Media.Imaging; +using ReactiveUI; +using StrawberryShake; + +namespace Artemis.UI.Screens.Workshop.Library; + +public class SubmissionDetailViewModel : RoutableScreen +{ + private readonly IWorkshopClient _client; + private readonly Func _getGetSpecificationsVm; + private readonly IRouter _router; + private readonly IWindowService _windowService; + private readonly IWorkshopService _workshopService; + private IGetSubmittedEntryById_Entry? _entry; + private EntrySpecificationsViewModel? _entrySpecificationsViewModel; + private bool _hasChanges; + + public SubmissionDetailViewModel(IWorkshopClient client, IWindowService windowService, IWorkshopService workshopService, IRouter router, Func getSpecificationsVm) { + _client = client; + _windowService = windowService; + _workshopService = workshopService; + _router = router; + _getGetSpecificationsVm = getSpecificationsVm; + + CreateRelease = ReactiveCommand.CreateFromTask(ExecuteCreateRelease); + DeleteSubmission = ReactiveCommand.CreateFromTask(ExecuteDeleteSubmission); + ViewWorkshopPage = ReactiveCommand.CreateFromTask(ExecuteViewWorkshopPage); + DiscardChanges = ReactiveCommand.CreateFromTask(ExecuteDiscardChanges, this.WhenAnyValue(vm => vm.HasChanges)); + SaveChanges = ReactiveCommand.CreateFromTask(ExecuteSaveChanges, this.WhenAnyValue(vm => vm.HasChanges)); + } + + public ReactiveCommand CreateRelease { get; } + public ReactiveCommand DeleteSubmission { get; } + public ReactiveCommand ViewWorkshopPage { get; } + public ReactiveCommand SaveChanges { get; } + public ReactiveCommand DiscardChanges { get; } + + public EntrySpecificationsViewModel? EntrySpecificationsViewModel + { + get => _entrySpecificationsViewModel; + set => RaiseAndSetIfChanged(ref _entrySpecificationsViewModel, value); + } + + public IGetSubmittedEntryById_Entry? Entry + { + get => _entry; + set => RaiseAndSetIfChanged(ref _entry, value); + } + + public bool HasChanges + { + get => _hasChanges; + private set => RaiseAndSetIfChanged(ref _hasChanges, value); + } + + public override async Task OnNavigating(WorkshopDetailParameters parameters, NavigationArguments args, CancellationToken cancellationToken) + { + IOperationResult result = await _client.GetSubmittedEntryById.ExecuteAsync(parameters.EntryId, cancellationToken); + if (result.IsErrorResult()) + return; + + Entry = result.Data?.Entry; + await ApplyFromEntry(cancellationToken); + } + + public override async Task OnClosing(NavigationArguments args) + { + if (!HasChanges) + return; + + bool confirmed = await _windowService.ShowConfirmContentDialog("You have unsaved changes", "Do you want to discard your unsaved changes?"); + if (!confirmed) + args.Cancel(); + } + + private async Task ApplyFromEntry(CancellationToken cancellationToken) + { + if (Entry == null) + return; + + if (EntrySpecificationsViewModel != null) + { + EntrySpecificationsViewModel.PropertyChanged -= EntrySpecificationsViewModelOnPropertyChanged; + ((INotifyCollectionChanged) EntrySpecificationsViewModel.SelectedCategories).CollectionChanged -= SelectedCategoriesOnCollectionChanged; + EntrySpecificationsViewModel.Tags.CollectionChanged -= TagsOnCollectionChanged; + } + + EntrySpecificationsViewModel viewModel = _getGetSpecificationsVm(); + + viewModel.IconBitmap = await GetEntryIcon(cancellationToken); + viewModel.Name = Entry.Name; + viewModel.Summary = Entry.Summary; + viewModel.Description = Entry.Description; + viewModel.PreselectedCategories = Entry.Categories.Select(c => c.Id).ToList(); + + viewModel.Tags.Clear(); + foreach (string tag in Entry.Tags.Select(c => c.Name)) + viewModel.Tags.Add(tag); + + EntrySpecificationsViewModel = viewModel; + EntrySpecificationsViewModel.PropertyChanged += EntrySpecificationsViewModelOnPropertyChanged; + ((INotifyCollectionChanged) EntrySpecificationsViewModel.SelectedCategories).CollectionChanged += SelectedCategoriesOnCollectionChanged; + EntrySpecificationsViewModel.Tags.CollectionChanged += TagsOnCollectionChanged; + } + + private async Task GetEntryIcon(CancellationToken cancellationToken) + { + if (Entry == null) + return null; + + Stream? stream = await _workshopService.GetEntryIcon(Entry.Id, cancellationToken); + return stream != null ? new Bitmap(stream) : null; + } + + private void UpdateHasChanges() + { + if (EntrySpecificationsViewModel == null || Entry == null) + return; + + List categories = EntrySpecificationsViewModel.Categories.Where(c => c.IsSelected).Select(c => c.Id).OrderBy(c => c).ToList(); + List tags = EntrySpecificationsViewModel.Tags.OrderBy(t => t).ToList(); + + HasChanges = EntrySpecificationsViewModel.Name != Entry.Name || + EntrySpecificationsViewModel.Description != Entry.Description || + EntrySpecificationsViewModel.Summary != Entry.Summary || + EntrySpecificationsViewModel.IconChanged || + !tags.SequenceEqual(Entry.Tags.Select(t => t.Name).OrderBy(t => t)) || + !categories.SequenceEqual(Entry.Categories.Select(c => c.Id).OrderBy(c => c)); + } + + private async Task ExecuteDiscardChanges() + { + await ApplyFromEntry(CancellationToken.None); + } + + private async Task ExecuteSaveChanges(CancellationToken cancellationToken) + { + if (Entry == null || EntrySpecificationsViewModel == null || !EntrySpecificationsViewModel.ValidationContext.GetIsValid()) + return; + + UpdateEntryInput input = new() + { + Id = Entry.Id, + Name = EntrySpecificationsViewModel.Name, + Summary = EntrySpecificationsViewModel.Summary, + Description = EntrySpecificationsViewModel.Description, + Categories = EntrySpecificationsViewModel.SelectedCategories, + Tags = EntrySpecificationsViewModel.Tags + }; + + IOperationResult result = await _client.UpdateEntry.ExecuteAsync(input, cancellationToken); + result.EnsureNoErrors(); + + if (EntrySpecificationsViewModel.IconChanged && EntrySpecificationsViewModel.IconBitmap != null) + { + using MemoryStream stream = new(); + EntrySpecificationsViewModel.IconBitmap.Save(stream); + ImageUploadResult imageResult = await _workshopService.SetEntryIcon(Entry.Id, new Progress(), stream, cancellationToken); + if (!imageResult.IsSuccess) + throw new ArtemisWorkshopException("Failed to upload image. " + imageResult.Message); + } + + HasChanges = false; + } + + private async Task ExecuteCreateRelease(CancellationToken cancellationToken) + { + if (Entry != null) + await _windowService.ShowDialogAsync(Entry); + } + + private async Task ExecuteDeleteSubmission(CancellationToken cancellationToken) + { + if (Entry == null) + return; + + bool confirmed = await _windowService.ShowConfirmContentDialog( + "Delete submission?", + "You cannot undo this by yourself.\r\n" + + "Users that have already downloaded your submission will keep it."); + if (!confirmed) + return; + + IOperationResult result = await _client.RemoveEntry.ExecuteAsync(Entry.Id, cancellationToken); + result.EnsureNoErrors(); + await _router.Navigate("workshop/library/submissions"); + } + + private async Task ExecuteViewWorkshopPage() + { + if (Entry != null) + await _workshopService.NavigateToEntry(Entry.Id, Entry.EntryType); + } + + private void TagsOnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) + { + UpdateHasChanges(); + } + + private void SelectedCategoriesOnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) + { + UpdateHasChanges(); + } + + private void EntrySpecificationsViewModelOnPropertyChanged(object? sender, PropertyChangedEventArgs e) + { + UpdateHasChanges(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabItemView.axaml b/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabItemView.axaml new file mode 100644 index 000000000..00e7eae8f --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabItemView.axaml @@ -0,0 +1,58 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabItemView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabItemView.axaml.cs new file mode 100644 index 000000000..be6199b60 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabItemView.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Artemis.UI.Screens.Workshop.Library.Tabs; + +public partial class InstalledTabItemView : UserControl +{ + public InstalledTabItemView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabItemViewModel.cs b/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabItemViewModel.cs new file mode 100644 index 000000000..1b22e37aa --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabItemViewModel.cs @@ -0,0 +1,70 @@ +using System; +using System.Reactive; +using System.Threading; +using System.Threading.Tasks; +using Artemis.UI.Shared; +using Artemis.UI.Shared.Routing; +using Artemis.UI.Shared.Services; +using Artemis.WebClient.Workshop; +using Artemis.WebClient.Workshop.Handlers.InstallationHandlers; +using Artemis.WebClient.Workshop.Services; +using ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.Library.Tabs; + +public class InstalledTabItemViewModel : ViewModelBase +{ + private readonly IWorkshopService _workshopService; + private readonly IRouter _router; + private readonly EntryInstallationHandlerFactory _factory; + private readonly IWindowService _windowService; + private bool _isRemoved; + + public InstalledTabItemViewModel(InstalledEntry installedEntry, IWorkshopService workshopService, IRouter router, EntryInstallationHandlerFactory factory, IWindowService windowService) + { + _workshopService = workshopService; + _router = router; + _factory = factory; + _windowService = windowService; + InstalledEntry = installedEntry; + + ViewWorkshopPage = ReactiveCommand.CreateFromTask(ExecuteViewWorkshopPage); + ViewLocal = ReactiveCommand.CreateFromTask(ExecuteViewLocal); + Uninstall = ReactiveCommand.CreateFromTask(ExecuteUninstall); + } + + public bool IsRemoved + { + get => _isRemoved; + private set => RaiseAndSetIfChanged(ref _isRemoved, value); + } + + public InstalledEntry InstalledEntry { get; } + public ReactiveCommand ViewWorkshopPage { get; } + public ReactiveCommand ViewLocal { get; } + public ReactiveCommand Uninstall { get; } + + private async Task ExecuteViewWorkshopPage() + { + await _workshopService.NavigateToEntry(InstalledEntry.EntryId, InstalledEntry.EntryType); + } + + private async Task ExecuteViewLocal(CancellationToken cancellationToken) + { + if (InstalledEntry.EntryType == EntryType.Profile && Guid.TryParse(InstalledEntry.LocalReference, out Guid profileId)) + { + await _router.Navigate($"profile-editor/{profileId}"); + } + } + + private async Task ExecuteUninstall(CancellationToken cancellationToken) + { + bool confirmed = await _windowService.ShowConfirmContentDialog("Do you want to uninstall this entry?", "Both the entry and its contents will be removed."); + if (!confirmed) + return; + + IEntryInstallationHandler handler = _factory.CreateHandler(InstalledEntry.EntryType); + await handler.UninstallAsync(InstalledEntry, cancellationToken); + IsRemoved = true; + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabView.axaml b/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabView.axaml new file mode 100644 index 000000000..fe1fef9e2 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabView.axaml @@ -0,0 +1,39 @@ + + + + + + + + + + Not much here yet, huh! + + Any entries you download from the workshop you can later manage here + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabView.axaml.cs new file mode 100644 index 000000000..8a9a8b444 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabView.axaml.cs @@ -0,0 +1,14 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.Library.Tabs; + +public partial class InstalledTabView : ReactiveUserControl +{ + public InstalledTabView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabViewModel.cs b/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabViewModel.cs new file mode 100644 index 000000000..7267c6e25 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabViewModel.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Reactive; +using System.Reactive.Linq; +using Artemis.UI.Shared.Routing; +using Artemis.WebClient.Workshop.Services; +using DynamicData; +using DynamicData.Binding; +using ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.Library.Tabs; + +public class InstalledTabViewModel : RoutableScreen +{ + private string? _searchEntryInput; + + public InstalledTabViewModel(IWorkshopService workshopService, IRouter router, Func getInstalledTabItemViewModel) + { + SourceList installedEntries = new(); + IObservable> pluginFilter = this.WhenAnyValue(vm => vm.SearchEntryInput).Throttle(TimeSpan.FromMilliseconds(100)).Select(CreatePredicate); + + installedEntries.Connect() + .Filter(pluginFilter) + .Sort(SortExpressionComparer.Descending(p => p.InstalledAt)) + .Transform(getInstalledTabItemViewModel) + .AutoRefresh(vm => vm.IsRemoved) + .Filter(vm => !vm.IsRemoved) + .Bind(out ReadOnlyObservableCollection installedEntryViewModels) + .Subscribe(); + + List entries = workshopService.GetInstalledEntries(); + installedEntries.AddRange(entries); + + Empty = entries.Count == 0; + InstalledEntries = installedEntryViewModels; + + OpenWorkshop = ReactiveCommand.CreateFromTask(async () => await router.Navigate("workshop")); + } + + public bool Empty { get; } + public ReactiveCommand OpenWorkshop { get; } + + public ReadOnlyObservableCollection InstalledEntries { get; } + + public string? SearchEntryInput + { + get => _searchEntryInput; + set => RaiseAndSetIfChanged(ref _searchEntryInput, value); + } + + private Func CreatePredicate(string? text) + { + if (string.IsNullOrWhiteSpace(text)) + return _ => true; + + return data => data.Name.Contains(text, StringComparison.InvariantCultureIgnoreCase); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabItemView.axaml b/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabItemView.axaml new file mode 100644 index 000000000..583f14c4f --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabItemView.axaml @@ -0,0 +1,76 @@ + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabItemView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabItemView.axaml.cs new file mode 100644 index 000000000..8bf14a3bf --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabItemView.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Artemis.UI.Screens.Workshop.Library.Tabs; + +public partial class SubmissionsTabItemView : UserControl +{ + public SubmissionsTabItemView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabItemViewModel.cs b/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabItemViewModel.cs new file mode 100644 index 000000000..21c8098ee --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabItemViewModel.cs @@ -0,0 +1,30 @@ +using System.Reactive; +using System.Threading; +using System.Threading.Tasks; +using Artemis.UI.Shared; +using Artemis.UI.Shared.Routing; +using Artemis.WebClient.Workshop; +using ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.Library.Tabs; + +public class SubmissionsTabItemViewModel : ViewModelBase +{ + private readonly IRouter _router; + + public SubmissionsTabItemViewModel(IGetSubmittedEntries_SubmittedEntries entry, IRouter router) + { + _router = router; + Entry = entry; + + NavigateToEntry = ReactiveCommand.CreateFromTask(ExecuteNavigateToEntry); + } + + public IGetSubmittedEntries_SubmittedEntries Entry { get; } + public ReactiveCommand NavigateToEntry { get; } + + private async Task ExecuteNavigateToEntry(CancellationToken cancellationToken) + { + await _router.Navigate($"workshop/library/submissions/{Entry.Id}"); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabView.axaml b/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabView.axaml new file mode 100644 index 000000000..c52644447 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabView.axaml @@ -0,0 +1,51 @@ + + + + + + + + + + + You are not logged in + + In order to manage your submissions you must be logged in. + + + + + + + + Oh boy, it's empty here 🤔 + + Any entries you submit to the workshop you can later manage here + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabView.axaml.cs new file mode 100644 index 000000000..cedd6574c --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabView.axaml.cs @@ -0,0 +1,14 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.Library.Tabs; + +public partial class SubmissionsTabView : ReactiveUserControl +{ + public SubmissionsTabView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabViewModel.cs b/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabViewModel.cs new file mode 100644 index 000000000..76947ec5d --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabViewModel.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.ObjectModel; +using System.Reactive; +using System.Threading; +using System.Threading.Tasks; +using Artemis.UI.Extensions; +using Artemis.UI.Screens.Workshop.CurrentUser; +using Artemis.UI.Screens.Workshop.SubmissionWizard; +using Artemis.UI.Shared.Routing; +using Artemis.UI.Shared.Services; +using Artemis.WebClient.Workshop; +using Artemis.WebClient.Workshop.Services; +using DynamicData; +using ReactiveUI; +using StrawberryShake; + +namespace Artemis.UI.Screens.Workshop.Library.Tabs; + +public class SubmissionsTabViewModel : RoutableScreen +{ + private readonly IWorkshopClient _client; + private readonly SourceCache _entries; + private readonly IWindowService _windowService; + private bool _isLoading = true; + private bool _workshopReachable; + + public SubmissionsTabViewModel(IWorkshopClient client, + IAuthenticationService authenticationService, + IWindowService windowService, + IWorkshopService workshopService, + Func getSubmissionsTabItemViewModel) + { + _client = client; + _windowService = windowService; + _entries = new SourceCache(e => e.Id); + _entries.Connect() + .Transform(getSubmissionsTabItemViewModel) + .Bind(out ReadOnlyObservableCollection entries) + .Subscribe(); + + AddSubmission = ReactiveCommand.CreateFromTask(ExecuteAddSubmission, this.WhenAnyValue(vm => vm.WorkshopReachable)); + Login = ReactiveCommand.CreateFromTask(ExecuteLogin, this.WhenAnyValue(vm => vm.WorkshopReachable)); + + IsLoggedIn = authenticationService.IsLoggedIn; + Entries = entries; + + this.WhenActivatedAsync(async d => + { + WorkshopReachable = await workshopService.ValidateWorkshopStatus(d.AsCancellationToken()); + if (WorkshopReachable) + await GetEntries(d.AsCancellationToken()); + }); + } + + public ReactiveCommand Login { get; } + public ReactiveCommand AddSubmission { get; } + + public IObservable IsLoggedIn { get; } + public ReadOnlyObservableCollection Entries { get; } + + public bool WorkshopReachable + { + get => _workshopReachable; + set => RaiseAndSetIfChanged(ref _workshopReachable, value); + } + + public bool IsLoading + { + get => _isLoading; + set => RaiseAndSetIfChanged(ref _isLoading, value); + } + + private async Task ExecuteLogin(CancellationToken ct) + { + await _windowService.CreateContentDialog().WithViewModel(out WorkshopLoginViewModel _).WithTitle("Workshop login").ShowAsync(); + await GetEntries(ct); + } + + private async Task ExecuteAddSubmission(CancellationToken arg) + { + await _windowService.ShowDialogAsync(); + } + + private async Task GetEntries(CancellationToken ct) + { + IsLoading = true; + + try + { + IOperationResult result = await _client.GetSubmittedEntries.ExecuteAsync(null, ct); + + if (result.Data?.SubmittedEntries == null) + _entries.Clear(); + else + _entries.Edit(e => + { + e.Clear(); + e.AddOrUpdate(result.Data.SubmittedEntries); + }); + } + finally + { + IsLoading = false; + } + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/WorkshopLibraryVIew.axaml b/src/Artemis.UI/Screens/Workshop/Library/WorkshopLibraryVIew.axaml new file mode 100644 index 000000000..af8f455a4 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Library/WorkshopLibraryVIew.axaml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + diff --git a/src/Artemis.UI/Screens/Workshop/Library/WorkshopLibraryVIew.axaml.cs b/src/Artemis.UI/Screens/Workshop/Library/WorkshopLibraryVIew.axaml.cs new file mode 100644 index 000000000..7758b5729 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Library/WorkshopLibraryVIew.axaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Reactive.Disposables; +using Artemis.UI.Shared; +using Avalonia.ReactiveUI; +using Avalonia.Threading; +using FluentAvalonia.UI.Controls; +using ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.Library; + +public partial class WorkshopLibraryView : ReactiveUserControl +{ + public WorkshopLibraryView() + { + InitializeComponent(); + this.WhenActivated(d => { ViewModel.WhenAnyValue(vm => vm.Screen).WhereNotNull().Subscribe(Navigate).DisposeWith(d); }); + } + + private void Navigate(ViewModelBase viewModel) + { + Dispatcher.UIThread.Invoke(() => TabFrame.NavigateFromObject(viewModel)); + } + + private void NavigationView_OnBackRequested(object? sender, NavigationViewBackRequestedEventArgs e) + { + ViewModel?.GoBack(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/WorkshopLibraryViewModel.cs b/src/Artemis.UI/Screens/Workshop/Library/WorkshopLibraryViewModel.cs new file mode 100644 index 000000000..56abc8ffd --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Library/WorkshopLibraryViewModel.cs @@ -0,0 +1,65 @@ +using System.Collections.ObjectModel; +using System.Linq; +using System.Reactive.Disposables; +using System.Threading; +using System.Threading.Tasks; +using Artemis.UI.Routing; +using Artemis.UI.Shared.Routing; +using ReactiveUI; +using System; +using System.Reactive.Linq; + +namespace Artemis.UI.Screens.Workshop.Library; + +public class WorkshopLibraryViewModel : RoutableHostScreen +{ + private readonly IRouter _router; + private RouteViewModel? _selectedTab; + private ObservableAsPropertyHelper? _viewingDetails; + + /// + public WorkshopLibraryViewModel(IRouter router) + { + _router = router; + + Tabs = new ObservableCollection + { + new("Installed", "workshop/library/installed"), + new("Submissions", "workshop/library/submissions") + }; + + this.WhenActivated(d => + { + _viewingDetails = _router.CurrentPath.Select(p => p != null && p.StartsWith("workshop/library/submissions/")).ToProperty(this, vm => vm.ViewingDetails).DisposeWith(d); + // Navigate on tab change + this.WhenAnyValue(vm => vm.SelectedTab) + .WhereNotNull() + .Subscribe(s => router.Navigate(s.Path, new RouterNavigationOptions {IgnoreOnPartialMatch = true})) + .DisposeWith(d); + }); + } + + public bool ViewingDetails => _viewingDetails?.Value ?? false; + public ObservableCollection Tabs { get; } + + public RouteViewModel? SelectedTab + { + get => _selectedTab; + set => RaiseAndSetIfChanged(ref _selectedTab, value); + } + + public override async Task OnNavigating(NavigationArguments args, CancellationToken cancellationToken) + { + SelectedTab = Tabs.FirstOrDefault(t => t.Matches(args.Path)); + if (SelectedTab == null) + await args.Router.Navigate(Tabs.First().Path); + } + + public void GoBack() + { + if (ViewingDetails) + _router.GoBack(); + else + _router.Navigate("workshop"); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Parameters/WorkshopDetailParameters.cs b/src/Artemis.UI/Screens/Workshop/Parameters/WorkshopDetailParameters.cs index dfd37805f..86503f0d4 100644 --- a/src/Artemis.UI/Screens/Workshop/Parameters/WorkshopDetailParameters.cs +++ b/src/Artemis.UI/Screens/Workshop/Parameters/WorkshopDetailParameters.cs @@ -1,8 +1,6 @@ -using System; - namespace Artemis.UI.Screens.Workshop.Parameters; public class WorkshopDetailParameters { - public Guid EntryId { get; set; } + public long EntryId { get; set; } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsView.axaml b/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsView.axaml index 12d0a8227..e8dbea39a 100644 --- a/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsView.axaml +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsView.axaml @@ -3,23 +3,131 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:profile="clr-namespace:Artemis.UI.Screens.Workshop.Profile" - mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" + xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" + xmlns:il="clr-namespace:AsyncImageLoader;assembly=AsyncImageLoader.Avalonia" + xmlns:converters="clr-namespace:Artemis.UI.Converters" + xmlns:mdxaml="https://github.com/whistyun/Markdown.Avalonia.Tight" + xmlns:mdsvg="https://github.com/whistyun/Markdown.Avalonia.Svg" + xmlns:ui="clr-namespace:Artemis.UI" + xmlns:converters1="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared" + mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="800" x:Class="Artemis.UI.Screens.Workshop.Profile.ProfileDetailsView" x:DataType="profile:ProfileDetailsViewModel"> - - - - - - - - - Side panel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + downloads + + + + + Created + + + + + Updated + + + - - Profile details panel + + + Latest release + + + - - + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsView.axaml.cs index 25ca88e9f..1150bd94c 100644 --- a/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsView.axaml.cs +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsView.axaml.cs @@ -1,4 +1,3 @@ -using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; namespace Artemis.UI.Screens.Workshop.Profile; @@ -9,9 +8,4 @@ public partial class ProfileDetailsView : ReactiveUserControl, IWorkshopViewModel +public class ProfileDetailsViewModel : RoutableScreen { private readonly IWorkshopClient _client; + private readonly ProfileEntryInstallationHandler _installationHandler; + private readonly INotificationService _notificationService; + private readonly IWindowService _windowService; + private readonly ObservableAsPropertyHelper _updatedAt; private IGetEntryById_Entry? _entry; - public ProfileDetailsViewModel(IWorkshopClient client) + public ProfileDetailsViewModel(IWorkshopClient client, ProfileEntryInstallationHandler installationHandler, INotificationService notificationService, IWindowService windowService) { _client = client; + _installationHandler = installationHandler; + _notificationService = notificationService; + _windowService = windowService; + _updatedAt = this.WhenAnyValue(vm => vm.Entry).Select(e => e?.LatestRelease?.CreatedAt ?? e?.CreatedAt).ToProperty(this, vm => vm.UpdatedAt); + + DownloadLatestRelease = ReactiveCommand.CreateFromTask(ExecuteDownloadLatestRelease); } - public EntryType? EntryType => null; + public ReactiveCommand DownloadLatestRelease { get; } + + public DateTimeOffset? UpdatedAt => _updatedAt.Value; public IGetEntryById_Entry? Entry { get => _entry; - set => RaiseAndSetIfChanged(ref _entry, value); + private set => RaiseAndSetIfChanged(ref _entry, value); } public override async Task OnNavigating(WorkshopDetailParameters parameters, NavigationArguments args, CancellationToken cancellationToken) @@ -32,7 +51,7 @@ public class ProfileDetailsViewModel : RoutableScreen result = await _client.GetEntryById.ExecuteAsync(entryId, cancellationToken); if (result.IsErrorResult()) @@ -40,4 +59,20 @@ public class ProfileDetailsViewModel : RoutableScreen(), cancellationToken); + if (result.IsSuccess) + _notificationService.CreateNotification().WithTitle("Profile installed").WithSeverity(NotificationSeverity.Success).Show(); + else + _notificationService.CreateNotification().WithTitle("Failed to install profile").WithMessage(result.Message).WithSeverity(NotificationSeverity.Error).Show(); + } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListView.axaml b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListView.axaml deleted file mode 100644 index 3ae086124..000000000 --- a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListView.axaml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - Categories - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListViewModel.cs b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListViewModel.cs deleted file mode 100644 index 98e45f00b..000000000 --- a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListViewModel.cs +++ /dev/null @@ -1,146 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reactive.Disposables; -using System.Reactive.Linq; -using System.Threading; -using System.Threading.Tasks; -using Artemis.UI.Screens.Workshop.Categories; -using Artemis.UI.Screens.Workshop.Entries; -using Artemis.UI.Screens.Workshop.Parameters; -using Artemis.UI.Shared; -using Artemis.UI.Shared.Routing; -using Artemis.UI.Shared.Services; -using Artemis.UI.Shared.Services.Builders; -using Artemis.WebClient.Workshop; -using ReactiveUI; -using StrawberryShake; - -namespace Artemis.UI.Screens.Workshop.Profile; - -public class ProfileListViewModel : RoutableScreen, IWorkshopViewModel -{ - private readonly IRouter _router; - private readonly INotificationService _notificationService; - private readonly IWorkshopClient _workshopClient; - private readonly ObservableAsPropertyHelper _showPagination; - private readonly ObservableAsPropertyHelper _isLoading; - private List? _entries; - private int _page; - private int _loadedPage = -1; - private int _totalPages = 1; - private int _entriesPerPage = 10; - - public ProfileListViewModel(IWorkshopClient workshopClient, IRouter router, CategoriesViewModel categoriesViewModel, INotificationService notificationService) - { - _workshopClient = workshopClient; - _router = router; - _notificationService = notificationService; - _showPagination = this.WhenAnyValue(vm => vm.TotalPages).Select(t => t > 1).ToProperty(this, vm => vm.ShowPagination); - _isLoading = this.WhenAnyValue(vm => vm.Page, vm => vm.LoadedPage, (p, c) => p != c).ToProperty(this, vm => vm.IsLoading); - - CategoriesViewModel = categoriesViewModel; - - // Respond to page changes - this.WhenAnyValue(vm => vm.Page).Skip(1).Subscribe(p => Task.Run(() => _router.Navigate($"workshop/profiles/{p}"))); - // Respond to filter changes - this.WhenActivated(d => CategoriesViewModel.WhenAnyValue(vm => vm.CategoryFilters).Skip(1).Subscribe(_ => - { - // Reset to page one, will trigger a query - if (Page != 1) - Page = 1; - // If already at page one, force a query - else - Task.Run(() => Query(CancellationToken.None)); - }).DisposeWith(d)); - } - - public bool ShowPagination => _showPagination.Value; - public bool IsLoading => _isLoading.Value; - - public CategoriesViewModel CategoriesViewModel { get; } - - public List? Entries - { - get => _entries; - set => RaiseAndSetIfChanged(ref _entries, value); - } - - public int Page - { - get => _page; - set => RaiseAndSetIfChanged(ref _page, value); - } - - public int LoadedPage - { - get => _loadedPage; - set => RaiseAndSetIfChanged(ref _loadedPage, value); - } - - public int TotalPages - { - get => _totalPages; - set => RaiseAndSetIfChanged(ref _totalPages, value); - } - - public int EntriesPerPage - { - get => _entriesPerPage; - set => RaiseAndSetIfChanged(ref _entriesPerPage, value); - } - - public override async Task OnNavigating(WorkshopListParameters parameters, NavigationArguments args, CancellationToken cancellationToken) - { - Page = Math.Max(1, parameters.Page); - - // Throttle page changes - await Task.Delay(200, cancellationToken); - - if (!cancellationToken.IsCancellationRequested) - await Query(cancellationToken); - } - - private async Task Query(CancellationToken cancellationToken) - { - try - { - EntryFilterInput filter = GetFilter(); - IOperationResult entries = await _workshopClient.GetEntries.ExecuteAsync(filter, EntriesPerPage * (Page - 1), EntriesPerPage, cancellationToken); - entries.EnsureNoErrors(); - - if (entries.Data?.Entries?.Items != null) - { - Entries = entries.Data.Entries.Items.Select(n => new EntryListViewModel(n, _router)).ToList(); - TotalPages = (int) Math.Ceiling(entries.Data.Entries.TotalCount / (double) EntriesPerPage); - } - else - TotalPages = 1; - } - catch (Exception e) - { - _notificationService.CreateNotification() - .WithTitle("Failed to load entries") - .WithMessage(e.Message) - .WithSeverity(NotificationSeverity.Error) - .Show(); - } - finally - { - LoadedPage = Page; - } - } - - private EntryFilterInput GetFilter() - { - EntryFilterInput filter = new() - { - EntryType = new EntryTypeOperationFilterInput {Eq = WebClient.Workshop.EntryType.Profile}, - And = CategoriesViewModel.CategoryFilters - }; - - return filter; - } - - public EntryType? EntryType => null; -} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfilePreviewView.axaml b/src/Artemis.UI/Screens/Workshop/Profile/ProfilePreviewView.axaml new file mode 100644 index 000000000..0b30e7d07 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfilePreviewView.axaml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfilePreviewView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Profile/ProfilePreviewView.axaml.cs new file mode 100644 index 000000000..b956e6ecf --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfilePreviewView.axaml.cs @@ -0,0 +1,79 @@ +using System; +using System.Linq; +using System.Reactive.Linq; +using Avalonia; +using Avalonia.Controls.PanAndZoom; +using Avalonia.Input; +using Avalonia.Media; +using Avalonia.ReactiveUI; +using ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.Profile; + +public partial class ProfilePreviewView : ReactiveUserControl +{ + private bool _movedByUser; + + public ProfilePreviewView() + { + InitializeComponent(); + + ZoomBorder.PropertyChanged += ZoomBorderOnPropertyChanged; + ZoomBorder.PointerMoved += ZoomBorderOnPointerMoved; + ZoomBorder.PointerWheelChanged += ZoomBorderOnPointerWheelChanged; + UpdateZoomBorderBackground(); + + this.WhenAnyValue(v => v.Bounds).Where(_ => !_movedByUser).Subscribe(_ => AutoFit()); + } + + private void ZoomBorderOnPointerWheelChanged(object? sender, PointerWheelEventArgs e) + { + _movedByUser = true; + } + + private void ZoomBorderOnPointerMoved(object? sender, PointerEventArgs e) + { + if (e.GetCurrentPoint(ZoomBorder).Properties.IsMiddleButtonPressed) + _movedByUser = true; + } + + private void ZoomBorderOnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) + { + if (e.Property.Name == nameof(ZoomBorder.Background)) + UpdateZoomBorderBackground(); + } + + private void UpdateZoomBorderBackground() + { + if (ZoomBorder.Background is VisualBrush visualBrush) + visualBrush.DestinationRect = new RelativeRect(ZoomBorder.OffsetX * -1, ZoomBorder.OffsetY * -1, 20, 20, RelativeUnit.Absolute); + } + + private void ZoomBorder_OnZoomChanged(object sender, ZoomChangedEventArgs e) + { + UpdateZoomBorderBackground(); + } + + private void AutoFit() + { + if (ViewModel == null || !ViewModel.Devices.Any()) + return; + + double left = ViewModel.Devices.Select(d => d.Rectangle.Left).Min(); + double top = ViewModel.Devices.Select(d => d.Rectangle.Top).Min(); + double bottom = ViewModel.Devices.Select(d => d.Rectangle.Bottom).Max(); + double right = ViewModel.Devices.Select(d => d.Rectangle.Right).Max(); + + // Add a 10 pixel margin around the rect + Rect scriptRect = new(new Point(left - 10, top - 10), new Point(right + 10, bottom + 10)); + + // The scale depends on the available space + double scale = Math.Min(3, Math.Min(Bounds.Width / scriptRect.Width, Bounds.Height / scriptRect.Height)); + + // Pan and zoom to make the script fit + ZoomBorder.Zoom(scale, 0, 0, true); + ZoomBorder.Pan(Bounds.Center.X - scriptRect.Center.X * scale, Bounds.Center.Y - scriptRect.Center.Y * scale, true); + + _movedByUser = false; + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfilePreviewViewModel.cs b/src/Artemis.UI/Screens/Workshop/Profile/ProfilePreviewViewModel.cs new file mode 100644 index 000000000..a874ff268 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfilePreviewViewModel.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reactive.Disposables; +using Artemis.Core; +using Artemis.Core.Services; +using Artemis.UI.Shared; +using Artemis.UI.Shared.Services; +using ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.Profile; + +public class ProfilePreviewViewModel : ActivatableViewModelBase +{ + private readonly IProfileService _profileService; + private readonly IWindowService _windowService; + private ProfileConfiguration? _profileConfiguration; + + public ProfilePreviewViewModel(IProfileService profileService, IRgbService rgbService, IWindowService windowService) + { + _profileService = profileService; + _windowService = windowService; + + Devices = new ObservableCollection(rgbService.EnabledDevices.OrderBy(d => d.ZIndex)); + + this.WhenAnyValue(vm => vm.ProfileConfiguration).Subscribe(_ => Update()); + this.WhenActivated(d => Disposable.Create(() => PreviewProfile(null)).DisposeWith(d)); + } + + public ObservableCollection Devices { get; } + + public ProfileConfiguration? ProfileConfiguration + { + get => _profileConfiguration; + set => RaiseAndSetIfChanged(ref _profileConfiguration, value); + } + + private void Update() + { + try + { + PreviewProfile(ProfileConfiguration); + } + catch (Exception e) + { + _windowService.ShowExceptionDialog("Failed to load preview", e); + } + } + + private void PreviewProfile(ProfileConfiguration? profileConfiguration) + { + _profileService.FocusProfile = profileConfiguration; + _profileService.UpdateFocusProfile = profileConfiguration != null; + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Search/SearchResultView.axaml b/src/Artemis.UI/Screens/Workshop/Search/SearchResultView.axaml new file mode 100644 index 000000000..4fa117ff3 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Search/SearchResultView.axaml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + by + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Search/SearchResultView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Search/SearchResultView.axaml.cs new file mode 100644 index 000000000..8490b69b2 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Search/SearchResultView.axaml.cs @@ -0,0 +1,14 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.Search; + +public partial class SearchResultView : ReactiveUserControl +{ + public SearchResultView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Search/SearchResultViewModel.cs b/src/Artemis.UI/Screens/Workshop/Search/SearchResultViewModel.cs new file mode 100644 index 000000000..b4c5c0810 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Search/SearchResultViewModel.cs @@ -0,0 +1,14 @@ +using Artemis.UI.Shared; +using Artemis.WebClient.Workshop; + +namespace Artemis.UI.Screens.Workshop.Search; + +public class SearchResultViewModel : ActivatableViewModelBase +{ + public SearchResultViewModel(ISearchEntries_SearchEntries entry) + { + Entry = entry; + } + + public ISearchEntries_SearchEntries Entry { get; } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml b/src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml index 171d4c400..c66d738c1 100644 --- a/src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml +++ b/src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml @@ -5,53 +5,42 @@ xmlns:search="clr-namespace:Artemis.UI.Screens.Workshop.Search" xmlns:workshop="clr-namespace:Artemis.WebClient.Workshop;assembly=Artemis.WebClient.Workshop" xmlns:windowing="clr-namespace:FluentAvalonia.UI.Windowing;assembly=FluentAvalonia" + xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="Artemis.UI.Screens.Workshop.Search.SearchView" x:DataType="search:SearchViewModel"> - + - - - - - - - - - - - - - - - - - - - - - - + + - + windowing:AppWindow.AllowInteractionInTitleBar="True" /> + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml.cs index e9da03bdb..c819fce33 100644 --- a/src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml.cs +++ b/src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml.cs @@ -1,6 +1,4 @@ -using System; using Avalonia.Controls; -using Avalonia.Markup.Xaml; namespace Artemis.UI.Screens.Workshop.Search; @@ -10,9 +8,4 @@ public partial class SearchView : UserControl { InitializeComponent(); } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Search/SearchViewModel.cs b/src/Artemis.UI/Screens/Workshop/Search/SearchViewModel.cs index b3370ee8b..000f0a330 100644 --- a/src/Artemis.UI/Screens/Workshop/Search/SearchViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Search/SearchViewModel.cs @@ -4,64 +4,84 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Artemis.UI.Screens.Workshop.CurrentUser; +using Artemis.UI.Services.Interfaces; using Artemis.UI.Shared; -using Artemis.UI.Shared.Routing; using Artemis.WebClient.Workshop; +using Artemis.WebClient.Workshop.Services; using ReactiveUI; +using Serilog; using StrawberryShake; namespace Artemis.UI.Screens.Workshop.Search; public class SearchViewModel : ViewModelBase { - public CurrentUserViewModel CurrentUserViewModel { get; } - private readonly IRouter _router; + private readonly ILogger _logger; + private readonly IWorkshopService _workshopService; + private readonly IDebugService _debugService; private readonly IWorkshopClient _workshopClient; - private EntryType? _entryType; - private ISearchEntries_SearchEntries? _selectedEntry; + private bool _isLoading; + private SearchResultViewModel? _selectedEntry; - public SearchViewModel(IWorkshopClient workshopClient, IRouter router, CurrentUserViewModel currentUserViewModel) + public SearchViewModel(ILogger logger, IWorkshopClient workshopClient, IWorkshopService workshopService, CurrentUserViewModel currentUserViewModel, IDebugService debugService) { - CurrentUserViewModel = currentUserViewModel; + _logger = logger; _workshopClient = workshopClient; - _router = router; + _workshopService = workshopService; + _debugService = debugService; + CurrentUserViewModel = currentUserViewModel; SearchAsync = ExecuteSearchAsync; this.WhenAnyValue(vm => vm.SelectedEntry).WhereNotNull().Subscribe(NavigateToEntry); } + public CurrentUserViewModel CurrentUserViewModel { get; } + public Func>> SearchAsync { get; } - public ISearchEntries_SearchEntries? SelectedEntry + public SearchResultViewModel? SelectedEntry { get => _selectedEntry; set => RaiseAndSetIfChanged(ref _selectedEntry, value); } - public EntryType? EntryType + public bool IsLoading { - get => _entryType; - set => RaiseAndSetIfChanged(ref _entryType, value); + get => _isLoading; + set => RaiseAndSetIfChanged(ref _isLoading, value); } - private void NavigateToEntry(ISearchEntries_SearchEntries entry) + public void ShowDebugger() { - string? url = null; - if (entry.EntryType == WebClient.Workshop.EntryType.Profile) - url = $"workshop/profiles/{entry.Id}"; - if (entry.EntryType == WebClient.Workshop.EntryType.Layout) - url = $"workshop/layouts/{entry.Id}"; - - if (url != null) - Task.Run(() => _router.Navigate(url)); + _debugService.ShowDebugger(); + } + + private void NavigateToEntry(SearchResultViewModel searchResult) + { + _workshopService.NavigateToEntry(searchResult.Entry.Id, searchResult.Entry.EntryType); } private async Task> ExecuteSearchAsync(string? input, CancellationToken cancellationToken) { - if (string.IsNullOrWhiteSpace(input)) - return new List(); - - IOperationResult results = await _workshopClient.SearchEntries.ExecuteAsync(input, EntryType, cancellationToken); - return results.Data?.SearchEntries.Cast() ?? new List(); + try + { + if (string.IsNullOrWhiteSpace(input) || input.Length < 2) + return new List(); + + IsLoading = true; + IOperationResult results = await _workshopClient.SearchEntries.ExecuteAsync(input, null, cancellationToken); + return results.Data?.SearchEntries.Select(e => new SearchResultViewModel(e) as object) ?? new List(); + } + catch (Exception e) + { + if (e is not TaskCanceledException) + _logger.Error(e, "Failed to execute search"); + } + finally + { + IsLoading = false; + } + + return new List(); } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Search/SearchViewStyles.axaml b/src/Artemis.UI/Screens/Workshop/Search/SearchViewStyles.axaml index 584a83924..c489f0406 100644 --- a/src/Artemis.UI/Screens/Workshop/Search/SearchViewStyles.axaml +++ b/src/Artemis.UI/Screens/Workshop/Search/SearchViewStyles.axaml @@ -19,7 +19,7 @@ - + + + + Submission type + + + Please select the type of content you want to submit to the workshop. + + + + + Profile + A profile which others can install to enjoy new lighting and interactions. + + + + + + + Layout + A layout providing users with a visual representation of a device. + + + + + diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/EntryTypeStepView.axaml.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/EntryTypeStepView.axaml.cs new file mode 100644 index 000000000..087084ca5 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/EntryTypeStepView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps; + +public partial class EntryTypeStepView : ReactiveUserControl +{ + public EntryTypeStepView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/EntryTypeStepViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/EntryTypeStepViewModel.cs new file mode 100644 index 000000000..e378e27a3 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/EntryTypeStepViewModel.cs @@ -0,0 +1,38 @@ +using System.Reactive.Linq; +using Artemis.WebClient.Workshop; +using ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps; + +public class EntryTypeStepViewModel : SubmissionViewModel +{ + private EntryType? _selectedEntryType; + + /// + public EntryTypeStepViewModel() + { + GoBack = ReactiveCommand.Create(() => State.ChangeScreen()); + Continue = ReactiveCommand.Create(ExecuteContinue, this.WhenAnyValue(vm => vm.SelectedEntryType).Select(e => e != null)); + } + +#if DEBUG + public bool ShowLayouts => true; +# else + public bool ShowLayouts => false; +#endif + + public EntryType? SelectedEntryType + { + get => _selectedEntryType; + set => RaiseAndSetIfChanged(ref _selectedEntryType, value); + } + + private void ExecuteContinue() + { + if (SelectedEntryType == null) + return; + + State.EntryType = SelectedEntryType.Value; + State.StartForCurrentEntry(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/LoginStepView.axaml b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/LoginStepView.axaml new file mode 100644 index 000000000..cfb532af8 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/LoginStepView.axaml @@ -0,0 +1,33 @@ + + + + + + + + First things first + + In order to submit anything to the workshop you must be logged in. + + Creating an account is free and we'll not bother you with a newsletter or crap like that. + + + + + + Click Log In below to (create an account) and log in. + + You'll also be able to log in with Google or Discord. + + + diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/LoginStepView.axaml.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/LoginStepView.axaml.cs new file mode 100644 index 000000000..3b4ec4b2b --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/LoginStepView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps; + +public partial class LoginStepView : ReactiveUserControl +{ + public LoginStepView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/LoginStepViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/LoginStepViewModel.cs new file mode 100644 index 000000000..5b6cf680b --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/LoginStepViewModel.cs @@ -0,0 +1,42 @@ +using System.Linq; +using System.Security.Claims; +using System.Threading; +using System.Threading.Tasks; +using Artemis.UI.Screens.Workshop.CurrentUser; +using Artemis.UI.Shared.Services; +using Artemis.WebClient.Workshop.Services; +using FluentAvalonia.UI.Controls; +using IdentityModel; +using ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps; + +public class LoginStepViewModel : SubmissionViewModel +{ + private readonly IAuthenticationService _authenticationService; + private readonly IWindowService _windowService; + + public LoginStepViewModel(IAuthenticationService authenticationService, IWindowService windowService) + { + _authenticationService = authenticationService; + _windowService = windowService; + + Continue = ReactiveCommand.CreateFromTask(ExecuteLogin); + ShowGoBack = false; + ShowHeader = false; + ContinueText = "Log In"; + } + + private async Task ExecuteLogin(CancellationToken ct) + { + ContentDialogResult result = await _windowService.CreateContentDialog().WithViewModel(out WorkshopLoginViewModel _).WithTitle("Workshop login").ShowAsync(); + if (result != ContentDialogResult.Primary) + return; + + Claim? emailVerified = _authenticationService.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.EmailVerified); + if (emailVerified?.Value == "true") + State.ChangeScreen(); + else + State.ChangeScreen(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileAdaptionHintsLayerViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileAdaptionHintsLayerViewModel.cs new file mode 100644 index 000000000..48b741698 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileAdaptionHintsLayerViewModel.cs @@ -0,0 +1,50 @@ +using System.Reactive; +using System.Reactive.Linq; +using System.Threading.Tasks; +using Artemis.Core; +using Artemis.Core.Services; +using Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs; +using Artemis.UI.Shared; +using Artemis.UI.Shared.Services; +using ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.Profile; + +public class ProfileAdaptionHintsLayerViewModel : ViewModelBase +{ + private readonly ObservableAsPropertyHelper _adaptionHintText; + private readonly IProfileService _profileService; + private readonly IWindowService _windowService; + private int _adaptionHintCount; + + public ProfileAdaptionHintsLayerViewModel(Layer layer, IWindowService windowService, IProfileService profileService) + { + _windowService = windowService; + _profileService = profileService; + _adaptionHintText = this.WhenAnyValue(vm => vm.AdaptionHintCount).Select(c => c == 1 ? "1 adaption hint" : $"{c} adaption hints").ToProperty(this, vm => vm.AdaptionHintText); + + Layer = layer; + EditAdaptionHints = ReactiveCommand.CreateFromTask(ExecuteEditAdaptionHints); + AdaptionHintCount = layer.Adapter.AdaptionHints.Count; + } + + public Layer Layer { get; } + + public ReactiveCommand EditAdaptionHints { get; } + + public int AdaptionHintCount + { + get => _adaptionHintCount; + private set => RaiseAndSetIfChanged(ref _adaptionHintCount, value); + } + + public string AdaptionHintText => _adaptionHintText.Value; + + private async Task ExecuteEditAdaptionHints() + { + await _windowService.ShowDialogAsync(Layer); + _profileService.SaveProfile(Layer.Profile, true); + + AdaptionHintCount = Layer.Adapter.AdaptionHints.Count; + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileAdaptionHintsStepView.axaml b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileAdaptionHintsStepView.axaml new file mode 100644 index 000000000..b85ffdb0f --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileAdaptionHintsStepView.axaml @@ -0,0 +1,67 @@ + + + + + + + + + Set up profile adaption hints + + + Add hints below to help decide where to place this each layer when the profile is imported by another user. + + + + + Learn more about adaption hints + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileAdaptionHintsStepView.axaml.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileAdaptionHintsStepView.axaml.cs new file mode 100644 index 000000000..a5f7815d7 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileAdaptionHintsStepView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.Profile; + +public partial class ProfileAdaptionHintsStepView : ReactiveUserControl +{ + public ProfileAdaptionHintsStepView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileAdaptionHintsStepViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileAdaptionHintsStepViewModel.cs new file mode 100644 index 000000000..fc55b987a --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileAdaptionHintsStepViewModel.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reactive; +using System.Reactive.Disposables; +using System.Threading.Tasks; +using Artemis.Core; +using Artemis.Core.Services; +using Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs; +using Artemis.UI.Shared.Services; +using DynamicData; +using DynamicData.Aggregation; +using ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.Profile; + +public class ProfileAdaptionHintsStepViewModel : SubmissionViewModel +{ + private readonly SourceList _layers; + private readonly IProfileService _profileService; + private readonly IWindowService _windowService; + + public ProfileAdaptionHintsStepViewModel(IWindowService windowService, IProfileService profileService, Func getLayerViewModel) + { + _windowService = windowService; + _profileService = profileService; + _layers = new SourceList(); + _layers.Connect().Bind(out ReadOnlyObservableCollection layers).Subscribe(); + + GoBack = ReactiveCommand.Create(() => State.ChangeScreen()); + Continue = ReactiveCommand.Create(ExecuteContinue, _layers.Connect().AutoRefresh(l => l.AdaptionHintCount).Filter(l => l.AdaptionHintCount == 0).IsEmpty()); + EditAdaptionHints = ReactiveCommand.CreateFromTask(ExecuteEditAdaptionHints); + Layers = layers; + + this.WhenActivated((CompositeDisposable _) => + { + if (State.EntrySource is ProfileConfiguration profileConfiguration && profileConfiguration.Profile != null) + _layers.Edit(l => + { + l.Clear(); + l.AddRange(profileConfiguration.Profile.GetAllLayers().Select(getLayerViewModel)); + }); + }); + } + + public ReactiveCommand EditAdaptionHints { get; } + public ReadOnlyObservableCollection Layers { get; } + + private async Task ExecuteEditAdaptionHints(Layer layer) + { + await _windowService.ShowDialogAsync(layer); + _profileService.SaveProfile(layer.Profile, true); + } + + private void ExecuteContinue() + { + if (Layers.Any(l => l.AdaptionHintCount == 0)) + return; + + if (State.EntryId == null) + State.ChangeScreen(); + else + State.ChangeScreen(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileSelectionStepView.axaml b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileSelectionStepView.axaml new file mode 100644 index 000000000..8fd0eb216 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileSelectionStepView.axaml @@ -0,0 +1,56 @@ + + + + + + + + + + Profile selection + + + Please select the profile you want to share, a preview will be shown below. + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileSelectionStepView.axaml.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileSelectionStepView.axaml.cs new file mode 100644 index 000000000..84cb5bf27 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileSelectionStepView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.Profile; + +public partial class ProfileSelectionStepView : ReactiveUserControl +{ + public ProfileSelectionStepView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileSelectionStepViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileSelectionStepViewModel.cs new file mode 100644 index 000000000..adad736d7 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileSelectionStepViewModel.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reactive.Disposables; +using System.Reactive.Linq; +using Artemis.Core; +using Artemis.Core.Services; +using Artemis.UI.Extensions; +using Artemis.UI.Screens.Workshop.Profile; +using Material.Icons; +using ReactiveUI; +using SkiaSharp; + +namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.Profile; + +public class ProfileSelectionStepViewModel : SubmissionViewModel +{ + private readonly IProfileService _profileService; + private ProfileConfiguration? _selectedProfile; + + /// + public ProfileSelectionStepViewModel(IProfileService profileService, ProfilePreviewViewModel profilePreviewViewModel) + { + _profileService = profileService; + + // Use copies of the profiles, the originals are used by the core and could be disposed + Profiles = new ObservableCollection(_profileService.ProfileConfigurations.Select(_profileService.CloneProfileConfiguration)); + foreach (ProfileConfiguration profileConfiguration in Profiles) + _profileService.LoadProfileConfigurationIcon(profileConfiguration); + + ProfilePreview = profilePreviewViewModel; + + GoBack = ReactiveCommand.Create(() => State.ChangeScreen()); + Continue = ReactiveCommand.Create(ExecuteContinue, this.WhenAnyValue(vm => vm.SelectedProfile).Select(p => p != null)); + + this.WhenAnyValue(vm => vm.SelectedProfile).Subscribe(p => Update(p)); + this.WhenActivated((CompositeDisposable _) => + { + ShowGoBack = State.EntryId == null; + if (State.EntrySource is ProfileConfiguration profileConfiguration) + SelectedProfile = Profiles.FirstOrDefault(p => p.ProfileId == profileConfiguration.ProfileId); + }); + } + + public ObservableCollection Profiles { get; } + public ProfilePreviewViewModel ProfilePreview { get; } + + public ProfileConfiguration? SelectedProfile + { + get => _selectedProfile; + set => RaiseAndSetIfChanged(ref _selectedProfile, value); + } + + private void Update(ProfileConfiguration? profileConfiguration) + { + ProfilePreview.ProfileConfiguration = null; + + foreach (ProfileConfiguration configuration in Profiles) + { + if (configuration == profileConfiguration) + _profileService.ActivateProfile(configuration); + else + _profileService.DeactivateProfile(configuration); + } + + ProfilePreview.ProfileConfiguration = profileConfiguration; + } + + private void ExecuteContinue() + { + if (SelectedProfile == null) + return; + + State.EntrySource = SelectedProfile; + State.Name = SelectedProfile.Name; + State.Icon = SelectedProfile.Icon.GetIconStream(); + + // Render the material icon of the profile + if (State.Icon == null && SelectedProfile.Icon.IconName != null) + State.Icon = Enum.Parse(SelectedProfile.Icon.IconName).EncodeToBitmap(128, 14, SKColors.White); + + State.ChangeScreen(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/SpecificationsStepView.axaml b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/SpecificationsStepView.axaml new file mode 100644 index 000000000..18e53f90a --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/SpecificationsStepView.axaml @@ -0,0 +1,26 @@ + + + + + + + + + + + Provide some general information on your submission below. + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/SpecificationsStepView.axaml.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/SpecificationsStepView.axaml.cs new file mode 100644 index 000000000..6d05e97a1 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/SpecificationsStepView.axaml.cs @@ -0,0 +1,17 @@ +using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps; + +public partial class SpecificationsStepView : ReactiveUserControl +{ + public SpecificationsStepView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/SpecificationsStepViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/SpecificationsStepViewModel.cs new file mode 100644 index 000000000..4e8a17c20 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/SpecificationsStepViewModel.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reactive.Disposables; +using Artemis.UI.Extensions; +using Artemis.UI.Screens.Workshop.Entries; +using Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.Profile; +using Artemis.WebClient.Workshop; +using DynamicData; +using ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps; + +public class SpecificationsStepViewModel : SubmissionViewModel +{ + private readonly Func _getEntrySpecificationsViewModel; + private EntrySpecificationsViewModel? _entrySpecificationsViewModel; + + public SpecificationsStepViewModel(Func getEntrySpecificationsViewModel) + { + _getEntrySpecificationsViewModel = getEntrySpecificationsViewModel; + + GoBack = ReactiveCommand.Create(ExecuteGoBack); + this.WhenActivated((CompositeDisposable d) => + { + DisplayName = $"{State.EntryType} Information"; + ApplyFromState(); + }); + } + + public EntrySpecificationsViewModel? EntrySpecificationsViewModel + { + get => _entrySpecificationsViewModel; + set => RaiseAndSetIfChanged(ref _entrySpecificationsViewModel, value); + } + + private void ExecuteGoBack() + { + // Apply what's there so far + ApplyToState(); + + switch (State.EntryType) + { + case EntryType.Layout: + break; + case EntryType.Plugin: + break; + case EntryType.Profile: + State.ChangeScreen(); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + private void ExecuteContinue() + { + if (EntrySpecificationsViewModel == null || !EntrySpecificationsViewModel.ValidationContext.GetIsValid()) + return; + + ApplyToState(); + State.ChangeScreen(); + } + + private void ApplyFromState() + { + EntrySpecificationsViewModel viewModel = _getEntrySpecificationsViewModel(); + + // Basic fields + viewModel.Name = State.Name; + viewModel.Summary = State.Summary; + viewModel.Description = State.Description; + + // Tags + viewModel.Tags.Clear(); + viewModel.Tags.AddRange(State.Tags); + + // Categories + viewModel.PreselectedCategories = State.Categories; + + // Icon + if (State.Icon != null) + { + State.Icon.Seek(0, SeekOrigin.Begin); + viewModel.IconBitmap = BitmapExtensions.LoadAndResize(State.Icon, 128); + } + + EntrySpecificationsViewModel = viewModel; + Continue = ReactiveCommand.Create(ExecuteContinue, EntrySpecificationsViewModel.ValidationContext.Valid); + } + + private void ApplyToState() + { + if (EntrySpecificationsViewModel == null) + return; + + // Basic fields + State.Name = EntrySpecificationsViewModel.Name; + State.Summary = EntrySpecificationsViewModel.Summary; + State.Description = EntrySpecificationsViewModel.Description; + + // Categories and tasks + State.Categories = EntrySpecificationsViewModel.Categories.Where(c => c.IsSelected).Select(c => c.Id).ToList(); + State.Tags = new List(EntrySpecificationsViewModel.Tags); + + // Icon + State.Icon?.Dispose(); + if (EntrySpecificationsViewModel.IconBitmap != null) + { + State.Icon = new MemoryStream(); + EntrySpecificationsViewModel.IconBitmap.Save(State.Icon); + } + else + { + State.Icon = null; + } + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/SubmitStepView.axaml b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/SubmitStepView.axaml new file mode 100644 index 000000000..381f0ffb9 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/SubmitStepView.axaml @@ -0,0 +1,71 @@ + + + + + + + + + Ready to submit? + + + We have all the information we need, are you ready to submit the following to the workshop? + + + + + + + + + + + + + + by + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Artemis.UI/Screens/Workshop/Layout/LayoutListView.axaml.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/SubmitStepView.axaml.cs similarity index 53% rename from src/Artemis.UI/Screens/Workshop/Layout/LayoutListView.axaml.cs rename to src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/SubmitStepView.axaml.cs index 9d604f4f6..ba64d1d7d 100644 --- a/src/Artemis.UI/Screens/Workshop/Layout/LayoutListView.axaml.cs +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/SubmitStepView.axaml.cs @@ -1,11 +1,11 @@ using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; -namespace Artemis.UI.Screens.Workshop.Layout; +namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps; -public partial class LayoutListView : ReactiveUserControl +public partial class SubmitStepView : ReactiveUserControl { - public LayoutListView() + public SubmitStepView() { InitializeComponent(); } diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/SubmitStepViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/SubmitStepViewModel.cs new file mode 100644 index 000000000..8544c30ef --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/SubmitStepViewModel.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using System.Reactive.Disposables; +using System.Reactive.Linq; +using Artemis.UI.Screens.Workshop.Categories; +using Artemis.WebClient.Workshop; +using Artemis.WebClient.Workshop.Services; +using Avalonia.Media.Imaging; +using IdentityModel; +using ReactiveUI; +using StrawberryShake; + +namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps; + +public class SubmitStepViewModel : SubmissionViewModel +{ + private ReadOnlyObservableCollection? _categories; + private Bitmap? _iconBitmap; + + /// + public SubmitStepViewModel(IAuthenticationService authenticationService, IWorkshopClient workshopClient) + { + CurrentUser = authenticationService.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Name)?.Value; + GoBack = ReactiveCommand.Create(() => State.ChangeScreen()); + Continue = ReactiveCommand.Create(() => State.ChangeScreen()); + + ContinueText = "Submit"; + + this.WhenActivated(d => + { + if (State.Icon != null) + { + State.Icon.Seek(0, SeekOrigin.Begin); + IconBitmap = new Bitmap(State.Icon); + IconBitmap.DisposeWith(d); + } + + Observable.FromAsync(workshopClient.GetCategories.ExecuteAsync).Subscribe(PopulateCategories).DisposeWith(d); + }); + } + + public Bitmap? IconBitmap + { + get => _iconBitmap; + set => RaiseAndSetIfChanged(ref _iconBitmap, value); + } + + public string? CurrentUser { get; } + + public ReadOnlyObservableCollection? Categories + { + get => _categories; + set => RaiseAndSetIfChanged(ref _categories, value); + } + + private void PopulateCategories(IOperationResult result) + { + if (result.Data == null) + Categories = null; + else + Categories = new ReadOnlyObservableCollection( + new ObservableCollection(result.Data.Categories.Where(c => State.Categories.Contains(c.Id)).Select(c => new CategoryViewModel(c))) + ); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/UploadStepView.axaml b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/UploadStepView.axaml new file mode 100644 index 000000000..e3b9e23c3 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/UploadStepView.axaml @@ -0,0 +1,45 @@ + + + + + + + + + + Uploading your submission... + + + + + + + + All done! Hit finish to view your submission. + + + + 😢 + + Unfortunately something went wrong while uploading your submission. + + Hit finish to view your submission, from there you can try to upload a new release. + If this keeps occuring, hit us up on Discord + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListView.axaml.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/UploadStepView.axaml.cs similarity index 53% rename from src/Artemis.UI/Screens/Workshop/Profile/ProfileListView.axaml.cs rename to src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/UploadStepView.axaml.cs index fb6c372c7..21d6bb439 100644 --- a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListView.axaml.cs +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/UploadStepView.axaml.cs @@ -1,11 +1,11 @@ using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; -namespace Artemis.UI.Screens.Workshop.Profile; +namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps; -public partial class ProfileListView : ReactiveUserControl +public partial class UploadStepView : ReactiveUserControl { - public ProfileListView() + public UploadStepView() { InitializeComponent(); } diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/UploadStepViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/UploadStepViewModel.cs new file mode 100644 index 000000000..ab59d122f --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/UploadStepViewModel.cs @@ -0,0 +1,184 @@ +using System; +using System.Reactive.Disposables; +using System.Reactive.Linq; +using System.Threading; +using System.Threading.Tasks; +using Artemis.UI.Shared.Routing; +using Artemis.UI.Shared.Services; +using Artemis.UI.Shared.Utilities; +using Artemis.WebClient.Workshop; +using Artemis.WebClient.Workshop.Exceptions; +using Artemis.WebClient.Workshop.Handlers.UploadHandlers; +using Artemis.WebClient.Workshop.Services; +using ReactiveUI; +using Serilog; +using StrawberryShake; + +namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps; + +public class UploadStepViewModel : SubmissionViewModel +{ + private readonly ILogger _logger; + private readonly EntryUploadHandlerFactory _entryUploadHandlerFactory; + private readonly Progress _progress = new(); + private readonly ObservableAsPropertyHelper _progressIndeterminate; + private readonly ObservableAsPropertyHelper _progressPercentage; + private readonly IRouter _router; + private readonly IWindowService _windowService; + private readonly IWorkshopClient _workshopClient; + private readonly IWorkshopService _workshopService; + + private long? _entryId; + private bool _failed; + private bool _finished; + private bool _succeeded; + + /// + public UploadStepViewModel(ILogger logger, + IWorkshopClient workshopClient, + IWorkshopService workshopService, + EntryUploadHandlerFactory entryUploadHandlerFactory, + IWindowService windowService, + IRouter router) + { + _logger = logger; + _workshopClient = workshopClient; + _workshopService = workshopService; + _entryUploadHandlerFactory = entryUploadHandlerFactory; + _windowService = windowService; + _router = router; + + ShowGoBack = false; + ContinueText = "Finish"; + Continue = ReactiveCommand.CreateFromTask(ExecuteContinue, this.WhenAnyValue(vm => vm.Finished)); + + _progressPercentage = Observable.FromEventPattern(x => _progress.ProgressChanged += x, x => _progress.ProgressChanged -= x) + .Select(e => e.EventArgs.ProgressPercentage) + .ToProperty(this, vm => vm.ProgressPercentage); + _progressIndeterminate = Observable.FromEventPattern(x => _progress.ProgressChanged += x, x => _progress.ProgressChanged -= x) + .Select(e => e.EventArgs.ProgressPercentage == 0) + .ToProperty(this, vm => vm.ProgressIndeterminate); + + this.WhenActivated(d => Observable.FromAsync(ExecuteUpload).Subscribe().DisposeWith(d)); + } + + public int ProgressPercentage => _progressPercentage.Value; + public bool ProgressIndeterminate => _progressIndeterminate.Value; + + public bool Finished + { + get => _finished; + set => RaiseAndSetIfChanged(ref _finished, value); + } + + public bool Succeeded + { + get => _succeeded; + set => RaiseAndSetIfChanged(ref _succeeded, value); + } + + public bool Failed + { + get => _failed; + set => RaiseAndSetIfChanged(ref _failed, value); + } + + private async Task ExecuteUpload(CancellationToken cancellationToken) + { + // Use the existing entry or create a new one + _entryId = State.EntryId ?? await CreateEntry(cancellationToken); + + // If a new entry had to be created but that failed, stop here, CreateEntry will send the user back + if (_entryId == null) + return; + + try + { + IEntryUploadHandler uploadHandler = _entryUploadHandlerFactory.CreateHandler(State.EntryType); + EntryUploadResult uploadResult = await uploadHandler.CreateReleaseAsync(_entryId.Value, State.EntrySource!, _progress, cancellationToken); + if (!uploadResult.IsSuccess) + { + string? message = uploadResult.Message; + if (message != null) + message += "\r\n\r\n"; + else + message = ""; + message += "Your submission has still been saved, you may try to upload a new release"; + await _windowService.ShowConfirmContentDialog("Failed to upload workshop entry", message, "Close", null); + } + + Succeeded = true; + } + catch (Exception e) + { + _logger.Error(e, "Failed to upload submission for entry {EntryId}", _entryId); + + // Something went wrong when creating a release :c + // We'll keep the workshop entry so that the user can make changes and try again + Failed = true; + } + finally + { + Finished = true; + } + } + + private async Task CreateEntry(CancellationToken cancellationToken) + { + IOperationResult result = await _workshopClient.AddEntry.ExecuteAsync(new CreateEntryInput + { + EntryType = State.EntryType, + Name = State.Name, + Summary = State.Summary, + Description = State.Description, + Categories = State.Categories, + Tags = State.Tags + }, cancellationToken); + + long? entryId = result.Data?.AddEntry?.Id; + if (result.IsErrorResult() || entryId == null) + { + await _windowService.ShowConfirmContentDialog("Failed to create workshop entry", result.Errors.ToString() ?? "Not even an error message", "Close", null); + State.ChangeScreen(); + return null; + } + + if (cancellationToken.IsCancellationRequested) + { + State.ChangeScreen(); + return null; + } + + + if (State.Icon == null) + return entryId; + + // Upload image + try + { + ImageUploadResult imageUploadResult = await _workshopService.SetEntryIcon(entryId.Value, _progress, State.Icon, cancellationToken); + if (!imageUploadResult.IsSuccess) + throw new ArtemisWorkshopException(imageUploadResult.Message); + } + catch (Exception e) + { + // It's not critical if this fails + await _windowService.ShowConfirmContentDialog( + "Failed to upload icon", + "Your submission will continue, you can try upload a new image afterwards\r\n" + e.Message, + "Continue", + null + ); + } + + return entryId; + } + + private async Task ExecuteContinue() + { + State.Close(); + + if (_entryId != null) + await _router.Navigate($"workshop/library/submissions/{_entryId.Value}"); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/ValidateEmailStepView.axaml b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/ValidateEmailStepView.axaml new file mode 100644 index 000000000..17745e6c1 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/ValidateEmailStepView.axaml @@ -0,0 +1,50 @@ + + + + + + + + Confirm email address + + Before you can continue, please confirm your email address. () + + You'll find the confirmation mail in your inbox. + + + Don't see an email? Check your spam box! + + + + + + + + + + + + PS: We take this step to avoid the workshop getting spammed with low quality content. + + + diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/ValidateEmailStepView.axaml.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/ValidateEmailStepView.axaml.cs new file mode 100644 index 000000000..a5899731e --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/ValidateEmailStepView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps; + +public partial class ValidateEmailStepView : ReactiveUserControl +{ + public ValidateEmailStepView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/ValidateEmailStepViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/ValidateEmailStepViewModel.cs new file mode 100644 index 000000000..a2a840421 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/ValidateEmailStepViewModel.cs @@ -0,0 +1,78 @@ +using System; +using System.Diagnostics; +using System.Linq; +using System.Reactive; +using System.Reactive.Disposables; +using System.Security.Claims; +using System.Threading; +using System.Threading.Tasks; +using Artemis.Core; +using Artemis.WebClient.Workshop; +using Artemis.WebClient.Workshop.Services; +using IdentityModel; +using ReactiveUI; +using Timer = System.Timers.Timer; + +namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps; + +public class ValidateEmailStepViewModel : SubmissionViewModel +{ + private readonly IAuthenticationService _authenticationService; + private ObservableAsPropertyHelper? _email; + + public ValidateEmailStepViewModel(IAuthenticationService authenticationService) + { + _authenticationService = authenticationService; + + Continue = ReactiveCommand.Create(ExecuteContinue); + Refresh = ReactiveCommand.CreateFromTask(ExecuteRefresh); + Resend = ReactiveCommand.Create(() => Utilities.OpenUrl(WorkshopConstants.AUTHORITY_URL + "/account/confirm/resend")); + + ShowGoBack = false; + ShowHeader = false; + + this.WhenActivated(d => + { + _email = authenticationService.GetClaim(JwtClaimTypes.Email).ToProperty(this, vm => vm.Email).DisposeWith(d); + + Timer updateTimer = new(TimeSpan.FromSeconds(15)); + updateTimer.Elapsed += (_, _) => Task.Run(Update); + updateTimer.Start(); + + updateTimer.DisposeWith(d); + }); + } + + public ReactiveCommand Refresh { get; } + public ReactiveCommand Resend { get; } + + public Claim? Email => _email?.Value; + + private async Task Update() + { + try + { + // Use the refresh token to login again, updating claims + await _authenticationService.AutoLogin(true); + + Claim? emailVerified = _authenticationService.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.EmailVerified); + if (emailVerified?.Value == "true") + ExecuteContinue(); + } + catch (Exception) + { + // ignored, meh + } + } + + private void ExecuteContinue() + { + State.ChangeScreen(); + } + + private async Task ExecuteRefresh(CancellationToken ct) + { + await Update(); + await Task.Delay(1000, ct); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepView.axaml b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepView.axaml index 7341a2307..9f9538c38 100644 --- a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepView.axaml +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepView.axaml @@ -2,10 +2,18 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - x:Class="Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.WelcomeStepView"> - - Welcome to the Workshop Submission Wizard 🧙 - Here we'll take you, step by step, through the process of uploading your submission to the workshop. + xmlns:steps="clr-namespace:Artemis.UI.Screens.Workshop.SubmissionWizard.Steps" + mc:Ignorable="d" d:DesignWidth="970" d:DesignHeight="900" + x:Class="Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.WelcomeStepView" + x:DataType="steps:WelcomeStepViewModel"> + + + Welcome to the Workshop Submission Wizard 🧙 + + + Here we'll take you, step by step, through the process of uploading your submission to the workshop. + + + - + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepView.axaml.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepView.axaml.cs index 9de30c623..cfeea65f8 100644 --- a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepView.axaml.cs +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepView.axaml.cs @@ -1,4 +1,3 @@ -using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps; @@ -9,9 +8,4 @@ public partial class WelcomeStepView : ReactiveUserControl { InitializeComponent(); } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepViewModel.cs index cf70f6410..87c96fb7d 100644 --- a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepViewModel.cs @@ -1,22 +1,38 @@ -using System.Reactive; +using System.Linq; +using System.Threading.Tasks; +using Artemis.WebClient.Workshop.Services; +using IdentityModel; using ReactiveUI; namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps; public class WelcomeStepViewModel : SubmissionViewModel { - #region Overrides of SubmissionViewModel + private readonly IAuthenticationService _authenticationService; - /// - public override ReactiveCommand Continue { get; } - - /// - public override ReactiveCommand GoBack { get; } = null!; - - public WelcomeStepViewModel() + public WelcomeStepViewModel(IAuthenticationService authenticationService) { + _authenticationService = authenticationService; + + Continue = ReactiveCommand.CreateFromTask(ExecuteContinue); + ShowHeader = false; ShowGoBack = false; } - #endregion + private async Task ExecuteContinue() + { + bool loggedIn = await _authenticationService.AutoLogin(true); + + if (!loggedIn) + { + State.ChangeScreen(); + } + else + { + if (_authenticationService.Claims.Any(c => c.Type == JwtClaimTypes.EmailVerified && c.Value == "true")) + State.ChangeScreen(); + else + State.ChangeScreen(); + } + } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionViewModel.cs new file mode 100644 index 000000000..282b34590 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionViewModel.cs @@ -0,0 +1,53 @@ +using System.Reactive; +using Artemis.UI.Shared; +using ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.SubmissionWizard; + +public abstract class SubmissionViewModel : ValidatableViewModelBase +{ + private ReactiveCommand? _continue; + private ReactiveCommand? _goBack; + private string _continueText = "Continue"; + private bool _showFinish; + private bool _showGoBack = true; + private bool _showHeader = true; + + public SubmissionWizardState State { get; set; } = null!; + + public ReactiveCommand? Continue + { + get => _continue; + set => RaiseAndSetIfChanged(ref _continue, value); + } + + public ReactiveCommand? GoBack + { + get => _goBack; + set => RaiseAndSetIfChanged(ref _goBack, value); + } + + public bool ShowHeader + { + get => _showHeader; + set => RaiseAndSetIfChanged(ref _showHeader, value); + } + + public bool ShowGoBack + { + get => _showGoBack; + set => RaiseAndSetIfChanged(ref _showGoBack, value); + } + + public bool ShowFinish + { + get => _showFinish; + set => RaiseAndSetIfChanged(ref _showFinish, value); + } + + public string ContinueText + { + get => _continueText; + set => RaiseAndSetIfChanged(ref _continueText, value); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardState.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardState.cs new file mode 100644 index 000000000..893896621 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardState.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.Profile; +using Artemis.UI.Shared.Services; +using Artemis.WebClient.Workshop; +using DryIoc; + +namespace Artemis.UI.Screens.Workshop.SubmissionWizard; + +public class SubmissionWizardState +{ + private readonly IContainer _container; + private readonly IWindowService _windowService; + private readonly IWorkshopWizardViewModel _wizardViewModel; + + public SubmissionWizardState(IWorkshopWizardViewModel wizardViewModel, IContainer container, IWindowService windowService) + { + _wizardViewModel = wizardViewModel; + _container = container; + _windowService = windowService; + } + + public EntryType EntryType { get; set; } + public long? EntryId { get; set; } + + public string Name { get; set; } = string.Empty; + public Stream? Icon { get; set; } + public string Summary { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + + public List Categories { get; set; } = new(); + public List Tags { get; set; } = new(); + public List Images { get; set; } = new(); + + public object? EntrySource { get; set; } + + public void ChangeScreen() where TSubmissionViewModel : SubmissionViewModel + { + try + { + _wizardViewModel.Screen = _container.Resolve(); + } + catch (Exception e) + { + _windowService.ShowExceptionDialog("Wizard screen failed to activate", e); + } + } + + public void Close() + { + _wizardViewModel.ShouldClose = true; + } + + public void StartForCurrentEntry() + { + if (EntryType == EntryType.Profile) + ChangeScreen(); + else + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml index 18315e3fc..d64ed0199 100644 --- a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml @@ -12,12 +12,13 @@ Icon="/Assets/Images/Logo/application.ico" Title="Artemis | Workshop submission wizard" Width="1000" - Height="735" + Height="950" WindowStartupLocation="CenterOwner"> - + + @@ -44,9 +45,7 @@ - + diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml.cs index 58dade5ef..6c7ece92f 100644 --- a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml.cs +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml.cs @@ -1,5 +1,6 @@ using System; using System.Reactive.Disposables; +using System.Reactive.Linq; using Artemis.UI.Shared; using Avalonia; using Avalonia.Threading; @@ -17,6 +18,7 @@ public partial class SubmissionWizardView : ReactiveAppWindow ViewModel.WhenAnyValue(vm => vm.Screen).Subscribe(Navigate).DisposeWith(d)); + this.WhenActivated(d => ViewModel.WhenAnyValue(vm => vm.ShouldClose).Where(c => c).Subscribe(_ => Close()).DisposeWith(d)); } private void Navigate(SubmissionViewModel viewModel) @@ -25,9 +27,9 @@ public partial class SubmissionWizardView : ReactiveAppWindow Frame.NavigateFromObject(viewModel)); } - catch (Exception) + catch (Exception e) { - // ignored + ViewModel?.WindowService.ShowExceptionDialog("Wizard screen failed to activate", e); } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardViewModel.cs index fed2c3241..a18c63e71 100644 --- a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardViewModel.cs @@ -1,47 +1,47 @@ -using System.Reactive; -using Artemis.UI.Screens.Workshop.CurrentUser; +using Artemis.UI.Screens.Workshop.CurrentUser; using Artemis.UI.Screens.Workshop.SubmissionWizard.Steps; using Artemis.UI.Shared; -using ReactiveUI; +using Artemis.UI.Shared.Services; +using DryIoc; namespace Artemis.UI.Screens.Workshop.SubmissionWizard; -public class SubmissionWizardViewModel : DialogViewModelBase +public class SubmissionWizardViewModel : ActivatableViewModelBase, IWorkshopWizardViewModel { + private readonly SubmissionWizardState _state; private SubmissionViewModel _screen; + private bool _shouldClose; - public SubmissionWizardViewModel(CurrentUserViewModel currentUserViewModel) + public SubmissionWizardViewModel(IContainer container, + IWindowService windowService, + CurrentUserViewModel currentUserViewModel, + WelcomeStepViewModel welcomeStepViewModel) { - _screen = new WelcomeStepViewModel(); + _state = new SubmissionWizardState(this, container, windowService); + _screen = welcomeStepViewModel; + _screen.State = _state; + + WindowService = windowService; CurrentUserViewModel = currentUserViewModel; + CurrentUserViewModel.AllowLogout = false; } + public IWindowService WindowService { get; } public CurrentUserViewModel CurrentUserViewModel { get; } public SubmissionViewModel Screen { get => _screen; - set => RaiseAndSetIfChanged(ref _screen, value); - } -} - -public abstract class SubmissionViewModel : ActivatableViewModelBase -{ - private bool _showFinish; - private bool _showGoBack = true; - - public abstract ReactiveCommand Continue { get; } - public abstract ReactiveCommand GoBack { get; } - - public bool ShowGoBack - { - get => _showGoBack; - set => RaiseAndSetIfChanged(ref _showGoBack, value); + set + { + value.State = _state; + RaiseAndSetIfChanged(ref _screen, value); + } } - public bool ShowFinish + public bool ShouldClose { - get => _showFinish; - set => RaiseAndSetIfChanged(ref _showFinish, value); + get => _shouldClose; + set => RaiseAndSetIfChanged(ref _shouldClose, value); } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs b/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs index f6b53a013..aa6fc9eb2 100644 --- a/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs @@ -1,38 +1,18 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using Artemis.UI.Screens.Workshop.Home; +using Artemis.UI.Screens.Workshop.Home; using Artemis.UI.Screens.Workshop.Search; using Artemis.UI.Shared; using Artemis.UI.Shared.Routing; -using Artemis.WebClient.Workshop; namespace Artemis.UI.Screens.Workshop; -public class WorkshopViewModel : RoutableScreen, IMainScreenViewModel +public class WorkshopViewModel : RoutableHostScreen, IMainScreenViewModel { - private readonly SearchViewModel _searchViewModel; - public WorkshopViewModel(SearchViewModel searchViewModel, WorkshopHomeViewModel homeViewModel) { - _searchViewModel = searchViewModel; - TitleBarViewModel = searchViewModel; HomeViewModel = homeViewModel; } public ViewModelBase TitleBarViewModel { get; } public WorkshopHomeViewModel HomeViewModel { get; } - - /// - public override Task OnNavigating(NavigationArguments args, CancellationToken cancellationToken) - { - _searchViewModel.EntryType = Screen?.EntryType; - return Task.CompletedTask; - } -} - -public interface IWorkshopViewModel -{ - public EntryType? EntryType { get; } } \ No newline at end of file diff --git a/src/Artemis.UI/Services/DebugService.cs b/src/Artemis.UI/Services/DebugService.cs index 138bfa994..62b644f29 100644 --- a/src/Artemis.UI/Services/DebugService.cs +++ b/src/Artemis.UI/Services/DebugService.cs @@ -22,7 +22,8 @@ public class DebugService : IDebugService private void CreateDebugger() { - _debugViewModel = _windowService.ShowWindow(); + _windowService.ShowWindow(out DebugViewModel debugViewModel); + _debugViewModel = debugViewModel; } public void ClearDebugger() diff --git a/src/Artemis.UI/Services/Updating/ReleaseInstaller.cs b/src/Artemis.UI/Services/Updating/ReleaseInstaller.cs index 04ca4f74f..91a9a2c9c 100644 --- a/src/Artemis.UI/Services/Updating/ReleaseInstaller.cs +++ b/src/Artemis.UI/Services/Updating/ReleaseInstaller.cs @@ -9,6 +9,8 @@ using System.Threading.Tasks; using Artemis.Core; using Artemis.UI.Exceptions; using Artemis.UI.Extensions; +using Artemis.UI.Shared.Extensions; +using Artemis.UI.Shared.Utilities; using Artemis.WebClient.Updating; using Octodiff.Core; using Octodiff.Diagnostics; @@ -32,7 +34,7 @@ public class ReleaseInstaller : CorePropertyChanged private IGetReleaseById_PublishedRelease _release = null!; private IGetReleaseById_PublishedRelease_Artifacts _artifact = null!; - private Progress _stepProgress = new(); + private Progress _stepProgress = new(); private string _status = string.Empty; private float _floatProgress; @@ -69,9 +71,7 @@ public class ReleaseInstaller : CorePropertyChanged public async Task InstallAsync(CancellationToken cancellationToken) { - _stepProgress = new Progress(); - - ((IProgress) _progress).Report(0); + _stepProgress = new Progress(); Status = "Retrieving details"; _logger.Information("Retrieving details for release {ReleaseId}", _releaseId); @@ -99,7 +99,7 @@ public class ReleaseInstaller : CorePropertyChanged { // 10 - 50% _stepProgress.ProgressChanged += StepProgressOnProgressChanged; - void StepProgressOnProgressChanged(object? sender, float e) => ((IProgress) _progress).Report(10f + e * 0.4f); + void StepProgressOnProgressChanged(object? sender, StreamProgress e) => ((IProgress) _progress).Report(10f + e.ProgressPercentage * 0.4f); Status = "Downloading..."; await using MemoryStream stream = new(); @@ -113,7 +113,7 @@ public class ReleaseInstaller : CorePropertyChanged { // 50 - 60% _stepProgress.ProgressChanged += StepProgressOnProgressChanged; - void StepProgressOnProgressChanged(object? sender, float e) => ((IProgress) _progress).Report(50f + e * 0.1f); + void StepProgressOnProgressChanged(object? sender, StreamProgress e) => ((IProgress) _progress).Report(50f + e.ProgressPercentage * 0.1f); Status = "Patching..."; await using FileStream newFileStream = new(Path.Combine(Constants.UpdatingFolder, $"{_release.Version}.zip"), FileMode.Create, FileAccess.ReadWrite, FileShare.Read); @@ -139,7 +139,7 @@ public class ReleaseInstaller : CorePropertyChanged { // 10 - 60% _stepProgress.ProgressChanged += StepProgressOnProgressChanged; - void StepProgressOnProgressChanged(object? sender, float e) => ((IProgress) _progress).Report(10f + e * 0.5f); + void StepProgressOnProgressChanged(object? sender, StreamProgress e) => ((IProgress) _progress).Report(10f + e.ProgressPercentage * 0.5f); Status = "Downloading..."; await using FileStream stream = new(Path.Combine(Constants.UpdatingFolder, $"{_release.Version}.zip"), FileMode.Create, FileAccess.ReadWrite, FileShare.Read); @@ -155,7 +155,7 @@ public class ReleaseInstaller : CorePropertyChanged { // 60 - 100% _stepProgress.ProgressChanged += StepProgressOnProgressChanged; - void StepProgressOnProgressChanged(object? sender, float e) => ((IProgress) _progress).Report(60f + e * 0.4f); + void StepProgressOnProgressChanged(object? sender, StreamProgress e) => ((IProgress) _progress).Report(60f + e.ProgressPercentage * 0.4f); Status = "Extracting..."; // Ensure the directory is empty diff --git a/src/Artemis.UI/Styles/Artemis.axaml b/src/Artemis.UI/Styles/Artemis.axaml index 3b700ecdc..55109b2d3 100644 --- a/src/Artemis.UI/Styles/Artemis.axaml +++ b/src/Artemis.UI/Styles/Artemis.axaml @@ -1,16 +1,32 @@  + xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" + xmlns:aedit="using:AvaloniaEdit" + xmlns:aedit2="using:AvaloniaEdit.Editing"> + + + + + + + + + avares://Artemis.UI/Assets/Fonts#Roboto Mono diff --git a/src/Artemis.UI/Styles/Markdown.axaml b/src/Artemis.UI/Styles/Markdown.axaml index 5374e71b0..6f03f8291 100644 --- a/src/Artemis.UI/Styles/Markdown.axaml +++ b/src/Artemis.UI/Styles/Markdown.axaml @@ -2,6 +2,9 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:avalonia="clr-namespace:Markdown.Avalonia;assembly=Markdown.Avalonia" xmlns:ctxt="clr-namespace:ColorTextBlock.Avalonia;assembly=ColorTextBlock.Avalonia"> + diff --git a/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj b/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj index 913205f9b..379f1ad87 100644 --- a/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj +++ b/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj @@ -23,12 +23,4 @@ - - - - HotkeyPressNodeCustomView.axaml - Code - - - diff --git a/src/Artemis.VisualScripting/Nodes/Static/Screens/DisplayValueNodeCustomView.axaml b/src/Artemis.VisualScripting/Nodes/Static/Screens/DisplayValueNodeCustomView.axaml index 8ddaf5f77..8831dd1e9 100644 --- a/src/Artemis.VisualScripting/Nodes/Static/Screens/DisplayValueNodeCustomView.axaml +++ b/src/Artemis.VisualScripting/Nodes/Static/Screens/DisplayValueNodeCustomView.axaml @@ -25,7 +25,7 @@ Text="{CompiledBinding Converter={StaticResource SKColorToStringConverter}}" VerticalAlignment="Center" HorizontalAlignment="Stretch" - FontFamily="Consolas"/> + FontFamily="{StaticResource RobotoMono}"/> - + diff --git a/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj b/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj index e09fefe42..391d5c4b5 100644 --- a/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj +++ b/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj @@ -25,6 +25,7 @@ + @@ -34,5 +35,21 @@ MSBuild:GenerateGraphQLCode + + MSBuild:GenerateGraphQLCode + + + MSBuild:GenerateGraphQLCode + + + MSBuild:GenerateGraphQLCode + + + MSBuild:GenerateGraphQLCode + + + + + diff --git a/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs b/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs index bdcdbede6..ddadc110e 100644 --- a/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs +++ b/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs @@ -1,5 +1,10 @@ +using System.Reflection; +using Artemis.WebClient.Workshop.Extensions; +using Artemis.WebClient.Workshop.Handlers.InstallationHandlers; +using Artemis.WebClient.Workshop.Handlers.UploadHandlers; using Artemis.WebClient.Workshop.Repositories; using Artemis.WebClient.Workshop.Services; +using Artemis.WebClient.Workshop.State; using DryIoc; using DryIoc.Microsoft.DependencyInjection; using IdentityModel.Client; @@ -18,11 +23,17 @@ public static class ContainerExtensions /// The builder building the current container public static void RegisterWorkshopClient(this IContainer container) { + Assembly[] workshopAssembly = {typeof(WorkshopConstants).Assembly}; + ServiceCollection serviceCollection = new(); serviceCollection .AddHttpClient() .AddWorkshopClient() + .AddHttpMessageHandler() .ConfigureHttpClient(client => client.BaseAddress = new Uri(WorkshopConstants.WORKSHOP_URL + "/graphql")); + serviceCollection.AddHttpClient(WorkshopConstants.WORKSHOP_CLIENT_NAME) + .AddHttpMessageHandler() + .ConfigureHttpClient(client => client.BaseAddress = new Uri(WorkshopConstants.WORKSHOP_URL)); serviceCollection.AddSingleton(r => { @@ -34,5 +45,10 @@ public static class ContainerExtensions container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); + container.Register(Reuse.Singleton); + + container.Register(Reuse.Transient); + container.RegisterMany(workshopAssembly, type => type.IsAssignableTo(), Reuse.Transient); + container.RegisterMany(workshopAssembly, type => type.IsAssignableTo(), Reuse.Transient); } } \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Entities/Release.cs b/src/Artemis.WebClient.Workshop/Entities/Release.cs new file mode 100644 index 000000000..ace9fb21f --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Entities/Release.cs @@ -0,0 +1,22 @@ +using System.ComponentModel.DataAnnotations; + +namespace Artemis.WebClient.Workshop.Entities; + +public class Release +{ + public long Id { get; set; } + + [MaxLength(64)] + public string Version { get; set; } = string.Empty; + + public DateTimeOffset CreatedAt { get; set; } + + public long Downloads { get; set; } + + public long DownloadSize { get; set; } + + [MaxLength(32)] + public string? Md5Hash { get; set; } + + public long EntryId { get; set; } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Exceptions/ArtemisWebClientException.cs b/src/Artemis.WebClient.Workshop/Exceptions/ArtemisWebClientException.cs index 1bd2af386..a5400594c 100644 --- a/src/Artemis.WebClient.Workshop/Exceptions/ArtemisWebClientException.cs +++ b/src/Artemis.WebClient.Workshop/Exceptions/ArtemisWebClientException.cs @@ -1,6 +1,4 @@ -using System; - -namespace Artemis.Core; +namespace Artemis.WebClient.Workshop.Exceptions; /// /// An exception thrown when a web client related error occurs diff --git a/src/Artemis.WebClient.Workshop/Exceptions/ArtemisWorkshopException.cs b/src/Artemis.WebClient.Workshop/Exceptions/ArtemisWorkshopException.cs new file mode 100644 index 000000000..968526086 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Exceptions/ArtemisWorkshopException.cs @@ -0,0 +1,22 @@ +namespace Artemis.WebClient.Workshop.Exceptions; + +/// +/// An exception thrown when a workshop related error occurs +/// +public class ArtemisWorkshopException : Exception +{ + /// + public ArtemisWorkshopException() + { + } + + /// + public ArtemisWorkshopException(string? message) : base(message) + { + } + + /// + public ArtemisWorkshopException(string? message, Exception? innerException) : base(message, innerException) + { + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Extensions/ClientBuilderExtensions.cs b/src/Artemis.WebClient.Workshop/Extensions/ClientBuilderExtensions.cs new file mode 100644 index 000000000..6db06795f --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Extensions/ClientBuilderExtensions.cs @@ -0,0 +1,18 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Http; +using StrawberryShake; + +namespace Artemis.WebClient.Workshop.Extensions; + +public static class ClientBuilderExtensions +{ + public static IClientBuilder AddHttpMessageHandler(this IClientBuilder builder) where THandler : DelegatingHandler where T : IStoreAccessor + { + builder.Services.Configure( + builder.ClientName, + options => options.HttpMessageHandlerBuilderActions.Add(b => b.AdditionalHandlers.Add(b.Services.GetRequiredService())) + ); + + return builder; + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/EntryInstallResult.cs b/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/EntryInstallResult.cs new file mode 100644 index 000000000..aaf56859e --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/EntryInstallResult.cs @@ -0,0 +1,26 @@ +namespace Artemis.WebClient.Workshop.Handlers.InstallationHandlers; + +public class EntryInstallResult +{ + public bool IsSuccess { get; set; } + public string? Message { get; set; } + public object? Result { get; set; } + + public static EntryInstallResult FromFailure(string? message) + { + return new EntryInstallResult + { + IsSuccess = false, + Message = message + }; + } + + public static EntryInstallResult FromSuccess(object installationResult) + { + return new EntryInstallResult + { + IsSuccess = true, + Result = installationResult + }; + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/EntryInstallationHandlerFactory.cs b/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/EntryInstallationHandlerFactory.cs new file mode 100644 index 000000000..ec9c63566 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/EntryInstallationHandlerFactory.cs @@ -0,0 +1,23 @@ +using Artemis.WebClient.Workshop.Handlers.InstallationHandlers.Implementations; +using DryIoc; + +namespace Artemis.WebClient.Workshop.Handlers.InstallationHandlers; + +public class EntryInstallationHandlerFactory +{ + private readonly IContainer _container; + + public EntryInstallationHandlerFactory(IContainer container) + { + _container = container; + } + + public IEntryInstallationHandler CreateHandler(EntryType entryType) + { + return entryType switch + { + EntryType.Profile => _container.Resolve(), + _ => throw new NotSupportedException($"EntryType '{entryType}' is not supported.") + }; + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/EntryUninstallResult.cs b/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/EntryUninstallResult.cs new file mode 100644 index 000000000..6d28edf9a --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/EntryUninstallResult.cs @@ -0,0 +1,24 @@ +namespace Artemis.WebClient.Workshop.Handlers.InstallationHandlers; + +public class EntryUninstallResult +{ + public bool IsSuccess { get; set; } + public string? Message { get; set; } + + public static EntryUninstallResult FromFailure(string? message) + { + return new EntryUninstallResult + { + IsSuccess = false, + Message = message + }; + } + + public static EntryUninstallResult FromSuccess() + { + return new EntryUninstallResult + { + IsSuccess = true + }; + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/IEntryInstallationHandler.cs b/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/IEntryInstallationHandler.cs new file mode 100644 index 000000000..d8e7ba951 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/IEntryInstallationHandler.cs @@ -0,0 +1,10 @@ +using Artemis.UI.Shared.Utilities; +using Artemis.WebClient.Workshop.Services; + +namespace Artemis.WebClient.Workshop.Handlers.InstallationHandlers; + +public interface IEntryInstallationHandler +{ + Task InstallAsync(IGetEntryById_Entry entry, long releaseId, Progress progress, CancellationToken cancellationToken); + Task UninstallAsync(InstalledEntry installedEntry, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/Implementations/ProfileEntryInstallationHandler.cs b/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/Implementations/ProfileEntryInstallationHandler.cs new file mode 100644 index 000000000..f3473f66a --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/Implementations/ProfileEntryInstallationHandler.cs @@ -0,0 +1,99 @@ +using Artemis.Core; +using Artemis.Core.Services; +using Artemis.UI.Shared.Extensions; +using Artemis.UI.Shared.Utilities; +using Artemis.WebClient.Workshop.Services; + +namespace Artemis.WebClient.Workshop.Handlers.InstallationHandlers.Implementations; + +public class ProfileEntryInstallationHandler : IEntryInstallationHandler +{ + private readonly IHttpClientFactory _httpClientFactory; + private readonly IProfileService _profileService; + private readonly IWorkshopService _workshopService; + + public ProfileEntryInstallationHandler(IHttpClientFactory httpClientFactory, IProfileService profileService, IWorkshopService workshopService) + { + _httpClientFactory = httpClientFactory; + _profileService = profileService; + _workshopService = workshopService; + } + + public async Task InstallAsync(IGetEntryById_Entry entry, long releaseId, Progress progress, CancellationToken cancellationToken) + { + using MemoryStream stream = new(); + + // Download the provided release + try + { + HttpClient client = _httpClientFactory.CreateClient(WorkshopConstants.WORKSHOP_CLIENT_NAME); + await client.DownloadDataAsync($"releases/download/{releaseId}", stream, progress, cancellationToken); + } + catch (Exception e) + { + return EntryInstallResult.FromFailure(e.Message); + } + + // Find existing installation to potentially replace the profile + InstalledEntry? installedEntry = _workshopService.GetInstalledEntry(entry); + if (installedEntry != null && Guid.TryParse(installedEntry.LocalReference, out Guid profileId)) + { + ProfileConfiguration? existing = _profileService.ProfileCategories.SelectMany(c => c.ProfileConfigurations).FirstOrDefault(c => c.ProfileId == profileId); + if (existing != null) + { + ProfileConfiguration overwritten = await _profileService.OverwriteProfile(stream, existing); + installedEntry.LocalReference = overwritten.ProfileId.ToString(); + + // Update the release and return the profile configuration + UpdateRelease(releaseId, installedEntry); + return EntryInstallResult.FromSuccess(overwritten); + } + } + + // Ensure there is an installed entry + installedEntry ??= _workshopService.CreateInstalledEntry(entry); + + // Add the profile as a fresh import + ProfileCategory category = _profileService.ProfileCategories.FirstOrDefault(c => c.Name == "Workshop") ?? _profileService.CreateProfileCategory("Workshop", true); + ProfileConfiguration imported = await _profileService.ImportProfile(stream, category, true, true, null); + installedEntry.LocalReference = imported.ProfileId.ToString(); + + // Update the release and return the profile configuration + UpdateRelease(releaseId, installedEntry); + return EntryInstallResult.FromSuccess(imported); + } + + public async Task UninstallAsync(InstalledEntry installedEntry, CancellationToken cancellationToken) + { + if (!Guid.TryParse(installedEntry.LocalReference, out Guid profileId)) + return EntryUninstallResult.FromFailure("Local reference does not contain a GUID"); + + return await Task.Run(() => + { + try + { + // Find the profile if still there + ProfileConfiguration? profile = _profileService.ProfileConfigurations.FirstOrDefault(c => c.ProfileId == profileId); + if (profile != null) + _profileService.DeleteProfile(profile); + + // Remove the release + _workshopService.RemoveInstalledEntry(installedEntry); + } + catch (Exception e) + { + return EntryUninstallResult.FromFailure(e.Message); + } + + return EntryUninstallResult.FromSuccess(); + }, cancellationToken); + } + + private void UpdateRelease(long releaseId, InstalledEntry installedEntry) + { + installedEntry.ReleaseId = releaseId; + installedEntry.ReleaseVersion = "TODO"; + installedEntry.InstalledAt = DateTimeOffset.UtcNow; + _workshopService.SaveInstalledEntry(installedEntry); + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/EntryUploadHandlerFactory.cs b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/EntryUploadHandlerFactory.cs new file mode 100644 index 000000000..17dc5245c --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/EntryUploadHandlerFactory.cs @@ -0,0 +1,24 @@ +using Artemis.WebClient.Workshop.Handlers.UploadHandlers.Implementations; +using DryIoc; + +namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers; + +public class EntryUploadHandlerFactory +{ + private readonly IContainer _container; + + public EntryUploadHandlerFactory(IContainer container) + { + _container = container; + } + + public IEntryUploadHandler CreateHandler(EntryType entryType) + { + return entryType switch + { + EntryType.Profile => _container.Resolve(), + EntryType.Layout => _container.Resolve(), + _ => throw new NotSupportedException($"EntryType '{entryType}' is not supported.") + }; + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/EntryUploadResult.cs b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/EntryUploadResult.cs new file mode 100644 index 000000000..f55a3dd77 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/EntryUploadResult.cs @@ -0,0 +1,28 @@ +using Artemis.WebClient.Workshop.Entities; + +namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers; + +public class EntryUploadResult +{ + public bool IsSuccess { get; set; } + public string? Message { get; set; } + public Release? Release { get; set; } + + public static EntryUploadResult FromFailure(string? message) + { + return new EntryUploadResult + { + IsSuccess = false, + Message = message + }; + } + + public static EntryUploadResult FromSuccess(Release release) + { + return new EntryUploadResult + { + IsSuccess = true, + Release = release + }; + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/IEntryUploadHandler.cs b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/IEntryUploadHandler.cs new file mode 100644 index 000000000..88ff68896 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/IEntryUploadHandler.cs @@ -0,0 +1,8 @@ +using Artemis.UI.Shared.Utilities; + +namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers; + +public interface IEntryUploadHandler +{ + Task CreateReleaseAsync(long entryId, object file, Progress progress, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/ImageUploadResult.cs b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/ImageUploadResult.cs new file mode 100644 index 000000000..7ebc08d2f --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/ImageUploadResult.cs @@ -0,0 +1,21 @@ +namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers; + +public class ImageUploadResult +{ + public bool IsSuccess { get; set; } + public string? Message { get; set; } + + public static ImageUploadResult FromFailure(string? message) + { + return new ImageUploadResult + { + IsSuccess = false, + Message = message + }; + } + + public static ImageUploadResult FromSuccess() + { + return new ImageUploadResult {IsSuccess = true}; + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/LayoutEntryUploadHandler.cs b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/LayoutEntryUploadHandler.cs new file mode 100644 index 000000000..0b16fae3d --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/LayoutEntryUploadHandler.cs @@ -0,0 +1,12 @@ +using Artemis.UI.Shared.Utilities; + +namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers.Implementations; + +public class LayoutEntryUploadHandler : IEntryUploadHandler +{ + /// + public async Task CreateReleaseAsync(long entryId, object file, Progress progress, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/ProfileEntryUploadHandler.cs b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/ProfileEntryUploadHandler.cs new file mode 100644 index 000000000..4ec607d85 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/ProfileEntryUploadHandler.cs @@ -0,0 +1,46 @@ +using System.Net.Http.Headers; +using Artemis.Core; +using Artemis.Core.Services; +using Artemis.UI.Shared.Utilities; +using Artemis.WebClient.Workshop.Entities; +using Newtonsoft.Json; + +namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers.Implementations; + +public class ProfileEntryUploadHandler : IEntryUploadHandler +{ + private readonly IHttpClientFactory _httpClientFactory; + private readonly IProfileService _profileService; + + public ProfileEntryUploadHandler(IHttpClientFactory httpClientFactory, IProfileService profileService) + { + _httpClientFactory = httpClientFactory; + _profileService = profileService; + } + + /// + public async Task CreateReleaseAsync(long entryId, object file, Progress progress, CancellationToken cancellationToken) + { + if (file is not ProfileConfiguration profileConfiguration) + throw new InvalidOperationException("Can only create releases for profile configurations"); + + await using Stream archiveStream = await _profileService.ExportProfile(profileConfiguration); + + // Submit the archive + HttpClient client = _httpClientFactory.CreateClient(WorkshopConstants.WORKSHOP_CLIENT_NAME); + + // Construct the request + MultipartFormDataContent content = new(); + ProgressableStreamContent streamContent = new(archiveStream, progress); + streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/zip"); + content.Add(streamContent, "file", "file.zip"); + + // Submit + HttpResponseMessage response = await client.PostAsync("releases/upload/" + entryId, content, cancellationToken); + if (!response.IsSuccessStatusCode) + return EntryUploadResult.FromFailure($"{response.StatusCode} - {await response.Content.ReadAsStringAsync(cancellationToken)}"); + + Release? release = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync(cancellationToken)); + return release != null ? EntryUploadResult.FromSuccess(release) : EntryUploadResult.FromFailure("Failed to deserialize response"); + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Queries/CreateEntry.graphql b/src/Artemis.WebClient.Workshop/Queries/CreateEntry.graphql new file mode 100644 index 000000000..7191bc704 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Queries/CreateEntry.graphql @@ -0,0 +1,5 @@ +mutation AddEntry ($input: CreateEntryInput!) { + addEntry(input: $input) { + id + } +} diff --git a/src/Artemis.WebClient.Workshop/Queries/GetCategories.graphql b/src/Artemis.WebClient.Workshop/Queries/GetCategories.graphql index d39be92f2..864caa217 100644 --- a/src/Artemis.WebClient.Workshop/Queries/GetCategories.graphql +++ b/src/Artemis.WebClient.Workshop/Queries/GetCategories.graphql @@ -1,5 +1,5 @@ query GetCategories { - categories { + categories(order: {name: ASC}) { id name icon diff --git a/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql b/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql index c7e639c31..e5e0648be 100644 --- a/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql +++ b/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql @@ -1,5 +1,5 @@ query GetEntries($filter: EntryFilterInput $skip: Int $take: Int) { - entries(where: $filter skip: $skip take: $take) { + entries(where: $filter skip: $skip take: $take, order: {createdAt: DESC}) { totalCount items { id @@ -8,7 +8,7 @@ query GetEntries($filter: EntryFilterInput $skip: Int $take: Int) { summary entryType downloads - createdAt + createdAt categories { name icon diff --git a/src/Artemis.WebClient.Workshop/Queries/GetEntryById.graphql b/src/Artemis.WebClient.Workshop/Queries/GetEntryById.graphql index e5ba4a96d..932ccef30 100644 --- a/src/Artemis.WebClient.Workshop/Queries/GetEntryById.graphql +++ b/src/Artemis.WebClient.Workshop/Queries/GetEntryById.graphql @@ -1,7 +1,23 @@ -query GetEntryById($id: UUID!) { +query GetEntryById($id: Long!) { entry(id: $id) { + id author name + summary entryType + downloads + createdAt + description + categories { + name + icon + } + latestRelease { + id + version + downloadSize + md5Hash + createdAt + } } } \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Queries/GetSubmittedEntries.graphql b/src/Artemis.WebClient.Workshop/Queries/GetSubmittedEntries.graphql new file mode 100644 index 000000000..d4199e074 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Queries/GetSubmittedEntries.graphql @@ -0,0 +1,14 @@ +query GetSubmittedEntries($filter: EntryFilterInput) { + submittedEntries(where: $filter order: {createdAt: DESC}) { + id + name + summary + entryType + downloads + createdAt + categories { + name + icon + } + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Queries/GetSubmittedEntryById.graphql b/src/Artemis.WebClient.Workshop/Queries/GetSubmittedEntryById.graphql new file mode 100644 index 000000000..ea7b0bab3 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Queries/GetSubmittedEntryById.graphql @@ -0,0 +1,17 @@ +query GetSubmittedEntryById($id: Long!) { + entry(id: $id) { + id + name + summary + entryType + downloads + createdAt + description + categories { + id + } + tags { + name + } + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Queries/RemoveEntry.graphql b/src/Artemis.WebClient.Workshop/Queries/RemoveEntry.graphql new file mode 100644 index 000000000..983fbe0d9 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Queries/RemoveEntry.graphql @@ -0,0 +1,5 @@ +mutation RemoveEntry ($id: Long!) { + removeEntry(id: $id) { + id + } +} diff --git a/src/Artemis.WebClient.Workshop/Queries/SearchEntries.graphql b/src/Artemis.WebClient.Workshop/Queries/SearchEntries.graphql index 620aeb70d..27e4eabbd 100644 --- a/src/Artemis.WebClient.Workshop/Queries/SearchEntries.graphql +++ b/src/Artemis.WebClient.Workshop/Queries/SearchEntries.graphql @@ -4,6 +4,7 @@ query SearchEntries($input: String! $type: EntryType) { name summary entryType + author categories { id name diff --git a/src/Artemis.WebClient.Workshop/Queries/UpdateEntry.graphql b/src/Artemis.WebClient.Workshop/Queries/UpdateEntry.graphql new file mode 100644 index 000000000..fe53ec3e5 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Queries/UpdateEntry.graphql @@ -0,0 +1,5 @@ +mutation UpdateEntry ($input: UpdateEntryInput!) { + updateEntry(input: $input) { + id + } +} diff --git a/src/Artemis.WebClient.Workshop/Services/AccessToken.cs b/src/Artemis.WebClient.Workshop/Services/AccessToken.cs index f67dd9395..7f4f7ba04 100644 --- a/src/Artemis.WebClient.Workshop/Services/AccessToken.cs +++ b/src/Artemis.WebClient.Workshop/Services/AccessToken.cs @@ -1,4 +1,5 @@ using Artemis.Core; +using Artemis.WebClient.Workshop.Exceptions; using IdentityModel.Client; namespace Artemis.WebClient.Workshop.Services; diff --git a/src/Artemis.WebClient.Workshop/Services/AuthenticationDelegatingHandler.cs b/src/Artemis.WebClient.Workshop/Services/AuthenticationDelegatingHandler.cs new file mode 100644 index 000000000..3adda3145 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Services/AuthenticationDelegatingHandler.cs @@ -0,0 +1,22 @@ +using System.Net.Http.Headers; + +namespace Artemis.WebClient.Workshop.Services; + +public class AuthenticationDelegatingHandler : DelegatingHandler +{ + private readonly IAuthenticationService _authenticationService; + + /// + public AuthenticationDelegatingHandler(IAuthenticationService authenticationService) + { + _authenticationService = authenticationService; + } + + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + string? token = await _authenticationService.GetBearer(); + if (token != null) + request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); + return await base.SendAsync(request, cancellationToken); + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Services/AuthenticationService.cs b/src/Artemis.WebClient.Workshop/Services/AuthenticationService.cs new file mode 100644 index 000000000..5f47d2567 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Services/AuthenticationService.cs @@ -0,0 +1,296 @@ +using System.Collections.ObjectModel; +using System.IdentityModel.Tokens.Jwt; +using System.Net; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Security.Claims; +using System.Security.Cryptography; +using System.Text; +using Artemis.Core; +using Artemis.WebClient.Workshop.Exceptions; +using Artemis.WebClient.Workshop.Repositories; +using DynamicData; +using IdentityModel; +using IdentityModel.Client; +using Serilog; + +namespace Artemis.WebClient.Workshop.Services; + +internal class AuthenticationService : CorePropertyChanged, IAuthenticationService +{ + private const string CLIENT_ID = "artemis.desktop"; + private readonly IAuthenticationRepository _authenticationRepository; + private readonly SemaphoreSlim _authLock = new(1); + private readonly SourceList _claims; + + private readonly IDiscoveryCache _discoveryCache; + private readonly ILogger _logger; + private readonly IHttpClientFactory _httpClientFactory; + private readonly BehaviorSubject _isLoggedInSubject = new(false); + + private AuthenticationToken? _token; + private bool _noStoredRefreshToken; + + public AuthenticationService(ILogger logger, IHttpClientFactory httpClientFactory, IDiscoveryCache discoveryCache, IAuthenticationRepository authenticationRepository) + { + _logger = logger; + _httpClientFactory = httpClientFactory; + _discoveryCache = discoveryCache; + _authenticationRepository = authenticationRepository; + + _claims = new SourceList(); + _claims.Connect().Bind(out ReadOnlyObservableCollection claims).Subscribe(); + Claims = claims; + } + + private async Task GetDiscovery() + { + DiscoveryDocumentResponse disco = await _discoveryCache.GetAsync(); + if (disco.IsError) + throw new ArtemisWebClientException("Failed to retrieve discovery document: " + disco.Error); + + return disco; + } + + private void SetCurrentUser(TokenResponse response) + { + _token = new AuthenticationToken(response); + SetStoredRefreshToken(_token.RefreshToken); + + JwtSecurityTokenHandler handler = new(); + JwtSecurityToken? token = handler.ReadJwtToken(response.IdentityToken); + if (token == null) + throw new ArtemisWebClientException("Failed to read JWT token"); + + _claims.Edit(c => + { + c.Clear(); + c.AddRange(token.Claims); + }); + + _isLoggedInSubject.OnNext(true); + } + + private async Task UseRefreshToken(string refreshToken) + { + try + { + DiscoveryDocumentResponse disco = await GetDiscovery(); + HttpClient client = _httpClientFactory.CreateClient(); + TokenResponse response = await client.RequestRefreshTokenAsync(new RefreshTokenRequest + { + Address = disco.TokenEndpoint, + ClientId = CLIENT_ID, + RefreshToken = refreshToken + }); + + if (response.IsError) + { + if (response.Error is OidcConstants.TokenErrors.ExpiredToken or OidcConstants.TokenErrors.InvalidGrant) + { + SetStoredRefreshToken(null); + return false; + } + + throw new ArtemisWebClientException("Failed to request refresh token: " + response.Error); + } + + SetCurrentUser(response); + return true; + } + catch (Exception e) + { + _logger.Error(e, "Failed to use refresh token"); + SetStoredRefreshToken(null); + return false; + } + } + + private static byte[] HashSha256(string inputString) + { + using SHA256 sha256 = SHA256.Create(); + return sha256.ComputeHash(Encoding.UTF8.GetBytes(inputString)); + } + + /// + public IObservable IsLoggedIn => _isLoggedInSubject.AsObservable(); + + /// + public ReadOnlyObservableCollection Claims { get; } + + /// + public IObservable GetClaim(string type) + { + return _claims.Connect() + .Filter(c => c.Type == JwtClaimTypes.Email) + .ToCollection() + .Select(f => f.FirstOrDefault()); + } + + public async Task GetBearer() + { + await _authLock.WaitAsync(); + + try + { + // If not logged in, attempt to auto login first + if (!_isLoggedInSubject.Value) + await InternalAutoLogin(); + + // If there is no token, even after an auto-login, there's no bearer to add + if (_token == null) + return null; + + // If the token is expiring, refresh it + if (_token.Expired && !await UseRefreshToken(_token.RefreshToken)) + return null; + + return _token.AccessToken; + } + catch (Exception e) + { + _logger.Error(e, "Failed to retrieve bearer token"); + return null; + } + finally + { + _authLock.Release(); + } + } + + /// + public async Task AutoLogin(bool force = false) + { + await _authLock.WaitAsync(); + + try + { + return await InternalAutoLogin(force); + } + finally + { + _authLock.Release(); + } + } + + + /// + public async Task Login(CancellationToken cancellationToken) + { + await _authLock.WaitAsync(cancellationToken); + + try + { + if (_isLoggedInSubject.Value) + return; + + // Start a HTTP listener, this port could be in use but chances are very slim + string redirectUri = "http://localhost:56789"; + using HttpListener listener = new(); + listener.Prefixes.Add(redirectUri + "/"); + listener.Start(); + + // Discover the Identity endpoint + DiscoveryDocumentResponse disco = await GetDiscovery(); + if (disco.AuthorizeEndpoint == null) + throw new ArtemisWebClientException("Could not determine the authorize endpoint"); + + // Generate the PKCE code verifier and code challenge + string codeVerifier = CryptoRandom.CreateUniqueId(); + string codeChallenge = Base64Url.Encode(HashSha256(codeVerifier)); + string state = Guid.NewGuid().ToString("N"); + + // Open the web browser for the user to log in and authorize the app + RequestUrl authRequestUrl = new(disco.AuthorizeEndpoint); + string url = authRequestUrl.CreateAuthorizeUrl( + CLIENT_ID, + "code", + "openid profile email offline_access api", + redirectUri, + state, + codeChallenge: codeChallenge, + codeChallengeMethod: OidcConstants.CodeChallengeMethods.Sha256); + Utilities.OpenUrl(url); + + // Wait for the callback with the code + HttpListenerContext context = await listener.GetContextAsync().WaitAsync(cancellationToken); + string? code = context.Request.QueryString.Get("code"); + string? returnState = context.Request.QueryString.Get("state"); + + // Validate that a code was given and that our state matches, ensuring we don't respond to a request we did not initialize + if (code == null || returnState != state) + throw new ArtemisWebClientException("Did not get the expected response on the callback"); + + // Redirect the browser to a page hosted by Identity indicating success + context.Response.StatusCode = (int) HttpStatusCode.Redirect; + context.Response.AddHeader("Location", $"{WorkshopConstants.AUTHORITY_URL}/account/login/success"); + context.Response.Close(); + + // Request auth tokens + HttpClient client = _httpClientFactory.CreateClient(); + TokenResponse response = await client.RequestAuthorizationCodeTokenAsync(new AuthorizationCodeTokenRequest + { + Address = disco.TokenEndpoint, + ClientId = CLIENT_ID, + Code = code, + CodeVerifier = codeVerifier, + RedirectUri = redirectUri + }, cancellationToken); + + if (response.IsError) + throw new ArtemisWebClientException("Failed to request device authorization: " + response.Error); + + // Set the current user using the new tokens + SetCurrentUser(response); + + listener.Stop(); + listener.Close(); + } + catch (HttpListenerException e) + { + throw new ArtemisWebClientException($"HTTP listener for login callback failed with error code {e.ErrorCode}", e); + } + finally + { + _authLock.Release(); + } + } + + /// + public void Logout() + { + _token = null; + _claims.Clear(); + SetStoredRefreshToken(null); + + _isLoggedInSubject.OnNext(false); + } + + private async Task InternalAutoLogin(bool force = false) + { + if (!force && _isLoggedInSubject.Value) + return true; + + if (_noStoredRefreshToken) + return false; + + string? refreshToken = GetStoredRefreshToken(); + if (refreshToken == null) + return false; + + return await UseRefreshToken(refreshToken); + } + + private string? GetStoredRefreshToken() + { + string? token = _authenticationRepository.GetRefreshToken(); + _noStoredRefreshToken = token == null; + return token; + } + + private void SetStoredRefreshToken(string? token) + { + _authenticationRepository.SetRefreshToken(token); + _noStoredRefreshToken = token == null; + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Services/IAuthenticationService.cs b/src/Artemis.WebClient.Workshop/Services/IAuthenticationService.cs deleted file mode 100644 index eed47ecff..000000000 --- a/src/Artemis.WebClient.Workshop/Services/IAuthenticationService.cs +++ /dev/null @@ -1,214 +0,0 @@ -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.IdentityModel.Tokens.Jwt; -using System.Security.Claims; -using Artemis.Core; -using Artemis.Core.Services; -using Artemis.WebClient.Workshop.Repositories; -using IdentityModel; -using IdentityModel.Client; - -namespace Artemis.WebClient.Workshop.Services; - -public interface IAuthenticationService : IProtectedArtemisService -{ - bool IsLoggedIn { get; } - string? UserCode { get; } - ReadOnlyObservableCollection Claims { get; } - - Task GetBearer(); - Task AutoLogin(); - Task Login(); - void Logout(); -} - -internal class AuthenticationService : CorePropertyChanged, IAuthenticationService -{ - private const string CLIENT_ID = "artemis.desktop"; - - private readonly IDiscoveryCache _discoveryCache; - private readonly IAuthenticationRepository _authenticationRepository; - private readonly IHttpClientFactory _httpClientFactory; - private readonly ObservableCollection _claims = new(); - private readonly SemaphoreSlim _bearerLock = new(1); - - private AuthenticationToken? _token; - private string? _userCode; - private bool _isLoggedIn; - - public AuthenticationService(IHttpClientFactory httpClientFactory, IDiscoveryCache discoveryCache, IAuthenticationRepository authenticationRepository) - { - _httpClientFactory = httpClientFactory; - _discoveryCache = discoveryCache; - _authenticationRepository = authenticationRepository; - - Claims = new ReadOnlyObservableCollection(_claims); - } - - /// - public bool IsLoggedIn - { - get => _isLoggedIn; - private set => SetAndNotify(ref _isLoggedIn, value); - } - - /// - public string? UserCode - { - get => _userCode; - private set => SetAndNotify(ref _userCode, value); - } - - /// - public ReadOnlyObservableCollection Claims { get; } - - public async Task GetBearer() - { - await _bearerLock.WaitAsync(); - - try - { - // If not logged in, attempt to auto login first - if (!IsLoggedIn) - await AutoLogin(); - - if (_token == null) - return null; - - // If the token is expiring, refresh it - if (_token.Expired && !await UseRefreshToken(_token.RefreshToken)) - return null; - - return _token.AccessToken; - } - finally - { - _bearerLock.Release(); - } - } - - /// - public async Task AutoLogin() - { - if (IsLoggedIn) - return true; - - string? refreshToken = _authenticationRepository.GetRefreshToken(); - if (refreshToken == null) - return false; - - return await UseRefreshToken(refreshToken); - } - - /// - public async Task Login() - { - DiscoveryDocumentResponse disco = await GetDiscovery(); - HttpClient client = _httpClientFactory.CreateClient(); - DeviceAuthorizationResponse response = await client.RequestDeviceAuthorizationAsync(new DeviceAuthorizationRequest - { - Address = disco.DeviceAuthorizationEndpoint, - ClientId = CLIENT_ID, - Scope = "openid profile email offline_access api" - }); - if (response.IsError) - throw new ArtemisWebClientException("Failed to request device authorization: " + response.Error); - if (response.DeviceCode == null) - throw new ArtemisWebClientException("Failed to request device authorization: Got no device code"); - - DateTimeOffset timeout = DateTimeOffset.UtcNow.AddSeconds(response.ExpiresIn ?? 1800); - - Process.Start(new ProcessStartInfo {FileName = response.VerificationUriComplete, UseShellExecute = true}); - await Task.Delay(TimeSpan.FromSeconds(response.Interval)); - while (DateTimeOffset.UtcNow < timeout) - { - bool success = await AttemptRequestDeviceToken(client, response.DeviceCode); - if (success) - return true; - await Task.Delay(TimeSpan.FromSeconds(response.Interval)); - } - - return false; - } - - /// - public void Logout() - { - _token = null; - _claims.Clear(); - _authenticationRepository.SetRefreshToken(null); - - IsLoggedIn = false; - } - - private async Task GetDiscovery() - { - DiscoveryDocumentResponse disco = await _discoveryCache.GetAsync(); - if (disco.IsError) - throw new ArtemisWebClientException("Failed to retrieve discovery document: " + disco.Error); - - return disco; - } - - private async Task AttemptRequestDeviceToken(HttpClient client, string deviceCode) - { - DiscoveryDocumentResponse disco = await GetDiscovery(); - TokenResponse response = await client.RequestDeviceTokenAsync(new DeviceTokenRequest - { - Address = disco.TokenEndpoint, - ClientId = CLIENT_ID, - DeviceCode = deviceCode - }); - - if (response.IsError) - { - if (response.Error == OidcConstants.TokenErrors.AuthorizationPending || response.Error == OidcConstants.TokenErrors.SlowDown) - return false; - - throw new ArtemisWebClientException("Failed to request device token: " + response.Error); - } - - SetCurrentUser(response); - return true; - } - - private void SetCurrentUser(TokenResponse response) - { - _token = new AuthenticationToken(response); - _authenticationRepository.SetRefreshToken(_token.RefreshToken); - - JwtSecurityTokenHandler handler = new(); - JwtSecurityToken? token = handler.ReadJwtToken(response.IdentityToken); - if (token == null) - throw new ArtemisWebClientException("Failed to read JWT token"); - - _claims.Clear(); - foreach (Claim responseClaim in token.Claims) - _claims.Add(responseClaim); - - IsLoggedIn = true; - } - - private async Task UseRefreshToken(string refreshToken) - { - DiscoveryDocumentResponse disco = await GetDiscovery(); - HttpClient client = _httpClientFactory.CreateClient(); - TokenResponse response = await client.RequestRefreshTokenAsync(new RefreshTokenRequest() - { - Address = disco.TokenEndpoint, - ClientId = CLIENT_ID, - RefreshToken = refreshToken - }); - - if (response.IsError) - { - if (response.Error == OidcConstants.TokenErrors.ExpiredToken) - return false; - - throw new ArtemisWebClientException("Failed to request refresh token: " + response.Error); - } - - SetCurrentUser(response); - return false; - } -} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Services/InstalledEntry.cs b/src/Artemis.WebClient.Workshop/Services/InstalledEntry.cs new file mode 100644 index 000000000..8d5cebd18 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Services/InstalledEntry.cs @@ -0,0 +1,68 @@ +using Artemis.Storage.Entities.Workshop; + +namespace Artemis.WebClient.Workshop.Services; + +public class InstalledEntry +{ + internal InstalledEntry(EntryEntity entity) + { + Entity = entity; + + Load(); + } + + public InstalledEntry(IGetEntryById_Entry entry) + { + Entity = new EntryEntity(); + + EntryId = entry.Id; + EntryType = entry.EntryType; + + Author = entry.Author; + Name = entry.Name; + } + + public long EntryId { get; set; } + public EntryType EntryType { get; set; } + + public string Author { get; set; } = string.Empty; + public string Name { get; set; } = string.Empty; + + public long ReleaseId { get; set; } + public string ReleaseVersion { get; set; } = string.Empty; + public DateTimeOffset InstalledAt { get; set; } + + public string? LocalReference { get; set; } + + internal EntryEntity Entity { get; } + + internal void Load() + { + EntryId = Entity.EntryId; + EntryType = (EntryType) Entity.EntryType; + + Author = Entity.Author; + Name = Entity.Name; + + ReleaseId = Entity.ReleaseId; + ReleaseVersion = Entity.ReleaseVersion; + InstalledAt = Entity.InstalledAt; + + LocalReference = Entity.LocalReference; + } + + internal void Save() + { + Entity.EntryId = EntryId; + Entity.EntryType = (int) EntryType; + + Entity.Author = Author; + Entity.Name = Name; + + Entity.ReleaseId = ReleaseId; + Entity.ReleaseVersion = ReleaseVersion; + Entity.InstalledAt = InstalledAt; + + Entity.LocalReference = LocalReference; + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Services/Interfaces/IAuthenticationService.cs b/src/Artemis.WebClient.Workshop/Services/Interfaces/IAuthenticationService.cs new file mode 100644 index 000000000..c3a3686ba --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Services/Interfaces/IAuthenticationService.cs @@ -0,0 +1,17 @@ +using System.Collections.ObjectModel; +using System.Security.Claims; +using Artemis.Core.Services; + +namespace Artemis.WebClient.Workshop.Services; + +public interface IAuthenticationService : IProtectedArtemisService +{ + IObservable IsLoggedIn { get; } + ReadOnlyObservableCollection Claims { get; } + + IObservable GetClaim(string type); + Task GetBearer(); + Task AutoLogin(bool force = false); + Task Login(CancellationToken cancellationToken); + void Logout(); +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Services/Interfaces/IWorkshopService.cs b/src/Artemis.WebClient.Workshop/Services/Interfaces/IWorkshopService.cs new file mode 100644 index 000000000..3f2303c00 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Services/Interfaces/IWorkshopService.cs @@ -0,0 +1,22 @@ +using Artemis.UI.Shared.Utilities; +using Artemis.WebClient.Workshop.Handlers.UploadHandlers; + +namespace Artemis.WebClient.Workshop.Services; + +public interface IWorkshopService +{ + Task GetEntryIcon(long entryId, CancellationToken cancellationToken); + Task SetEntryIcon(long entryId, Progress progress, Stream icon, CancellationToken cancellationToken); + Task GetWorkshopStatus(CancellationToken cancellationToken); + Task ValidateWorkshopStatus(CancellationToken cancellationToken); + Task NavigateToEntry(long entryId, EntryType entryType); + + List GetInstalledEntries(); + InstalledEntry? GetInstalledEntry(IGetEntryById_Entry entry); + InstalledEntry CreateInstalledEntry(IGetEntryById_Entry entry); + void RemoveInstalledEntry(InstalledEntry installedEntry); + void SaveInstalledEntry(InstalledEntry entry); + + + public record WorkshopStatus(bool IsReachable, string Message); +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Services/WorkshopService.cs b/src/Artemis.WebClient.Workshop/Services/WorkshopService.cs new file mode 100644 index 000000000..f40a15375 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Services/WorkshopService.cs @@ -0,0 +1,139 @@ +using System.Net.Http.Headers; +using Artemis.Storage.Entities.Workshop; +using Artemis.Storage.Repositories.Interfaces; +using Artemis.UI.Shared.Routing; +using Artemis.UI.Shared.Utilities; +using Artemis.WebClient.Workshop.Handlers.UploadHandlers; + +namespace Artemis.WebClient.Workshop.Services; + +public class WorkshopService : IWorkshopService +{ + private readonly IHttpClientFactory _httpClientFactory; + private readonly IRouter _router; + private readonly IEntryRepository _entryRepository; + + public WorkshopService(IHttpClientFactory httpClientFactory, IRouter router, IEntryRepository entryRepository) + { + _httpClientFactory = httpClientFactory; + _router = router; + _entryRepository = entryRepository; + } + + public async Task GetEntryIcon(long entryId, CancellationToken cancellationToken) + { + HttpClient client = _httpClientFactory.CreateClient(WorkshopConstants.WORKSHOP_CLIENT_NAME); + try + { + HttpResponseMessage response = await client.GetAsync($"entries/{entryId}/icon", cancellationToken); + response.EnsureSuccessStatusCode(); + return await response.Content.ReadAsStreamAsync(cancellationToken); + } + catch (HttpRequestException) + { + // ignored + return null; + } + } + + public async Task SetEntryIcon(long entryId, Progress progress, Stream icon, CancellationToken cancellationToken) + { + icon.Seek(0, SeekOrigin.Begin); + + // Submit the archive + HttpClient client = _httpClientFactory.CreateClient(WorkshopConstants.WORKSHOP_CLIENT_NAME); + + // Construct the request + MultipartFormDataContent content = new(); + ProgressableStreamContent streamContent = new(icon, progress); + streamContent.Headers.ContentType = new MediaTypeHeaderValue("image/png"); + content.Add(streamContent, "file", "file.png"); + + // Submit + HttpResponseMessage response = await client.PostAsync($"entries/{entryId}/icon", content, cancellationToken); + if (!response.IsSuccessStatusCode) + return ImageUploadResult.FromFailure($"{response.StatusCode} - {await response.Content.ReadAsStringAsync(cancellationToken)}"); + return ImageUploadResult.FromSuccess(); + } + + /// + public async Task GetWorkshopStatus(CancellationToken cancellationToken) + { + try + { + // Don't use the workshop client which adds auth headers + HttpClient client = _httpClientFactory.CreateClient(); + HttpResponseMessage response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Head, WorkshopConstants.WORKSHOP_URL + "/status"), cancellationToken); + return new IWorkshopService.WorkshopStatus(response.IsSuccessStatusCode, response.StatusCode.ToString()); + } + catch (OperationCanceledException e) + { + return new IWorkshopService.WorkshopStatus(false, e.Message); + } + catch (HttpRequestException e) + { + return new IWorkshopService.WorkshopStatus(false, e.Message); + } + } + + /// + public async Task ValidateWorkshopStatus(CancellationToken cancellationToken) + { + IWorkshopService.WorkshopStatus status = await GetWorkshopStatus(cancellationToken); + if (!status.IsReachable && !cancellationToken.IsCancellationRequested) + await _router.Navigate($"workshop/offline/{status.Message}"); + return status.IsReachable; + } + + public async Task NavigateToEntry(long entryId, EntryType entryType) + { + switch (entryType) + { + case EntryType.Profile: + await _router.Navigate($"workshop/entries/profiles/details/{entryId}"); + break; + case EntryType.Layout: + await _router.Navigate($"workshop/entries/layouts/details/{entryId}"); + break; + case EntryType.Plugin: + await _router.Navigate($"workshop/entries/plugins/details/{entryId}"); + break; + default: + throw new ArgumentOutOfRangeException(nameof(entryType)); + } + } + + public List GetInstalledEntries() + { + return _entryRepository.GetAll().Select(e => new InstalledEntry(e)).ToList(); + } + + /// + public InstalledEntry? GetInstalledEntry(IGetEntryById_Entry entry) + { + EntryEntity? entity = _entryRepository.GetByEntryId(entry.Id); + if (entity == null) + return null; + + return new InstalledEntry(entity); + } + + /// + public InstalledEntry CreateInstalledEntry(IGetEntryById_Entry entry) + { + return new InstalledEntry(entry); + } + + /// + public void RemoveInstalledEntry(InstalledEntry installedEntry) + { + _entryRepository.Remove(installedEntry.Entity); + } + + /// + public void SaveInstalledEntry(InstalledEntry entry) + { + entry.Save(); + _entryRepository.Save(entry.Entity); + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/WorkshopConstants.cs b/src/Artemis.WebClient.Workshop/WorkshopConstants.cs index b514ae862..192a92b56 100644 --- a/src/Artemis.WebClient.Workshop/WorkshopConstants.cs +++ b/src/Artemis.WebClient.Workshop/WorkshopConstants.cs @@ -4,4 +4,5 @@ public static class WorkshopConstants { public const string AUTHORITY_URL = "https://identity.artemis-rgb.com"; public const string WORKSHOP_URL = "https://workshop.artemis-rgb.com"; + public const string WORKSHOP_CLIENT_NAME = "WorkshopApiClient"; } \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/graphql.config.yml b/src/Artemis.WebClient.Workshop/graphql.config.yml index 9662a514f..a8ba99703 100644 --- a/src/Artemis.WebClient.Workshop/graphql.config.yml +++ b/src/Artemis.WebClient.Workshop/graphql.config.yml @@ -2,7 +2,7 @@ schema: schema.graphql extensions: endpoints: Default GraphQL Endpoint: - url: https://workshop.artemis-rgb.com/graphql + url: https://localhost:7281/graphql headers: user-agent: JS GraphQL introspect: true diff --git a/src/Artemis.WebClient.Workshop/schema.graphql b/src/Artemis.WebClient.Workshop/schema.graphql index 59efce290..c889bca85 100644 --- a/src/Artemis.WebClient.Workshop/schema.graphql +++ b/src/Artemis.WebClient.Workshop/schema.graphql @@ -7,7 +7,7 @@ schema { type Category { icon: String! - id: Int! + id: Long! name: String! } @@ -37,8 +37,11 @@ type Entry { downloads: Long! entryType: EntryType! icon: Image - id: UUID! + iconId: UUID + id: Long! images: [Image!]! + latestRelease: Release + latestReleaseId: Long name: String! releases: [Release!]! summary: String! @@ -52,14 +55,16 @@ type Image { type Mutation { addEntry(input: CreateEntryInput!): Entry + removeEntry(id: Long!): Entry updateEntry(input: UpdateEntryInput!): Entry } type Query { categories(order: [CategorySortInput!], where: CategoryFilterInput): [Category!]! entries(order: [EntrySortInput!], skip: Int, take: Int, where: EntryFilterInput): EntriesCollectionSegment - entry(id: UUID!): Entry + entry(id: Long!): Entry searchEntries(input: String!, order: [EntrySortInput!], type: EntryType, where: EntryFilterInput): [Entry!]! + submittedEntries(order: [EntrySortInput!], where: EntryFilterInput): [Entry!]! } type Release { @@ -67,14 +72,14 @@ type Release { downloadSize: Long! downloads: Long! entry: Entry! - entryId: UUID! - id: UUID! + entryId: Long! + id: Long! md5Hash: String version: String! } type Tag { - id: Int! + id: Long! name: String! } @@ -106,7 +111,7 @@ scalar UUID input CategoryFilterInput { and: [CategoryFilterInput!] icon: StringOperationFilterInput - id: IntOperationFilterInput + id: LongOperationFilterInput name: StringOperationFilterInput or: [CategoryFilterInput!] } @@ -118,7 +123,7 @@ input CategorySortInput { } input CreateEntryInput { - categories: [Int!]! + categories: [Long!]! description: String! entryType: EntryType! name: String! @@ -151,8 +156,11 @@ input EntryFilterInput { downloads: LongOperationFilterInput entryType: EntryTypeOperationFilterInput icon: ImageFilterInput - id: UuidOperationFilterInput + iconId: UuidOperationFilterInput + id: LongOperationFilterInput images: ListFilterInputTypeOfImageFilterInput + latestRelease: ReleaseFilterInput + latestReleaseId: LongOperationFilterInput name: StringOperationFilterInput or: [EntryFilterInput!] releases: ListFilterInputTypeOfReleaseFilterInput @@ -168,7 +176,10 @@ input EntrySortInput { downloads: SortEnumType entryType: SortEnumType icon: ImageSortInput + iconId: SortEnumType id: SortEnumType + latestRelease: ReleaseSortInput + latestReleaseId: SortEnumType name: SortEnumType summary: SortEnumType } @@ -192,21 +203,6 @@ input ImageSortInput { mimeType: SortEnumType } -input IntOperationFilterInput { - eq: Int - gt: Int - gte: Int - in: [Int] - lt: Int - lte: Int - neq: Int - ngt: Int - ngte: Int - nin: [Int] - nlt: Int - nlte: Int -} - input ListFilterInputTypeOfCategoryFilterInput { all: CategoryFilterInput any: Boolean @@ -256,13 +252,24 @@ input ReleaseFilterInput { downloadSize: LongOperationFilterInput downloads: LongOperationFilterInput entry: EntryFilterInput - entryId: UuidOperationFilterInput - id: UuidOperationFilterInput + entryId: LongOperationFilterInput + id: LongOperationFilterInput md5Hash: StringOperationFilterInput or: [ReleaseFilterInput!] version: StringOperationFilterInput } +input ReleaseSortInput { + createdAt: SortEnumType + downloadSize: SortEnumType + downloads: SortEnumType + entry: EntrySortInput + entryId: SortEnumType + id: SortEnumType + md5Hash: SortEnumType + version: SortEnumType +} + input StringOperationFilterInput { and: [StringOperationFilterInput!] contains: String @@ -280,15 +287,15 @@ input StringOperationFilterInput { input TagFilterInput { and: [TagFilterInput!] - id: IntOperationFilterInput + id: LongOperationFilterInput name: StringOperationFilterInput or: [TagFilterInput!] } input UpdateEntryInput { - categories: [Int!]! + categories: [Long!]! description: String! - id: UUID! + id: Long! name: String! summary: String! tags: [String!]!