text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;

namespace TXM.Core
{
    [Serializable]
    public enum TournamentCut
    {
        NoCut,
        Top64,
        Top32,
        Top16,
        Top8,
        Top4
    }
    [Serializable]
    public class Tournament : ISerializable
    {
        private int version = 2;

        #region Tournament Information
        public List<Player> Participants { get; set; }
        public List<Player> Teamplayer { get; set; }
        public bool FirstRound { get; set; }
        public List<Pairing> PrePaired { get; set; }
        public string Name { get; set; }
        public List<string> Nicknames { get; internal set; }
        public int MaxPoints { get; set; }
        public List<Round> Rounds { get; internal set; }
        public string FilePath { get; internal set; }
        public string AutoSavePath { get; internal set; }
        public int DisplayedRound { get; set; }
        public TournamentCut Cut { get; set; }
        public bool CutStarted { get; internal set; }
        public bool WonByeCalculated { get; internal set; }
        public List<Pairing> Pairings { get; set; }
        public bool TeamProtection { get; set; }
        public bool Single { get; set; }
        public bool PrintDDGER { get; set; }
        public bool PrintDDENG { get; set; }
        public AbstractRules Rule { get; set; }
        public bool bonus;
        #endregion

        #region GUI_State
        public string ButtonGetResultsText { get; set; }
        public bool ButtonCutState { get; set; }
        #endregion

        #region T3 Information
        public int T3ID { get; set; }
        public string GOEPPVersion { get; internal set; }
        #endregion

        #region internal Fields
        internal static List<int> givenStartNo = new List<int>();
        public Player WonBye = Player.GetWonBye();
        public Player Bye = Player.GetBye();
        private Player Bonus = Player.GetBonus();
        internal List<Player> ListOfPlayers;
        private List<Player>[] PointGroup;
        internal int WonByes;
        internal int currentCountOfPlayer;
        internal List<Player> WinnerLastRound;
        internal bool bye;
        #endregion

        #region Constructors
        public Tournament(string name, int t3ID, string GOEPPversion, AbstractRules rules, bool firstround = true, int maxPoints = 100, TournamentCut cut = TournamentCut.NoCut)
        {
            Player.ResetID();
            Name = name;
            T3ID = t3ID;
            GOEPPVersion = GOEPPversion;
            Participants = new List<Player>();
            Nicknames = new List<string>();
            givenStartNo = new List<int>();
            FirstRound = firstround;
            MaxPoints = maxPoints;
            Cut = cut;
            CutStarted = false;
            WonByeCalculated = false;
            Pairings = new List<Pairing>();
            Rounds = new List<Round>();
            Rule = rules;
            Single = true;
            bonus = false;
        }
        public Tournament(int t3ID, string name, AbstractRules rules, string GOEPPversion = "")
            : this(name, t3ID, GOEPPversion, rules)
        { }
        public Tournament(string name, AbstractRules rules)
            : this(0, name, rules)
        { }

        public Tournament(string name, int maxPoints, TournamentCut cut, AbstractRules rules)
            : this(name, 0, "", rules, true, maxPoints, cut)
        { }
        #endregion

        #region public functions
        public Player GetPlayerByNr(int nr)
        {
            foreach (var p in Participants)
            {
                if (p.ID == nr)
                    return p;
            }
            return null;
        }

        public void AddPlayer(Player player)
        {
            Participants.Add(player);
            Nicknames.Add(player.Nickname);
            if (Pairings.Count > 0)
            {
                if (Pairings[Pairings.Count - 1].Player2 == Bye)
                {
                    Pairings[Pairings.Count - 1].Player2 = player;
                    Pairings[Pairings.Count - 1].ResultEdited = false;
                }
                else
                    Pairings.Add(new Pairing() { Player1 = player, ResultEdited = true, Player2 = Bye });
            }
        }

        public void Sort()
        {
            Participants = Rule.SortTable(Participants);
        }

        internal void SplitTeams()
        {
            foreach (var tp in Teamplayer)
            {
                int a = 0;
                for (int i = 0; i < Participants.Count; i++)
                {
                    if (Participants[i].Team == tp.Team)
                    {
                        a = i;
                        break;
                    }
                }
                tp.Wins = Participants[a].Wins;
                tp.Rank = Participants[a].Rank;
                tp.ModifiedWins = Participants[a].ModifiedWins;
                tp.Losses = Participants[a].Losses;
                tp.Draws = Participants[a].Draws;
                tp.TournamentPoints = Participants[a].TournamentPoints;
                tp.DestroyedPoints = Participants[a].DestroyedPoints;
                tp.LostPoints = Participants[a].LostPoints;
                tp.StrengthOfSchedule = Participants[a].StrengthOfSchedule;
                tp.MarginOfVictory = Participants[a].MarginOfVictory;
            }
            Participants = Teamplayer;
        }

        public List<Pairing> GetSeed(bool start, bool cut)
        {
            if (Rule.IsRandomSeeding)
            {
                return GetSeedRandom(start, cut);
            }
            else
            {
                return GetSeedNonRandom(start, cut);
            }
        }

        public List<Pairing> GetSeedRandom(bool start, bool cut)
        {
            Pairing.ResetTableNr();
            int temp, pos = 0;
            bool swappedGroup = false;

            #region Cut
            if (Cut != TournamentCut.NoCut && (cut || CutStarted))
            {
                CalculateWonBye();
                if (cut)
                {
                    Sort();
                    CutStarted = true;
                    if (Cut == TournamentCut.Top8)
                        currentCountOfPlayer = 8;
                    else if (Cut == TournamentCut.Top16)
                        currentCountOfPlayer = 16;
                    else if (Cut == TournamentCut.Top32)
                        currentCountOfPlayer = 32;
                    else if (Cut == TournamentCut.Top64)
                        currentCountOfPlayer = 64;
                    else
                        currentCountOfPlayer = 4;

                    ListOfPlayers = new List<Player>();

                    for (int i = 0; i < currentCountOfPlayer; i++)
                        ListOfPlayers.Add(Participants[i]);

                    Pairings = new List<Pairing>();

                    while (ListOfPlayers.Count > 0)
                    {
                        Pairings.Add(new Pairing());
                        Pairings[pos].Player1 = ListOfPlayers[0];
                        Pairings[pos].Player2 = ListOfPlayers[ListOfPlayers.Count - 1];
                        ListOfPlayers.Remove(Pairings[pos].Player1);
                        ListOfPlayers.Remove(Pairings[pos].Player2);
                        pos++;
                    }
                }
                else
                {
                    Pairings = new List<Pairing>();

                    for (int i = 0; i < WinnerLastRound.Count / 2; i++)
                    {
                        Pairings.Add(new Pairing());
                        Pairings[i].Player1 = WinnerLastRound[i];
                        Pairings[i].Player2 = WinnerLastRound[WinnerLastRound.Count - 1 - i];
                    }
                }
            }
            #endregion
            else
            {
                if (start)
                    Start();
                else
                {
                    Sort();
                    Rounds[Rounds.Count - 1].Participants = new List<Player>();
                    foreach (Player p in Participants)
                        Rounds[Rounds.Count - 1].Participants.Add(new Player(p));

                }

                ListOfPlayers = new List<Player>();
                Random random = new Random();

                foreach (Player p in Participants)
                {
                    if (!(p.Disqualified || p.Dropped))
                        ListOfPlayers.Add(p);
                }

                Pairings = new List<Pairing>();

                if (start)
                {
                    if (PrePaired != null)
                    {
                        foreach (Pairing p in PrePaired)
                        {
                            Pairings.Add(p);
                            ListOfPlayers.Remove(p.Player1);
                            ListOfPlayers.Remove(p.Player2);
                            if (p.Player1.Bye)
                                p.ResultEdited = true;
                            pos++;
                        }
                    }
                    List<Player> wonByes = GetWonByes();
                    for (int i = 0; i < wonByes.Count; i++)
                    {
                        Pairings.Add(new Pairing());
                        Pairings[pos].Player1 = wonByes[i];
                        Pairings[pos].Player2 = WonBye;
                        Pairings[pos].ResultEdited = true;
                        pos++;
                    }
                    if (ListOfPlayers.Count % 2 == 0)
                        bye = false;
                    else
                        bye = true;
                }
                else
                {
                    if (ListOfPlayers.Count % 2 == 0)
                        bye = false;
                    else
                        bye = true;
                }
                if (start)
                {
                    while (ListOfPlayers.Count > 0)
                    {
                        Pairings.Add(new Pairing());
                        if (ListOfPlayers.Count == 1)
                        {
                            Pairings[pos].Player1 = ListOfPlayers[0];
                            Pairings[pos].Player2 = Bye;
                            Pairings[pos].Player1.Bye = true;
                            Pairings[pos].ResultEdited = true;
                            ListOfPlayers.Remove(Pairings[pos].Player1);
                            pos++;
                            break;
                        }
                        Pairings[pos].Player1 = ListOfPlayers[0];
                        for (int i = 0; i < ListOfPlayers.Count; i++)
                        {
                            temp = random.Next(1, ListOfPlayers.Count);
                            if (TeamProtection && (Pairings[pos].Player1.Team != ListOfPlayers[temp].Team || Pairings[pos].Player1.Team == ""))
                            {
                            Pairings[pos].Player2 = ListOfPlayers[temp];
                            break;
                            }
                            else
                                Pairings[pos].Player2 = ListOfPlayers[temp];
                        }
                        if (Pairings[pos].Player2 == null)
                            Pairings[pos].Player2 = ListOfPlayers[1];

                        ListOfPlayers.Remove(Pairings[pos].Player1);
                        ListOfPlayers.Remove(Pairings[pos].Player2);
                        pos++;
                    }
                }
                else
                {
                    CountGroups();

                    int group = 0;
                    for (int i = 0; i < PointGroup.Length; i++)
                    {
                        while (PointGroup[i].Count >= 2)
                        {
                            Pairings.Add(new Pairing());
                            if (swappedGroup)
                            {
                                temp = PointGroup[i].Count - 1;
                                swappedGroup = false;
                            }
                            else
                            {
                                temp = random.Next(0, PointGroup[i].Count);
                            }
                            Pairings[pos].Player1 = PointGroup[i][temp];
                            PointGroup[i].RemoveAt(temp);
                            temp = random.Next(0, PointGroup[i].Count);
                            group = -1;
                            for (int j = i; j < PointGroup.Length; j++)
                            {
                                if (!HasPlayedVsWholePointGroup((Player)Pairings[pos].Player1, j))
                                {
                                    group = j;
                                    break;
                                }
                            }
                            if (group != -1)
                            {
                                temp = random.Next(0, PointGroup[i].Count);
                                while (Pairings[pos].Player1.HasPlayedVS(PointGroup[group][temp]))
                                {
                                    temp = random.Next(0, PointGroup[i].Count);
                                }
                            }
                            else
                            {
                                //Was passiert wenn ein Spieler schon gegen alle gespielt hat?
                                group = i;
                            }
                            Pairings[pos].Player2 = PointGroup[group][temp];
                            PointGroup[group].RemoveAt(temp);
                            pos++;
                        }
                        if (PointGroup[i].Count == 1)
                        {
                            if (PointGroup.Length == i + 1 && bye)
                            {
                                Pairings.Add(new Pairing());
                                Pairings[pos].Player1 = PointGroup[i][0];
                                Pairings[pos].Player2 = Bye;
                                Pairings[pos].Player1.Bye = true;
                                Pairings[pos].ResultEdited = true;
                            }
                            else
                            {
                                PointGroup[i + 1].Add(PointGroup[i][0]);
                                swappedGroup = true;
                            }
                        }
                    }
                }

                //Prüfen, ob die letzten beiden schon gegeneinander gespielt haben
                temp = Pairings.Count - 1;

                if (Pairings[temp] == null)
                    temp--;

                if (Pairings[temp].Player1.HasPlayedVS(Pairings[temp].Player2) && Pairings[temp].Player1.EnemyCount < Participants.Count)
                {
                    for (int i = temp - 1; i >= 0; i--)
                    {
                        if (!Pairings[temp].Player1.HasPlayedVS(Pairings[i].Player1) && !Pairings[temp].Player2.HasPlayedVS(Pairings[i].Player2))
                        {
                            ChangePairing(temp, 0, i, 0);
                            break;
                        }
                        if (!Pairings[temp].Player1.HasPlayedVS(Pairings[i].Player2) && !Pairings[temp].Player2.HasPlayedVS(Pairings[i].Player1))
                        {
                            ChangePairing(temp, 0, i, 1);
                            break;
                        }
                    }
                }
            }

            if (Rounds == null)
                Rounds = new List<Round>();
            Rounds.Add(new Round(Pairings, Participants));
            DisplayedRound = Rounds.Count;
            CheckTableNr();

            return Pairings;
        }

