internal static void SetProperty(IParser parser, PhasesTemplateReference reference, Scalar scalar)
        {
            if (String.Equals(scalar.Value, YamlConstants.Phases, StringComparison.Ordinal))
            {
                parser.Expect<SequenceStart>();
                var selectors = new List<PhaseSelector>();
                while (parser.Allow<SequenceEnd>() == null)
                {
                    var selector = new PhaseSelector();
                    parser.Expect<MappingStart>();
                    ReadExactString(parser, YamlConstants.Name);
                    selector.Name = ReadNonEmptyString(parser);
                    while (parser.Allow<MappingEnd>() == null)
                    {
                        scalar = parser.Expect<Scalar>();
                        SetProperty(parser, selector, scalar);
                    }
                }

                reference.PhaseSelectors = selectors;
            }
            else
            {
                SetProperty(parser, reference as StepsTemplateReference, scalar);
            }
        }
        private static void ApplyStepOverrides(PhasesTemplateReference reference, PhasesTemplate template)
        {
            // Select by phase name.
            var byPhaseNames =
                (reference.PhaseSelectors ?? new List <PhaseSelector>(0))
                .Join(inner: (template.Phases ?? new List <IPhase>(0)).Cast <Phase>(),
                      outerKeySelector: (PhaseSelector phaseSelector) => phaseSelector.Name,
                      innerKeySelector: (Phase phase) => phase.Name,
                      resultSelector: (PhaseSelector phaseSelector, Phase phase) => new { Selector = phaseSelector, Phase = phase })
                .ToArray();

            // Apply overrides from phase selectors.
            foreach (var byPhaseName in byPhaseNames)
            {
                ApplyStepOverrides(byPhaseName.Selector.StepOverrides, byPhaseName.Phase.Steps);
            }

            // Apply unqualified overrides.
            var allStepLists =
                (template.Phases ?? new List <IPhase>(0))
                .Cast <Phase>()
                .Select((Phase phase) => phase.Steps ?? new List <IStep>(0))
                .Concat(new[] { template.Steps ?? new List <IStep>(0) })
                .ToArray();

            foreach (List <IStep> stepList in allStepLists)
            {
                ApplyStepOverrides(reference.StepOverrides, stepList);
            }
        }
        internal static IPhase ReadPhase(IParser parser, Boolean simpleOnly)
        {
            IPhase result;
            parser.Expect<MappingStart>();
            Scalar scalar = parser.Expect<Scalar>();
            if (String.Equals(scalar.Value, YamlConstants.Name, StringComparison.Ordinal))
            {
                var phase = new Phase { Name = ReadNonEmptyString(parser) };
                while (parser.Allow<MappingEnd>() == null)
                {
                    scalar = parser.Expect<Scalar>();
                    switch (scalar.Value ?? String.Empty)
                    {
                        case YamlConstants.DependsOn:
                            if (parser.Accept<Scalar>())
                            {
                                scalar = parser.Expect<Scalar>();
                                if (!String.IsNullOrEmpty(scalar.Value))
                                {
                                    phase.DependsOn = new List<String>();
                                    phase.DependsOn.Add(scalar.Value);
                                }
                            }
                            else
                            {
                                phase.DependsOn = ReadSequenceOfString(parser);
                            }

                            break;

                        case YamlConstants.Condition:
                            phase.Condition = ReadNonEmptyString(parser);
                            break;

                        case YamlConstants.ContinueOnError:
                            phase.ContinueOnError = ReadNonEmptyString(parser);
                            break;

                        case YamlConstants.EnableAccessToken:
                            phase.EnableAccessToken = ReadNonEmptyString(parser);
                            break;

                        case YamlConstants.Deployment:
                            if (phase.Target != null)
                            {
                                ValidateNull(phase.Target as QueueTarget, YamlConstants.Queue, YamlConstants.Deployment, scalar);
                                ValidateNull(phase.Target as ServerTarget, YamlConstants.Server, YamlConstants.Deployment, scalar);
                                throw new NotSupportedException("Unexpected previous target type"); // Should not reach here
                            }

                            phase.Target = ReadDeploymentTarget(parser);
                            break;

                        case YamlConstants.Queue:
                            if (phase.Target != null)
                            {
                                ValidateNull(phase.Target as DeploymentTarget, YamlConstants.Deployment, YamlConstants.Queue, scalar);
                                ValidateNull(phase.Target as ServerTarget, YamlConstants.Server, YamlConstants.Queue, scalar);
                                throw new NotSupportedException("Unexpected previous target type"); // Should not reach here
                            }

                            phase.Target = ReadQueueTarget(parser);
                            break;

                        case YamlConstants.Server:
                            if (phase.Target != null)
                            {
                                ValidateNull(phase.Target as DeploymentTarget, YamlConstants.Deployment, YamlConstants.Server, scalar);
                                ValidateNull(phase.Target as QueueTarget, YamlConstants.Queue, YamlConstants.Server, scalar);
                                throw new NotSupportedException("Unexpected previous target type"); // Should not reach here
                            }

                            phase.Target = ReadServerTarget(parser);
                            break;

                        case YamlConstants.Variables:
                            phase.Variables = ReadVariables(parser, simpleOnly: false);
                            break;

                        case YamlConstants.Steps:
                            phase.Steps = ReadSteps(parser, simpleOnly: false);
                            break;

                        default:
                            throw new SyntaxErrorException(scalar.Start, scalar.End, $"Unexpected process property: '{scalar.Value}'");
                    }
                }

                result = phase;
            }
            else if (String.Equals(scalar.Value, YamlConstants.Template, StringComparison.Ordinal))
            {
                if (simpleOnly)
                {
                    throw new SyntaxErrorException(scalar.Start, scalar.End, $"A phases template cannot reference another phases '{YamlConstants.Template}'.");
                }

                var reference = new PhasesTemplateReference { Name = ReadNonEmptyString(parser) };
                while (parser.Allow<MappingEnd>() == null)
                {
                    scalar = parser.Expect<Scalar>();
                    SetProperty(parser, reference, scalar);
                }

                result = reference;
            }
            else
            {
                throw new SyntaxErrorException(scalar.Start, scalar.End, $"Unknown phase type: '{scalar.Value}'");
            }

            return result;
        }