/// <summary>
        /// Enables processing of HTTP Web requests by a custom HttpHandler that implements 
        /// the <see cref="T:System.Web.IHttpHandler"></see> interface.
        /// </summary>
        /// <param name="context">An <see cref="T:System.Web.HttpContext"></see> object that provides references 
        /// to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.
        /// </param>
        public void ProcessRequest(HttpContext context)
        {
            string title = RetrieveTitle(context);
            SyndicationFormat format = RetrieveFormat(context);
            List<IPublishable> list = GenerateItemList(context);
            list = CleanList(list);

            if (string.IsNullOrEmpty(context.Request.QueryString["post"]))
            {
                // Shorten the list to the number of posts stated in the settings, except for the comment feed.
                int max = Math.Min(TrainSettings.Instance.PostsPerFeed, list.Count);
                list = list.FindAll(delegate(IPublishable item)
                {
                    return item.IsVisible == true;
                });

                list = list.GetRange(0, max);
            }

            SetHeaderInformation(context, list, format);

            if (TrainSettings.Instance.EnableHttpCompression)
                HttpModules.CompressionModule.CompressResponse(context);

            SyndicationGenerator generator = new SyndicationGenerator(TrainSettings.Instance, Category.Categories);
            generator.WriteFeed(format, context.Response.OutputStream, list, title);
        }
        //============================================================
        //	PRIVATE ATOM METHODS
        //============================================================
        #region WriteAtomContent(XmlWriter writer, List<IPublishable> publishables)
        /// <summary>
        /// Writes the Atom feed element information to the specified <see cref="XmlWriter"/> using the supplied collection.
        /// </summary>
        /// <param name="writer">The <see cref="XmlWriter"/> to write channel element information to.</param>
        /// <param name="publishables">The collection of <see cref="IPublishable"/> objects used to generate syndication content.</param>
        /// <param name="title">The title of the ATOM content.</param>
        private void WriteAtomContent(XmlWriter writer, List <IPublishable> publishables, string title)
        {
            //------------------------------------------------------------
            //	Write required feed elements
            //------------------------------------------------------------
            writer.WriteElementString("id", Utils.AbsoluteWebRoot.ToString());
            writer.WriteElementString("title", title);
            writer.WriteElementString("updated", (publishables.Count > 0) ? SyndicationGenerator.ToW3CDateTime(publishables[0].DateModified.ToUniversalTime()) : SyndicationGenerator.ToW3CDateTime(DateTime.UtcNow));

            //------------------------------------------------------------
            //	Write recommended feed elements
            //------------------------------------------------------------
            writer.WriteStartElement("link");
            writer.WriteAttributeString("href", Utils.AbsoluteWebRoot.ToString());
            writer.WriteEndElement();

            writer.WriteStartElement("link");
            writer.WriteAttributeString("rel", "self");
            writer.WriteAttributeString("href", Utils.AbsoluteWebRoot + "syndication.axd?format=atom");
            writer.WriteEndElement();

            //writer.WriteStartElement("link");
            //writer.WriteAttributeString("rel", "alternate");
            //writer.WriteAttributeString("href", Utils.FeedUrl.ToString());
            //writer.WriteEndElement();

            //------------------------------------------------------------
            //	Write optional feed elements
            //------------------------------------------------------------
            writer.WriteElementString("subtitle", this.Settings.Description);

            //------------------------------------------------------------
            //	Write common/shared feed elements
            //------------------------------------------------------------
            this.WriteAtomContentCommonElements(writer);

            foreach (IPublishable publishable in publishables)
            {
                //------------------------------------------------------------
                //	Skip publishable content if it is not visible
                //------------------------------------------------------------
                if (!publishable.IsVisible)
                {
                    continue;
                }

                //------------------------------------------------------------
                //	Write <entry> element for publishable content
                //------------------------------------------------------------
                WriteAtomEntry(writer, publishable);
            }
        }
        /// <summary>
        /// Writes the Atom feed entry element information to the specified <see cref="XmlWriter"/> using the supplied <see cref="Page"/>.
        /// </summary>
        /// <param name="writer">The <see cref="XmlWriter"/> to write feed entry element information to.</param>
        /// <param name="publishable">The <see cref="IPublishable"/> used to generate feed entry content.</param>
        private static void WriteAtomEntry(XmlWriter writer, IPublishable publishable)
        {
            Training post    = publishable as Training;
            Comment  comment = publishable as Comment;

            //------------------------------------------------------------
            //	Raise serving event
            //------------------------------------------------------------
            ServingEventArgs arg = new ServingEventArgs(publishable.Content, ServingLocation.Feed);

            publishable.OnServing(arg);
            if (arg.Cancel)
            {
                return;
            }

            //------------------------------------------------------------
            //	Modify publishable content to make references absolute
            //------------------------------------------------------------
            string content = ConvertPathsToAbsolute(arg.Body);

            writer.WriteStartElement("entry");
            //------------------------------------------------------------
            //	Write required entry elements
            //------------------------------------------------------------
            writer.WriteElementString("id", Utils.ConvertToAbsolute(publishable.RelativeLink).ToString());
            writer.WriteElementString("title", publishable.Title);
            writer.WriteElementString("updated", SyndicationGenerator.ToW3CDateTime(publishable.DateCreated.ToUniversalTime()));

            //------------------------------------------------------------
            //	Write recommended entry elements
            //------------------------------------------------------------
            writer.WriteStartElement("link");
            writer.WriteAttributeString("rel", "self");
            writer.WriteAttributeString("href", SyndicationGenerator.GetPermaLink(publishable).ToString());
            writer.WriteEndElement();

            writer.WriteStartElement("link");
            writer.WriteAttributeString("href", Utils.ConvertToAbsolute(publishable.RelativeLink).ToString());
            writer.WriteEndElement();

            writer.WriteStartElement("author");
            writer.WriteElementString("name", publishable.Author);
            writer.WriteEndElement();

            writer.WriteStartElement("summary");
            writer.WriteAttributeString("type", "html");
            writer.WriteString(content);
            writer.WriteEndElement();

            //------------------------------------------------------------
            //	Write optional entry elements
            //------------------------------------------------------------
            writer.WriteElementString("published", SyndicationGenerator.ToW3CDateTime(publishable.DateCreated.ToUniversalTime()));

            writer.WriteStartElement("link");
            writer.WriteAttributeString("rel", "related");
            writer.WriteAttributeString("href", String.Concat(Utils.ConvertToAbsolute(publishable.RelativeLink).ToString(), "#comment"));
            writer.WriteEndElement();

            //------------------------------------------------------------
            //	Write enclosure tag for podcasting support
            //------------------------------------------------------------
            if (TrainSettings.Instance.EnableEnclosures)
            {
                string encloser = GetEnclosure(content);
                if (!string.IsNullOrEmpty(encloser))
                {
                    writer.WriteRaw(encloser);
                }
            }

            //------------------------------------------------------------
            //	Write entry category elements
            //------------------------------------------------------------
            if (publishable.Categories != null)
            {
                foreach (Category category in publishable.Categories)
                {
                    writer.WriteStartElement("category");
                    writer.WriteAttributeString("term", category.Title);
                    writer.WriteEndElement();
                }
            }

            //------------------------------------------------------------
            //	Write Dublin Core syndication extension elements
            //------------------------------------------------------------
            if (!String.IsNullOrEmpty(publishable.Author))
            {
                writer.WriteElementString("dc", "publisher", "http://purl.org/dc/elements/1.1/", publishable.Author);
            }
            if (!String.IsNullOrEmpty(publishable.Description))
            {
                writer.WriteElementString("dc", "description", "http://purl.org/dc/elements/1.1/", publishable.Description);
            }

            //------------------------------------------------------------
            //	Write pingback syndication extension elements
            //------------------------------------------------------------
            Uri pingbackServer;

            if (Uri.TryCreate(String.Concat(Utils.AbsoluteWebRoot.ToString().TrimEnd('/'), "/pingback.axd"), UriKind.RelativeOrAbsolute, out pingbackServer))
            {
                writer.WriteElementString("pingback", "server", "http://madskills.com/public/xml/rss/module/pingback/", pingbackServer.ToString());
                writer.WriteElementString("pingback", "target", "http://madskills.com/public/xml/rss/module/pingback/", SyndicationGenerator.GetPermaLink(publishable).ToString());
            }

            //------------------------------------------------------------
            //	Write slash syndication extension elements
            //------------------------------------------------------------
            if (post != null && post.Comments != null)
            {
                writer.WriteElementString("slash", "comments", "http://purl.org/rss/1.0/modules/slash/", post.Comments.Count.ToString(CultureInfo.InvariantCulture));
            }

            //------------------------------------------------------------
            //	Write trackback syndication extension elements
            //------------------------------------------------------------
            if (post != null && post.TrackbackLink != null)
            {
                writer.WriteElementString("trackback", "ping", "http://madskills.com/public/xml/rss/module/trackback/", post.TrackbackLink.ToString());
            }

            //------------------------------------------------------------
            //	Write well-formed web syndication extension elements
            //------------------------------------------------------------
            writer.WriteElementString("wfw", "comment", "http://wellformedweb.org/CommentAPI/", String.Concat(Utils.ConvertToAbsolute(publishable.RelativeLink).ToString(), "#comment"));
            writer.WriteElementString("wfw", "commentRss", "http://wellformedweb.org/CommentAPI/", Utils.AbsoluteWebRoot.ToString().TrimEnd('/') + "/syndication.axd?post=" + publishable.Id.ToString());

            //------------------------------------------------------------
            //	Write </entry> element
            //------------------------------------------------------------
            writer.WriteEndElement();
        }
        /// <summary>
        /// Converts the supplied <see cref="DateTime"/> to its equivalent <a href="http://www.w3.org/TR/NOTE-datetime">W3C DateTime</a> string representation.
        /// </summary>
        /// <param name="utcDateTime">The Coordinated Universal Time (UTC) <see cref="DateTime"/> to convert.</param>
        /// <returns>The equivalent <a href="http://www.w3.org/TR/NOTE-datetime">W3C DateTime</a> string representation.</returns>
        private static string ToW3CDateTime(DateTime utcDateTime)
        {
            TimeSpan utcOffset = TimeSpan.Zero;

            return((utcDateTime + utcOffset).ToString("yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture) + SyndicationGenerator.FormatW3cOffset(utcOffset, ":"));
        }