        public List<Pairing> GetSeedNonRandom(bool start, bool cut)
        {
            Pairing.ResetTableNr();
            int temp, pos = 0;

            if (Cut != TournamentCut.NoCut && (cut || CutStarted))
            {
                CalculateWonBye();
                if (cut)
                {
                    Sort();
                    CutStarted = true;
                    if (Cut == TournamentCut.Top8)
                        currentCountOfPlayer = 8;
                    else if (Cut == TournamentCut.Top16)
                        currentCountOfPlayer = 16;
                    else
                        currentCountOfPlayer = 4;

                    ListOfPlayers = new List<Player>();

                    for (int i = 0; i < currentCountOfPlayer; i++)
                        ListOfPlayers.Add(Participants[i]);

                    Pairings = new List<Pairing>();

                    while (ListOfPlayers.Count > 0)
                    {
                        Pairings.Add(new Pairing());
                        Pairings[pos].Player1 = ListOfPlayers[0];
                        Pairings[pos].Player2 = ListOfPlayers[ListOfPlayers.Count - 1];
                        ListOfPlayers.Remove(Pairings[pos].Player1);
                        ListOfPlayers.Remove(Pairings[pos].Player2);
                        pos++;
                    }
                }
                else
                {
                    Pairings = new List<Pairing>();

                    for (int i = 0; i < WinnerLastRound.Count / 2; i++)
                    {
                        Pairings.Add(new Pairing());
                        Pairings[i].Player1 = WinnerLastRound[i];
                        Pairings[i].Player2 = WinnerLastRound[WinnerLastRound.Count - 1 - i];
                    }
                }
            }
            else
            {
                if (start)
                    Start();
                else
                {
                    Sort();
                    Rounds[Rounds.Count - 1].Participants = new List<Player>();
                    foreach (Player p in Participants)
                        Rounds[Rounds.Count - 1].Participants.Add(new Player(p));

                }

                ListOfPlayers = new List<Player>();

                foreach (Player p in Participants)
                {
                    if (!p.Disqualified)
                        ListOfPlayers.Add(p);
                }

                Pairings = new List<Pairing>();

                if (start)
                {
                    if (PrePaired != null)
                    {
                        foreach (Pairing p in PrePaired)
                        {
                            Pairings.Add(p);
                            ListOfPlayers.Remove(p.Player1);
                            ListOfPlayers.Remove(p.Player2);
                            if (p.Player1.Bye)
                                p.ResultEdited = true;
                            pos++;
                        }
                    }
                    List<Player> wonFreeTickets = GetWonByes();
                    for (int i = 0; i < wonFreeTickets.Count; i++)
                    {
                        Pairings.Add(new Pairing());
                        Pairings[pos].Player1 = wonFreeTickets[i];
                        Pairings[pos].Player2 = WonBye;
                        Pairings[pos].ResultEdited = true;
                        pos++;
                    }
                    if (ListOfPlayers.Count % 2 == 0)
                        bye = false;
                    else
                        bye = true;
                }
                else
                {
                    if (Participants.Count % 2 == 0)
                        bye = false;
                    else
                        bye = true;
                }
                if (start)
                {
                    Random random = new Random();
                    while (ListOfPlayers.Count > 0)
                    {
                        Pairings.Add(new Pairing());
                        if (ListOfPlayers.Count == 1)
                        {
                            Pairings[pos].Player1 = ListOfPlayers[0];
                            Pairings[pos].Player2 = Bye;
                            Pairings[pos].Player1.Bye = true;
                            Pairings[pos].ResultEdited = true;
                            ListOfPlayers.Remove(Pairings[pos].Player1);
                            pos++;
                            break;
                        }
                        Pairings[pos].Player1 = ListOfPlayers[0];

                        for (int i = 0; i < ListOfPlayers.Count; i++)
                        {
                            temp = random.Next(1, ListOfPlayers.Count);
                            if (TeamProtection && (Pairings[pos].Player1.Team != ListOfPlayers[temp].Team || Pairings[pos].Player1.Team == ""))
                            {
                                Pairings[pos].Player2 = ListOfPlayers[temp];
                                break;
                            }

                        }

                        if (Pairings[pos].Player2 == null)
                            Pairings[pos].Player2 = ListOfPlayers[1];

                        ListOfPlayers.Remove(Pairings[pos].Player1);
                        ListOfPlayers.Remove(Pairings[pos].Player2);
                        pos++;
                    }
                }
                else
                {
                    while (ListOfPlayers.Count > 0)
                    {
                        Pairings.Add(new Pairing());
                        if (ListOfPlayers.Count == 1)
                        {
                            Pairings[pos].Player1 = ListOfPlayers[0];
                            Pairings[pos].Player2 = Bye;
                            Pairings[pos].Player1.Bye = true;
                            Pairings[pos].ResultEdited = true;
                            ListOfPlayers.Remove(Pairings[pos].Player1);
                            pos++;
                            break;
                        }
                        Pairings[pos].Player1 = ListOfPlayers[0];
                        for (int i = 1; i < ListOfPlayers.Count; i++)
                        {
                            if (!Pairings[pos].Player1.HasPlayedVS(ListOfPlayers[i]))
                            {
                                Pairings[pos].Player2 = ListOfPlayers[i];
                                break;
                            }
                        }
                        if (Pairings[pos].Player2 == null)
                            Pairings[pos].Player2 = ListOfPlayers[1];

                        ListOfPlayers.Remove(Pairings[pos].Player1);
                        ListOfPlayers.Remove(Pairings[pos].Player2);
                        pos++;
                    }
                }

                //Prüfen, ob die letzten beiden schon gegeneinander gespielt haben
                temp = Pairings.Count - 1;

                if (Pairings[temp] == null)
                    temp--;

                if (Pairings[temp].Player1.HasPlayedVS(Pairings[temp].Player2) && Pairings[temp].Player1.EnemyCount < Participants.Count)
                {
                    for (int i = temp - 1; i >= 0; i--)
                    {
                        if (!Pairings[temp].Player1.HasPlayedVS(Pairings[i].Player1) && !Pairings[temp].Player2.HasPlayedVS(Pairings[i].Player2))
                        {
                            ChangePairing(temp, 0, i, 0);
                            break;
                        }
                        if (!Pairings[temp].Player1.HasPlayedVS(Pairings[i].Player2) && !Pairings[temp].Player2.HasPlayedVS(Pairings[i].Player1))
                        {
                            ChangePairing(temp, 0, i, 1);
                            break;
                        }
                    }
                }
            }

            if (Rounds == null)
                Rounds = new List<Round>();
            Rounds.Add(new Round(Pairings, Participants));
            DisplayedRound = Rounds.Count;

            return Pairings;
        }

        private void CheckTableNr()
        {
            foreach (Pairing p in Pairings)
            {
                if (p.Player1.TableNo != 0 && p.Player1.Bye == false && p.TableNr != p.Player1.TableNo)
                {
                    if ((p.Player2.TableNo != 0 && p.Player1.TableNo < p.Player2.TableNo) || p.Player2.TableNo == 0)
                    {
                        ChangePairings(p.Player1.TableNo, p.TableNr);
                    }
                    else if (p.Player2.TableNo != 0 && p.Player1.TableNo > p.Player2.TableNo && p.Player2.TableNo != p.TableNr)
                    {
                        ChangePairings(p.Player2.TableNo, p.TableNr);
                    }
                }
                else if (p.Player2.TableNo != 0)
                {
                    ChangePairings(p.Player2.TableNo, p.TableNr);
                }
            }
        }

        private void ChangePairings(int a, int b)
        {
            int tablenra = a;
            int tablenrb = b;
            a--;
            b--;
            if(a >= Pairings.Count)
            {
                a = Pairings.Count-1;
            }
            if(b >= Pairings.Count)
            {
                b = Pairings.Count - 1;
            }

            Player a1 = Pairings[a].Player1;
            Player a2 = Pairings[a].Player2;
            bool result = Pairings[a].ResultEdited;
            Pairings[a].Player1 = Pairings[b].Player1;
            Pairings[a].Player2 = Pairings[b].Player2;
            Pairings[a].ResultEdited = Pairings[b].ResultEdited;
            Pairings[b].Player1 = a1;
            Pairings[b].Player2 = a2;
            Pairings[b].ResultEdited = result;
            Pairings[a].TableNr = tablenra;
            Pairings[b].TableNr = tablenrb;
        }

