/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.products.ov.validation.commons.writeins;

import static com.scytl.products.ov.commons.util.MathUtils.isqrt;
import static org.junit.Assert.assertEquals;


import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

public class WriteinEncoderTest {

    private static BigInteger p_50_bits;

    private static BigInteger q_50_bits;

    private static BigInteger p_1024_bits;

    private static BigInteger q_1024_bits;

    private static BigInteger p_2048_bits;

    private static BigInteger q_2048_bits;

    private static BigInteger p_3072_bits;

    private static BigInteger q_3072_bits;

    private static WriteinEncoder _target;

    @Rule
    public ExpectedException expectedEx = ExpectedException.none();

    @BeforeClass
    public static void setUp() {

        p_50_bits = new BigInteger("632675155738559");
        q_50_bits = new BigInteger("316337577869279");

        p_1024_bits = new BigInteger(
            "127221604274531153456037811894129045050707427287018126451033610258225414570293456088114804760360499690320725081015613357713860609352611107211595355579330171109403165025745399040683371804753828679517508339451541325761038070090645847220458502400371988111691904960115084260054586776319747845360881674068179759939");
        q_1024_bits = new BigInteger(
            "63610802137265576728018905947064522525353713643509063225516805129112707285146728044057402380180249845160362540507806678856930304676305553605797677789665085554701582512872699520341685902376914339758754169725770662880519035045322923610229251200185994055845952480057542130027293388159873922680440837034089879969");

        p_2048_bits = new BigInteger(
            "16370518994319586760319791526293535327576438646782139419846004180837103527129035954742043590609421369665944746587885814920851694546456891767644945459124422553763416586515339978014154452159687109161090635367600349264934924141746082060353483306855352192358732451955232000593777554431798981574529854314651092086488426390776811367125009551346089319315111509277347117467107914073639456805159094562593954195960531136052208019343392906816001017488051366518122404819967204601427304267380238263913892658950281593755894747339126531018026798982785331079065126375455293409065540731646939808640273393855256230820509217411510058759");
        q_2048_bits = new BigInteger(
            "8185259497159793380159895763146767663788219323391069709923002090418551763564517977371021795304710684832972373293942907460425847273228445883822472729562211276881708293257669989007077226079843554580545317683800174632467462070873041030176741653427676096179366225977616000296888777215899490787264927157325546043244213195388405683562504775673044659657555754638673558733553957036819728402579547281296977097980265568026104009671696453408000508744025683259061202409983602300713652133690119131956946329475140796877947373669563265509013399491392665539532563187727646704532770365823469904320136696927628115410254608705755029379");

        p_3072_bits = new BigInteger(
            "3878981618363851403422785607049427732736469525765273964840494068543041817727859944747888587785804791336126334735655317568383325026575396502302408923900497193860574810106417647833293156361473237473851593342226591737416569274097190298794282094798839851447612748747028941226550444236500328284988232883708279903371633902500527667563618336033732682721663174483318675000290047145413356364086211940765433079496799025339463611957630842302927071374023550249041067140503160804595502533730751141852343308661226499943816174201254213525974778805126213286835381698767182787838530784771675962353210590958127004175441983883147456311021868868237863493150560311147255716532038537882133905836196893266079070881906364328006937745533954805623786263044779903135192824449840823134335864515601600386396870002243889016433896192256236768999995365293442167853292116446399454096548352527896137561043092342974345122064784985329026450531982131124347170447");
        q_3072_bits = new BigInteger(
            "1939490809181925701711392803524713866368234762882636982420247034271520908863929972373944293892902395668063167367827658784191662513287698251151204461950248596930287405053208823916646578180736618736925796671113295868708284637048595149397141047399419925723806374373514470613275222118250164142494116441854139951685816951250263833781809168016866341360831587241659337500145023572706678182043105970382716539748399512669731805978815421151463535687011775124520533570251580402297751266865375570926171654330613249971908087100627106762987389402563106643417690849383591393919265392385837981176605295479063502087720991941573728155510934434118931746575280155573627858266019268941066952918098446633039535440953182164003468872766977402811893131522389951567596412224920411567167932257800800193198435001121944508216948096128118384499997682646721083926646058223199727048274176263948068780521546171487172561032392492664513225265991065562173585223");

        String alphabet =
            "IyAnKCksLS4vMDEyMzQ1Njc4OUFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXrCoMKixaDFocW9xb7FksWTxbjDgMOBw4LDg8OEw4XDhsOHw4jDicOKw4vDjMONw47Dj8OQw5HDksOTw5TDlcOWw5jDmcOaw5vDnMOdw57Dn8Ogw6HDosOjw6TDpcOmw6fDqMOpw6rDq8Osw63DrsOvw7DDscOyw7PDtMO1w7bDuMO5w7rDu8O8w73DvsO/";
        _target = new WriteinEncoder(alphabet);
    }

