/// <summary> /// End a validation scoring session. /// Write out results here. /// </summary> /// <param name="registry">The registry containing the required values for this hook's execution.</param> /// <param name="resolver">A helper resolver for complex registry entries (automatically cached).</param> protected override void ScoreEnd(IRegistry registry, IRegistryResolver resolver) { string resultKey = ParameterRegistry.Get <string>("result_key"); double accuracy = (double)ParameterRegistry.Get <int>("correct_classifications") / ParameterRegistry.Get <int>("total_classifications"); resolver.ResolveSet(resultKey, accuracy, true); }
/// <summary> /// Invoke this hook with a certain parameter registry. /// </summary> /// <param name="registry">The registry containing the required values for this hook's execution.</param> /// <param name="resolver">A helper resolver for complex registry entries (automatically cached).</param> public override void SubInvoke(IRegistry registry, IRegistryResolver resolver) { int epoch = registry.Get <int>("epoch"); int iteration = registry.Get <int>("iteration"); Report(epoch, iteration); }
/// <summary> /// Invoke this hook with a certain parameter registry. /// </summary> /// <param name="registry">The registry containing the required values for this hook's execution.</param> /// <param name="resolver">A helper resolver for complex registry entries (automatically cached).</param> public void Invoke(IRegistry registry, IRegistryResolver resolver) { if (InvokeCriteria == null || InvokeCriteria.CheckCriteria(registry, resolver)) { SubInvoke(registry, resolver); } }
/// <summary> /// Invoke this hook with a certain parameter registry if optional conditional criteria are satisfied. /// </summary> /// <param name="registry">The registry containing the required values for this hook's execution.</param> /// <param name="resolver">A helper resolver for complex registry entries (automatically cached).</param> public override void SubInvoke(IRegistry registry, IRegistryResolver resolver) { IValueModifier modifier = ParameterRegistry.Get <IValueModifier>("modifier"); string identifier = ParameterRegistry.Get <string>("parameter_identifier"); object parameter = resolver.ResolveGetSingle <object>(identifier); INumber asNumber = parameter as INumber; INDArray asArray = parameter as INDArray; if (asNumber != null) { parameter = modifier.Modify(identifier, asNumber, asNumber.AssociatedHandler); } else if (asArray != null) { parameter = modifier.Modify(identifier, asArray, asArray.AssociatedHandler); } else { throw new InvalidOperationException($"Cannot apply modifier {modifier} to parameter \"{identifier}\" with value {parameter}, " + $"parameter is neither {nameof(INumber)} nor {nameof(INDArray)}."); } resolver.ResolveSet(identifier, parameter); }
public override bool CheckCriteria(IRegistry registry, IRegistryResolver resolver) { HookInvokeCriteria baseCriteria = ParameterRegistry.Get <HookInvokeCriteria>("base_criteria"); long targetRepetitions = ParameterRegistry.Get <long>("target_repetitions"); long currentRepititions = ParameterRegistry.Get <long>("current_repetitions"); bool withoutInterruption = ParameterRegistry.Get <bool>("without_interruption"); if (baseCriteria.CheckCriteria(registry, resolver)) { currentRepititions++; } else if (withoutInterruption) { currentRepititions = 0; } bool fire = currentRepititions >= targetRepetitions; if (fire) { currentRepititions = 0; } ParameterRegistry["current_repetitions"] = currentRepititions; return(fire); }
/// <summary> /// Invoke this hook with a certain parameter registry. /// </summary> /// <param name="registry">The registry containing the required values for this hook's execution.</param> /// <param name="resolver">A helper resolver for complex registry entries (automatically cached).</param> public override void SubInvoke(IRegistry registry, IRegistryResolver resolver) { string registryEntry = ParameterRegistry.Get <string>("registry_entry"); string resultEntry = ParameterRegistry.Get <string>("shared_result_entry"); double value = resolver.ResolveGetSingle <double>(registryEntry); double previousAccumulatedValue = ParameterRegistry.Get <double>("accumulated_value"); int currentInterval = HookUtils.GetCurrentInterval(registry, TimeStep.TimeScale); int resetInterval = ParameterRegistry.Get <int>("reset_interval"); int resetEvery = ParameterRegistry.Get <int>("reset_every"); int countSinceReset = ParameterRegistry.Get <int>("count_since_reset"); if (currentInterval == resetInterval || resetEvery > 0 && currentInterval % resetEvery == 0) { previousAccumulatedValue = 0.0; countSinceReset = 0; } countSinceReset++; double result = value + previousAccumulatedValue; if (ParameterRegistry.Get <bool>("average_mode")) { result /= countSinceReset; } ParameterRegistry["count_since_reset"] = countSinceReset; ParameterRegistry["accumulated_value"] = value + previousAccumulatedValue; resolver.ResolveSet(resultEntry, result, addIdentifierIfNotExists: true); }
/// <inheritdoc /> public virtual void SynchroniseSet <T>(IRegistry registry, string key, T val, Action <T> onSuccess = null, Action <Exception> onError = null) { // check if the registry is from an operator foreach (IOperator op in Sigma.RunningOperatorsByTrainer.Values) { if (ReferenceEquals(op.Registry, registry)) { //TODO: test if callback is called //TODO: on error check sources for other to set the value op.InvokeCommand(new SetValueCommand <T>(key, val, () => onSuccess?.Invoke(val))); return; } } IRegistryResolver resolver = RegistryResolvers.TryGetValue(registry, () => new RegistryResolver(registry)); // check if at least one value has been set if (resolver.ResolveSet(key, val, true, typeof(T)).Length > 0) { onSuccess?.Invoke(val); } else { onError?.Invoke(new KeyNotFoundException($"{key} was not found in {registry} and could not be created.")); } }
/// <inheritdoc /> public virtual T SynchroniseGet <T>(IRegistry registry, string key) { if (registry != null) { IRegistryResolver resolver = RegistryResolvers.TryGetValue(registry, () => new RegistryResolver(registry)); //return resolver.ResolveGetSingle<>() string[] emptyArrayThrowaway; T[] result = resolver.ResolveGet <T>(key, out emptyArrayThrowaway); if (result.Length != 0) { return(result[0]); } } foreach (ISynchronisationSource source in Sources) { T res; if (source.TryGet(key, out res)) { return(res); } } return(default(T)); }
/// <summary> /// Invoke this hook with a certain parameter registry if optional conditional criteria are satisfied. /// </summary> /// <param name="registry">The registry containing the required values for this hook's execution.</param> /// <param name="resolver">A helper resolver for complex registry entries (automatically cached).</param> public override void SubInvoke(IRegistry registry, IRegistryResolver resolver) { string baseResultKey = ParameterRegistry.Get <string>("base_result_key"); long lastTime = resolver.ResolveGetSingleWithDefault(baseResultKey + "_last", -1L); long averageTime = resolver.ResolveGetSingleWithDefault(baseResultKey + "_average", -1L); Report(TimeStep.TimeScale, lastTime, averageTime); }
/// <summary> /// Invoke this hook with a certain parameter registry if optional conditional criteria are satisfied. /// </summary> /// <param name="registry">The registry containing the required values for this hook's execution.</param> /// <param name="resolver">A helper resolver for complex registry entries (automatically cached).</param> public override void SubInvoke(IRegistry registry, IRegistryResolver resolver) { try { ((IParameterVisualiser)ParameterRegistry[VisualiserIdentifier]).Read(); } catch (TaskCanceledException) { // TODO: log to console } }
/// <summary> /// Begin a validation scoring session. /// Reset the scoring here. /// </summary> /// <param name="registry">The registry containing the required values for this hook's execution.</param> /// <param name="resolver">A helper resolver for complex registry entries (automatically cached).</param> protected override void ScoreBegin(IRegistry registry, IRegistryResolver resolver) { int[] tops = ParameterRegistry.Get <int[]>("tops"); foreach (int t in tops) { ParameterRegistry[$"correct_classifications_top{t}"] = 0; } ParameterRegistry["total_classifications"] = 0; }
/// <summary> /// Invoke this command and set all required values. /// </summary> /// <param name="registry">The registry containing the required values for this command's execution.</param> /// <param name="resolver">A helper resolver for complex registry entries (automatically cached).</param> public override void SubInvoke(IRegistry registry, IRegistryResolver resolver) { string[] keys = (string[])ParameterRegistry[KeyIdentifier]; T[] values = (T[])ParameterRegistry[ValueIdentifier]; for (int i = 0; i < keys.Length; i++) { //TODO: validate if successfully set and call error otherwise (for each key?) resolver.ResolveSet(keys[i], values[i], AddItentifierIfNotExists, typeof(T)); } }
public override bool CheckCriteria(IRegistry registry, IRegistryResolver resolver) { string parameter = ParameterRegistry.Get <string>("parameter_identifier"); object rawValue = SimpleDirectEntries[0] ? registry.Get(parameter) : resolver.ResolveGetSingle <object>(parameter); double value = (double)Convert.ChangeType(rawValue, typeof(double)); bool thresholdReached = _InternalThresholdReached(value, ParameterRegistry.Get <double>("threshold_value"), ParameterRegistry.Get <ComparisonTarget>("target")); bool fire = thresholdReached && (!ParameterRegistry.Get <bool>("last_check_met") || ParameterRegistry.Get <bool>("fire_continously")); ParameterRegistry["last_check_met"] = thresholdReached; return(fire); }
/// <summary> /// Invoke this hook with a certain parameter registry. /// </summary> /// <param name="registry">The registry containing the required values for this hook's execution.</param> /// <param name="resolver">A helper resolver for complex registry entries (automatically cached).</param> public override void SubInvoke(IRegistry registry, IRegistryResolver resolver) { int[] tops = ParameterRegistry.Get <int[]>("tops"); IDictionary <int, double> topDictionary = new Dictionary <int, double>(); foreach (int top in tops) { topDictionary[top] = resolver.ResolveGetSingle <double>("shared.classification_accuracy_top" + top); } Report(topDictionary); }
/// <summary> /// Resolve all registry entries using a given registry resolver. /// </summary> /// <param name="registryResolver">The registry resolver to use.</param> /// <param name="allRegistryEntries">The registry entries to resolve.</param> /// <param name="resultAllResolvedRegistryEntries">The resulting resolved registry entries.</param> public static void ResolveAllRequiredRegistry(IRegistryResolver registryResolver, IEnumerable <string> allRegistryEntries, ISet <string> resultAllResolvedRegistryEntries) { resultAllResolvedRegistryEntries.Clear(); foreach (string registryEntry in allRegistryEntries) { string[] resolvedEntries; registryResolver.ResolveGet <object>(registryEntry, out resolvedEntries, null); resultAllResolvedRegistryEntries.AddRange(resolvedEntries); } }
/// <summary> /// Invoke this hook with a certain parameter registry if optional conditional criteria are satisfied. /// </summary> /// <param name="registry">The registry containing the required values for this hook's execution.</param> /// <param name="resolver">A helper resolver for complex registry entries (automatically cached).</param> public override void SubInvoke(IRegistry registry, IRegistryResolver resolver) { IDictionary <string, object> values = (IDictionary <string, object>)ParameterRegistry[ValueIdentifier]; //TODO: validate lock requirement, probably it is required lock (values) { foreach (KeyValuePair <string, object> valuePair in registry) { values[valuePair.Key] = valuePair.Value; } } }
/// <summary> /// Invoke this hook with a certain parameter registry if optional conditional criteria are satisfied. /// </summary> /// <param name="registry">The registry containing the required values for this hook's execution.</param> /// <param name="resolver">A helper resolver for complex registry entries (automatically cached).</param> public override void SubInvoke(IRegistry registry, IRegistryResolver resolver) { if (ParameterRegistry.ContainsKey("last_time")) { bool removeExtremas = ParameterRegistry.Get <bool>("remove_extremas"); long lastTime = ParameterRegistry.Get <long>("last_time"); long currentTime = Operator.RunningTimeMilliseconds; long elapsedTime = currentTime - lastTime; LinkedList <long> lastRunningTimes = ParameterRegistry.Get <LinkedList <long> >("last_running_times"); string sharedResultBaseKey = ParameterRegistry.Get <string>("shared_result_base_key"); int averageSpan = ParameterRegistry.Get <int>("average_span"); lastRunningTimes.AddLast(elapsedTime); int numberRunningTimes = lastRunningTimes.Count; if (numberRunningTimes > averageSpan) { lastRunningTimes.RemoveFirst(); numberRunningTimes--; } long averageTime = lastRunningTimes.Sum(); if (removeExtremas) { LinkedList <long> runningTimesCopy = new LinkedList <long>(lastRunningTimes); int timesToRemove = (int)Math.Sqrt(lastRunningTimes.Count / 2.0f); // TODO magic number while (timesToRemove-- > 0) { long removedTime = timesToRemove % 2 == 0 ? runningTimesCopy.Max() : runningTimesCopy.Min(); runningTimesCopy.Remove(removedTime); } averageTime = runningTimesCopy.Sum(); numberRunningTimes = runningTimesCopy.Count; } averageTime /= numberRunningTimes; resolver.ResolveSet(sharedResultBaseKey + "_last", elapsedTime, addIdentifierIfNotExists: true); resolver.ResolveSet(sharedResultBaseKey + "_average", averageTime, addIdentifierIfNotExists: true); resolver.ResolveSet(sharedResultBaseKey + "_min", lastRunningTimes.Min(), addIdentifierIfNotExists: true); resolver.ResolveSet(sharedResultBaseKey + "_max", lastRunningTimes.Max(), addIdentifierIfNotExists: true); } ParameterRegistry["last_time"] = Operator.RunningTimeMilliseconds; }
public override bool CheckCriteria(IRegistry registry, IRegistryResolver resolver) { IList <HookInvokeCriteria> criterias = ParameterRegistry.Get <IList <HookInvokeCriteria> >("criterias"); for (int i = 0; i < criterias.Count; i++) { if (!criterias[i].CheckCriteria(registry, resolver)) { return(false); } } return(true); }
/// <summary> /// Invoke this hook with a certain parameter registry if optional conditional criteria are satisfied. /// </summary> /// <param name="registry">The registry containing the required values for this hook's execution.</param> /// <param name="resolver">A helper resolver for complex registry entries (automatically cached).</param> public override void SubInvoke(IRegistry registry, IRegistryResolver resolver) { IDictionary <string, INDArray> block = (IDictionary <string, INDArray>)ParameterRegistry[DataIdentifier]; IPassNetworkReceiver receiver = (IPassNetworkReceiver)ParameterRegistry[ReceiverIdentifier]; INetwork network = resolver.ResolveGetSingle <INetwork>("network.self"); IDataProvider provider = new DefaultDataProvider(); provider.SetExternalOutputLink("external_default", (targetsRegistry, layer, targetBlock) => { receiver.ReceivePass((INDArray)targetsRegistry["activations"]); }); DataUtils.ProvideExternalInputData(provider, network, block); network.Run(Operator.Handler, false); DataUtils.ProvideExternalOutputData(provider, network, block); }
/// <summary> /// Invoke this hook with a certain parameter registry if optional conditional criteria are satisfied. /// </summary> /// <param name="registry">The registry containing the required values for this hook's execution.</param> /// <param name="resolver">A helper resolver for complex registry entries (automatically cached).</param> public override void SubInvoke(IRegistry registry, IRegistryResolver resolver) { if (!ParameterRegistry.Get <bool>("requested_stop")) // TODO should there be a flag to always stop / reset this parameter (e.g. if training is restarted with the same hooks)? { _logger.Info($"Stopping training because condition {InvokeCriteria} was met."); Operator.SignalStop(); ParameterRegistry["requested_stop"] = true; } else { _logger.Debug($"Should stop training but stop signal was already sent."); } }
protected BaseWorker(IOperator @operator, IComputationHandler handler, ThreadPriority priority = ThreadPriority.Highest) { Operator = @operator; Handler = handler; LocalLocalHookTimeSteps = new Dictionary <IHook, ITimeStep>(); ThreadPriority = priority; _bufferHooksToInvoke = new List <IHook>(); _bufferHooksToInvokeInBackground = new List <IHook>(); _bufferRegistryEntries = new HashSet <string>(); _bufferResolvedRegistryEntries = new HashSet <string>(); _bufferRegistry = new Registry(); _bufferRegistryResolver = new RegistryResolver(_bufferRegistry); _stateLock = new object(); _waitForResume = new ManualResetEvent(false); }
/// <summary> /// End a validation scoring session. /// Write out results here. /// </summary> /// <param name="registry">The registry containing the required values for this hook's execution.</param> /// <param name="resolver">A helper resolver for complex registry entries (automatically cached).</param> protected override void ScoreEnd(IRegistry registry, IRegistryResolver resolver) { int[] tops = ParameterRegistry.Get <int[]>("tops"); foreach (int top in tops) { string resultBaseKey = ParameterRegistry.Get <string>("result_base_key"); int totalClassifications = ParameterRegistry.Get <int>("total_classifications"); int correctClassifications = ParameterRegistry.Get <int>($"correct_classifications_top{top}"); double score = ((double)correctClassifications) / totalClassifications; resolver.ResolveSet(resultBaseKey + top, score, addIdentifierIfNotExists: true); } }
/// <inheritdoc /> public string GetName(IRegistry registry, IRegistryResolver resolver, object sender) { for (int i = 0; i < _parameterIdentifiers.Length; i++) { _bufferParameters[i] = resolver.ResolveGetSingle <object>(_parameterIdentifiers[i]); } string name = string.Format(_formatString, _bufferParameters); for (var i = 0; i < _bufferParameters.Length; i++) { _bufferParameters[i] = null; } return(name); }
/// <inheritdoc /> public override void SubInvoke(IRegistry registry, IRegistryResolver resolver) { IComputationHandler handler = Operator.Handler; string registryEntryToProcess = ParameterRegistry.Get <string>("registry_entry_to_process"); Func <T, IComputationHandler, INumber> metricFunction = ParameterRegistry.Get <Func <T, IComputationHandler, INumber> >("metric_function"); string metricSharedResultIdentifier = ParameterRegistry.Get <string>("metric_shared_result_identifier"); object[] entries = resolver.ResolveGet <object>(registryEntryToProcess); double totalMetric = 0.0; int count = 0; foreach (object entry in entries) { T entryAsT = entry as T; IEnumerable <T> entryAsEnumerable = entry as IEnumerable <T>; IDictionary <string, T> entryAsDictionary = entry as IDictionary <string, T>; if (entryAsDictionary != null) { entryAsEnumerable = entryAsDictionary.Values; } if (entryAsT != null) { totalMetric += metricFunction.Invoke(entryAsT, handler).GetValueAs <double>(); count++; } else if (entryAsEnumerable != null) { foreach (T value in entryAsEnumerable) { totalMetric += metricFunction.Invoke(value, handler).GetValueAs <double>(); count++; } } else { throw new InvalidOperationException($"Cannot process metric for entry of type {entry.GetType()} with identifier \"{registryEntryToProcess}\", must be {typeof(T)} or enumerable thereof."); } } double resultMetric = totalMetric / count; resolver.ResolveSet(metricSharedResultIdentifier, resultMetric, addIdentifierIfNotExists: true); }
/// <summary> /// Invoke this hook with a certain parameter registry. /// </summary> /// <param name="registry">The registry containing the required values for this hook's execution.</param> /// <param name="resolver">A helper resolver for complex registry entries (automatically cached).</param> public override void SubInvoke(IRegistry registry, IRegistryResolver resolver) { INetwork network = resolver.ResolveGetSingle <INetwork>("network.self"); ITrainer trainer = resolver.ResolveGetSingle <ITrainer>("trainer.self"); string validationIteratorName = ParameterRegistry.Get <string>("validation_iterator_name"); string finalExternalOutputAlias = ParameterRegistry.Get <string>("final_external_output_alias"); string activationsAlias = ParameterRegistry.Get <string>("output_activations_alias"); string targetsAlias = ParameterRegistry.Get <string>("targets_alias"); if (!trainer.AdditionalNameDataIterators.ContainsKey(validationIteratorName)) { throw new InvalidOperationException($"Additional named data iterator for validation with name \"{validationIteratorName}\" does not exist in referenced trainer {trainer} but is required."); } IDataIterator validationIterator = trainer.AdditionalNameDataIterators[validationIteratorName]; ScoreBegin(registry, resolver); foreach (var block in validationIterator.Yield(Operator.Handler, Operator.Sigma)) { trainer.ProvideExternalInputData(network, block); network.Run(Operator.Handler, trainingPass: false); INDArray finalOutputPredictions = null; foreach (ILayerBuffer layerBuffer in network.YieldExternalOutputsLayerBuffers()) { foreach (string outputAlias in layerBuffer.ExternalOutputs) { if (outputAlias.Equals(finalExternalOutputAlias)) { finalOutputPredictions = Operator.Handler.ClearTrace(layerBuffer.Outputs[outputAlias].Get <INDArray>(activationsAlias)); goto FoundOutput; } } ; } throw new InvalidOperationException($"Cannot find final output with alias \"{finalExternalOutputAlias}\" in the current network (but is required to score validation)."); FoundOutput: ScoreIntermediate(finalOutputPredictions, block[targetsAlias], Operator.Handler); } ScoreEnd(registry, resolver); }
public override bool CheckCriteria(IRegistry registry, IRegistryResolver resolver) { ExtremaTarget target = ParameterRegistry.Get <ExtremaTarget>("target"); string parameter = ParameterRegistry.Get <string>("parameter_identifier"); double value = SimpleDirectEntries[0] ? registry.Get <double>(parameter) : resolver.ResolveGetSingle <double>(parameter); double currentExtremum = ParameterRegistry.Get <double>("current_extremum"); bool reachedExtremum = target == ExtremaTarget.Min && value <currentExtremum || target == ExtremaTarget.Max && value> currentExtremum; if (double.IsNaN(currentExtremum) || reachedExtremum) { ParameterRegistry["current_extremum"] = value; return(true); } return(false); }
/// <summary> /// Invoke this hook with a certain parameter registry. /// </summary> /// <param name="registry">The registry containing the required values for this hook's execution.</param> /// <param name="resolver">A helper resolver for complex registry entries (automatically cached).</param> public override void SubInvoke(IRegistry registry, IRegistryResolver resolver) { string[] accumulatedIdentifiers = ParameterRegistry.Get <string[]>("accumulated_identifiers"); string[] valueIdentifiers = ParameterRegistry.Get <string[]>("value_identifiers"); IDictionary <string, object> valuesByIdentifier = ParameterRegistry.Get <IDictionary <string, object> >("value_buffer"); for (int i = 0; i < valueIdentifiers.Length; i++) { // TODO let callee decide if it's a number (double) / something else object value = resolver.ResolveGetSingle <double>(accumulatedIdentifiers[i]); valuesByIdentifier[valueIdentifiers[i]] = value; } ReportValues(valuesByIdentifier, ParameterRegistry.Get <bool>("report_epoch_iteration"), registry.Get <int>("epoch"), registry.Get <int>("iteration")); }
/// <summary> /// Invoke this hook with a certain parameter registry if optional conditional criteria are satisfied. /// </summary> /// <param name="registry">The registry containing the required values for this hook's execution.</param> /// <param name="resolver">A helper resolver for complex registry entries (automatically cached).</param> public override void SubInvoke(IRegistry registry, IRegistryResolver resolver) { INDArray desiredTargets = ParameterRegistry.Get <INDArray>("desired_targets"); int uid = ParameterRegistry.Get <int>("uid"); bool success = resolver.ResolveGetSingleWithDefault($"shared.target_maximisation_result_{uid}_success", false); if (!success) { _logger.Warn($"Failed target maximisation for {desiredTargets}, nothing to print."); } else { IComputationHandler handler = Operator.Handler; INDArray inputs = resolver.ResolveGetSingle <INDArray>($"shared.target_maximisation_result_{uid}_input"); OnTargetMaximisationSuccess(handler, inputs, desiredTargets); } }
/// <summary> /// Invoke this hook with a certain parameter registry if optional conditional criteria are satisfied. /// </summary> /// <param name="registry">The registry containing the required values for this hook's execution.</param> /// <param name="resolver">A helper resolver for complex registry entries (automatically cached).</param> public override void SubInvoke(IRegistry registry, IRegistryResolver resolver) { string registryEntryToSave = ParameterRegistry.Get <string>("registry_entry_to_save"); INamer fileNamer = ParameterRegistry.Get <INamer>("file_namer"); object toSerialise = resolver.ResolveGetSingle <object>(registryEntryToSave); bool verbose = ParameterRegistry.Get <bool>("verbose"); Func <T, T> selectFunction = ParameterRegistry.Get <Func <T, T> >("select_function"); toSerialise = selectFunction.Invoke((T)toSerialise); lock (fileNamer) { Serialisation.WriteBinaryFile(toSerialise, fileNamer.GetName(registry, resolver, this), verbose: false); } if (verbose) { _logger.Info($"Saved \"{registryEntryToSave}\" to \"{SigmaEnvironment.Globals.Get<string>("storage_path")}{fileNamer}\"."); } }
/// <summary> /// Check if the criteria is satisfied using a certain parameter registry and helper resolver from the base hook. /// </summary> /// <param name="registry">The registry.</param> /// <param name="resolver">The helper resolver.</param> /// <returns>A boolean indicating if this criteria is satisfied.</returns> public override bool CheckCriteria(IRegistry registry, IRegistryResolver resolver) { bool active; lock (ParameterRegistry) { int state = ParameterRegistry.Get <int>("state"); active = state > 0; if (state != int.MaxValue && state > int.MinValue) { state--; } ParameterRegistry["state"] = state; } return(active); }