public ActionResult Details(int id, string slug)
        {
            var post = Session
                .Include<Post>(x => x.CommentsId)
                .Include(x => x.AuthorId)
                .Load(id);

            if (post == null)
                return HttpNotFound();

            if (post.IsPublicPost(Request.QueryString["key"]) == false)
                return HttpNotFound();

            var comments = Session.Load<PostComments>(post.CommentsId);
            var vm = new PostViewModel
            {
                Post = post.MapTo<PostViewModel.PostDetails>(),
                Comments = comments.Comments
                    .OrderBy(comment => comment.CreatedAt)
                    .MapTo<PostViewModel.Comment>(),
                NextPost = Session.GetPostReference(x => x.PublishAt > post.PublishAt),
                PreviousPost = Session.GetPostReference(x => x.PublishAt < post.PublishAt),
                AreCommentsClosed = comments.AreCommentsClosed(post),
            };

            vm.Post.Author = Session.Load<User>(post.AuthorId).MapTo<PostViewModel.UserDetails>();

            if (vm.Post.Slug != slug)
                return RedirectToActionPermanent("Details", new { id, vm.Post.Slug });

            SetWhateverUserIsTrustedCommenter(vm);

            return View("Details", vm);
        }
        public ActionResult Details(int id, string slug, Guid key)
        {
            var post = RavenSession
                .Include<Post>(x => x.CommentsId)
                .Include(x => x.AuthorId)
                .Load(id);

            if (post == null)
                return HttpNotFound();

            if (post.IsPublicPost(key) == false)
                return HttpNotFound();

            var comments = RavenSession.Load<PostComments>(post.CommentsId) ?? new PostComments();
            var vm = new PostViewModel
                     {
                     	Post = post.MapTo<PostViewModel.PostDetails>(),
                     	Comments = comments.Comments
                     		.OrderBy(comment => comment.CreatedAt)
                     		.MapTo<PostViewModel.Comment>(),
                     	NextPost = RavenSession.GetNextPrevPost(post, true),
                     	PreviousPost = RavenSession.GetNextPrevPost(post, false),
                     	AreCommentsClosed = comments.AreCommentsClosed(post, BlogConfig.NumberOfDayToCloseComments),
                     };

            vm.Post.Author = RavenSession.Load<User>(post.AuthorId).MapTo<PostViewModel.UserDetails>();

            if (vm.Post.Slug != slug)
                return RedirectToActionPermanent("Details", new {id, vm.Post.Slug});

            SetWhateverUserIsTrustedCommenter(vm);

            return View("Details", vm);
        }
		private static List<PostInSeries> FilterPostsInSeries(PostViewModel model)
		{
			return model
				.SeriesInfo
				.PostsInSeries
				.OrderBy(x => x.PublishAt)
				.Where(x => x.PublishAt <= DateTimeOffset.UtcNow)
				.ToList();
		}
		private static int GetCurrentPostIndexInSeries(PostViewModel model, List<PostInSeries> postsInSeries)
		{
			var currentPostId = model.Post.Id;
			for (var index = 0; index < postsInSeries.Count; index++)
			{
				var postInSeries = postsInSeries[index];
				if (postInSeries.Id == currentPostId)
					return index;
			}

			return 0;
		}
		public virtual ActionResult Details(int id, string slug, Guid key)
		{
			var post = RavenSession
				.Include<Post>(x => x.CommentsId)
				.Include(x => x.AuthorId)
				.Load(id);

			if (post == null)
				return HttpNotFound();

			if (post.IsPublicPost(key) == false)
				return HttpNotFound();

            SeriesInfo seriesInfo = GetSeriesInfo(post.Title);

			var comments = RavenSession.Load<PostComments>(post.CommentsId) ?? new PostComments();
			var vm = new PostViewModel
			         {
			         	Post = post.MapTo<PostViewModel.PostDetails>(),
			         	Comments = comments.Comments
                            .OrderBy(x => x.CreatedAt)
                            .MapTo<PostViewModel.Comment>(),
			         	NextPost = RavenSession.GetNextPrevPost(post, true),
			         	PreviousPost = RavenSession.GetNextPrevPost(post, false),
			         	AreCommentsClosed = comments.AreCommentsClosed(post, BlogConfig.NumberOfDayToCloseComments),
                        SeriesInfo = seriesInfo
			         };

			vm.Post.Author = RavenSession.Load<User>(post.AuthorId).MapTo<PostViewModel.UserDetails>();

			var comment = TempData["new-comment"] as CommentInput;

			if(comment != null)
			{
				vm.Comments.Add(new PostViewModel.Comment
				{
					CreatedAt = DateTimeOffset.Now.ToString(),
					Author = comment.Name,
					Body = MarkdownResolver.Resolve(comment.Body),
					Id = -1,
					Url = UrlResolver.Resolve(comment.Url),
					Tooltip = "Comment by " + comment.Name,
					EmailHash = EmailHashResolver.Resolve(comment.Email)
				});
			}

			if (vm.Post.Slug != slug)
				return RedirectToActionPermanent("Details", new {id, vm.Post.Slug});

			SetWhateverUserIsTrustedCommenter(vm);

			return View("Details", vm);
		}
		public static MvcHtmlString PreviousSeriesArticleLink(this HtmlHelper helper, PostViewModel model)
		{
			if (model.SeriesInfo == null)
				return Empty;

			if (model.SeriesInfo.PostsInSeries == null)
				return Empty;

			var postsInSeries = FilterPostsInSeries(model);

			var postIndexInSeries = GetCurrentPostIndexInSeries(model, postsInSeries);
			if (postIndexInSeries <= 0 || postsInSeries.Count <= 1)
				return Empty;

			var previousPostInSeries = postsInSeries[postIndexInSeries - 1];
			return helper.ActionLink(
				"‹ previous series post",
				MVC.PostDetails.ActionNames.Details,
				MVC.PostDetails.Name,
				new { id = previousPostInSeries.Id, previousPostInSeries.Slug },
				new { @class = "pull-left" });
		}
		public static MvcHtmlString NextSeriesArticleLink(this HtmlHelper helper, PostViewModel model)
		{
			if (model.SeriesInfo == null)
				return Empty;

			if (model.SeriesInfo.PostsInSeries == null)
				return Empty;

			var postsInSeries = FilterPostsInSeries(model);

			var postIndexInSeries = GetCurrentPostIndexInSeries(model, postsInSeries);
			var nextPostIndexInSeries = postIndexInSeries + 1;
			if (nextPostIndexInSeries >= postsInSeries.Count)
				return Empty;

			var nextPostInSeries = postsInSeries[nextPostIndexInSeries];
			return helper.ActionLink(
				"next series post ›",
				MVC.PostDetails.ActionNames.Details,
				MVC.PostDetails.Name,
				new { id = nextPostInSeries.Id, nextPostInSeries.Slug },
				new { @class = "pull-right" });
		}
        private void SetWhateverUserIsTrustedCommenter(PostViewModel vm)
        {
            if (Request.IsAuthenticated)
            {
                var user = RavenSession.GetCurrentUser();
                vm.Input = user.MapTo<CommentInput>();
                vm.IsTrustedCommenter = true;
                vm.IsLoggedInCommenter = true;
                return;
            }

            var cookie = Request.Cookies[CommenterUtil.CommenterCookieName];
            if (cookie == null) return;

            var commenter = RavenSession.GetCommenter(cookie.Value);
            if (commenter == null)
            {
                vm.IsLoggedInCommenter = false;
                Response.Cookies.Set(new HttpCookie(CommenterUtil.CommenterCookieName) {Expires = DateTime.Now.AddYears(-1)});
                return;
            }

            vm.IsLoggedInCommenter = string.IsNullOrWhiteSpace(commenter.OpenId) == false;
            vm.Input = commenter.MapTo<CommentInput>();
            vm.IsTrustedCommenter = commenter.IsTrustedCommenter == true;
        }
        private void SetWhateverUserIsTrustedCommenter(PostViewModel vm)
        {
            if (Request.IsAuthenticated)
            {
                var user = Session.GetCurrentUser();
                vm.Input = user.MapTo<CommentInput>();
                vm.IsTrustedCommenter = true;
                return;
            }

            var cookie = Request.Cookies[CommenterCookieName];
            if (cookie == null)
                return;

            var commenter = Session.GetCommenter(cookie.Value);
            if (commenter == null)
                return;

            vm.Input = commenter.MapTo<CommentInput>();
            vm.IsTrustedCommenter = commenter.IsTrustedCommenter == true;
        }