    @Test
    public void whenEncodeAndDecodeEmptyStringsAndEmptyRepsThenExpectedSizeOfEncoding() {

        List<String> initialStrings = new ArrayList<String>();
        List<String> usableRepresentationsEncode = new ArrayList<String>();

        int numDesiredElementsInEncoding = 10;

        List<BigInteger> encoded = _target.encode(initialStrings, p_2048_bits, q_2048_bits,
            numDesiredElementsInEncoding, usableRepresentationsEncode);

        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = new ArrayList<String>();
        List<String> decoded = _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);
        assertEquals(initialStrings, decoded);
    }

    @Test
    public void whenEncodeAndDecodeSingleCharacterThenOk() {

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add("2#a");

        List<String> usableRepresentationsEncode = Arrays.asList("2");
        int numDesiredElementsInEncoding = 10;

        List<BigInteger> encoded = _target.encode(initialStrings, p_2048_bits, q_2048_bits,
            numDesiredElementsInEncoding, usableRepresentationsEncode);

        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = Arrays.asList("2");
        List<String> decoded = _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);
        assertEquals(initialStrings, decoded);
    }

    @Test
    public void whenEncodeAndDecodeThenOk_p50bits() {

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add("2#eeny");
        initialStrings.add("17#meeny");
        initialStrings.add("67#miny");

        List<String> usableRepresentationsEncode = Arrays.asList("2", "17", "67");
        int numDesiredElementsInEncoding = 12;

        List<BigInteger> encoded = _target.encode(initialStrings, p_50_bits, q_50_bits, numDesiredElementsInEncoding,
            usableRepresentationsEncode);

        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = Arrays.asList("2", "17", "67");
        List<String> decoded = _target.decode(encoded, p_50_bits, usableRepresentationsDecode);

        assertEquals(initialStrings, decoded);
    }

    @Test
    public void whenEncodeAndDecodeThenOk_p1024bits() {

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add("2#eeny");
        initialStrings.add("17#meeny");
        initialStrings.add("67#miny");

        List<String> usableRepresentationsEncode = Arrays.asList("2", "17", "67");
        int numDesiredElementsInEncoding = 10;

        List<BigInteger> encoded = _target.encode(initialStrings, p_1024_bits, q_1024_bits,
            numDesiredElementsInEncoding, usableRepresentationsEncode);

        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = Arrays.asList("2", "17", "67");
        List<String> decoded = _target.decode(encoded, p_1024_bits, usableRepresentationsDecode);

        assertEquals(initialStrings, decoded);
    }

    @Test
    public void whenEncodeAndDecodeThenOk_p2048bits() {

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add("2#eeny");
        initialStrings.add("17#meeny");
        initialStrings.add("67#miny");

        List<String> usableRepresentationsEncode = Arrays.asList("2", "17", "67");
        int numDesiredElementsInEncoding = 10;

        List<BigInteger> encoded = _target.encode(initialStrings, p_2048_bits, q_2048_bits,
            numDesiredElementsInEncoding, usableRepresentationsEncode);
        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = Arrays.asList("2", "17", "67");
        List<String> decoded = _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);

        assertEquals(initialStrings, decoded);
    }

    @Test
    public void whenEncodeAndDecodeThenOk_p3072bits() {

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add("2#eeny");
        initialStrings.add("17#meeny");
        initialStrings.add("67#miny");

        List<String> usableRepresentationsEncode = Arrays.asList("2", "17", "67");
        int numDesiredElementsInEncoding = 10;

        List<BigInteger> encoded = _target.encode(initialStrings, p_3072_bits, q_3072_bits,
            numDesiredElementsInEncoding, usableRepresentationsEncode);
        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = Arrays.asList("2", "17", "67");
        List<String> decoded = _target.decode(encoded, p_3072_bits, usableRepresentationsDecode);

        assertEquals(initialStrings, decoded);
    }

    @Test
    public void whenEncodeAndDecodeStringThatIncludesSpacesThenOk() {

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add("2#Fred Flintstone");

        List<String> usableRepresentationsEncode = Arrays.asList("2");
        int numDesiredElementsInEncoding = 10;

        List<BigInteger> encoded = _target.encode(initialStrings, p_2048_bits, q_2048_bits,
            numDesiredElementsInEncoding, usableRepresentationsEncode);
        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = Arrays.asList("2");
        List<String> decoded = _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);
        assertEquals(initialStrings, decoded);
    }

    @Test
    public void whenEncodeAndDecodeNameWithManyAccentsThenOk() {

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add("2#Doe Mäöüéà'-çôî");

        List<String> usableRepresentationsEncode = Arrays.asList("2");
        int numDesiredElementsInEncoding = 10;

        List<BigInteger> encoded = _target.encode(initialStrings, p_2048_bits, q_2048_bits,
            numDesiredElementsInEncoding, usableRepresentationsEncode);

        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = Arrays.asList("2");
        List<String> decoded = _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);
        assertEquals(initialStrings, decoded);
    }

    @Test
    public void whenEncodeAndDecodeMultipleStringsThatIncludesSpacesThenOk() {

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add("2#Elvis Presley");
        initialStrings.add("17#Micky Mouse");
        initialStrings.add("67#Pope John Paul II");
        initialStrings.add("107#Fred Flintstone");

        List<String> usableRepresentationsEncode = Arrays.asList("2", "17", "67", "107");
        int numDesiredElementsInEncoding = 10;

        List<BigInteger> encoded = _target.encode(initialStrings, p_2048_bits, q_2048_bits,
            numDesiredElementsInEncoding, usableRepresentationsEncode);
        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = Arrays.asList("2", "17", "67", "107");
        List<String> decoded = _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);
        assertEquals(initialStrings, decoded);
    }

    @Test
    public void whenEncodeAndDecodeMultipleStringsThatContainASingleCharacterThenOk() {

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add("2#a");
        initialStrings.add("17#b");
        initialStrings.add("67#c");
        initialStrings.add("107#d");
        initialStrings.add("139#e");
        initialStrings.add("151#f");
        initialStrings.add("163#g");
        initialStrings.add("197#h");
        initialStrings.add("229#i");
        initialStrings.add("241#j");
        initialStrings.add("367#k");

        List<String> usableRepresentationsEncode =
            Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197", "229", "241", "367");
        int numDesiredElementsInEncoding = 10;

        List<BigInteger> encoded = _target.encode(initialStrings, p_2048_bits, q_2048_bits,
            numDesiredElementsInEncoding, usableRepresentationsEncode);
        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode =
            Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197", "229", "241", "367");
        List<String> decoded = _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);
        assertEquals(initialStrings, decoded);
    }

    @Test
    public void whenEncodeAndDecodeAListThatOnlyIncludesSpacesThenOk() {

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add("2#                ");
        initialStrings.add("17#                ");
        initialStrings.add("67#                ");
        initialStrings.add("107#                ");
        initialStrings.add("139#                ");

        List<String> usableRepresentationsEncode = Arrays.asList("2", "17", "67", "107", "139");
        int numDesiredElementsInEncoding = 10;

        List<BigInteger> encoded = _target.encode(initialStrings, p_2048_bits, q_2048_bits,
            numDesiredElementsInEncoding, usableRepresentationsEncode);
        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = Arrays.asList("2", "17", "67", "107", "139");
        List<String> decoded = _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);
        assertEquals(initialStrings, decoded);
    }

    @Test
    public void whenEncodeAndDecodeLargeAmountOfDataThenOk() {

        List<String> initialStrings = generate8StringsOf100Characters();

        List<String> usableRepresentationsEncode = Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197");
        int numDesiredElementsInEncoding = 10;

        List<BigInteger> encoded = _target.encode(initialStrings, p_2048_bits, q_2048_bits,
            numDesiredElementsInEncoding, usableRepresentationsEncode);
        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197");
        List<String> decoded = _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);
        assertEquals(initialStrings, decoded);
    }

    @Test
    public void whenEncodeAndDecodeVeryLargeAmountOfDataThenOk_p50bits() {

        List<String> initialStrings = generate20StringsOf120Characters();

        List<String> usableRepresentationsEncode = Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197",
            "229", "241", "367", "373", "431", "463", "601", "683", "719", "757", "701", "821");
        int numDesiredElementsInEncoding = 1248;

        List<BigInteger> encoded = _target.encode(initialStrings, p_50_bits, q_50_bits, numDesiredElementsInEncoding,
            usableRepresentationsEncode);
        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197",
            "229", "241", "367", "373", "431", "463", "601", "683", "719", "757", "701", "821");
        List<String> decoded = _target.decode(encoded, p_50_bits, usableRepresentationsDecode);
        assertEquals(initialStrings, decoded);
    }

    @Test
    public void whenEncodeAndDecodeVeryLargeAmountOfDataThenOk_p1024bits() {

        List<String> initialStrings = generate20StringsOf120Characters();

        List<String> usableRepresentationsEncode = Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197",
            "229", "241", "367", "373", "431", "463", "601", "683", "719", "757", "701", "821");
        int numDesiredElementsInEncoding = 49;

        List<BigInteger> encoded = _target.encode(initialStrings, p_1024_bits, q_1024_bits,
            numDesiredElementsInEncoding, usableRepresentationsEncode);
        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197",
            "229", "241", "367", "373", "431", "463", "601", "683", "719", "757", "701", "821");
        List<String> decoded = _target.decode(encoded, p_1024_bits, usableRepresentationsDecode);
        assertEquals(initialStrings, decoded);
    }

    @Test
    public void whenEncodeAndDecodeVeryLargeAmountOfDataAndDesiredSizeOfEncodingIsOneLessThanActualSizeThenException_p2048bits() {

        expectedEx.expect(RuntimeException.class);
        expectedEx.expectMessage(
            "The encoding has more elements than the desired number. Desired number: 24, actual number: 25");

        List<String> initialStrings = generate20StringsOf120Characters();

        List<String> usableRepresentationsEncode = Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197",
            "229", "241", "367", "373", "431", "463", "601", "683", "719", "757", "701", "821");
        int numDesiredElementsInEncoding = 24;

        _target.encode(initialStrings, p_2048_bits, q_2048_bits, numDesiredElementsInEncoding,
            usableRepresentationsEncode);
    }

    @Test
    public void whenEncodeAndDecodeVeryLargeAmountOfDataAndDesiredSizeOfEncodingIsExactlyTheSameAsActualSizeThenOk_p2048bits() {

        List<String> initialStrings = generate20StringsOf120Characters();

        List<String> usableRepresentationsEncode = Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197",
            "229", "241", "367", "373", "431", "463", "601", "683", "719", "757", "701", "821");
        int numDesiredElementsInEncoding = 25;

        List<BigInteger> encoded = _target.encode(initialStrings, p_2048_bits, q_2048_bits,
            numDesiredElementsInEncoding, usableRepresentationsEncode);
        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197",
            "229", "241", "367", "373", "431", "463", "601", "683", "719", "757", "701", "821");
        List<String> decoded = _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);
        assertEquals(initialStrings, decoded);
    }

    @Test
    public void whenEncodeAndDecodeVeryLargeAmountOfDataAndDesiredSizeOfEncodingIsOneMoreThanTheSameAsActualSizeThenOk_p2048bits() {

        List<String> initialStrings = generate20StringsOf120Characters();

        List<String> usableRepresentationsEncode = Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197",
            "229", "241", "367", "373", "431", "463", "601", "683", "719", "757", "701", "821");
        int numDesiredElementsInEncoding = 26;

        List<BigInteger> encoded = _target.encode(initialStrings, p_2048_bits, q_2048_bits,
            numDesiredElementsInEncoding, usableRepresentationsEncode);
        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197",
            "229", "241", "367", "373", "431", "463", "601", "683", "719", "757", "701", "821");
        List<String> decoded = _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);
        assertEquals(initialStrings, decoded);
    }

    @Test
    public void whenEncodeAndDecodeVeryLargeAmountOfDataThenOk_p3072bits() {

        List<String> initialStrings = generate20StringsOf120Characters();

        List<String> usableRepresentationsEncode = Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197",
            "229", "241", "367", "373", "431", "463", "601", "683", "719", "757", "701", "821");
        int numDesiredElementsInEncoding = 17;

        List<BigInteger> encoded = _target.encode(initialStrings, p_3072_bits, q_3072_bits,
            numDesiredElementsInEncoding, usableRepresentationsEncode);
        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197",
            "229", "241", "367", "373", "431", "463", "601", "683", "719", "757", "701", "821");
        List<String> decoded = _target.decode(encoded, p_3072_bits, usableRepresentationsDecode);
        assertEquals(initialStrings, decoded);
    }

    @Test
    public void whenEncodeAndDecodeStringsOfVariousLengthsThenOk() {

        List<String> initialStrings = generateStringsOfVariousLengths();

        List<String> usableRepresentationsEncode = Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197",
            "229", "241", "367", "373", "431", "463", "601", "683", "719", "757");
        int numDesiredElementsInEncoding = 10;

        List<BigInteger> encoded = _target.encode(initialStrings, p_2048_bits, q_2048_bits,
            numDesiredElementsInEncoding, usableRepresentationsEncode);
        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197",
            "229", "241", "367", "373", "431", "463", "601", "683", "719", "757");
        List<String> decoded = _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);
        assertEquals(initialStrings, decoded);
    }

    @Test
    public void whenEncodeAndDecodeAllAlphabetCharsThenOk() {

        List<String> initialStrings = new ArrayList<String>();

        int numDesiredElementsInEncoding = 10;

        String alphabetWithoutSeperator = _target.getAlphabet().substring(1);
        String representation = "2";
        String seperator = _target.getAlphabet().substring(0, 1);
        List<String> usableRepresentationsEncode = Arrays.asList("2");

        initialStrings.add(representation + seperator + alphabetWithoutSeperator);

        List<BigInteger> encoded = _target.encode(initialStrings, p_2048_bits, q_2048_bits,
            numDesiredElementsInEncoding, usableRepresentationsEncode);
        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = Arrays.asList("2");
        List<String> decoded = _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);
        assertEquals(initialStrings, decoded);
    }

    @Test
    public void ensure102CharsCanBeEncodedInOneElementRegardlessOfCharacter() {

        ///////////////////////////////////
        //
        // test one of the initial characters in alphabet
        //
        ///////////////////////////////////

        String stringWith102InitialChars = "1#((((((((((";
        for (int i = 0; i < 9; i++) {
            stringWith102InitialChars += "((((((((((";
        }

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add(stringWith102InitialChars);

        List<String> usableRepresentationsEncode = Arrays.asList("1");
        int numDesiredElementsInEncoding = 1;

        List<BigInteger> encoded = _target.encode(initialStrings, p_2048_bits, q_2048_bits,
            numDesiredElementsInEncoding, usableRepresentationsEncode);

        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = Arrays.asList("1");
        List<String> decoded = _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);

        assertEquals(initialStrings, decoded);

        ///////////////////////////////////
        //
        // test last character in alphabet
        //
        ///////////////////////////////////

        String stringWith102LastChars = "1#ÿÿÿÿÿÿÿÿÿÿ";
        for (int i = 0; i < 9; i++) {
            stringWith102LastChars += "ÿÿÿÿÿÿÿÿÿÿ";
        }

        initialStrings = new ArrayList<String>();
        initialStrings.add(stringWith102LastChars);

        encoded = _target.encode(initialStrings, p_2048_bits, q_2048_bits, numDesiredElementsInEncoding,
            usableRepresentationsEncode);

        assertEquals(numDesiredElementsInEncoding, encoded.size());

        decoded = _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);

        assertEquals(initialStrings, decoded);
    }

    @Test
    public void whenEncodeAndDecode6CharPrimePlusSeparatorPlus95CharStringThenOk() {

        String composedOf6charPrime1charSeperator95CharString = "478453#34567890";
        for (int i = 0; i < 8; i++) {
            composedOf6charPrime1charSeperator95CharString += "1234567890";
        }

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add(composedOf6charPrime1charSeperator95CharString);

        List<String> usableRepresentationsEncode = Arrays.asList("478453");

        int numDesiredElementsInEncoding = 1;
        List<BigInteger> encoded = _target.encode(initialStrings, p_2048_bits, q_2048_bits,
            numDesiredElementsInEncoding, usableRepresentationsEncode);

        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = Arrays.asList("478453");
        List<String> decoded = _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);

        assertEquals(initialStrings, decoded);
    }

    @Test
    public void whenEncodeTwoStrings_150Chars_20chars_thenTwoElements() {

        String stringWith150Chars = "1#34567890";
        for (int i = 0; i < 14; i++) {
            stringWith150Chars += "1234567890";
        }

        String stringWith20Chars = "2#11111111";
        stringWith20Chars += "1111111111";

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add(stringWith150Chars);
        initialStrings.add(stringWith20Chars);

        List<String> usableRepresentationsEncode = Arrays.asList("1", "2");
        int numDesiredElementsInEncoding = 2;

        List<BigInteger> encoded = _target.encode(initialStrings, p_2048_bits, q_2048_bits,
            numDesiredElementsInEncoding, usableRepresentationsEncode);

        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = Arrays.asList("1", "2");
        List<String> decoded = _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);

        assertEquals(initialStrings, decoded);
    }

    //////////////////////////////////////////////////////
    //
    // Exception handling
    //
    //////////////////////////////////////////////////////

    @Test
    public void whenRepIsNotIntegerThenException() {

        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage("Exception during encoding - invalid representation found in encoded write-in: a");

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add("a#a");

        List<String> usableRepresentationsEncode = Arrays.asList("2");
        int numDesiredElementsInEncoding = 10;

        _target.encode(initialStrings, p_2048_bits, q_2048_bits, numDesiredElementsInEncoding,
            usableRepresentationsEncode);
    }

    @Test
    public void whenEncodeStringWithInvalidCharThenException() {

        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage("Invalid character for writein encoding: ?");

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add("2#eeny");
        initialStrings.add("17#meeny");
        initialStrings.add("67#mi?ny");

        List<String> usableRepresentationsEncode = Arrays.asList("2", "17", "67");
        int numDesiredElementsInEncoding = 10;

        _target.encode(initialStrings, p_2048_bits, q_2048_bits, numDesiredElementsInEncoding,
            usableRepresentationsEncode);
    }

    @Test
    public void whenEncodeStringWithSeparatorCharThenException() {

        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage(
            "There should be exactly one separator character in each writein string, but this was not the case for: 17#m#eeny");

        String separator = _target.getAlphabet().substring(0, 1);
        String stringContainingSeperator = "m" + separator + "eeny";

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add("2#eeny");
        initialStrings.add("17#" + stringContainingSeperator);
        initialStrings.add("67#miny");

        List<String> usableRepresentationsEncode = Arrays.asList("1", "17", "67");
        int numDesiredElementsInEncoding = 10;

        _target.encode(initialStrings, p_2048_bits, q_2048_bits, numDesiredElementsInEncoding,
            usableRepresentationsEncode);
    }
    
    @Test
    public void whenDecodingIfContainsNoWriteinDataThenException() {
        
        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage(
            "Exception during decoding - empty write-in is not valid");
        
        // Prepare encoding of the following write ins: 1#A#2#
        // With numeric representation: 013 003 022 003 014 003
        BigInteger encodedWriteIns = new BigInteger("013003022003014003").pow(2);
        List<BigInteger> encoded = new ArrayList<>();
        encoded.add(encodedWriteIns);
        
        List<String> usableRepresentationsDecode = Arrays.asList("1", "2");
        _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);
    }
    
    @Test
    public void whenDecodingIfContainsNoWriteinData2ThenException() {
        
        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage(
            "Exception during decoding - empty write-in is not valid");
        
        // Prepare encoding of the following write ins: 1#
        // With numeric representation: 013 003
        BigInteger encodedWriteIns = new BigInteger("013003").pow(2);
        List<BigInteger> encoded = new ArrayList<>();
        encoded.add(encodedWriteIns);
        
        List<String> usableRepresentationsDecode = Arrays.asList("1");
        _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);
    }
    
    @Test
    public void whenDecodingIfContainsSeparatorCharThenIllegalArgumentException() {
        
        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage("The decoded write-ins contain invalid character sequence");
        
        // Prepare encoding of the following write ins: 1#A#AA 2#BBB
        // With numeric representation: 013 003 022 003 022 022 003 014 003 023 023 023
        BigInteger encodedWriteIns = new BigInteger("013003022003022022003014003023023023").pow(2);
        List<BigInteger> encoded = new ArrayList<>();
        encoded.add(encodedWriteIns);
        
        List<String> usableRepresentationsDecode = Arrays.asList("1", "2");
        _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);
    }
    
    @Test
    public void whenDecodingIfContainsOnlyOneNumberThenIllegalArgumentException() {
        
        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage("The decoded write-ins contain invalid character sequence");
        
        // Prepare encoding of the following write in: 1111
        // With numeric representation: 013 013 013 013
        BigInteger encodedWriteIns = new BigInteger("013013013013").pow(2);
        List<BigInteger> encoded = new ArrayList<>();
        encoded.add(encodedWriteIns);
        
        List<String> usableRepresentationsDecode = Arrays.asList("1111");
        _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);
    }
    
    @Test
    public void whenEncodeIfArrayOfStringsIsNullThenException() {

        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage("Exception during encoding - there are valid representations but no write-ins");
        List<String> initialStrings = null;
        int numDesiredElementsInEncoding = 10;
        List<String> usableRepresentationsEncode =
            Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197", "229", "241", "367");

        _target.encode(initialStrings, p_2048_bits, q_2048_bits, numDesiredElementsInEncoding,
            usableRepresentationsEncode);
    }

    @Test
    public void whenDecodeIfArrayOfStringsIsNullThenException() {

        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage("Exception during decoding - there are valid representations but no write-ins");

        int numDesiredElementsInEncoding = 10;

        List<BigInteger> encoded = new ArrayList<>();
        for (int i = 0; i < numDesiredElementsInEncoding; i++) {
            encoded.add(new BigInteger("2"));
        }

        List<String> usableRepresentationsDecode =
            Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197", "229", "241", "367");
        _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);
    }
    
    @Test
    public void whenDecodeIfContainsInvalidCharacterThenException() {

        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage("The write-ins cannot be decoded to a valid string");

        int numDesiredElementsInEncoding = 10;

        List<BigInteger> encoded = new ArrayList<>();
        encoded.add(new BigInteger("63127089121098304"));
        for (int i = 0; i < numDesiredElementsInEncoding; i++) {
            encoded.add(new BigInteger("2"));
        }

        List<String> usableRepresentationsDecode =
            Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197", "229", "241", "367");
        _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);
    }

    @Test
    public void whenEncodeIfArrayOfStringsIsEmptyThenException() {

        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage("Exception during encoding - there are valid representations but no write-ins");
        List<String> initialStrings = new ArrayList<>();
        int numDesiredElementsInEncoding = 10;
        List<String> usableRepresentationsEncode =
            Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197", "229", "241", "367");

        _target.encode(initialStrings, p_2048_bits, q_2048_bits, numDesiredElementsInEncoding,
            usableRepresentationsEncode);
    }

    @Test
    public void whenEncodeWithNullPThenException() {

        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage("The p parameter was null");

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add("2#eeny");
        initialStrings.add("17#meeny");
        initialStrings.add("67#miny");

        List<String> usableRepresentationsEncode = Arrays.asList("2", "17", "67");
        int numDesiredElementsInEncoding = 10;

        BigInteger nullP = null;
        _target.encode(initialStrings, nullP, q_2048_bits, numDesiredElementsInEncoding, usableRepresentationsEncode);
    }

    @Test
    public void whenEncodeWithNullQThenException() {

        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage("The q parameter was null");

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add("2#eeny");
        initialStrings.add("17#meeny");
        initialStrings.add("67#miny");

        List<String> usableRepresentationsEncode = Arrays.asList("2", "17", "67");
        int numDesiredElementsInEncoding = 10;

        BigInteger nullQ = null;
        _target.encode(initialStrings, p_2048_bits, nullQ, numDesiredElementsInEncoding, usableRepresentationsEncode);
    }

    @Test
    public void whenEncodeWithTooSmallPThenOk() {

        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage("Encoded writein too big for the mathematical group");

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add("2#eeny");

        List<String> usableRepresentationsEncode = Arrays.asList("2");
        int numDesiredElementsInEncoding = 10;
        BigInteger pSmall = new BigInteger("23");
        BigInteger qSmall = new BigInteger("11");

        _target.encode(initialStrings, pSmall, qSmall, numDesiredElementsInEncoding, usableRepresentationsEncode);
    }

    @Test
    public void whenNumDesiredElementsIsLessThanOneThenException() {

        expectedEx.expect(RuntimeException.class);
        expectedEx.expectMessage("The number of desired elements was 0");
        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add("2#eeny");
        initialStrings.add("17#meeny");
        initialStrings.add("67#miny");

        List<String> usableRepresentationsEncode = Arrays.asList("2", "17", "67");
        int numDesiredElementsInEncoding = 0;

        _target.encode(initialStrings, p_2048_bits, q_2048_bits, numDesiredElementsInEncoding,
            usableRepresentationsEncode);
    }

    @Test
    public void whenEncodeTwoStringsAndOneHasNonExistingRepresentationThenException() {

        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage("Exception during encoding - invalid representation found in encoded write-in: 2");

        List<String> usableRepresentationsEncode = Arrays.asList("1", "3");

        String string1 = "1#34567890";
        String string2 = "2#11111111";
        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add(string1);
        initialStrings.add(string2);

        int numDesiredElementsInEncoding = 2;

        _target.encode(initialStrings, p_2048_bits, q_2048_bits, numDesiredElementsInEncoding,
            usableRepresentationsEncode);
    }

    @Test
    public void whenDecodeTwoStringsAndOneHasNonExistingRepresentationThenException() {

        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage("Exception during decoding - invalid representation found in encoded write-in: 2");

        int numDesiredElementsInEncoding = 2;

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add("1#34567890");
        initialStrings.add("2#11111111");

        List<String> usableRepresentationsEncode = Arrays.asList("1", "2");

        List<BigInteger> encoded = _target.encode(initialStrings, p_2048_bits, q_2048_bits,
            numDesiredElementsInEncoding, usableRepresentationsEncode);

        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = Arrays.asList("1");
        _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);
    }

    @Test
    public void whenEncodeTwoStringsThatHaveTheSameRepresentationThenException() {

        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage("Exception during encoding - repeated representation: 1");

        String string1 = "1#34567890";
        String string2 = "1#11111111";

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add(string1);
        initialStrings.add(string2);

        List<String> usableRepresentationsEncode = Arrays.asList("1", "2");

        int numDesiredElementsInEncoding = 2;

        _target.encode(initialStrings, p_2048_bits, q_2048_bits, numDesiredElementsInEncoding,
            usableRepresentationsEncode);
    }
    

    @Test
    public void whenDecodeTwoStringsThatHaveTheSameRepresentationThenException() {

        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage("Exception during decoding - repeated representation: 1");

        int numDesiredElementsInEncoding = 2;

        // Given the specified alphabet, the following WIs could be encoded as follows:
        // WIs: "1#AAA", "1#BBB"
        // Encoded to 3-character numbers: 013 003 020 020 020 003 013 003 021 021 021
        // Note: there is one separate character added between the two input WIs, for that reason there are 11
        // 3-character numbers.
        // Converted to single number and squared: 169078529641040999557077605434163006708885521799114009323882441
        //
        // This encoding would not be generated by a correct encoder (due to validations during encoding). A correct
        // encoder would not permit two WIs with the same representation.

        List<BigInteger> encoded = new ArrayList<>();
        encoded.add(new BigInteger("169078529641040999557077605434163006708885521799114009323882441"));
        encoded.add(new BigInteger("2"));

        assertEquals(numDesiredElementsInEncoding, encoded.size());

        List<String> usableRepresentationsDecode = Arrays.asList("1");
        _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);
    }

    @Test
    public void whenEncodeWithUnusedRepresentationThenException() {

        expectedEx.expect(RuntimeException.class);
        expectedEx.expectMessage("Exception during encoding - representations not used: [51545]");
        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add("2#a");
        initialStrings.add("17#b");
        initialStrings.add("67#c");
        initialStrings.add("107#d");
        initialStrings.add("139#e");
        initialStrings.add("151#f");
        initialStrings.add("163#g");
        initialStrings.add("197#h");
        initialStrings.add("229#i");
        initialStrings.add("241#j");
        initialStrings.add("367#k");

        List<String> usableRepresentationsEncode =
            Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197", "229", "241", "367", "51545");
        int numDesiredElementsInEncoding = 2;

        _target.encode(initialStrings, p_2048_bits, q_2048_bits, numDesiredElementsInEncoding,
            usableRepresentationsEncode);
    }

    @Test
    public void whenDecodeWithUnusedRepresentationThenException() {

        expectedEx.expect(RuntimeException.class);
        expectedEx.expectMessage("Exception during decoding - representations not used: [51545]");

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add("2#a");
        initialStrings.add("17#b");
        initialStrings.add("67#c");
        initialStrings.add("107#d");
        initialStrings.add("139#e");
        initialStrings.add("151#f");
        initialStrings.add("163#g");
        initialStrings.add("197#h");
        initialStrings.add("229#i");
        initialStrings.add("241#j");
        initialStrings.add("367#k");

        List<String> usableRepresentationsEncode =
            Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197", "229", "241", "367");
        int numDesiredElementsInEncoding = 2;

        List<BigInteger> encoded = _target.encode(initialStrings, p_2048_bits, q_2048_bits,
            numDesiredElementsInEncoding, usableRepresentationsEncode);

        List<String> usableRepresentationsDecode =
            Arrays.asList("2", "17", "67", "107", "139", "151", "163", "197", "229", "241", "367", "51545");
        _target.decode(encoded, p_2048_bits, usableRepresentationsDecode);
    }

    //////////////////////////////////////////////////////
    //
    // Square and squareroot
    //
    //////////////////////////////////////////////////////

    @Test
    public void whenSquareAndSquarerootRangeValidValuesThenOk_p59() {

        BigInteger p = new BigInteger("59");
        BigInteger q = new BigInteger("29");

        for (int i = 0; i <= 7; i++) {

            BigInteger value = BigInteger.valueOf(i);

            BigInteger square = _target.squareToEnsureIsGroupElement(value, p, q);

            BigInteger result = isqrt(square);

            assertEquals(value, result);
        }
    }

    @Test
    public void whenSquareAndSquarerootThenOk_10() {

        BigInteger p = p_2048_bits;
        BigInteger q = q_2048_bits;
        BigInteger value = new BigInteger("10");

        BigInteger square = _target.squareToEnsureIsGroupElement(value, p, q);

        BigInteger result = isqrt(square);

        assertEquals(value, result);
    }

    @Test
    public void whenSquareAndSquarerootThenOk_10digits() {

        BigInteger p = p_2048_bits;
        BigInteger q = q_2048_bits;
        BigInteger value = new BigInteger("1234567890");

        BigInteger square = _target.squareToEnsureIsGroupElement(value, p, q);

        BigInteger result = isqrt(square);

        assertEquals(value, result);
    }

    @Test
    public void whenSquareAndSquarerootThenOk_100digits() {

        BigInteger p = p_2048_bits;
        BigInteger q = q_2048_bits;
        BigInteger value = new BigInteger(
            "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");

        BigInteger square = _target.squareToEnsureIsGroupElement(value, p, q);

        BigInteger result = isqrt(square);

        assertEquals(value, result);
    }

    @Test
    public void whenSquareAndSquarerootThenOk_200digits() {

        BigInteger p = p_2048_bits;
        BigInteger q = q_2048_bits;
        BigInteger value = new BigInteger(
            "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");

        BigInteger square = _target.squareToEnsureIsGroupElement(value, p, q);

        BigInteger result = isqrt(square);

        assertEquals(value, result);
    }

    @Test
    public void whenSquareAndSquarerootThenOk_300digits() {

        BigInteger p = p_2048_bits;
        BigInteger q = q_2048_bits;
        BigInteger value = new BigInteger(
            "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");

        BigInteger square = _target.squareToEnsureIsGroupElement(value, p, q);

        BigInteger result = isqrt(square);

        assertEquals(value, result);
    }

    private List<String> generateStringsOfVariousLengths() {

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add("2#A");
        initialStrings.add("17#BB");
        initialStrings.add("67#CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC");
        initialStrings.add(
            "107#DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD");
        initialStrings.add("139#EEEEEEEEEEEEEEEEEEEEEEEEEE");
        initialStrings.add("151#FFFF");
        initialStrings.add("163#GGGGGGGGGGGGGGGGGG");
        initialStrings.add(
            "197#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH");
        initialStrings.add("229#IIIIIIIIIIIIIIIIIIIIIIIIII");
        initialStrings.add("241#JJJJJJJJJJJJJ");
        initialStrings.add("367#KKKKKKK");
        initialStrings.add("373#LLL");
        initialStrings.add("431#MM");
        initialStrings.add("463#N");
        initialStrings.add("601#OO");
        initialStrings.add("683#PPPPPP");
        initialStrings.add("719#QQQQQQQQQQQ");
        initialStrings.add("757#RRRRRRRRRRRRRRRRRR");

        return initialStrings;
    }

    private List<String> generate8StringsOf100Characters() {

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add(
            "2#AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
        initialStrings.add(
            "17#BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB");
        initialStrings.add(
            "67#CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC");
        initialStrings.add(
            "107#DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD");
        initialStrings.add(
            "139#EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE");
        initialStrings.add(
            "151#FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
        initialStrings.add(
            "163#GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG");
        initialStrings.add(
            "197#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH");

        return initialStrings;
    }

    private List<String> generate20StringsOf120Characters() {

        List<String> initialStrings = new ArrayList<String>();
        initialStrings.add(
            "2#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
        initialStrings.add(
            "17#bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
        initialStrings.add(
            "67#cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc");
        initialStrings.add(
            "107#dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd");
        initialStrings.add(
            "139#eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee");
        initialStrings.add(
            "151#ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
        initialStrings.add(
            "163#gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg");
        initialStrings.add(
            "197#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh");
        initialStrings.add(
            "229#iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii");
        initialStrings.add(
            "241#jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj");
        initialStrings.add(
            "367#kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkZZZZZZZZZZZZZZZZZZZZZZZ");
        initialStrings.add(
            "373#llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll");
        initialStrings.add(
            "431#mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm");
        initialStrings.add(
            "463#n n n n n n n n n n n n n n n n n n n n n n n n nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn");
        initialStrings.add(
            "601#oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooopppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp");
        initialStrings.add(
            "683#ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ");
        initialStrings.add(
            "719#ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ");
        initialStrings.add(
            "701#ææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ");
        initialStrings.add(
            "757#start of spaces                                                                                            end of spaces");
        initialStrings.add(
            "821#çççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççç");
        return initialStrings;
    }
}