        //TODO: Ändern auf Rules
        public void RemoveLastRound()
        {
            foreach (var p in Participants)
                p.RemoveLastResult();
            foreach (var p in Pairings)
            {
                p.Player1Score = 0;
                p.Player2Score = 0;
                if (p.Player1.Bye || (p.Player1.WonBye && FirstRound))
                    p.ResultEdited = true;
                else
                    p.ResultEdited = false;
            }
        }

        public void GetResults(List<Pairing> results, bool update = false)
        {
            Result r;
            int winnerID = 0;
            bool winner;
            WinnerLastRound = new List<Player>();
            if(bonus)
            {
                foreach (Pairing pairing in results)
                {
                    r = new Result(0, 0, Bonus, MaxPoints, 1, pairing.Player1Score);
                    Rule.AddBonus(pairing.Player1, r);
                }
                return;
            }
            if (!update)
            {
                foreach (Pairing pairing in results)
                {
                    if (pairing.Winner == "Player 1")
                        winnerID = pairing.Player1.ID;
                    else if(pairing.Winner == "Player 2")
                        winnerID = pairing.Player2.ID;
                    else
                        winnerID = (pairing.Player1Score > pairing.Player2Score) ? pairing.Player1.ID : pairing.Player2.ID;
                    r = new Result(pairing.Player1Score, pairing.Player2Score, pairing.Player2, MaxPoints, winnerID, pairing.Player1Points);
                    winner = Rule.AddResult(pairing.Player1, r);
                    if (winner)
                        WinnerLastRound.Add(pairing.Player1);
                    if (pairing.Player2 != WonBye && pairing.Player2 != Bye)
                    {
                        r = new Result(pairing.Player2Score, pairing.Player1Score, pairing.Player1, MaxPoints, winnerID, pairing.Player2Points);
                        winner = Rule.AddResult(pairing.Player2, r);
                        if (winner)
                            WinnerLastRound.Add(pairing.Player2);
                    }
                }
                FirstRound = false;
            }
            else
            {
                for (int i = 0; i < results.Count; i++)
                {
                    if (results[i].ResultEdited)
                    {
                        if (results[i].Winner == "Player 1")
                            winnerID = results[i].Player1.ID;
                        else if (results[i].Winner == "Player 2")
                            winnerID = results[i].Player2.ID;
                        else
                            winnerID = (results[i].Player1Score > results[i].Player2Score) ? results[i].Player1.ID : results[i].Player2.ID;
                        r = new Result(results[i].Player1Score, results[i].Player2Score, results[i].Player2, MaxPoints, winnerID, results[i].Player1Points);
                        Rule.Update(results[i].Player1, r, DisplayedRound);
                        r = new Result(results[i].Player2Score, results[i].Player1Score, results[i].Player1, MaxPoints, winnerID, results[i].Player2Points);
                        Rule.Update(results[i].Player2, r, DisplayedRound);
                    }
                }
            }
            foreach (Player player in Participants)
                player.SumStrengthOfSchedule();
            foreach (Player player in Participants)
                player.SumExtendedStrengthOfSchedule();
            for (int i = 0; i < results.Count; i++)
                results[i].ResultEdited = false;
            if (update)
                Rounds[DisplayedRound - 1].Pairings = results;
            else
                Rounds[Rounds.Count - 1].Pairings = results;
            PrePaired = new List<Pairing>();
			Sort();
        }

        public void ChangePlayer(Player player)
        {
            Participants[GetIndexOf(player)] = (Player)player;
        }

        public Player GetStrongestUnplayedEnemy(Player player)
        {
            for (int i = Participants.Count - 1; i >= 0; i--)
            {
                if (!player.HasPlayedVS(Participants[i]))
                    return Participants[i];
            }
            return null;
        }
        #endregion

        #region private functions
        private int GetIndexOf(Player player)
        {
            for (int i = 0; i < Participants.Count; i++)
            {
                if (Participants[i].Equals(player))
                    return i;
            }
            return -1;
        }

        private int GetIndexOfInRound(Player player, int round)
        {
            for (int i = 0; i < Rounds[round].Participants.Count; i++)
            {
                if (Rounds[round].Participants[i].Equals(player))
                    return i;
            }
            return -1;
        }

        private void CountGroups()
        {
            List<int> v = new List<int>();
            foreach (Player player in ListOfPlayers)
            {
                if (!v.Contains(player.TournamentPoints))
                {
                    v.Add(player.TournamentPoints);
                }
            }
            PointGroup = new List<Player>[v.Count];
            v.OrderBy(x => x);
            for (int i = 0; i < v.Count; i++)
            {
                PointGroup[i] = new List<Player>();
                foreach (Player player in ListOfPlayers)
                {
                    if (v[i] == player.TournamentPoints)
                    {
                        PointGroup[i].Add(player);
                    }
                }
            }
        }

        private bool HasPlayedVsWholePointGroup(Player Player, int groupNr)
        {
            Player enemy;
            for (int i = 0; i < PointGroup[groupNr].Count; i++)
            {
                enemy = PointGroup[groupNr][i];
                if (!Player.HasPlayedVS(enemy) && !Player.Equals(enemy))
                    return false;
            }
            return true;
        }

        private void Start()
        {
            if(!Single)
            {
                Teamplayer = Participants;
                Participants = new List<Player>();
                foreach( var tp in Teamplayer)
                {
                    int a = -1;
                    for(int i = 0; i < Participants.Count; i++)
                    {
                        if(Participants[i].Team == tp.Team)
                        {
                            a = i;
                            break;
                        }
                    }
                    if (a == -1)
                    {
                        Participants.Add(new Player(tp.Team) { Team = tp.Team, Forename = tp.Forename, Faction = tp.Faction });
                    }
                    else
                        Participants[a].Forename += ", " + tp.Forename;
                }
            }
            WonByes = 0;
            foreach (Player p in Participants)
            {
                if (p.WonBye)
                    WonByes++;
            }
        }

        private List<Player> GetWonByes()
        {
            List<Player> result = new List<Player>();
            for (int i = 0; i < ListOfPlayers.Count; i++)
            {
                if (ListOfPlayers[i].WonBye)
                {
                    result.Add(ListOfPlayers[i]);
                    ListOfPlayers.RemoveAt(i);
                    //i--;
                }
            }
            return result;
        }

        private void ChangePairing(int player1Game, int player1Pos, int player2Game, int player2Pos)
        {
            int player1EnemyPos = (player1Pos == 0) ? 1 : 0;
            if (player1Game == player2Game)
                return;
            Player player2;
            if (player2Pos == 0)
            {
                player2 = Pairings[player2Game].Player1;
                if (player1EnemyPos == 0)
                {
                    Pairings[player2Game].Player1 = Pairings[player1Game].Player1;
                    Pairings[player1Game].Player1 = player2;
                }
                else
                {
                    Pairings[player2Game].Player1 = Pairings[player1Game].Player2;
                    Pairings[player1Game].Player2 = player2;
                }
            }
            else
            {
                player2 = Pairings[player2Game].Player2;
                if (player1EnemyPos == 0)
                {
                    Pairings[player2Game].Player2 = Pairings[player1Game].Player1;
                    Pairings[player1Game].Player1 = player2;
                }
                else
                {
                    Pairings[player2Game].Player2 = Pairings[player1Game].Player2;
                    Pairings[player1Game].Player2 = player2;
                }
            }
            Pairings[player1Game].Player1.Bye = false;
            Pairings[player1Game].Player2.Bye = false;
            Pairings[player2Game].Player1.Bye = false;
            Pairings[player2Game].Player2.Bye = false;
            Pairings[player1Game].ResultEdited = false;
            Pairings[player2Game].ResultEdited = false;
            if (Pairings[player1Game].Player1 == Bye)
            {
                Pairings[player1Game].Player2.Bye = true;
                Pairings[player1Game].ResultEdited = true;
            }
            else if (Pairings[player1Game].Player2 == Bye)
            {
                Pairings[player1Game].Player1.Bye = true;
                Pairings[player1Game].ResultEdited = true;
            }
            else if (Pairings[player2Game].Player1 == Bye)
            {
                Pairings[player2Game].Player2.Bye = true;
                Pairings[player2Game].ResultEdited = true;
            }
            else if (Pairings[player2Game].Player2 == Bye)
            {
                Pairings[player2Game].Player1.Bye = true;
                Pairings[player2Game].ResultEdited = true;
            }
        }
        #endregion

        public void RemovePlayer(Player player)
        {
            Participants.Remove(player);
        }

        public void CalculateWonBye()
        {
            if (!WonByeCalculated)
            {
                foreach (var player in (Participants))
                {
                    if (player.WonBye)
                    {
                        player.AddLastEnemy(GetStrongestUnplayedEnemy(player));
                    }
                }
            }
            WonByeCalculated = true;
        }

        public void DisqualifyPlayer(Player player)
        {
            for (int i = 0; i < player.Enemies.Count; i++)
            {
                Player enemy = player.Enemies[i];
                Rule.Update(player, new Result(0, MaxPoints, enemy, MaxPoints, enemy.ID), i + 1);
                Rule.Update(enemy, new Result(MaxPoints, 0, player, MaxPoints, enemy.ID), i + 1);
            }
            for (int i = 0; i < player.Enemies.Count; i++)
            {
                player.Enemies[i].SumStrengthOfSchedule();
                player.Enemies[i].SumExtendedStrengthOfSchedule();
            }
            player.SumStrengthOfSchedule();
            player.SumExtendedStrengthOfSchedule();
            player.Disqualify();
        }

        public void DropPlayer(Player player)
        {
            player.Drop();
        }

        public int GetIndexOfPlayer(Player p)
        {
            for (int i = 0; i < Participants.Count; i++)
            {
                if (Participants[i].ID == p.ID)
                    return i;
            }
            return 0;
        }

        public List<Pairing> GetBonusSeed()
        {
            Pairings = new List<Pairing>();

            foreach(var p in Participants)
            {
                Pairings.Add(new Pairing() { Player1 = p, Player2 = Bonus });
            }

            if (Rounds == null)
                Rounds = new List<Round>();
            Rounds.Add(new Round(Pairings, Participants));
            DisplayedRound = Rounds.Count;
            bonus = true;
            return Pairings;
        }

