/// <summary>
        /// Process the job classes on a single page.
        /// </summary>
        /// <param name="page">The textual data of a single page, broken by newline and realigned.</param>
        /// <returns>A collection of JobClass objects from the page.</returns>
        IEnumerable<JobClass> processClassesOnPage(IEnumerable<string> page)
        {
            var jobClasses = new List<JobClass>();

            //to process the chunks sequentially (considering more than one at a time)
            var queue = new Queue<string>(page);

            while (queue.Any())
            {
                var jobClass = new JobClass();
                var steps = new List<JobClassStep>();
                var currentStep = new JobClassStep();

                IEnumerable<string> dataChunks = queue.Dequeue().Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);

                //assign the title, code, bargaining unit, grade for this class
                dataChunks = assignClassData(dataChunks.ToList(), jobClass);

                //if there is leftover data -> step definition
                if (dataChunks.Any())
                {
                    currentStep = assignStepData(dataChunks);
                    steps.Add(currentStep);
                }

                //add each subsequent step for this class
                while (queue.Any() && queue.Peek().StartsWith(jobClass.Grade))
                {
                    dataChunks = queue.Dequeue().Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries).Skip(1);
                    currentStep = assignStepData(dataChunks);
                    steps.Add(currentStep);
                }

                jobClass.Steps = steps;
                jobClasses.Add(jobClass);
            }

            return jobClasses;
        }
        /// <summary>
        /// Consumes a line of data to populate a JobClassStep
        /// </summary>
        /// <param name="dataChunks">A collection of salary step data points.</param>
        /// <returns>A JobClassStep object representation of the data.</returns>
        JobClassStep assignStepData(IEnumerable<string> dataChunks)
        {
            var step = new JobClassStep();
            //a job class step consists of 5 data points
            if (dataChunks.Count() == 5)
            {
                //convert to numeric and order increasing
                var numberChunks = dataChunks.Select(d => decimal.Parse(d)).OrderBy(d => d).ToArray();
                step.StepNumber = (int)numberChunks[0];
                step.HourlyRate = numberChunks[1];
                step.BiWeeklyRate = numberChunks[2];
                step.MonthlyRate = numberChunks[3];
                step.AnnualRate = numberChunks[4];
            }
            else
            {
                throw new InvalidOperationException(String.Format("Couldn't parse step data: {0}", String.Join(" ", dataChunks)));
            }

            return step;
        }