public static List <List <Papers> > GroupPapers(List <Papers> papers)
        {
            Random r = new Random();

            papers.OrderBy(p => r.Next());

            List <List <Papers> > timeGroups = new List <List <Papers> >();

            TimeSpan timeZoneStart = TimeSpan.FromHours(-12);
            TimeSpan timePeriod    = TimeSpan.FromHours(24).Divide(timeZoneGroups);

            for (int i = 0; i < timeZoneGroups; i++)
            {
                timeGroups.Add(new List <Papers>());
            }
            foreach (Papers p in papers)
            {
                TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById(p.TimeZone);
                TimeSpan     ts  = tzi.BaseUtcOffset;

                for (int i = 0; i < timeZoneGroups; i++)
                {
                    if (ts.TotalMinutes <= timeZoneStart.Add(timePeriod.Multiply(i + 1)).TotalMinutes)
                    {
                        timeGroups[i].Add(p);
                        break;
                    }
                }
            }

            List <Dictionary <int, List <Papers> > > topicGroups = new List <Dictionary <int, List <Papers> > >();

            for (int i = 0; i < timeZoneGroups; i++)
            {
                topicGroups.Add(new Dictionary <int, List <Papers> >());
                foreach (Papers p in timeGroups[i])
                {
                    int key = PaperTopic.GetCategory(p.PaperTopic).ID;
                    if (!topicGroups[i].ContainsKey(key))
                    {
                        topicGroups[i].Add(key, new List <Papers>());
                    }
                    topicGroups[i][key].Add(p);
                }
            }

            List <List <List <Papers> > > finalGroups = new List <List <List <Papers> > >();

            for (int i = 0; i < timeZoneGroups; i++)
            {
                finalGroups.Add(new List <List <Papers> >());
                int j = 0;
                foreach (List <Papers> topicGroup in topicGroups[i].Values)
                {
                    finalGroups[i].Add(new List <Papers>());
                    foreach (Papers p in topicGroup)
                    {
                        if (finalGroups[i][j].Count >= papersPerGroup)
                        {
                            j++;
                            finalGroups[i].Add(new List <Papers>());
                        }
                        finalGroups[i][j].Add(p);
                    }

                    List <List <Papers> > groupsToRemove = new List <List <Papers> >();
                    foreach (List <Papers> fg in finalGroups[i])
                    {
                        if (fg.Count < minPapersPerGroup)
                        {
                            groupsToRemove.Add(fg);
                        }
                    }

                    foreach (List <Papers> gtr in groupsToRemove)
                    {
                        finalGroups[i].Remove(gtr);
                    }

                    foreach (Papers p in finalGroups[i].SelectMany(p => p))
                    {
                        topicGroup.Remove(p);
                    }
                }
                if (finalGroups[i].Count == 0)
                {
                    finalGroups[i].Add(new List <Papers>());
                }

                int k = 0;
                foreach (Papers p in topicGroups[i].Values.SelectMany(l => l).OrderBy(p => r.Next()))
                {
                    while (finalGroups[i][k].Count >= papersPerGroup)
                    {
                        k++;
                        finalGroups[i].Add(new List <Papers>());
                    }
                    finalGroups[i][k].Add(p);
                }
            }

            return(finalGroups.SelectMany(fg => fg).Where(fg => fg.Count > 0).ToList());
        }
        // returns the parent, or the topic itself if it is null (is a parent)
        public static PaperTopic GetCategory(int ID)
        {
            PaperTopic topic = Get(ID);

            return(topic.ParentID == null ? topic : Get(topic.ParentID));
        }