        public Tournament(SerializationInfo info, StreamingContext context)
        {
            version = (int)info.GetValue("Tournament_Version", typeof(int));
            WonBye = Player.GetWonBye();
            Bye = Player.GetBye();
            Bonus = Player.GetBonus();
            if (version == 0)
            {
                Participants = (List<Player>)info.GetValue("Tournament_Participants", typeof(List<Player>));
                Teamplayer = (List<Player>)info.GetValue("Tournament_Teamplayer", typeof(List<Player>));
                FirstRound = (bool)info.GetValue("Tournament_FirstRound", typeof(bool));
                PrePaired = (List<Pairing>)info.GetValue("Tournament_PrePaired", typeof(List<Pairing>));
                Name = (string)info.GetValue("Tournament_Name", typeof(string));
                Nicknames = (List<string>)info.GetValue("Tournament_Nicknames", typeof(List<string>));
                MaxPoints = (int)info.GetValue("Tournament_MaxPoints", typeof(int));
                Rounds = (List<Round>)info.GetValue("Tournament_Rounds", typeof(List<Round>));
                FilePath = (string)info.GetValue("Tournament_FilePath", typeof(string));
                AutoSavePath = (string)info.GetValue("Tournament_AutoSavePath", typeof(string));
                DisplayedRound = (int)info.GetValue("Tournament_DisplayedRound", typeof(int));
                Cut = (TournamentCut)info.GetValue("Tournament_Cut", typeof(TournamentCut));
                CutStarted = (bool)info.GetValue("Tournament_CutStarted", typeof(bool));
                WonByeCalculated = (bool)info.GetValue("Tournament_WonByeCalculated", typeof(bool));
                Pairings = (List<Pairing>)info.GetValue("Tournament_Pairings", typeof(List<Pairing>));
                TeamProtection = (bool)info.GetValue("Tournament_TeamProtection", typeof(bool));
                Single = (bool)info.GetValue("Tournament_Single", typeof(bool));
                PrintDDGER = (bool)info.GetValue("Tournament_PrintDDGER", typeof(bool));
                PrintDDENG = (bool)info.GetValue("Tournament_PrintDDENG", typeof(bool));
                Rule = (AbstractRules)info.GetValue("Tournament_Rule", typeof(AbstractRules));
                bool ButtonGetResultState = (bool)info.GetValue("Tournament_ButtonGetResultState", typeof(bool));
                bool ButtonNextRoundState = (bool)info.GetValue("Tournament_ButtonNextRoundState", typeof(bool));
                ButtonCutState = (bool)info.GetValue("Tournament_ButtonCutState", typeof(bool));
                T3ID = (int)info.GetValue("Tournament_T3ID", typeof(int));
                GOEPPVersion = (string)info.GetValue("Tournament_GOEPPVersion", typeof(string));
                givenStartNo = (List<int>)info.GetValue("Tournament_givenStartNo", typeof(List<int>));
                ListOfPlayers = (List<Player>)info.GetValue("Tournament_ListOfPlayers", typeof(List<Player>));
                PointGroup = (List<Player>[])info.GetValue("Tournament_PointGroup", typeof(List<Player>[]));
                WonByes = (int)info.GetValue("Tournament_WonByes", typeof(int));
                currentCountOfPlayer = (int)info.GetValue("Tournament_currentCountOfPlayer", typeof(int));
                WinnerLastRound = (List<Player>)info.GetValue("Tournament_WinnerLastRound", typeof(List<Player>));
                bye = (bool)info.GetValue("Tournament_bye", typeof(bool));
                if(ButtonNextRoundState == true)
                {
                    ButtonGetResultsText = "Next Round";
                }
                else if(ButtonGetResultState == true)
                {
                    ButtonGetResultsText = "Get Results";
                }
                else
                {
                    ButtonGetResultsText = "Start Tournament";
                }
                bonus = false;
                version = 2;
            }
            else if (version == 1)
            {
                Participants = (List<Player>)info.GetValue("Tournament_Participants", typeof(List<Player>));
                Teamplayer = (List<Player>)info.GetValue("Tournament_Teamplayer", typeof(List<Player>));
                FirstRound = (bool)info.GetValue("Tournament_FirstRound", typeof(bool));
                PrePaired = (List<Pairing>)info.GetValue("Tournament_PrePaired", typeof(List<Pairing>));
                Name = (string)info.GetValue("Tournament_Name", typeof(string));
                Nicknames = (List<string>)info.GetValue("Tournament_Nicknames", typeof(List<string>));
                MaxPoints = (int)info.GetValue("Tournament_MaxPoints", typeof(int));
                Rounds = (List<Round>)info.GetValue("Tournament_Rounds", typeof(List<Round>));
                FilePath = (string)info.GetValue("Tournament_FilePath", typeof(string));
                AutoSavePath = (string)info.GetValue("Tournament_AutoSavePath", typeof(string));
                DisplayedRound = (int)info.GetValue("Tournament_DisplayedRound", typeof(int));
                Cut = (TournamentCut)info.GetValue("Tournament_Cut", typeof(TournamentCut));
                CutStarted = (bool)info.GetValue("Tournament_CutStarted", typeof(bool));
                WonByeCalculated = (bool)info.GetValue("Tournament_WonByeCalculated", typeof(bool));
                Pairings = (List<Pairing>)info.GetValue("Tournament_Pairings", typeof(List<Pairing>));
                TeamProtection = (bool)info.GetValue("Tournament_TeamProtection", typeof(bool));
                Single = (bool)info.GetValue("Tournament_Single", typeof(bool));
                PrintDDGER = (bool)info.GetValue("Tournament_PrintDDGER", typeof(bool));
                PrintDDENG = (bool)info.GetValue("Tournament_PrintDDENG", typeof(bool));
                Rule = (AbstractRules)info.GetValue("Tournament_Rule", typeof(AbstractRules));
                ButtonGetResultsText = (string)info.GetValue("Tournament_ButtonGetResultsText", typeof(string));
                ButtonCutState = (bool)info.GetValue("Tournament_ButtonCutState", typeof(bool));
                T3ID = (int)info.GetValue("Tournament_T3ID", typeof(int));
                GOEPPVersion = (string)info.GetValue("Tournament_GOEPPVersion", typeof(string));
                givenStartNo = (List<int>)info.GetValue("Tournament_givenStartNo", typeof(List<int>));
                ListOfPlayers = (List<Player>)info.GetValue("Tournament_ListOfPlayers", typeof(List<Player>));
                PointGroup = (List<Player>[])info.GetValue("Tournament_PointGroup", typeof(List<Player>[]));
                WonByes = (int)info.GetValue("Tournament_WonByes", typeof(int));
                currentCountOfPlayer = (int)info.GetValue("Tournament_currentCountOfPlayer", typeof(int));
                WinnerLastRound = (List<Player>)info.GetValue("Tournament_WinnerLastRound", typeof(List<Player>));
                bye = (bool)info.GetValue("Tournament_bye", typeof(bool));
                bonus = false;
                version = 2;
            }
            else if (version == 2)
            {
                Participants = (List<Player>)info.GetValue("Tournament_Participants", typeof(List<Player>));
                Teamplayer = (List<Player>)info.GetValue("Tournament_Teamplayer", typeof(List<Player>));
                FirstRound = (bool)info.GetValue("Tournament_FirstRound", typeof(bool));
                PrePaired = (List<Pairing>)info.GetValue("Tournament_PrePaired", typeof(List<Pairing>));
                Name = (string)info.GetValue("Tournament_Name", typeof(string));
                Nicknames = (List<string>)info.GetValue("Tournament_Nicknames", typeof(List<string>));
                MaxPoints = (int)info.GetValue("Tournament_MaxPoints", typeof(int));
                Rounds = (List<Round>)info.GetValue("Tournament_Rounds", typeof(List<Round>));
                FilePath = (string)info.GetValue("Tournament_FilePath", typeof(string));
                AutoSavePath = (string)info.GetValue("Tournament_AutoSavePath", typeof(string));
                DisplayedRound = (int)info.GetValue("Tournament_DisplayedRound", typeof(int));
                Cut = (TournamentCut)info.GetValue("Tournament_Cut", typeof(TournamentCut));
                CutStarted = (bool)info.GetValue("Tournament_CutStarted", typeof(bool));
                WonByeCalculated = (bool)info.GetValue("Tournament_WonByeCalculated", typeof(bool));
                Pairings = (List<Pairing>)info.GetValue("Tournament_Pairings", typeof(List<Pairing>));
                TeamProtection = (bool)info.GetValue("Tournament_TeamProtection", typeof(bool));
                Single = (bool)info.GetValue("Tournament_Single", typeof(bool));
                PrintDDGER = (bool)info.GetValue("Tournament_PrintDDGER", typeof(bool));
                PrintDDENG = (bool)info.GetValue("Tournament_PrintDDENG", typeof(bool));
                Rule = (AbstractRules)info.GetValue("Tournament_Rule", typeof(AbstractRules));
                ButtonGetResultsText = (string)info.GetValue("Tournament_ButtonGetResultsText", typeof(string));
                ButtonCutState = (bool)info.GetValue("Tournament_ButtonCutState", typeof(bool));
                T3ID = (int)info.GetValue("Tournament_T3ID", typeof(int));
                GOEPPVersion = (string)info.GetValue("Tournament_GOEPPVersion", typeof(string));
                givenStartNo = (List<int>)info.GetValue("Tournament_givenStartNo", typeof(List<int>));
                ListOfPlayers = (List<Player>)info.GetValue("Tournament_ListOfPlayers", typeof(List<Player>));
                PointGroup = (List<Player>[])info.GetValue("Tournament_PointGroup", typeof(List<Player>[]));
                WonByes = (int)info.GetValue("Tournament_WonByes", typeof(int));
                currentCountOfPlayer = (int)info.GetValue("Tournament_currentCountOfPlayer", typeof(int));
                WinnerLastRound = (List<Player>)info.GetValue("Tournament_WinnerLastRound", typeof(List<Player>));
                bye = (bool)info.GetValue("Tournament_bye", typeof(bool));
                bonus = (bool)info.GetValue("Tournament_bonus", typeof(bool));
            }
            Rule = AbstractRules.GetRule(Rule.GetName());
        }

