/// <inheritdoc /> protected override void Mqtt_MqttMsgPublishReceived(MqttApplicationMessageReceivedEventArgs e) { var topic = e.ApplicationMessage.Topic; var message = e.ApplicationMessage.ConvertPayloadToString(); _log.LogInformation("MQTT message received for topic {Topic}: {Message}", topic, message); if (topic == TopicRoot + "/REQUEST_SYNC") { _messageHub.Publish(new RequestSyncEvent()); } else if (_stateCache.TryGetValue(topic, out string currentState)) { if (_stateCache.TryUpdate(topic, message, currentState)) { // Identify updated devices that handle reportState var devices = _deviceRepository.GetAll() .Where(device => !device.Disabled) .Where(device => device.WillReportState) .Where(device => device.Traits.Any(trait => trait.State.Values.Any(state => state.Topic == topic))) .ToList(); // Trigger reportState _messageHub.Publish(new ReportStateEvent { Devices = devices }); } } }
public Task SetUpstreamOptions(UpstreamOptions options) { options.Timestamp = systemClock.UtcNow.UtcDateTime; StorageService.Repo.Upsert(options); logger.Swallow(() => messageHub.Publish(options)); return(Task.CompletedTask); }
public void CopyToClipboard(string text) { if (text == null) { return; } Clipboard.SetText(text); _messageHub.Publish($"'{text}' is copied to clipboard".ToMessage()); }
public void TicketChecker_TicketScanAddedEvent_OnPropertyChangedRaised() { // Arrange var eventRaised = false; _indexViewModel.OnPropertyChanged += (s, e) => { eventRaised = true; }; // Act _eventAggregator.Publish(new TicketScanAdded("dsfjs89wj")); // Assert Assert.That(eventRaised, Is.True); _indexViewModel.OnPropertyChanged -= (s, e) => { eventRaised = true; }; }
public void AddCommentToExistingCommit(GitInfo gitInfo, string message) { _ = gitInfo ?? throw new ArgumentNullException(nameof(gitInfo)); _ = message ?? throw new ArgumentNullException(nameof(message)); _messageHub.Publish($"Adding {message} to the commit message...".ToMessage()); var lastCommit = gitInfo.Branch.Tip; try { gitInfo.Repo.Refs.RewriteHistory( new RewriteHistoryOptions { BackupRefsNamespace = Guid.NewGuid().ToString(), OnError = exception => { _messageHub.Publish(exception); _messageHub.Publish("Cannot rewrite comment".ToWarning()); }, OnSucceeding = () => _messageHub.Publish("Successfully rewritten last commit message".ToMessage()), CommitHeaderRewriter = c => { if (c.Message.Contains(message)) { message = c.Message; } else { if (c.Message.EndsWith("\n", StringComparison.OrdinalIgnoreCase)) { message = c.Message + message; } else { message = c.Message + "\n" + message; } } return(CommitRewriteInfo.From(c, message)); } }, lastCommit); } catch (Exception ex) { _logger.Error(ex); } }
public void SendMessage(Message message) { _logger.Information(Constants.LogMessageTemplate, message.MessageId, GetType().Name, "SendMessageEvent", "Sent message event raised."); _messageHub.Publish(message); }
public PolygonWsClient(IMessageHub messageHub, IOptions <AppSettings> appSettings, ILogger <IPolygonWsClient> logger) { _logger = logger; _products = new List <IProductModel>(); var url = $"{appSettings.Value.Microservices.PolygonApi}/stocks/prices"; if (string.IsNullOrWhiteSpace(url)) { _logger.LogCritical("Polygon websocket url is null"); return; } _connection = new HubConnectionBuilder() .WithUrl(url) .Build(); _connection.On <JArray>("AssetsPricesUpdated", (data) => { var str = data.ToString(); var res = JsonConvert.DeserializeObject <IList <StreamingMessage> >(str, new StreamMessageConverter()); messageHub.Publish(res); }); _connection.Closed += ConnectionOnClosed; Connect(); }
private void OnTimerTick(object sender, EventArgs e) { var now = DateTime.Now; for (var i = 0; i < _schedules.Count; i++) { var item = _schedules[i]; var dateTime = item.Key; var channel = item.Value; var delta = dateTime - now; var isDueSoon = delta <= TimeSpan.FromMinutes(15); var isStillPlaying = dateTime.AddMinutes(105) >= now; if (isDueSoon) { _schedules.Remove(item); if (isStillPlaying) { _hub.Publish(new SchedulerMessage(dateTime, channel)); break; } } } }
/// <summary> /// Handles a <see cref="Models.Request.SyncIntent"/>. /// </summary> /// <param name="intent">Intent to process.</param> /// <returns>A <see cref="Models.Response.SyncResponsePayload"/>.</returns> public Models.Response.SyncResponsePayload Handle(Models.Request.SyncIntent intent) { _log.LogInformation("Received SYNC intent"); // Convert to an event to publish var commandEvent = new SyncIntentReceivedEvent { Time = DateTimeOffset.Now }; _messageHub.Publish(commandEvent); var syncResponsePayload = new Models.Response.SyncResponsePayload { AgentUserId = _config.GetValue <string>("googleHomeGraph:agentUserId"), Devices = _deviceRepository.GetAll() .Where(device => !device.Disabled) .Select(x => new Models.Response.Device { Id = x.Id, Type = x.Type, RoomHint = x.RoomHint, WillReportState = x.WillReportState, Traits = x.Traits.Select(trait => trait.Trait).ToList(), Attributes = x.Traits .Where(trait => trait.Attributes != null) .SelectMany(trait => trait.Attributes) .ToDictionary(kv => kv.Key, kv => kv.Value), Name = x.Name, DeviceInfo = x.DeviceInfo, CustomData = x.CustomData }).ToList() }; return(syncResponsePayload); }
public async Task CloneAsync(TfsInfo tfsInfo, string directoryPath, CancellationToken cancellationToken) { _ = tfsInfo ?? throw new ArgumentNullException(nameof(tfsInfo)); _ = directoryPath ?? throw new ArgumentNullException(nameof(directoryPath)); _messageHub.Publish("Creating temp directory..."); var tempDirectoryPath = CreateTempRepoDirectory(directoryPath); _messageHub.Publish($"Temp directory is '{tempDirectoryPath}'".ToMessage()); await _cmdUtility.ExecuteCommandAsync(GitTfsPath, $"clone \"{Settings.Default.TfsUri}\" \"{tfsInfo.MappedServerFolder}\"", tempDirectoryPath, cancellationToken) .ConfigureAwait(false); var tempWorkspacePath = Directory.GetDirectories(tempDirectoryPath).Single(); // git-tfs should create one directory and place everything inside it _messageHub.Publish($"Temp workspace directory is '{tempWorkspacePath}'".ToMessage()); try { await _cmdUtility.ExecuteCommandAsync(GitTfsPath, "cleanup", tempWorkspacePath, cancellationToken).ConfigureAwait(false); await _cmdUtility.ExecuteCommandAsync("cmd", "/c git gc", tempWorkspacePath, cancellationToken).ConfigureAwait(false); } catch { _messageHub.Publish("Cannot cleanup".ToWarning()); } var finalGitPath = Path.Combine(directoryPath, ".git"); if (Directory.Exists(finalGitPath)) { _messageHub.Publish($"Deleting '{finalGitPath}'...".ToMessage()); Directory.Delete(finalGitPath); } _messageHub.Publish($"Moving '.git' folder from temp directory '{tempWorkspacePath}' to the permanent one '{finalGitPath}'...".ToMessage()); var tempGitDirectoryPath = Path.Combine(tempWorkspacePath, ".git"); Directory.Move(tempGitDirectoryPath, finalGitPath); _messageHub.Publish($"Deleting temp directory '{tempDirectoryPath}'...".ToMessage()); try { Directory.Delete(tempDirectoryPath, true); } catch { _messageHub.Publish($"Cannot delete temp directory '{tempDirectoryPath}'. Please delete it manually".ToWarning()); } _messageHub.Publish($"Repository is cloned to '{directoryPath}'!".ToSuccess()); }
public async Task Synchronize(Set set, bool requestFromSynchronizer = false) { _messageHub.Publish(new ThumbnailSynchronizerStart()); if (_preferencesService.ThumbnailCachingStrategy == ThumbnailCachingStrategy.NeverCache || (_preferencesService.ThumbnailCachingStrategy == ThumbnailCachingStrategy.OnlyCacheDisplayedThumbnails && requestFromSynchronizer) || set is null || string.IsNullOrWhiteSpace(set.Images.FirstOrDefault()?.ThumbnailUrl)) { _messageHub.Publish(new ThumbnailSynchronizerEnd()); return; } try { byte[] thumbnail = null; try { thumbnail = await set.Images[0].ThumbnailUrl.GetBytesAsync().ConfigureAwait(false); _messageHub.Publish(new ThumbnailAcquired { Thumbnail = set.Images[0].ThumbnailUrl }); } #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body catch { } #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body if (thumbnail is null || thumbnail.Length == 0) { _messageHub.Publish(new ThumbnailSynchronizerEnd()); return; } _messageHub.Publish(new SynchronizingThumbnailStart { Thumbnail = set.Images[0].ThumbnailUrl }); await _fileSystemService.SaveThumbnailToCache(set.Theme.Name, set.Subtheme.Name, set.NumberWithVariant, thumbnail).ConfigureAwait(false); _messageHub.Publish(new SynchronizingThumbnailEnd { Thumbnail = set.Images[0].ThumbnailUrl }); } catch (Exception ex) { _messageHub.Publish(new ThumbnailSynchronizerException { Exception = ex }); } _messageHub.Publish(new ThumbnailSynchronizerEnd()); }
public Task Handle(TicketScanStartedNotification notification, CancellationToken cancellationToken) { var seat = new SeatModel(notification.Seat.Number, notification.Seat.Letter); _ticketRepository.Add(new TicketScanModel(notification.Identifier, seat)); _eventAggregator.Publish(new TicketScanAdded(notification.Identifier)); _logger.LogDebug($"Published {nameof(TicketScanAdded)} event for transaction {notification.Identifier}"); return(Task.CompletedTask); }
public void HubMultiplePublisherSingleSubscriberAndGlobalAuditHandlerSimple() { Action action = () => { _hubMultiplePublisherSingleSubscriberAndGlobalAuditHandlerSimple.Publish("Hello there!"); }; Parallel.Invoke(action, action, action, action, action); }
private void SetupViewForms <TViewModel>(IView <TViewModel> view) where TViewModel : IViewModel { var viewForm = view as Form; if (viewForm == null) { return; } viewForm.FormClosed += (sender, e) => _eventAggregator.Publish(ViewClosedEvent.Create(view)); }
public async Task HubMultiplePublisherSingleSubscriberSimple() { var count = 0; var tasks = Enumerable.Range(0, 5).Select(n => Task.Run(() => { while (Interlocked.Increment(ref count) < 100) { _hubMultiplePublisherSingleSubscriberSimple.Publish("Hello there!"); } })); await Task.WhenAll(tasks); }
public async Task ExecuteWithDisabledWorkspace(TfsInfo tfsInfo, string executable, string command, string directoryPath, CancellationToken cancellationToken) { _ = tfsInfo ?? throw new ArgumentNullException(nameof(tfsInfo)); _ = executable ?? throw new ArgumentNullException(nameof(executable)); _ = command ?? throw new ArgumentNullException(nameof(command)); _ = directoryPath ?? throw new ArgumentNullException(nameof(directoryPath)); var mapping = new WorkingFolder(tfsInfo.MappedServerFolder, directoryPath); try { _messageHub.Publish("Deleting TFS mapping...".ToMessage()); tfsInfo.Workspace.DeleteMapping(mapping); await _cmdUtility.ExecuteCommandAsync(executable, command, directoryPath, cancellationToken).ConfigureAwait(false); } finally { _messageHub.Publish("Restoring TFS mapping...".ToMessage()); await RestoreMappingAsync(tfsInfo, directoryPath, mapping).ConfigureAwait(false); } }
private async Task MoveElevator() { while (true) { await Task.Delay(TimeBetweenFloors * 1000).ConfigureAwait(false); await Task.Run(() => { _elevatorStatus.MoveToNextFloor(); }).ConfigureAwait(false); _messageHub.Publish(new FloorChangedMessage { Direction = _elevatorStatus.CurrentDirection, Floor = _elevatorStatus.CurrentFloor }); } }
private void UserControl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { if (isInDrag) { var element = sender as FrameworkElement; element.ReleaseMouseCapture(); isInDrag = false; e.Handled = true; currentPoint = e.GetPosition(null); MouseReleased?.Invoke(this, currentPoint); hub.Publish(new ItemPositionUpdate { Item = this, Position = currentPoint }); } }
/// <summary> /// Processes the file location and returns the team with the least points difference. /// </summary> /// <param name="fileLocation"> The full path to the file we are processing. </param> /// <returns> The team with the least points difference. </returns> public async Task ProcessAsync(string fileLocation) { // Contract requirements. if (string.IsNullOrWhiteSpace(fileLocation)) { throw new ArgumentNullException(nameof(fileLocation), "The file location can not be null."); } _logger.Information($"{GetType().Name} (ProcessAsync): Starting to process the file: {fileLocation}."); var result = await Processor.ProcessorWork(fileLocation, _footballReader, _footballMapper, _footballWriter) .ConfigureAwait(false); _logger.Information($"{GetType().Name} (ProcessAsync): Publishing the result: {result.ProcessResult}."); _messageHub.Publish(result); }
static void RunTest(IMessageHub hub, int count) { sw.Restart(); counter = 0; for (var i = 0; i < count; i++) { hub.Publish(new ChannelMessageHub.TestHubMessage { Index = i }); } new Timing() .Timeout(30000) .Polling(TimeSpan.FromMilliseconds(1)).Expect(() => counter == count * 2); results[hub.GetType().Name] = sw.ElapsedMilliseconds; }
/// <summary> /// Handles a <see cref="Models.Request.QueryIntent"/>. /// </summary> /// <param name="intent">Intent to process.</param> /// <returns>A <see cref="Models.Response.QueryResponsePayload"/>.</returns> public Models.Response.QueryResponsePayload Handle(Models.Request.QueryIntent intent) { _log.LogInformation("Received QUERY intent for devices: " + string.Join(", ", intent.Payload.Devices.Select(x => x.Id))); // Payload for disabled a or missing device var offlineDeviceState = new Dictionary <string, object> { { "errorCode", "deviceNotFound" }, { "online", false } }; // Get distinct devices var distinctRequestDeviceIds = intent.Payload.Devices .GroupBy(device => device.Id) .Select(group => group.First()) .Select(device => device.Id); var devices = _deviceRepository.GetAll() .Where(device => !device.Disabled) .Where(device => distinctRequestDeviceIds.Contains(device.Id)) .ToList(); // Build reponse payload var queryResponsePayload = new Models.Response.QueryResponsePayload { Devices = distinctRequestDeviceIds .ToDictionary( queryDeviceId => queryDeviceId, queryDeviceId => { var device = devices.FirstOrDefault(x => x.Id == queryDeviceId); return(device != null ? device.GetGoogleQueryState(_stateCache) : offlineDeviceState); }) }; // Trigger reportState before returning var reportStateDevices = devices.Where(device => device.WillReportState).ToList(); var shouldTriggerReportState = false; if (reportStateDevices.Any() && shouldTriggerReportState) { _messageHub.Publish(new ReportStateEvent { Devices = reportStateDevices }); } return(queryResponsePayload); }
/// <summary> /// Processes the file location and returns the team with the least points difference. /// </summary> /// <param name="fileLocation"> The full path to the file we are processing. </param> /// <returns> The team with the least points difference. </returns> public async Task ProcessAsync(string fileLocation) { // Contract requirements. if (string.IsNullOrWhiteSpace(fileLocation)) { throw new ArgumentNullException(nameof(fileLocation), "The file location can not be null."); } var footballData = await _footballReader.ReadAsync(fileLocation).ConfigureAwait(false); var mappedData = await _footballMapper.MapAsync(footballData).ConfigureAwait(false); var result = await _footballNotify.NotifyAsync(mappedData).ConfigureAwait(false); _messageHub.Publish(result); }
internal async Task PullAsync() { await _cmdUtility.ExecuteTaskAsync( async cancellationToken => { await _gitTfsUtility.PullAsync(_tfsInfo, _directoryPath, cancellationToken).ConfigureAwait(false); _tfsUtility.GetLatest(_tfsInfo); var gitInfo = await _gitUtility.GetInfoAsync(_directoryPath).ConfigureAwait(false); _messageHub.Publish(gitInfo); var conflictsCount = gitInfo?.ConflictsCount; if (conflictsCount > 0) { throw new InvalidOperationException( conflictsCount == 1 ? $"There is {conflictsCount} conflict. Please solve it" : $"There are {conflictsCount} conflicts. Please solve them"); } }) .ConfigureAwait(false); }
public UnshelveViewModel( [NotNull] string directoryPath, [NotNull] GitInfo gitInfo, [NotNull] TfsInfo tfsInfo, [NotNull] IMessageHub messageHub, [NotNull] IGitUtility gitUtility, [NotNull] ICmdUtility cmdUtility, [NotNull] IGitTfsUtility gitTfsUtility, [NotNull] ITfsUtility tfsUtility, [NotNull] SynchronizationContext synchronizationContext, [NotNull] Func <string, bool, ConfirmationViewModel> confirmationViewModelFactory, [NotNull] Func <ConfirmationViewModel, IConfirmationWindow> confirmationWindowFactory, [NotNull] ICommandManager commandManager, [NotNull] IRateLimiter rateLimiter) : base(commandManager) { _messageHub = messageHub ?? throw new ArgumentNullException(nameof(messageHub)); _gitUtility = gitUtility ?? throw new ArgumentNullException(nameof(gitUtility)); _cmdUtility = cmdUtility ?? throw new ArgumentNullException(nameof(cmdUtility)); _gitTfsUtility = gitTfsUtility ?? throw new ArgumentNullException(nameof(gitTfsUtility)); _tfsUtility = tfsUtility ?? throw new ArgumentNullException(nameof(tfsUtility)); _synchronizationContext = synchronizationContext ?? throw new ArgumentNullException(nameof(synchronizationContext)); _confirmationViewModelFactory = confirmationViewModelFactory ?? throw new ArgumentNullException(nameof(confirmationViewModelFactory)); _confirmationWindowFactory = confirmationWindowFactory ?? throw new ArgumentNullException(nameof(confirmationWindowFactory)); _rateLimiter = rateLimiter ?? throw new ArgumentNullException(nameof(rateLimiter)); _gitInfo = gitInfo ?? throw new ArgumentNullException(nameof(gitInfo)); _tfsInfo = tfsInfo ?? throw new ArgumentNullException(nameof(tfsInfo)); _directoryPath = directoryPath ?? throw new ArgumentNullException(nameof(directoryPath)); UnshelveCommand = AddCommand(Unshelve, () => CanExecute); CancelCommand = AddCommand(Cancel, () => !IsLoading); OpenShelvesetInBrowserCommand = AddCommand(OpenShelvesetInBrowser, () => ShelvesetName != null); CopyShelvesetToClipboardCommand = AddCommand(CopyShelvesetToClipboard, () => ShelvesetName != null); if (User == null) { UsersSearchPattern = string.Empty; // sets current user } _messageHub.Publish(DialogType.Unshelve); _subscriptionTokens.Add(messageHub.Subscribe <TaskState>(OnTaskAction)); }
public async Task Handle(TicketScanResultNotification notification, CancellationToken cancellationToken) { var ticketScan = _ticketRepository.Find(notification.Identifier); if (ticketScan is null) { return; } if (notification.Result is null) { ticketScan.SetFaulted(); } else { ticketScan.SetScanResult(notification.Result.OwnsTicket, notification.Result.Name); } _eventAggregator.Publish(new TicketScanUpdated(ticketScan.Identifier)); _logger.LogDebug($"Published {nameof(TicketScanUpdated)} event for transaction {ticketScan.Identifier}"); }
public ShelveViewModel( [NotNull] string directoryPath, [NotNull] GitInfo gitInfo, [NotNull] TfsInfo tfsInfo, [NotNull] IMessageHub messageHub, [NotNull] IGitUtility gitUtility, [NotNull] ICmdUtility cmdUtility, [NotNull] IGitTfsUtility gitTfsUtility, [NotNull] ITfsUtility tfsUtility, [NotNull] SynchronizationContext synchronizationContext, [NotNull] Func <string, bool, ConfirmationViewModel> confirmationViewModelFactory, [NotNull] Func <ConfirmationViewModel, IConfirmationWindow> confirmationWindowFactory, [NotNull] ICommandManager commandManager) : base(commandManager) { _messageHub = messageHub ?? throw new ArgumentNullException(nameof(messageHub)); _gitUtility = gitUtility ?? throw new ArgumentNullException(nameof(gitUtility)); _cmdUtility = cmdUtility ?? throw new ArgumentNullException(nameof(cmdUtility)); _gitTfsUtility = gitTfsUtility ?? throw new ArgumentNullException(nameof(gitTfsUtility)); _tfsUtility = tfsUtility ?? throw new ArgumentNullException(nameof(tfsUtility)); _synchronizationContext = synchronizationContext ?? throw new ArgumentNullException(nameof(synchronizationContext)); _confirmationViewModelFactory = confirmationViewModelFactory ?? throw new ArgumentNullException(nameof(confirmationViewModelFactory)); _confirmationWindowFactory = confirmationWindowFactory ?? throw new ArgumentNullException(nameof(confirmationWindowFactory)); _gitInfo = gitInfo ?? throw new ArgumentNullException(nameof(gitInfo)); _tfsInfo = tfsInfo ?? throw new ArgumentNullException(nameof(tfsInfo)); _directoryPath = directoryPath ?? throw new ArgumentNullException(nameof(directoryPath)); ShelveOrCheckinCommand = AddCommand(ShelveOrCheckin, () => CanExecute); CancelCommand = AddCommand(Cancel, () => !IsLoading); IsDirty = CommitDirty = _gitInfo.IsDirty; ShelvesetName = GetShelvesetName(); CommitMessage = _gitInfo.CommitMessage ?? string.Empty; CommitMessages = _gitInfo.CommitMessages; _messageHub.Publish(DialogType.Shelve); _subscriptionTokens.Add(messageHub.Subscribe <TaskState>(OnTaskAction)); }
/// <inheritdoc /> public void Add(Device device) { if (_devices.TryAdd(device.Id, device)) { // Save changes Persist(); // Determine if subscription changes need to be published if (!device.Disabled) { // Publish necessary subscription changes var deviceTopics = device.Traits .SelectMany(trait => trait.State) .Where(state => !string.IsNullOrEmpty(state.Value.Topic)) .Select(state => state.Value.Topic); // Publish event for subscription changes _messageHub.Publish(new ConfigSubscriptionChangeEvent { AddedSubscriptions = deviceTopics }); } } }
public void HubSinglePublisherSingleSubscriberSimple() { _hubSinglePublisherSingleSubscriberSimple.Publish("Hello there!"); }
public void HubSinglePublisherMultipleSubscriberSimple() { _hubSinglePublisherMultipleSubscriberSimple.Publish(35); }
public async Task <IEnumerable <Subtheme> > Synchronize(string apiKey, Theme theme) { _messageHub.Publish(new SubthemeSynchronizerStart()); var subthemes = new List <Subtheme>(); try { var getSubthemesParameters = new ParameterTheme { ApiKey = apiKey, Theme = theme.Name }; var bricksetSubthemes = (await _bricksetApiService.GetSubthemes(getSubthemesParameters)).ToList(); _messageHub.Publish(new SubthemesAcquired { Theme = theme.Name, Count = bricksetSubthemes.Count }); foreach (var bricksetSubtheme in bricksetSubthemes) { _messageHub.Publish(new SynchronizingSubthemeStart { Theme = theme.Name, Subtheme = bricksetSubtheme.Subtheme }); try { var subtheme = bricksetSubtheme.ToSubtheme(); subtheme.Theme = theme; var persistedSubtheme = _subthemeRepository.Get(subtheme.Theme.Name, subtheme.Name); if (persistedSubtheme != null) { subtheme.Id = persistedSubtheme.Id; } _subthemeRepository.AddOrUpdate(subtheme); subthemes.Add(subtheme); } catch (Exception ex) { _messageHub.Publish(new SynchronizingSubthemeException { Theme = theme.Name, Subtheme = bricksetSubtheme.Subtheme, Exception = ex }); } _messageHub.Publish(new SynchronizingSubthemeEnd { Theme = theme.Name, Subtheme = bricksetSubtheme.Subtheme }); } } catch (Exception ex) { _messageHub.Publish(new SubthemeSynchronizerException { Theme = theme.Name, Exception = ex }); } _messageHub.Publish(new SubthemeSynchronizerEnd()); return(subthemes); }