/// <summary>
        /// Установить обратные ссылки.
        /// </summary>
        /// <param name="src">Исходный тред.</param>
        public void SetBackLinks(PostTreeCollection src)
        {
            if (src.Posts == null)
            {
                src.Posts = new List<PostTree>();
            }
            var hashService = Services.GetServiceOrThrow<ILinkHashService>();
            var transformService = Services.GetServiceOrThrow<ILinkTransformService>();
            var postLinks = src.Posts.DeduplicateToDictionary(p => p.Link, hashService.GetComparer());
            var oldQuoteCounts = src.Posts.Select(p => new {p.Link, Count = p.Quotes?.Count ?? 0}).DeduplicateToDictionary(p => p.Link, hashService.GetComparer());
            foreach (var post in src.Posts)
            {
                if (post.Quotes == null)
                {
                    post.Quotes = new List<BoardLinkBase>();
                }
            }
            foreach (var post in src.Posts)
            {
                if (post.Comment != null && post.Comment.Nodes != null)
                {
                    var links = post.Comment.Nodes.SelectMany(n => n.FlatHierarchy(nn =>
                    {
                        var n1 = nn as PostNode;
                        if (n1 != null)
                        {
                            return n1.Children ?? new List<PostNodeBase>();
                        }
                        return Enumerable.Empty<PostNodeBase>();
                    })).OfType<PostNodeBoardLink>()
                    .Where(l => l.BoardLink != null)
                    .Select(l => l.BoardLink)
                    .ToList();
                    foreach (var l in links)
                    {
                        if (postLinks.ContainsKey(l))
                        {
                            postLinks[l].Quotes.Add(post.Link);
                        }
                    }
                }
            }
            foreach (var post in src.Posts.Where(p => p.Quotes.Count > 1))
            {
                post.Quotes = post.Quotes.Distinct(hashService.GetComparer()).OrderBy(l => l, transformService.GetLinkComparer()).ToList();
            }

            foreach (var post in src.Posts)
            {
                var oldCount = oldQuoteCounts.ContainsKey(post.Link) ? oldQuoteCounts[post.Link].Count : 0;
                if (oldCount != post.Quotes.Count)
                {
                    post.GeneratePostStamp();
                }
            }
        }
 /// <summary>
 /// Сортировать дерево по возрастанию номеров постов.
 /// </summary>
 /// <param name="src">Исходный тред.</param>
 public void SortThreadTree(PostTreeCollection src)
 {
     if (src.Posts == null)
     {
         src.Posts = new List<PostTree>();
     }
     var comparer = Services.GetServiceOrThrow<ILinkTransformService>().GetLinkComparer();
     src.Posts.Sort((x, y) => comparer.Compare(x.Link, y.Link));
 }