		public void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			info.AddValue("Tournament_Version", version, typeof(int));
			info.AddValue("Tournament_Participants", Participants, typeof(List<Player>));
			info.AddValue("Tournament_Teamplayer", Teamplayer, typeof(List<Player>));
			info.AddValue("Tournament_FirstRound", FirstRound, typeof(bool));
			info.AddValue("Tournament_PrePaired", PrePaired, typeof(List<Pairing>));
			info.AddValue("Tournament_Name", Name, typeof(string));
			info.AddValue("Tournament_Nicknames", Nicknames, typeof(List<string>));
			info.AddValue("Tournament_MaxPoints", MaxPoints, typeof(int));
			info.AddValue("Tournament_Rounds", Rounds, typeof(List<Round>));
			info.AddValue("Tournament_FilePath", FilePath, typeof(string));
			info.AddValue("Tournament_AutoSavePath", AutoSavePath, typeof(string));
			info.AddValue("Tournament_DisplayedRound", DisplayedRound, typeof(int));
			info.AddValue("Tournament_Cut", Cut, typeof(TournamentCut));
			info.AddValue("Tournament_CutStarted", CutStarted, typeof(bool));
			info.AddValue("Tournament_WonByeCalculated", WonByeCalculated, typeof(bool));
			info.AddValue("Tournament_Pairings", Pairings, typeof(List<Pairing>));
			info.AddValue("Tournament_TeamProtection", TeamProtection, typeof(bool));
			info.AddValue("Tournament_Single", Single, typeof(bool));
			info.AddValue("Tournament_PrintDDGER", PrintDDGER, typeof(bool));
			info.AddValue("Tournament_PrintDDENG", PrintDDENG, typeof(bool));
			info.AddValue("Tournament_Rule", Rule, typeof(AbstractRules));
			info.AddValue("Tournament_ButtonGetResultsText", ButtonGetResultsText, typeof(string));
			info.AddValue("Tournament_ButtonCutState", ButtonCutState, typeof(bool));
			info.AddValue("Tournament_T3ID", T3ID, typeof(int));
			info.AddValue("Tournament_GOEPPVersion", GOEPPVersion, typeof(string));
			info.AddValue("Tournament_givenStartNo", givenStartNo, typeof(List<int>));
			info.AddValue("Tournament_ListOfPlayers", ListOfPlayers, typeof(List<Player>));
			info.AddValue("Tournament_PointGroup", PointGroup, typeof(List<Player>[]));
			info.AddValue("Tournament_WonByes", WonByes, typeof(int));
			info.AddValue("Tournament_currentCountOfPlayer", currentCountOfPlayer, typeof(int));
			info.AddValue("Tournament_WinnerLastRound", WinnerLastRound, typeof(List<Player>));
			info.AddValue("Tournament_bye", bye, typeof(bool));
            info.AddValue("Tournament_bonus", bonus, typeof(bool));
        }
    }
}


text:
using StructureMap.Configuration.DSL;
using TryCatchFail.LearnStructureMap.Lesson1.DataProviders;
using TryCatchFail.LearnStructureMap.Lesson1.Utils;

namespace TryCatchFail.LearnStructureMap.Lesson1
{
	public class ProgramRegistry : Registry
	{
		public ProgramRegistry()
		{
			Scan(scan =>
			     	{
			     		scan.TheCallingAssembly();
			     		scan.WithDefaultConventions();
			     		scan.LookForRegistries();
			     	});

			For<IProductDataProvider>().Use<ProductDataProvider>()
				.Decorate().With<ValidPriceDecorator>()
				.AndThen<DescriptionTrimmerDecorator>()
				.AndThen<ArchivingDecorator>();
		}
	}
}

redpajama_set_name: RedPajamaGithub


text:
<agents multiple-routes="true" right-lane-ratio=".6">
   <route id="route0" spawn-probability=".2" HotShot="0" OldLady="0" Normal="1" SUMODefault="0"/>
   <route id="route1" spawn-probability=".15" HotShot="0" OldLady="0" Normal="1" SUMODefault="0"/>

   <route id="all" spawn-probability="0.3" HotShot="0.3" OldLady="0.3" Normal="0.4" SUMODefault="0"/>
</agents>


text:
apt-get update
apt-get install -y nodejs
apt-get install -y npm

npm install pm2 -g


text:
package net.oneandone.incubator.neo.http.sink;

import java.io.File;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.time.Duration;
import java.time.Instant;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType;
import javax.xml.bind.annotation.XmlRootElement;

import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.JerseyClientBuilder;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.io.Files;
import com.unitedinternet.mam.incubator.hammer.http.sink.MamHttpSink;

import net.oneandone.incubator.neo.http.sink.HttpSink;
import net.oneandone.incubator.neo.http.sink.HttpSink.Method;
import net.oneandone.incubator.neotest.WebServer;

public class HttpSinkTest {

    private TestServlet servlet = new TestServlet();
    private WebServer server;

    @Before
    public void setUp() throws Exception {
        server = WebServer.withServlet(servlet)
                          .start();
    }

    @After
    public void tearDown() throws Exception {
        server.close();
    }

    public static final class TestServlet extends HttpServlet {
        private static final long serialVersionUID = -1136798776740561582L;

        private final AtomicInteger errorsToThrow = new AtomicInteger(0);

        public void setErrorsToThrow(int num) {
            errorsToThrow.set(num);
        }

        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            if (req.getParameter("delayMillis") != null) {
                try {
                	long millis = Long.parseLong(req.getParameter("delayMillis"));
                    Thread.sleep(millis);
                } catch (InterruptedException ignore) { }
            }

            if (errorsToThrow.get() > 0) {
                errorsToThrow.decrementAndGet();
                resp.sendError(500);
                return;
            }

            if (req.getParameter("status") != null) {
                int status = Integer.parseInt(req.getParameter("status"));
                resp.setStatus(status);
                return;
            }

            resp.setStatus(200);
        }
    }

    @Test
    public void testWithClient() throws Exception {
        Client client = JerseyClientBuilder.createClient();

        HttpSink sink = HttpSink.target(server.getBasepath() + "rest/topics")
                                .withClient(client)
                                .withRetryAfter(ImmutableList.of(Duration.ofMillis(100), Duration.ofMillis(100)))
                                .open();
        Submission submission = sink.submit(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json");
        Assert.assertEquals(Submission.State.COMPLETED, submission.getState());

        sink.close();
        client.close();
    }

    @Test
    public void testSuccess() throws Exception {
        HttpSink sink = HttpSink.target(server.getBasepath() + "rest/topics")
                                .withRetryAfter(ImmutableList.of(Duration.ofMillis(100), Duration.ofMillis(100)))
                                .open();
        Submission submission = sink.submit(new CustomerChangedEvent(44545453), MediaType.valueOf("application/vnd.example.event.customerdatachanged+json"));
        Assert.assertEquals(Submission.State.COMPLETED, submission.getState());

        Assert.assertTrue(submission.toString().contains("(1 of 3) executed with success "));

        sink.close();
    }

    @Test
    public void testSuccesAsync() throws Exception {
    	ClientConfig configuration = new ClientConfig();
    	configuration.property(ClientProperties.CONNECT_TIMEOUT, 5000);
    	configuration.property(ClientProperties.READ_TIMEOUT, 5000);
        Client client = JerseyClientBuilder.createClient(configuration);

        HttpSink sink = HttpSink.target(server.getBasepath() + "rest/topics?delayMillis=300")
                                .withRetryAfter(ImmutableList.of(Duration.ofMillis(100), Duration.ofMillis(100)))
                                .withClient(client)
                                .open();
        CompletableFuture<Submission> submission = sink.submitAsync(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json");
        Assert.assertFalse(submission.isDone());

        try {
            Thread.sleep(1500);
        } catch (InterruptedException ignore) { }

        Assert.assertTrue(submission.isDone());
        Assert.assertEquals(Submission.State.COMPLETED, submission.get().getState());

        client.close();
        sink.close();
    }

    @Test
    public void testPersistentSuccess() throws Exception {
        HttpSink sink = HttpSink.target(server.getBasepath() + "rest/topics")
                                .withRetryAfter(ImmutableList.of(Duration.ofMillis(100), Duration.ofMillis(110)))
                                .withPersistency(Files.createTempDir())
                                .open();
        Submission submission = sink.submit(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json");
        Assert.assertEquals(Submission.State.COMPLETED, submission.getState());

        Assert.assertFalse(((PersistentSubmission) submission).getSubmissionDir().asFile().exists());
        sink.close();
    }

    @Test
    public void testPersistentDefaultDirSuccess() throws Exception {
        HttpSink sink = HttpSink.target(server.getBasepath() + "rest/topics")
                                .withRetryAfter(ImmutableList.of(Duration.ofMillis(100), Duration.ofMillis(110)))
                                .withPersistency(true)
                                .open();
        Submission submission = sink.submit(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json");
        Assert.assertEquals(Submission.State.COMPLETED, submission.getState());

        Assert.assertFalse(((PersistentSubmission) submission).getSubmissionDir().asFile().exists());
        sink.close();
    }

    @Test
    public void testServerErrorRetriesExceeded() throws Exception {
         HttpSink sink = HttpSink.target(server.getBasepath() + "rest/topics?status=500")
                                 .withRetryAfter(ImmutableList.of(Duration.ofMillis(100), Duration.ofMillis(150)))
                                 .open();
         Submission submission = sink.submit(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json");
         Assert.assertEquals(Submission.State.PENDING, submission.getState());
         Assert.assertEquals(submission, sink.getPendingSubmissions().iterator().next());

         try {
             Thread.sleep(1000);
         } catch (InterruptedException ignore) { }

         Assert.assertEquals(1, sink.getMetrics().getNumDiscarded().getCount());
         Assert.assertEquals(2, sink.getMetrics().getNumRetries().getCount());
         Assert.assertEquals(0, sink.getMetrics().getNumSuccess().getCount());

         sink.close();
    }

    @Test
    public void testPersistentServerErrorRetriesExceeded() throws Exception {
         HttpSink sink = HttpSink.target(server.getBasepath() + "rest/topics?status=500")
                                 .withRetryAfter(ImmutableList.of(Duration.ofMillis(100), Duration.ofMillis(150)))
                                 .withPersistency(Files.createTempDir())
                                 .open();
         Submission submission = sink.submit(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json");
         Assert.assertEquals(Submission.State.PENDING, submission.getState());
         Assert.assertEquals(submission, sink.getPendingSubmissions().iterator().next());

         try {
             Thread.sleep(1000);
         } catch (InterruptedException ignore) { }

         Assert.assertEquals(1, sink.getMetrics().getNumDiscarded().getCount());
         Assert.assertEquals(2, sink.getMetrics().getNumRetries().getCount());
         Assert.assertEquals(0, sink.getMetrics().getNumSuccess().getCount());

         Assert.assertNull(((PersistentSubmission) submission).getSubmissionDir().asFile().listFiles());

         sink.close();

         System.out.println(submission);

         Assert.assertTrue(submission.toString().contains("/rest/topics?status=500 (DISCARDED)"));
         Assert.assertTrue(submission.toString().contains("(3 of 3) failed with HTTP 500"));
         Assert.assertTrue(submission.toString().contains("No retries left. Discarding it"));
    }

    @Test
    public void testRejectingError() throws Exception {
         HttpSink sink = HttpSink.target(server.getBasepath() + "rest/topics?status=400")
                                 .withRetryAfter(ImmutableList.of(Duration.ofMillis(100), Duration.ofMillis(100)))
                                 .open();

         try {
             sink.submit(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json");
             Assert.fail("BadRequestException expected");
         } catch (BadRequestException expected) { }

         Assert.assertEquals(1, sink.getMetrics().getNumDiscarded().getCount());
         Assert.assertEquals(0, sink.getMetrics().getNumRetries().getCount());
         Assert.assertEquals(0, sink.getMetrics().getNumSuccess().getCount());

         sink.close();
    }

    @Test
    public void testServerErrorIncompletedRetries() throws Exception {
         HttpSink sink = HttpSink.target(server.getBasepath() + "rest/topics?status=500")
                                 .withRetryAfter(Duration.ofMillis(100), Duration.ofMillis(110), Duration.ofSeconds(2))
                                 .open();
         Submission submission = sink.submit(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json");
         Assert.assertEquals(Submission.State.PENDING, submission.getState());

         try {
             Thread.sleep(1000);
         } catch (InterruptedException ignore) { }

         Assert.assertEquals(1, sink.getPendingSubmissions().size());
         Assert.assertEquals(2, sink.getMetrics().getNumRetries().getCount());
         Assert.assertEquals(0, sink.getMetrics().getNumSuccess().getCount());
         Assert.assertEquals(0, sink.getMetrics().getNumDiscarded().getCount());

         try {
             Thread.sleep(2000);
         } catch (InterruptedException ignore) { }

         Assert.assertEquals(0, sink.getPendingSubmissions().size());
         Assert.assertEquals(3, sink.getMetrics().getNumRetries().getCount());

         sink.close();
    }

    @Test
    public void testPersistentServerErrorIncompletedRetries() throws Exception {
         HttpSink sink = HttpSink.target(server.getBasepath() + "rest/topics?status=500")
                                 .withRetryAfter(Duration.ofMillis(100), Duration.ofHours(2))
                                 .withPersistency(Files.createTempDir())
                                 .open();
         Submission submission = sink.submit(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json");
         Assert.assertEquals(Submission.State.PENDING, submission.getState());

         try {
             Thread.sleep(1000);
         } catch (InterruptedException ignore) { }

         Assert.assertEquals(1, sink.getPendingSubmissions().size());
         Assert.assertEquals(1, sink.getMetrics().getNumRetries().getCount());
         Assert.assertEquals(0, sink.getMetrics().getNumSuccess().getCount());
         Assert.assertEquals(0, sink.getMetrics().getNumDiscarded().getCount());

         sink.close();

         File[] files = ((PersistentSubmission) submission).getSubmissionDir().asFile().listFiles();
         List<File> fileList = Lists.newArrayList(files);
         Collections.sort(fileList);

         Assert.assertEquals(3, fileList.size());

         Properties props = new Properties();
         props.load(new FileInputStream(fileList.get(2)));
         Assert.assertEquals(2, Splitter.on('&').splitToList(props.getProperty("lastTrials")).size());
    }

    @Test
    public void testServerErrorRetryWithSuccess() throws Exception {
        servlet.setErrorsToThrow(2);

        HttpSink sink = HttpSink.target(server.getBasepath() + "rest/topics")
                                .withRetryAfter(ImmutableList.of(Duration.ofMillis(100), Duration.ofMillis(110)))
                                .open();
        Submission submission = sink.submit(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json");
        Assert.assertEquals(Submission.State.PENDING, submission.getState());

        try {
            Thread.sleep(1000);
        } catch (InterruptedException ignore) { }

        Assert.assertEquals(0, sink.getMetrics().getNumDiscarded().getCount());
        Assert.assertEquals(2, sink.getMetrics().getNumRetries().getCount());
        Assert.assertEquals(1, sink.getMetrics().getNumSuccess().getCount());

        sink.close();
    }

    @Test
    public void testPersistentServerErrorRetryWithSuccess() throws Exception {
        servlet.setErrorsToThrow(2);

        HttpSink sink = HttpSink.target(server.getBasepath() + "rest/topics")
                                .withRetryAfter(ImmutableList.of(Duration.ofMillis(100), Duration.ofMillis(110)))
                                .withPersistency(Files.createTempDir())
                                .open();
        Submission submission = sink.submit(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json");
        Assert.assertEquals(Submission.State.PENDING, submission.getState());

        try {
            Thread.sleep(1000);
        } catch (InterruptedException ignore) { }

        Assert.assertEquals(0, sink.getMetrics().getNumDiscarded().getCount());
        Assert.assertEquals(2, sink.getMetrics().getNumRetries().getCount());
        Assert.assertEquals(1, sink.getMetrics().getNumSuccess().getCount());

        Assert.assertFalse(((PersistentSubmission) submission).getSubmissionDir().asFile().exists());
        sink.close();
    }

    @Test
    public void testPersistentServerErrorRetryWithClose() throws Exception {
        servlet.setErrorsToThrow(2);

        HttpSink sink = HttpSink.target(server.getBasepath() + "rest/topics")
                                .withRetryAfter(ImmutableList.of(Duration.ofMillis(100), Duration.ofHours(2)))
                                .withPersistency(Files.createTempDir())
                                .open();
        Submission submission = sink.submit(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json");
        Assert.assertEquals(Submission.State.PENDING, submission.getState());

        try {
            Thread.sleep(1000);
        } catch (InterruptedException ignore) { }

        Assert.assertEquals(0, sink.getMetrics().getNumDiscarded().getCount());
        Assert.assertEquals(1, sink.getMetrics().getNumRetries().getCount());
        Assert.assertEquals(0, sink.getMetrics().getNumSuccess().getCount());

        ImmutableSet<Submission> submissions = sink.getPendingSubmissions();
        Assert.assertEquals(1, submissions.size());

        sink.close();

        File[] files = ((PersistentSubmission) submissions.iterator().next()).getSubmissionDir().asFile().listFiles();
        List<File> fileList = Lists.newArrayList(files);
        Collections.sort(fileList);

        Properties props = new Properties();
        props.load(new FileInputStream(fileList.get(2)));
        Assert.assertEquals(2, Splitter.on('&').splitToList(props.getProperty("lastTrials")).size());
    }

    @Test
    public void testServerErrorPersistentRetryWithSuccess() throws Exception {
        servlet.setErrorsToThrow(2);

        HttpSink sink = HttpSink.target(server.getBasepath() + "rest/topics")
                                .withRetryAfter(ImmutableList.of(Duration.ofMillis(100), Duration.ofMillis(100), Duration.ofMillis(100)))
                                .withPersistency(Files.createTempDir())
                                .open();
        Submission submission = sink.submit(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json");
        Assert.assertEquals(Submission.State.PENDING, submission.getState());

        try {
            Thread.sleep(1000);
        } catch (InterruptedException ignore) { }

        Assert.assertEquals(Submission.State.COMPLETED, submission.getState());
        Assert.assertEquals(0, sink.getMetrics().getNumDiscarded().getCount());
        Assert.assertEquals(2, sink.getMetrics().getNumRetries().getCount());
        Assert.assertEquals(1, sink.getMetrics().getNumSuccess().getCount());

        sink.close();
    }

    @Test
    public void testClientError() throws IOException {
        HttpSink sink = HttpSink.target(server.getBasepath() + "rest/topics?status=400")
                                .withRetryAfter(ImmutableList.of(Duration.ofMillis(100), Duration.ofMillis(100)))
                                .open();

        try {
            sink.accept(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json");
            Assert.fail("BadRequestException expected");

        } catch (BadRequestException expected) {

    	} catch (RuntimeException rt) {
    		System.out.println("RT: " + rt);
    		throw rt;
    	}

        sink.close();
    }

    @Test
    public void testMaxBufferSizeExceeded() throws IOException {
        int maxsize = 2;

        HttpSink sink = HttpSink.target(server.getBasepath() + "rest/topics?status=500")
                                .withRetryAfter(ImmutableList.of(Duration.ofHours(2)))
                                .withRetryBufferSize(maxsize)
                                .open();

        for (int i = 0; i < maxsize; i++)
        try {
            sink.accept(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json");
        } catch (BadRequestException expected) { }

        try {
            Thread.sleep(1000);
        } catch (InterruptedException ignore) { }

        Assert.assertEquals(2, sink.getPendingSubmissions().size());

        try {
            sink.accept(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json");
            Assert.fail("IllegalStateException exepcted");
        } catch (IllegalStateException exepected) { }

        sink.close();
    }

    @Test
    public void testReschedulePersistentQueryWithDiscardResult() throws Exception {
        URI target = URI.create("http://localhost:1/rest/topics");

        // create query file to simluate former crash
        PersistentSubmission sub = newPersistentSubmission(Files.createTempDir(),
        												   target,
        												   Entity.entity(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json"),
        												   ImmutableList.of(Duration.ofMillis(100)),
        												   Instant.now().minus(Duration.ofMinutes(5)));
        Assert.assertEquals(1, sub.getSubmissionDir().asFile().listFiles().length);

        HttpSink sink = HttpSink.target(target)
                                .withRetryAfter(ImmutableList.of(Duration.ofMillis(100), Duration.ofMillis(100)))
                                .withPersistency(sub.getSubmissionDir().asFile().getParentFile().getParentFile())
                                .open();

        try {
            Thread.sleep(3000);
        } catch (InterruptedException ignore) { }

        Assert.assertEquals(1, sink.getMetrics().getNumDiscarded().getCount());
        Assert.assertEquals(1, sink.getMetrics().getNumRetries().getCount());
        Assert.assertEquals(0, sink.getMetrics().getNumSuccess().getCount());

        sink.close();

        Assert.assertNull(sub.getSubmissionDir().asFile().listFiles());
    }

    @Test
    public void testReschedulePersistentQueryWithStillRetryResult() throws Exception {
        URI target = URI.create(server.getBasepath() + "rest/topics?status=500");

        // create query file to simulate former crash
        PersistentSubmission sub = newPersistentSubmission(Files.createTempDir(),
        											       target,
        											       Entity.entity(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json"),
        											       ImmutableList.of(Duration.ofMillis(100), Duration.ofHours(10)),
        											       Instant.now().minus(Duration.ofMinutes(5)));

        Properties props = new Properties();
        props.load(new FileInputStream(sub.getSubmissionDir().asFile().listFiles()[0]));
        Assert.assertEquals("100&36000000", props.getProperty("retries"));
        Assert.assertEquals("", props.getProperty("lastTrials"));

        HttpSink sink = HttpSink.target(target)
                                .withRetryAfter(ImmutableList.of(Duration.ofMillis(100), Duration.ofMillis(100)))
                                .withPersistency(sub.getSubmissionDir().asFile().getParentFile().getParentFile())
                                .open();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException ignore) { }

        Assert.assertEquals(0, sink.getMetrics().getNumDiscarded().getCount());
        Assert.assertEquals(1, sink.getMetrics().getNumRetries().getCount());
        Assert.assertEquals(0, sink.getMetrics().getNumSuccess().getCount());

        ImmutableSet<Submission> submissions = sink.getPendingSubmissions();
        Assert.assertEquals(1, submissions.size());
        sink.close();

        File[] files = ((PersistentSubmission) submissions.iterator().next()).getSubmissionDir().asFile().listFiles();
        List<File> fileList = Lists.newArrayList(files);
        Collections.sort(fileList);

        Assert.assertEquals(3, fileList.size());
        Properties props1 = new Properties();
        props1.load(new FileInputStream(fileList.get(1)));
        Assert.assertEquals("", props1.getProperty("lastTrials"));

        Properties props2 = new Properties();
        props2.load(new FileInputStream(fileList.get(2)));
        Assert.assertEquals(1, Splitter.on('&').splitToList(props2.getProperty("lastTrials")).size());
    }

    @Test
    public void testReschedulePersistentConcurrentAccess() throws Exception {

        URI target = URI.create(server.getBasepath() + "rest/topics?status=500");

        // create query file to simulate former crash
        PersistentSubmission sub = newPersistentSubmission(Files.createTempDir(),
        												   target,
        												   Entity.entity(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json"),
        												   ImmutableList.of(Duration.ofMillis(100), Duration.ofHours(10)),
        												   Instant.now().minus(Duration.ofMinutes(5)));

        Assert.assertEquals(1, sub.getSubmissionDir().asFile().listFiles().length);
        String content = Joiner.on("\n").join(Files.readLines(sub.getSubmissionDir().asFile().listFiles()[0], Charsets.UTF_8));
        Assert.assertTrue(content.contains("retries=100&36000000"));

        // open the sink (former query should be processed and failed again -> uri is bad)
        HttpSink sink = HttpSink.target(target)
                                .withRetryAfter(ImmutableList.of(Duration.ofMillis(100), Duration.ofMillis(100)))
                                .withPersistency(sub.getSubmissionDir().asFile().getParentFile().getParentFile())
                                .open();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException ignore) { }

        Assert.assertEquals(1, sink.getPendingSubmissions().size());
        Assert.assertEquals(0, sink.getMetrics().getNumDiscarded().getCount());
        Assert.assertEquals(1, sink.getMetrics().getNumRetries().getCount());
        Assert.assertEquals(0, sink.getMetrics().getNumSuccess().getCount());

        // start a second, concurrent sink
        HttpSink sink2 = HttpSink.target(target)
                                 .withRetryAfter(ImmutableList.of(Duration.ofMillis(100), Duration.ofMillis(100)))
                                 .withPersistency(sub.getSubmissionDir().asFile().getParentFile().getParentFile())
                                 .open();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException ignore) { }

        // the crashed query will not be visible for the second sink -> locked by the other one
        Assert.assertEquals(0, sink2.getPendingSubmissions().size());
        Assert.assertEquals(0, sink2.getMetrics().getNumDiscarded().getCount());
        Assert.assertEquals(0, sink2.getMetrics().getNumRetries().getCount());
        Assert.assertEquals(0, sink2.getMetrics().getNumSuccess().getCount());

        Assert.assertEquals(1, sink.getPendingSubmissions().size());
        Assert.assertEquals(0, sink.getMetrics().getNumDiscarded().getCount());
        Assert.assertEquals(1, sink.getMetrics().getNumRetries().getCount());
        Assert.assertEquals(0, sink.getMetrics().getNumSuccess().getCount());

        ImmutableSet<Submission> submissions = sink.getPendingSubmissions();
        Assert.assertEquals(1, submissions.size());

        sink.close();

        File[] files = ((PersistentSubmission) submissions.iterator().next()).getSubmissionDir().asFile().listFiles();
        List<File> fileList = Lists.newArrayList(files);
        Collections.sort(fileList);

        Assert.assertEquals(3, fileList.size());

        Properties props = new Properties();
        props.load(new FileInputStream(fileList.get(1)));
        Assert.assertEquals("", props.getProperty("lastTrials"));

        Properties props2 = new Properties();
        props2.load(new FileInputStream(fileList.get(2)));
        Assert.assertEquals(1, Splitter.on('&').splitToList(props2.getProperty("lastTrials")).size());

        sink2.close();
    }

    @Test
    public void testReschedulePersistentQueryWithSuccessResult() throws Exception {

        URI target = URI.create(server.getBasepath() + "rest/topics");

        // create a query file to
        PersistentSubmission sub = newPersistentSubmission(Files.createTempDir(),
        												   target,
        												   Entity.entity(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json"),
        												   ImmutableList.of(Duration.ofMillis(100)),
        												   Instant.now().minus(Duration.ofMinutes(5)));
        Assert.assertEquals(1, sub.getSubmissionDir().asFile().listFiles().length);

        HttpSink sink = HttpSink.target(target)
                                .withRetryAfter(ImmutableList.of(Duration.ofMillis(100), Duration.ofMillis(100)))
                                .withPersistency(sub.getSubmissionDir().asFile().getParentFile().getParentFile())
                                .open();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException ignore) { }

        Assert.assertEquals(0, sink.getMetrics().getNumDiscarded().getCount());
        Assert.assertEquals(1, sink.getMetrics().getNumRetries().getCount());
        Assert.assertEquals(1, sink.getMetrics().getNumSuccess().getCount());

        sink.close();

        Assert.assertEquals(0, ((HttpSinkBuilderImpl.PersistentHttpSink) sink).getSubmissionStoreDir().listFiles().length);
    }

    @Test
    public void testExtendedHttpSink() throws Exception {

        HttpSink sink = MamHttpSink.target(server.getBasepath() + "rest/topics")
                                   .withRetryAfter(ImmutableList.of(Duration.ofMillis(100), Duration.ofMillis(100)))
                                   .open();
        Submission submission = sink.submit(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json");
        Assert.assertEquals(Submission.State.COMPLETED, submission.getState());

        sink.close();
    }

    @Test
    public void testReschedulePersistentPendingQueryWithSuccessResult() throws Exception {

        URI target = URI.create(server.getBasepath() + "rest/topics");

        // create a query file to
        PersistentSubmission sub = newPersistentSubmission(Files.createTempDir(),
        												   target,
        												   Entity.entity(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json"),
        												   ImmutableList.of(Duration.ofMinutes(0), Duration.ofMinutes(20), Duration.ofSeconds(91)),
        												   Instant.now().minus(Duration.ofMinutes(5)),
        												   2,
        												   Instant.now().minus(Duration.ofSeconds(90)));
        Assert.assertEquals(1, sub.getSubmissionDir().asFile().listFiles().length);

        HttpSink sink = HttpSink.target(target)
                                .withRetryAfter(ImmutableList.of(Duration.ofMillis(100), Duration.ofMillis(100)))
                                .withPersistency(sub.getSubmissionDir().asFile().getParentFile().getParentFile())
                                .open();

        try {
            Thread.sleep(2000);
        } catch (InterruptedException ignore) { }

        Assert.assertEquals(0, sink.getMetrics().getNumDiscarded().getCount());
        Assert.assertEquals(1, sink.getMetrics().getNumRetries().getCount());
        Assert.assertEquals(1, sink.getMetrics().getNumSuccess().getCount());

        sink.close();

        Assert.assertNull(sub.getSubmissionDir().asFile().listFiles());
    }

    @Test
    public void testPersistentParallelitySuccess() throws Exception {
    	HttpSink sink = HttpSink.target(server.getBasepath() + "rest/topics?delayMillis=1500")
                                .withRetryAfter(ImmutableList.of(Duration.ofMillis(100), Duration.ofMillis(110)))
                                .withPersistency(Files.createTempDir())
                                .withRetryBufferSize(20000)
                                .open();

        int num = 10;
        for (int i = 0; i < num; i++) {
        	sink.submitAsync(new CustomerChangedEvent(44545453), "application/vnd.example.event.customerdatachanged+json");
        }

        try {
        	Thread.sleep(2000);
        } catch (InterruptedException ignore) { }

        Assert.assertEquals(num, sink.getMetrics().getNumSuccess().getCount());
        Assert.assertEquals(0, sink.getMetrics().getNumDiscarded().getCount());
        Assert.assertEquals(0, sink.getMetrics().getNumRetries().getCount());

        sink.close();
    }

    @Test
    public void testExample() throws Exception {
    	MyExampleService exampleService = new MyExampleService(URI.create(server.getBasepath() + "rest/topics"));
    	exampleService.myBusinessMethod();

    	try {
    		Thread.sleep(1000);
    	} catch (InterruptedException ignore) { }

    	exampleService.close();
    }

    @XmlRootElement
    public static class CustomerChangedEvent {
        public Header header = new Header();
        public int accountid;

        public CustomerChangedEvent() { }

        public CustomerChangedEvent(int accountid) {
            this.accountid = accountid;
        }
    }

    public static class Header {
        public String eventId = UUID.randomUUID().toString().replace("-", "");
        public String timestamp = Instant.now().toString();
        public AuthenticationInfo authInfo;

        public Header() {  }

        public Header(String eventId, String timestamp, AuthenticationInfo authInfo) {
            this.eventId = eventId;
            this.timestamp = timestamp;
            this.authInfo = authInfo;
        }

        public Header withAuthInfo(AuthenticationInfo.AuthenticationScheme scheme, String principalname) {
            return new Header(eventId, timestamp, new AuthenticationInfo(scheme, principalname));
        }
    }

    public static final class AuthenticationInfo  {
        public static enum AuthenticationScheme { BASIC, CLIENTCERT, DIGEST, PLAIN, FORM, OAUTHBEARER };

        public AuthenticationInfo() {  }

        public AuthenticationInfo(AuthenticationScheme scheme, String principalname) {
            this.principalname = principalname;
            this.scheme = scheme;
        }

        public String principalname;
        public AuthenticationScheme scheme;
    }

    private static PersistentSubmission newPersistentSubmission(File dir, URI uri, Entity<?> entity, ImmutableList<Duration> delays, Instant lastModified) {
        return newPersistentSubmission(dir, uri, entity, delays, lastModified, 0, Instant.now());
    }

    private static PersistentSubmission newPersistentSubmission(File dir, URI uri, Entity<?> entity, ImmutableList<Duration> delays, Instant lastModified, int trials, Instant dateLastTrial) {
        	SubmissionMonitor monitor = new SubmissionMonitor();
        	PersistentSubmission.SubmissionsStore submissionsDir = new PersistentSubmission.SubmissionsStore(dir, uri, Method.POST);
            PersistentSubmission persistentSubmission = new PersistentSubmission(monitor, UUID.randomUUID().toString(), uri, Method.POST, entity, ImmutableSet.of(404), delays, submissionsDir);
            persistentSubmission.release();

            persistentSubmission.getSubmissionDir().close();

            try {
            	Thread.sleep(1000);
            } catch (InterruptedException ignore) { }

            File submissionFile = persistentSubmission.getSubmissionDir().asFile().listFiles()[0];
            submissionFile.setLastModified(lastModified.toEpochMilli());

            return persistentSubmission;
    }
}


text:
PyCon 2016
==========

.. image:: https://readthedocs.org/projects/pycon-notes-2016/badge/?version=latest
  :target: http://pycon-notes-2016.readthedocs.io/en/latest/?badge=latest
  :alt: Documentation Status


text:
<!doctype html>

    <meta charset="utf-8" />
    <title>Classic Slides with impress.js | Simple example impress.js slide show | by Henrik Ingo @henrikingo</title>

    <meta name="description" content="Simple example impress.js slide show" />
    <meta name="author" content="Henrik Ingo" />

    <link rel="stylesheet" href="../../extras/highlight/styles/github.css">
    <link rel="stylesheet" href="../../extras/mermaid/mermaid.forest.css">

    <link href="..\..\css\impress-common.css" rel="stylesheet" />

    <link href="css/classic-slides.css" rel="stylesheet" />

Your browser doesn't support the features required by impress.js, so you are presented with a simplified version of this presentation.

For the best experience please use the latest Chrome, Safari or Firefox browser.

Example Presentation:

            Classic Slides

Henrik Ingo

2015

        Any element with the class="notes" will not be displayed. This can
        be used for speaker notes. In fact, the impressConsole plugin will
        show it in the speaker console!

Table of Contents

A title slide

Table of Contents

Text slide

Bullet points

Blockquote & image

More basic text styles

Motion effects 101

Add-ons

More info

Table of Contents, with links to other slides of this same presentation.

Note that instead of absolute positioning we use relative positioning,
           with the data-rel-x and data-rel-y attributes. This means the step is
           positioned relative to the foregoing step. In other words, this is
           equivalent to data-x="0" data-y="-3000".

A slide with text

This slide has a few paragraphs
(p element) of normal text.

Personally I like centered or even justified text, as it looks less boring. This can of course be set in the css file.

I really like the style on links in these presentations. I modified the border to be beveled, but it's mostly from @bartaz' original demo. @bartaz is the creator of impress.js.

         In this slide, we don't even specify the relative position, rather
         that too is inherited. So this slide will again be 1000px to the
         right of the previous one.

Bullet points

A slide with bullet points. This is the first point.

Second point

Third point. Under this point we also have some sub-bullets:

Sub-bullet 1

Sub-bullet 2

A blockquote & image

        Spread love everywhere you go.
Let no one ever come to you without leaving happier.

Mother Teresa

Image credit: Peta_de_Aztlan@Flickr. CC-BY 2.0

            We use data-rel-position="relative" to make data-rel-rotate-* work,
            and make data-rel-x/data-rel-y/data-rel-y be calculated at the coordination related to previous slide.
            The relative position and rotation will be inherited by following slides,
            so it's not necessary to repeat it again and again.

More text styles

As usual, use em to emphasize,

           strong for strong, u for underline,

           strike for strikethrough and <q>q for inline quotations</q>.

If you're a software engineer like me, you will often use the
           <code> tag for monospaced inline text.

Motion effects 101

Items on the slide can

Fly in

Fade in

And zoom in

...just like in PowerPoint. Yeah, I know I'm being lame, but it was fun to learn to do this in CSS3.

This step here doesn't introduce anything new when it comes to data attributes, but you
        should notice in the demo that some words of this text are being animated.
        It's a very basic CSS transition that is applied to the elements when this step element is
        reached.

        At the very beginning of the presentation all step elements are given the class of `future`.
        It means that they haven't been visited yet.

        When the presentation moves to given step `future` is changed to `present` class name.
        That's how animation on this step works - text moves when the step has `present` class.

        Finally when the step is left the `present` class is removed from the element and `past`
        class is added.

        So basically every step element has one of three classes: `future`, `present` and `past`.
        Only one current step has the `present` class.

This step zoom in to left bottom of previous slide to see to small text.

It's a empty and transparent.

data-rel-reset is used to prevent this step from inheriting the relative positioning from previous slide.

Add-ons

This version of impress.js includes several add-ons, striving to make this a
           full featured presentation app.

The previous step breaks the slide flow, changes the relative position and rotation.

This slide use data-rel-to to inherit relative position and rotation from the slide before previous slide.

Impress.js plugins

A new plugin framework allows for rich extensibility,
            without bloating the core rendering library.

Press 'P' to open a presenter console.

When you move the mouse, navigation controls are visible on your bottom right

Autoplay makes the slides advance after a timeout

Relative positioning plugin is often a more convenient way to position your slides when editing. (See html for this presentation.)

This presentation also uses speaker notes. They are not visible in the presentation, but shown in the impress console.

If you pressed P only now, this is the first time you see these notes. In fact, there has been notes on preceding slides as well.
           You can use the navigation controls at the bottom of the impress console to browse back to them.

And did you notice how those bullet points appear one by one as you press space/arrow? That's another plugin, called substeps.

Highlight.js

        // `init` API function that initializes (and runs) the presentation.
        var init = function () {
            if (initialized) { return; }
            execPreInitPlugins();

            // First we set up the viewport for mobile devices.
            // For some reason iPad goes nuts when it is not done properly.
            var meta = $("meta[name='viewport']") || document.createElement("meta");
            meta.content = "width=device-width, minimum-scale=1, maximum-scale=1, user-scalable=no";
            if (meta.parentNode !== document.head) {
                meta.name = 'viewport';
                document.head.appendChild(meta);
            }

The Highlight.js library provides really nice color coding of source code.
           It automatically applies to any code inside a <pre><code> element.

Highlight.js is found under the extras/
           directory, since it is an independent third party plugin, not really an impress.js plugin. You have
           to include it via it's own <link> and <script> tags.

Mermaid.js

        %% This is a comment in mermaid markup
        graph LR
          A(Support for
diagrams)
          B[Provided by
mermaid.js]
          C{Already
know
mermaid?}
          D(Tutorial)
          E(Great, hope you enjoy!)
          A-->B
          B-->C
          C--No-->D
          C--Yes-->E
          classDef startEnd fill:#fcc,stroke:#353,stroke-width:2px;
          class A,D,E startEnd;

MathJax.js

Use \(\LaTeX\), MathML or AsciiMath to properly show mathematical formula.

          Mermaid.js, likewise in a href="https://github.com/impress/impress.js/tree/master/extras">extras/
           directory, draws SVG diagrams from a MarkDown-like syntax. To learn
          more about it read the fine manual.

# Markdown.js

* [Markdown.js](https://github.com/evilstreak/markdown-js) integration: for authors in a hurry!
  * ...or lazy ;-)
* Jot down bullet points in *Markdown*
  * ...have it automatically converted to HTML
  * Markdown is converted into a presentation client side, in the browser. This is unlike
   existing tools like [Hovercraft](https://github.com/regebro/hovercraft) and
   markdown-impress where you generate a new
   html file on the command line.
* [A more advanced Markdown presentation is here.](../markdown/)

Remember, in impress.js the full power of HTML5, CSS3 & JavaScript is always at your fingertips!

For example, you can use tables, forms, or dynamic charts as you would on any web page:

Acme Inc Quarterly Profits

Q1	234€

Q2	255€

Q3	<input id="acme-q3" size="5" oninput="acmeDrawGraph();" />€ (insert here)

Q4	<input id="acme-q4" size="5" oninput="acmeDrawGraph();" />€

More info

DOCUMENTATION.md is the API reference.

Source of this presentation itself is commented

Advanced Impress.js demo by @bartaz

Again, the html
                and css source is well commented.

More examples and demos:

examples/ in this repository

on the impress.js wiki

Check out Impressionist: a 3D GUI to create impress.js presentations


text:
package org.acplt.oncrpc;

import java.io.IOException;

/**
 * The OncRpcGetPortResult class represents the result from
 * a PMAP_GETPORT remote procedure call to the ONC/RPC portmapper.
 *
 * @version $Revision: 1.1.1.1 $ $Date: 2003/08/13 12:03:41 $ $State: Exp $ $Locker:  $
 * @author Harald Albrecht
 */
public class OncRpcGetPortResult implements XdrAble {

    /**
     * The port number of the ONC/RPC in question. This is the only interesting
     * piece of information in this class. Go live with it, you don't have
     * alternatives.
     */
    public int port;

    /**
     * Default constructor for initializing an OncRpcGetPortParams
     * result object. It sets the port member to a useless value.
     */
    public OncRpcGetPortResult() {
        port = 0;
    }

    /**
     * Encodes -- that is: serializes -- an OncRpcGetPortParams
     * object into a XDR stream.
     *
     * @throws OncRpcException if an ONC/RPC error occurs.
     * @throws IOException if an I/O error occurs.
     */
    public void xdrEncode(XdrEncodingStream xdr)
           throws OncRpcException, IOException {
        xdr.xdrEncodeInt(port);
    }

    /**
     * Decodes -- that is: deserializes -- an OncRpcGetPortParams
     * object from a XDR stream.
     *
     * @throws OncRpcException if an ONC/RPC error occurs.
     * @throws IOException if an I/O error occurs.
     */
    public void xdrDecode(XdrDecodingStream xdr)
           throws OncRpcException, IOException {
        port = xdr.xdrDecodeInt();
    }

}

// End of OncRpcGetPortResult.java


text:
import loginPage from '../../pageobjects/login.page';
import mainContent from '../../pageobjects/main-content.page';
import { username, email, password } from '../../data/user.js';

// Basic usage test start
describe('[User Creation]', function() {
	this.retries(2);

	before(() => {
		loginPage.open();
		// This Can Cause Timeouts erros if the server is slow so it should have a big wait
		loginPage.emailOrUsernameField.waitForVisible(15000);
	});

	it('it should create user', () => {
		loginPage.gotToRegister();

		loginPage.registerNewUser({ username, email, password });

		loginPage.inputUsername.waitForExist(5000);

		loginPage.submitButton.click();

		mainContent.mainContent.waitForExist(5000);
	});
});