package org.votesmart.classes;

import org.votesmart.api.*;
import org.votesmart.data.Bill;
import org.votesmart.data.BillAction;
import org.votesmart.data.BillActionVotes;
import org.votesmart.data.BillVetoes;
import org.votesmart.data.Bills;
import org.votesmart.data.BillsByOfficial;
import org.votesmart.data.VotesCategories;

/**
 * <pre>
 * Votes Class
 *
 * * - Required
 * * - Multiple rows
 *
 * Votes.getCategories
 * This method dumps categories that contain released bills according to year and state.
 * Input: year*, stateId (default: 'NA')
 * Output: {@link VotesCategories}
 *
 * Votes.getBill
 * This method dumps general information on a bill.
 * Input: billId*
 * Output: {@link Bill}
 *
 * Votes.getBillAction
 * This gets detailed action information on a certain stage of the bill.
 * Input: actionId*
 * Output: {@link BillAction}
 *
 * Votes.getBillActionVotes
 * Method provides votes listed by candidate on a certain bill action.
 * Input: actionId*
 * Output: {@link BillActionVotes}
 *
 * Votes.getBillActionVoteByOfficial
 * Returns a single vote according to official and action.
 * Input: actionId*, candidateId*
 * Output: {@link BillActionVotes}
 *
 * Votes.getByBillNumber
 * Returns a list of bills that are like the billNumber input.
 * Input: billNumber*
 * Output: {@link Bills}
 *
 * Votes.getBillsByCategoryYearState
 * Returns a list of bills that fit the category, year, and state input.
 * Input: categoryId*, year*, stateId
 * Output: {@link Bills}
 *
 * Votes.getBillsByYearState
 * Returns a list of bills that fit the year and state input.
 * Input: year*, stateId
 * Output: {@link Bills}
 *
 * Votes.getBillsByOfficialYearOffice
 * Returns a list of bills that fit the candidate and year.
 * Input: candidateId*, year*, officeId (Default: NULL(all))
 * Output: {@link Bills}
 *
 * Votes.getBillsByOfficialCategoryOffice
 * Returns a list of bills that fit the candidate and category.
 * Input: candidateId*, categoryId*, officeId (Default: NULL(all))
 * Output: {@link Bills}
 *
 * Votes.getByOfficial
 * This method dumps all the bills an official has voted on based on the candidateId, officeId, categoryId, and year
 * Input: candidateId*, officeId, categoryId, year
 * Output: {@link BillsByOfficial}
 *
 * Votes.getBillsBySponsorYear
 * Returns a list of bills that fit the sponsor's candidateId and year.
 * Input: candidateId*, year*
 * Output: {@link BillsByOfficial}
 *
 * Votes.getBillsBySponsorCategory
 * Returns a list of bills that fit the sponsor's candidateId and category.
 * Input: candidateId*, categoryId*
 * Output: {@link BillsByOfficial}
 *
 * Votes.getBillsByStateRecent
 * Returns a list of recent bills according to the state. Max returned is 100 or however much less you want.
 * Input: amount (default: 100, max: 100), state (default: 'NA')
 * Output: {@link Bills}
 *
 * Votes.getVetoes
 * Returns a list of vetoes according to candidate.
 * Input: candidateId
 * Output: {@link BillVetoes}
 *
 * ==============  EXAMPLE USAGE ===============
 *
 * // Votes class
 * VotesClass votesClass = new VotesClass();
 *
 * // total votesCategories
 * VotesCategories votesCategories = votesClass.getCategories("2013");
 *
 * // for State
 * votesCategories = votesClass.getCategories("2013", state.stateId);
 * CategoryMin votesCategory = votesCategories.category.get(0);
 *
 * // for category, for 2013, for State
 * Bills bills = votesClass.getBillsByCategoryYearState(votesCategory.categoryId, "2013", state.stateId);
 *
 * // by Official, Category, Office
 * bills = votesClass.getBillsByOfficialCategoryOffice(leader.candidateId, votesCategory.categoryId);
 * </pre>
 *
 */
public class VotesClass extends ClassesBase {

	/**
	 * Constructor for testing purposes
	 *
	 * @param api
	 */
	public VotesClass(VoteSmartAPI api) {
		super(api);
	}

	/**
	 * Default Constructor
	 */
	public VotesClass() throws VoteSmartException {
		super();
	}

	/**
	 * This method dumps categories that contain released bills according to year and state.
	 * Input: year*, stateId (default: 'NA')
	 *
	 * @param year
	 * @return {@link VotesCategories}
	 */
	public VotesCategories getCategories(String year) throws VoteSmartException, VoteSmartErrorException {
		return api.query("Votes.getCategories", new ArgMap("year", year), VotesCategories.class );
	}

	/**
	 * This method dumps categories that contain released bills according to year and state.
	 * Input: year*, stateId (default: 'NA')
	 *
	 * @param year
	 * @param stateId
	 * @return {@link VotesCategories}
	 */
	public VotesCategories getCategories(String year, String stateId) throws VoteSmartException, VoteSmartErrorException {
		return api.query("Votes.getCategories", new ArgMap("year", year, "stateId", stateId), VotesCategories.class );
	}

	/**
	 * This method dumps general information on a bill.
	 * Input: billId*
	 *
	 * @param billId
	 * @return {@link Bill}
	 */
	public Bill getBill(String billId) throws VoteSmartException, VoteSmartErrorException {
		return api.query("Votes.getBill", new ArgMap("billId", billId), Bill.class );
	}

	/**
	 * This gets detailed action information on a certain stage of the bill
	 * Input: actionId*
	 *
	 * @param actionId
	 * @return {@link BillAction}
	 */
	public BillAction getBillAction(String actionId) throws VoteSmartException, VoteSmartErrorException {
		return api.query("Votes.getBillAction", new ArgMap("actionId", actionId), BillAction.class );
	}

	/**
	 * Method provides votes listed by candidate on a certain bill action.
	 * Input: actionId*
	 *
	 * @param actionId
	 * @return {@link BillActionVotes}
	 */
	public BillActionVotes getBillActionVotes(String actionId) throws VoteSmartException, VoteSmartErrorException {
		return api.query("Votes.getBillActionVotes", new ArgMap("actionId", actionId), BillActionVotes.class );
	}

	/**
	 * Returns a single vote according to official and action.
	 * Input: actionId*, candidateId*
	 *
	 * @param actionId
	 * @param candidateId
	 * @return {@link BillActionVotes}
	 */
	public BillActionVotes getBillActionVoteByOfficial(String actionId, String candidateId) throws VoteSmartException, VoteSmartErrorException {
		return api.query("Votes.getBillActionVoteByOfficial", new ArgMap("actionId", actionId, "candidateId", candidateId), BillActionVotes.class );
	}

	/**
	 * Returns a list of bills that are like the billNumber input.
	 * Input: billNumber*
	 *
	 * @param billNumber
	 * @return {@link Bills}
	 */
	public Bills getByBillNumber(String billNumber) throws VoteSmartException, VoteSmartErrorException {
		return api.query("Votes.getByBillNumber", new ArgMap("billNumber", billNumber), Bills.class );
	}

	/**
	 * Returns a list of bills that fit the category, year, and state input.
	 * Input: categoryId*, year*, stateId
	 *
	 * @param categoryId
	 * @param year
	 * @return {@link Bills}
	 */
	public Bills getBillsByCategoryYearState(String categoryId, String year) throws VoteSmartException, VoteSmartErrorException {
		return api.query("Votes.getBillsByCategoryYearState", new ArgMap("categoryId", categoryId, "year", year), Bills.class );
	}

	/**
	 * Returns a list of bills that fit the category, year, and state input.
	 * Input: categoryId*, year*, stateId
	 *
	 * @param categoryId
	 * @param year
	 * @param stateId
	 * @return {@link Bills}
	 */
	public Bills getBillsByCategoryYearState(String categoryId, String year, String stateId) throws VoteSmartException, VoteSmartErrorException {
		return api.query("Votes.getBillsByCategoryYearState", new ArgMap("categoryId", categoryId, "year", year, "stateId", stateId), Bills.class );
	}

	/**
	 * Returns a list of bills that fit the candidate and year.
	 * Input: candidateId*, year*, officeId (Default: NULL(all))
	 *
	 * @param candidateId
	 * @param year
	 * @return {@link Bills}
	 */
	public Bills getBillsByOfficialYearOffice(String candidateId, String year) throws VoteSmartException, VoteSmartErrorException {
		return api.query("Votes.getBillsByOfficialYearOffice", new ArgMap("candidateId", candidateId, "year", year), Bills.class );
	}

	/**
	 * Returns a list of bills that fit the candidate and year.
	 * Input: candidateId*, year*, officeId (Default: NULL(all))
	 *
	 * @param candidateId
	 * @param year
	 * @param officeId
	 * @return {@link Bills}
	 */
	public Bills getBillsByOfficialYearOffice(String candidateId, String year, String officeId) throws VoteSmartException, VoteSmartErrorException {
		return api.query("Votes.getBillsByOfficialYearOffice", new ArgMap("candidateId", candidateId, "year", year, "officeId", officeId), Bills.class );
	}

	/**
	 * Returns a list of bills that fit the candidate and category.
	 * Input: candidateId*, categoryId*, officeId (Default: NULL(all))
	 *
	 * @param candidateId
	 * @param categoryId
	 * @return {@link Bills}
	 */
	public Bills getBillsByOfficialCategoryOffice(String candidateId, String categoryId) throws VoteSmartException, VoteSmartErrorException {
		return api.query("Votes.getBillsByOfficialCategoryOffice", new ArgMap("candidateId", candidateId, "categoryId", categoryId), Bills.class );
	}

	/**
	 * Returns a list of bills that fit the candidate and category.
	 * Input: candidateId*, categoryId*, officeId (Default: NULL(all))
	 *
	 * @param candidateId
	 * @param categoryId
	 * @param officeId
	 * @return {@link Bills}
	 */
	public Bills getBillsByOfficialCategoryOffice(String candidateId, String categoryId, String officeId) throws VoteSmartException, VoteSmartErrorException {
		return api.query("Votes.getBillsByOfficialCategoryOffice", new ArgMap("candidateId", candidateId, "categoryId", categoryId, "officeId", officeId), Bills.class );
	}

	/**
	 * This method dumps all the bills an official has voted on based on the candidateId, officeId, categoryId, and year
	 * Input: candidateId*, officeId, categoryId, year
	 *
	 * @param candidateId
	 * @param officeId
	 * @return {@link BillsByOfficial}
	 */
	public BillsByOfficial getByOfficial(String candidateId, String officeId) throws VoteSmartException, VoteSmartErrorException {
		return api.query("Votes.getByOfficial", new ArgMap("candidateId", candidateId, "officeId", officeId), BillsByOfficial.class );
	}

	/**
	 * This method dumps all the bills an official has voted on based on the candidateId, officeId, categoryId, and year
	 * Input: candidateId*, officeId, categoryId, year
	 *
	 * @param candidateId
	 * @param officeId
	 * @param categoryId
	 * @return {@link BillsByOfficial}
	 */
	public BillsByOfficial getByOfficial(String candidateId, String officeId, String categoryId) throws VoteSmartException, VoteSmartErrorException {
		return api.query("Votes.getByOfficial", new ArgMap("candidateId", candidateId, "officeId", officeId, "categoryId", categoryId), BillsByOfficial.class );
	}

	/**
	 * This method dumps all the bills an official has voted on based on the candidateId, officeId, categoryId, and year
	 * Input: candidateId*, officeId, categoryId, year
	 *
	 * @param candidateId
	 * @param officeId
	 * @param categoryId
	 * @param year
	 * @return {@link BillsByOfficial}
	 */
	public BillsByOfficial getByOfficial(String candidateId, String officeId, String categoryId, String year) throws VoteSmartException, VoteSmartErrorException {
		return api.query("Votes.getByOfficial", new ArgMap("candidateId", candidateId, "officeId", officeId, "categoryId", categoryId, "year", year), BillsByOfficial.class );
	}

	/**
	 * Returns a list of bills that fit the sponsor's candidateId and year.
	 * Input: candidateId*, year*
	 *
	 * @param candidateId
	 * @param year
	 * @return {@link Bills}
	 */
	public Bills getBillsBySponsorYear(String candidateId, String year) throws VoteSmartException, VoteSmartErrorException {
		return api.query("Votes.getBillsBySponsorYear", new ArgMap("candidateId", candidateId, "year", year), Bills.class );
	}

	/**
	 * Returns a list of bills that fit the sponsor's candidateId and category.
	 * Input: candidateId*, categoryId*
	 *
	 * @param candidateId
	 * @param categoryId
	 * @return {@link Bills}
	 */
	public Bills getBillsBySponsorCategory(String candidateId, String categoryId) throws VoteSmartException, VoteSmartErrorException {
		return api.query("Votes.getBillsBySponsorCategory", new ArgMap("candidateId", candidateId, "categoryId", categoryId), Bills.class );
	}

	/**
	 * Returns a list of recent bills according to the state. Max returned is 100 or however much less you want.
	 * Input: amount (default: 100, max: 100), state (default: 'NA')
	 *
	 * Note: Currently, the caching will only the most recent call. It won't cache all calls.
	 *
	 * @param amount
	 * @param state
	 * @return {@link Bills}
	 */
	public Bills getBillsByStateRecent(String amount, String state) throws VoteSmartException, VoteSmartErrorException {
		return api.query("Votes.getBillsByStateRecent", new ArgMap("amount", amount, "state", state), Bills.class );
	}

	/**
	 * Returns a list of vetoes according to candidate.
	 * Input: candidateId
	 *
	 * @param candidateId
	 * @return {@link BillVetoes}
	 */
	public BillVetoes getVetoes(String candidateId) throws VoteSmartException, VoteSmartErrorException {
		return api.query("Votes.getVetoes", new ArgMap("candidateId", candidateId), BillVetoes.class );
	}

}


package org.votesmart.classes;

import org.votesmart.api.*;
import org.votesmart.data.State;
import org.votesmart.data.StateList;

/**
 * <pre>
 * State Class
 *
 * State.getStateIDs()
 * This method grabs a simple state ID and name list for mapping ID to state names.
 * Input: none
 * Output: {@link StateList}
 *
 * State.getState()
 * This method grabs a various data we keep on a state
 * Input: stateId*
 * Output: {@link State}
 *
 * ============== EXAMPLE USAGE =============
 *
 * StateClass stateClass = new StateClass();
 *
 * StateList allStates = stateClass.getStateIDs();
 * StateList.List.State state = null;
 * for( StateList.List.State aState: allStates.list.state ) {
 * 		if (aState.name.equals("California")) {
 * 			state = aState;
 * 			break;
 * 		}
 * }
 * // Get State Details
 * State stateDetail = stateClass.getState(state.stateId);
 * </pre>
 *
 */
public class StateClass extends ClassesBase {

	/**
	 * Constructor for testing purposes
	 *
	 * @param api
	 */
	public StateClass(VoteSmartAPI api) {
		super(api);
	}

	/**
	 * Default Constructor
	 */
	public StateClass() throws VoteSmartException {
		super();
	}

	/**
	 * This method grabs a simple state ID and name list for mapping ID to state names.
	 *
	 * @return {@link StateList}
	 */
	public StateList getStateIDs() throws VoteSmartException, VoteSmartErrorException {
		return api.query("State.getStateIDs", null, StateList.class );
	}

	/**
	 * This method grabs a various data we keep on a state.
	 * Input: stateId*
	 *
	 * @param stateId
	 * @return {@link State}
	 */
	public State getState(String stateId) throws VoteSmartException, VoteSmartErrorException {
		return api.query("State.getState", new ArgMap("stateId", stateId), State.class );
	}

}


package org.votesmart.classes;

import org.votesmart.api.*;
import org.votesmart.data.Npat;

/**
 * <pre>
 * NPAT/PCT Class
 * * - Required
 * * - Multiple rows
 * * - Possibly Recursive
 *
 * Npat.getNpat()
 * This method returns the candidates most recently filled out NPAT/PCT.
 * NOTE: This is the only class that responds with recursive data.
 * Input: candidateId*
 * Output: {@link Npat}
 *
 * ========== EXAMPLE USAGE =============
 *
 * // Npat class
 * NpatClass npatClass = new NpatClass();
 *
 * // Npat if it exists
 * Npat npat = npatClass.getNpat(leader.candidateId);
 * </pre>
 *
 */
public class NpatClass extends ClassesBase {

	/**
	 * Constructor for testing purposes.
	 *
	 * @param api
	 */
	public NpatClass(VoteSmartAPI api) {
		super(api);
	}

	/**
	 * Default Constructor
	 */
	public NpatClass() throws VoteSmartException {
		super();
	}
	/**
	 * This method returns the candidates most recently filled out NPAT/PCT.
	 * NOTE: This is the only class that responds with recursive data.
	 *
	 * @param candidateId
	 * @return {@link Npat}:
	 */
	public Npat getNpat(String candidateId) throws VoteSmartException, VoteSmartErrorException {
		return api.query("Npat.getNpat", new ArgMap("candidateId", candidateId), Npat.class );
	}

}


package at.borkowski.spicej.streams;

import java.io.IOException;
import java.io.InputStream;

import at.borkowski.spicej.WouldBlockException;
import at.borkowski.spicej.shapers.RateShaper;
import at.borkowski.spicej.streams.RateHelper.IdleNotify;
import at.borkowski.spicej.ticks.TickSource;

/**
 * Provides an {@link InputStream} with a limited rate of bytes.
 *
 * A stream has two blocking modes: blocking and non-blocking. If the stream is
 * in non-blocking mode, any call that would cause the stream to block (ie. all
 * read calls when no data is available) throw a {@link WouldBlockException}.
 *
 * A stream has two boring modes: boring and non-boring. The boring flag
 * modifies he behavior of {@link #read(byte[], int, int)} and
 * {@link #read(byte[])}.
 *
 * According to {@link InputStream}, they method read between 1 and n bytes,
 * where n is the size of the effective buffer.
 *
 * If the {@link RateLimitInputStream} is in boring mode, the methods block
 * until all actually available bytes have been read, even if many ticks must be
 * waited for the data to become available according to the set rate.
 *
 * In non-boring mode, the methods do not block and read only data which can be
 * read immediately (except for the first byte which, according to the
 * definition of {@link InputStream}, causes blocking for all read methods).
 *
 * Note that blocking and boring are two different concept even though they seem
 * similar. Non-blocking will cause methods to throw exceptions, where
 * non-boring only means that read methods exit sooner in certain situations
 * than in boring mode.
 *
 * Streams are non-boring by default.
 *
 */
public class RateLimitInputStream extends InputStream implements RateShaper {
   private final InputStream real;

   private final RateHelper rateHelper;

   private boolean boring = false;

   /**
    * Constructs a byte-rate-limited {@link InputStream}.
    *
    * The rate is given using two numbers: bytes per tick, and a prescale.
    *
    * The prescale divides the incoming ticks by a constant number. A prescale
    * of 1 means that each tick coming from the tick source is counting towards
    * the rate, a prescale of 2 means every second, and so on. The prescale can
    * be used to achieve low byte rates, ie. rates below 1 byte per tick.
    *
    * For example, a rate of 1 byte per tick and a prescale of 4 means that one
    * byte is read after 4 ticks coming from the tick source.
    *
    * @param real
    *           The actual {@link InputStream} to read from
    * @param tickSource
    *           The tick source
    * @param byteRate
    *           The rate, ie. the limit of how many bytes per tick (after
    *           prescaling) should be readable from this stream
    * @param prescale
    *           The prescaling, ie. the frequency of ticks to actually consider
    *           for rating.
    */
   public RateLimitInputStream(InputStream real, TickSource tickSource, int byteRate, int prescale) {
      this.real = real;

      this.rateHelper = new RateHelper(tickSource, byteRate, prescale);
   }

   @Override
   public void setByteRate(int bytesPerTick) {
      rateHelper.setThingsPerTick(bytesPerTick);
   }

   @Override
   public int getByteRate() {
      return rateHelper.getThingsPerTick();
   }

   // len <= num
   private int realRead(byte[] b, int off, int len) throws IOException {
      int lenToRead = rateHelper.take(len);

      int rd = real.read(b, off, lenToRead);
      if (rd != lenToRead)
         rateHelper.giveBack(lenToRead - rd);
      return rd;
   }

   /**
    * Reads one byte from the stream. This method blocks if there is no byte
    * available from the underlying {@link InputStream} or a rate block has been
    * encountered, regardless of the stream's boring flag.
    */
   @Override
   public int read() throws IOException {
      rateHelper.takeOne();

      return real.read();
   }

   /**
    * This method complies with {@link InputStream#read(byte[], int, int)} and
    * imposes stronger postconditions.
    *
    * Reads up to len bytes from the stream. This method blocks for
    * the first byte reagrdless of the stream's boring flag. For all subsequent
    * bytes, the behavior depends on the boring flag:
    *
    *

    *
In boring mode, the stream blocks until all bytes actually available
    * from the underlying InputStream (reported by
    * {@link InputStream#available()}) have been read, even if this means
    * waiting for the next tick.

    *
In non-boring mode, the stream does not block for the first byte's
    * subsequent bytes. This means that if a rate limitation is in place (ie.
    * the rate has been reached for the current tick), this method does not
    * attempt to read the bytes (the number of actually read bytes is returned
    * conforming with {@link InputStream#read(byte[], int, int)}.

    *

    */
   @Override
   public int read(byte[] b, int off, int len) throws IOException {
      int done = 0;
      while (done < len && (done == 0 || available() > 0 || (boring && real.available() > 0)))
         done += realRead(b, off + done, Math.min(len - done, Math.max(1, rateHelper.getThingsPerTick())));
      return done;
   }

   /**
    * Behaves the same as:
    *
    *

    * read(b, 0, b.length);
    *

    */
   @Override
   public int read(byte[] b) throws IOException {
      return read(b, 0, b.length);
   }

   /**
    * This method complies with {@link InputStream#available()} and imposes
    * stronger postconditions.
    *
    * The returned value is the number of bytes available for immediate reading.
    * If there is no rate limitation in place (ie. the rate has not been reached
    * for the current tick), the {@link InputStream#available()} method of the
    * underlying {@link InputStream} is called. If a rate limitation is in
    * place, the number of bytes readable in the current tick is returned.
    */
   @Override
   public int available() throws IOException {
      return Math.min(real.available(), rateHelper.getTimewiseAvailable());
   }

   @Override
   public void close() throws IOException {
      real.close();
      rateHelper.close();
   }

   @Override
   public synchronized void mark(int readlimit) {
      real.mark(readlimit);
   }

   @Override
   public boolean markSupported() {
      return real.markSupported();
   }

   @Override
   public synchronized void reset() throws IOException {
      real.reset();
   }

   /**
    * Testability function only. See {@link RateHelper}.
    */
   void test__SetIdleNotify(IdleNotify target) {
      rateHelper.test__SetIdleNotify(target);
   }

   /**
    * Sets the boring flag.
    *
    * @param boring
    *           whether the stream should be in boring mode (see
    *           {@link #RateLimitInputStream(InputStream, TickSource, int, int)}
    *           ).
    */
   public void setBoring(boolean boring) {
      this.boring = boring;
   }

   /**
    * Sets the non-blocking flag.
    *
    * @param nonBlocking
    *           whether the stream should be in non-blocking mode (see
    *           {@link RateLimitInputStream}).
    */
   public void setNonBlocking(boolean nonBlocking) {
      rateHelper.setNonBlocking(nonBlocking);
   }

   /**
    * Returns the underlying {@link InputStream}.
    *
    * @return the underlying stream
    */
   public InputStream getBaseStream() {
      return real;
   }

   /**
    * Returns the {@link TickSource} this stream uses.
    *
    * @return the used tick source
    */
   public TickSource getTickSource() {
      return rateHelper.getTickSource();
   }

   @Override
   public int getPrescale() {
      return rateHelper.getPrescale();
   }

   @Override
   public void setPrescale(int prescale) {
      rateHelper.setPrescale(prescale);
   }

}


package at.borkowski.spicej.impl;

/**
 * Provides helper methods for sleeping and waking sleepers up.
 */
public class SleepWakeup {
   private final Object lock = new Object();

   /**
    * Wakes up all sleeping threads currently in {@link #sleep()}.
    */
   public void wakeup() {
      synchronized (lock) {
         lock.notifyAll();
      }
   }

   /**
    * Blocks the calling thread until another thread calls this object's
    * {@link #wakeup()} or a certain timeout passes. This method can be used in
    * a loop or similar environment to avoid CPU over-utilization.
    */
   public void sleep() {
      synchronized (lock) {
         try {
            lock.wait(5000);
         } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
         }
      }
   }

   /**
    * Sleeps for the provided amount of milliseconds, ignoring thread
    * interrupts.
    *
    * @param ms
    *           how many milliseconds to sleep
    */
   public static void sleep(int ms) {
      long deadline = System.currentTimeMillis() + ms;
      while (System.currentTimeMillis() < deadline) {
         try {
            Thread.sleep(Math.max(1, (deadline - System.currentTimeMillis()) / 2));
         } catch (InterruptedException ignore) {}
      }
   }
}


package at.borkowski.spicej.streams;

import java.util.concurrent.atomic.AtomicInteger;

import at.borkowski.spicej.WouldBlockException;
import at.borkowski.spicej.impl.SleepWakeup;
import at.borkowski.spicej.ticks.TickListener;
import at.borkowski.spicej.ticks.TickSource;

/**
 * A helper class for managing a constant rate of something. It uses a concept
 * of "things" to denote the item to have a constant rate, this is in our
 * context always a placeholder for "byte".
 */
class RateHelper {
   private final TickSource tickSource;
   private int thingsPerTick;
   private int prescale;

   private final Listener listener;

   private AtomicInteger spent = new AtomicInteger();
   private SleepWakeup sleep = new SleepWakeup();
   private int timewiseAvailable;
   private boolean nonBlockng = false;

   private IdleNotify test__IdleNotify;

   /**
    * Creates a helper and registers it with the given {@link TickSource}.
    *
    * @param tickSource
    *           The tick source to use.
    * @param thingsRate
    *           How many "things" (eg. bytes) per tick (after prescaling) should
    *           be allowed.
    * @param prescale
    *           How to prescale ticks
    */
   RateHelper(TickSource tickSource, int thingsRate, int prescaler) {
      this.tickSource = tickSource;
      this.thingsPerTick = thingsRate;
      this.prescale = prescaler;

      timewiseAvailable = thingsRate;

      tickSource.addListener(listener = new Listener());
   }

   /**
    * Cleans up used resources, unregisters the tick source.
    */
   public void close() {
      tickSource.removeListener(listener);
   }

   /**
    * Sets the rate of things (eg. bytes) per tick (after prescaling).
    *
    * @param thingsPerTick
    */
   public void setThingsPerTick(int thingsPerTick) {
      this.thingsPerTick = thingsPerTick;
      timewiseAvailable = (int) (thingsPerTick - spent.get());
   }

   /**
    * Returns the current rate of things (eg. bytes) per tick.
    *
    * @return
    */
   public int getThingsPerTick() {
      return thingsPerTick;
   }

   /**
    * Takes one thing (eg. byte). This method blocks until one thing can be used
    * according to the current rate and prescaling settings.
    */
   public void takeOne() {
      while (true) {
         int stored = spent.get();
         if (stored >= thingsPerTick)
            sleep();
         else if (spent.compareAndSet(stored, stored + 1))
            break;
      }
   }

   /**
    * Takes several things (eg. bytes). This method blocks until at least one
    * thing can be used according to the current rate and prescaling settings.
    *
    * This method returns at least 1.
    *
    * @param n
    *           up to how many things to take
    * @return the number of things that have been taken, at least 1
    */
   public int take(int n) {
      int lenToTake;
      while (true) {
         int stored = spent.get();
         lenToTake = Math.min(n, thingsPerTick - stored);
         if (stored >= thingsPerTick)
            sleep();
         else if (spent.compareAndSet(stored, stored + lenToTake))
            break;
      }
      timewiseAvailable -= lenToTake;
      return lenToTake;
   }

   /**
    * Returns several things (eg. bytes) as unused. This method is useful in
    * cases where {@link #take(int)} has been called, but not all of the number
    * of things returned have been used.
    *
    * @param n
    *           How many things to give back
    */
   public void giveBack(int n) {
      spent.addAndGet(-n);
      timewiseAvailable += n;
      wakeup();
   }

   private void wakeup() {
      sleep.wakeup();
   }

   private void sleep() {
      if (test__IdleNotify != null && test__IdleNotify.idle())
         return;
      if (nonBlockng)
         throw new WouldBlockException();

      sleep.sleep();
   }

   /**
    * Testability method: sets a target to call when waiting (blocking) occurs.
    * This is necessary for unit tests.
    */
   void test__SetIdleNotify(IdleNotify target) {
      this.test__IdleNotify = target;
   }

   private class Listener implements TickListener {
      @Override
      public void tick(long tick) {
         if (prescale <= 1 || tick % prescale == 0) {
            int value;
            while (true) {
               int stored = spent.get();
               if (stored > thingsPerTick && spent.compareAndSet(stored, value = (stored - thingsPerTick)))
                  break;
               else if (spent.compareAndSet(stored, (value = 0)))
                  break;
            }
            timewiseAvailable = (int) (thingsPerTick - value);
            wakeup();
         }
      }
   }

   /**
    * Returns an estimate on how many things are available in the current tick.
    * This method might underestimate, meaning that estimate might be lower than
    * the actual number of things available, but never higher.
    *
    * @return
    */
   public int getTimewiseAvailable() {
      return Math.max(0, timewiseAvailable);
   }

   /**
    * Testability only. An interface for a handler of the event that the
    * {@link RateHelper} would sleep and wait for the next tick. This is
    * necessary for unit tests.
    */
   interface IdleNotify {
      /**
       * Called whenever the {@link RateHelper} would sleep and wait for the
       * next tick.
       *
       * @return true if the calling {@link RateHelper} is supposed to abort the
       *         actual sleeping and re-check the tick immediately, false
       *         otherwise.
       */
      boolean idle();
   }

   /**
    * Sets the {@link RateHelper}'s non-blocking mode, specifying that this
    * object's {@link #take(int)} and {@link #takeOne()} methods throw
    * {@link WouldBlockException} whenever the stream would block and wait for a
    * tick to happen, in order for new data to become available.
    *
    * @param nonBlocking
    *           true if non-blocking mode should be turned on,
    *           false otherwise
    */
   public void setNonBlocking(boolean nonBlocking) {
      this.nonBlockng = nonBlocking;
   }

   /**
    * Returns the {@link TickSource} used by this {@link RateHelper} instance.
    *
    * @return the used tick source
    */
   public TickSource getTickSource() {
      return tickSource;
   }

   /**
    * Returns the current prescale
    *
    * @return the current prescale
    */
   public int getPrescale() {
      return prescale;
   }

   /**
    * Sets a new prescale
    *
    * @param prescale
    *           the new prescale
    */
   public void setPrescale(int prescale) {
      this.prescale = prescale;
   }

}


package at.borkowski.spicej.rt;

import at.borkowski.spicej.streams.DelayedInputStream;

/**
 * A utility class allowing easy calculation of parameters required for creating
 * a {@link DelayedInputStream} with real-time delay.
 *
 * Two parameters are necessary for creating a delayed stream: The tick interval
 * in nanoseconds, and the delay in ticks. A low interval has the advantage of a
 * more precise delay, but the disadvantage of higher CPU load.
 *
 * This class uses the notion of an <b>epsilon</b> value to specify the allowed
 * error in the result delay. The error results from a higher tick interval.
 *
 * The default epsilon value is {@link #DEFAULT_EPSILON}.
 *
 * Epsilon must be between 0 and 1, exclusively. The theoretical value of 0
 * means no tolerated error at all, and the value of 1 means that an error of
 * 100% is permitted. A value of 0.01 means a permitted error of 1%, and so on.
 *
 * Note that the actual error may be (much) higher than epsilon, since binding
 * ticks to real time is a real-time application and as such prone to the
 * effects of preemptive computing. However, the theoretical (optimal) error
 * will not exceed epsilon (except for cases where the error is due to integer
 * rounding, this applies to very low delay values).
 */
public class DelayCalculator {
   private DelayCalculator() {}

   /**
    * The default epsilon value (see {@link DelayCalculator}).
    */
   public static final float DEFAULT_EPSILON = 0.05F;

   /**
    * The highest acceptable inverval.
    */
   public static final long MAX_INTERVAL = 1000 * 1000000;

   /**
    * Returns a result for the given delay in nanoseconds and the default
    * epsilon value ({@link #DEFAULT_EPSILON}).
    *
    * @param nanoseconds
    *           The required delay in nanoseconds
    * @return The calculation result
    */
   public static Result calculate(long nanoseconds) {
      return calculate(nanoseconds, DEFAULT_EPSILON);
   }

   /**
    * Returns a result for the given delay and epsilon (error rate). Epsilon
    * must be between 0 and 1, exclusively. See {@link DelayCalculator} for
    * details.
    *
    * @param nanoseconds
    *           The required delay in nanoseconds
    * @param epsilon
    *           The permitted error (0 < epsilon < 1)
    * @return The calculation result
    */
   public static Result calculate(long nanoseconds, float epsilon) {
      if (epsilon <= 0 || epsilon >= 1)
         throw new IllegalArgumentException("0 < epsilon < 1 not satisfied");

      long max_divider = (int) (1D / epsilon);
      if (nanoseconds < max_divider)
         return new Result(nanoseconds, 1);

      long interval = Math.min(MAX_INTERVAL, nanoseconds / max_divider);
      long correction = nanoseconds / interval;

      return new Result(interval, correction);
   }

   public static class Result {
      private final long tickNanosecondsInterval;
      private final long delay;

      private Result(long tickNanosecondsInterval, long delay) {
         this.tickNanosecondsInterval = tickNanosecondsInterval;
         this.delay = delay;
      }

      public long getDelay() {
         return delay;
      }

      public long getTickNanosecondsInterval() {
         return tickNanosecondsInterval;
      }
   }
}


package at.borkowski.spicej.rt;

import at.borkowski.spicej.impl.AbstractTickSource;
import at.borkowski.spicej.ticks.TickListener;

/**
 * A tick source bound to real time. Any tick interval can be specified in
 * nanoseconds, but obviously the platform poses natural bounds for this
 * interval.
 *
 * The lower bound is the resolution of {@link System#nanoTime()}, the upper
 * bound is {@link Integer#MAX_VALUE}.
 *
 * Ticks are generated at a fixed tick-to-tick interval, regardless of the
 * duration of handling ticks. If the handling of ticks for all is not finished
 * until the next tick, one or more subsequent ticks will be fired immediately.
 *
 * Ticks start at 0 and are processed in single-threaded mode.
 *
 * If the last tick listener has been removed from this source, it shuts itself
 * down via {@link #stop()}, if it's not set to keepAlive mode using
 * {@link #setKeepAlive(boolean)}.
 */
public class RealTimeTickSource extends AbstractTickSource {
   private final long interval;
   private boolean keepAlive = false;

   private MyTimer timer;

   /**
    * The threshold below which busy waiting is employed. Waiting via Java sleep
    * methods has the advantage of reduced CPU usage, however, a certain time
    * cost is encountered.
    *
    * Therefore, intervals below {@link #BUSY_WAITING_THRESHOLD} are implemented
    * with busy waiting. Intervals above are implemented by synchronized
    * waiting.
    *
    * On the current development machine, this threshold had to be at least a
    * value of 4.2 ms to ensure the real-time tests passing, which is why 15 ms
    * have been chosen as a margin. Above 10 ms of threshold, an constat error
    * rate of less than 1 % was measured.
    */
   public static final long BUSY_WAITING_THRESHOLD = 10 * 1000000;

   /**
    * The threshold above which a different implementation of the internal timer
    * is used, which is only considering milliseconds. This means that above
    * this threshold, the precision of this tick source is reduced to
    * milliseconds.
    */
   public static final long MILLISECOND_THRESHOLD = 50 * 1000000;

   /**
    * Creates a running real time tick source with ticks generated at the given
    * interval.
    *
    * @param nanoSecondsPerTick
    *           the interval of ticks in nanoseconds
    *
    */
   public RealTimeTickSource(long nanoSecondsPerTick) {
      this(nanoSecondsPerTick, true);
   }

   /**
    * Creates a tick source with ticks generated at the given interval.
    *
    * @param nanoSecondsPerTick
    *           the interval of ticks in nanoseconds
    * @param start
    *           whether the tick source should be started upon creation
    */
   public RealTimeTickSource(long nanoSecondsPerTick, boolean start) {
      this.interval = nanoSecondsPerTick;
      if (start)
         start();
   }

   /**
    * Sets the keepAlive mode of this tick source. If keepAlive is false
    * (default), the source shuts itself down via {@link #stop()} upon the
    * removal of the last tick listener. If keepAlive is true, the source stays
    * active.
    *
    * @param keepAlive
    *           whether the keepAlive mode should be on
    */
   public void setKeepAlive(boolean keepAlive) {
      this.keepAlive = keepAlive;
   }

   @Override
   public void reset() {
      stop();
   }

   /**
    * If the last tick listener has been removed from this source, it shuts
    * itself down via {@link #stop()}, if it's not set to keepAlive mode using
    * {@link #setKeepAlive(boolean)}.
    */
   @Override
   public void removeListener(TickListener listener) {
      super.removeListener(listener);

      if (listeners.isEmpty() && !keepAlive)
         stop();
   }

   /**
    * Starts generating tick events, starting from 0. This method must not be
    * called when the tick source is already running.
    */
   public void start() {
      if (timer != null)
         throw new IllegalStateException("already running");

      if (interval < BUSY_WAITING_THRESHOLD)
         timer = new MyBusyTimer();
      else if (interval < MILLISECOND_THRESHOLD)
         timer = new MyWaitingTimer();
      else
         timer = new MyMillisecondTimer();

      Thread thread = new Thread(timer, "timer");
      thread.setDaemon(true);
      thread.start();
   }

   /**
    * Stops generating tick events. It is not guaranteed how many tick events
    * are generated after the completion of this method, but best effort is made
    * to stop the ticks as soon as possible.
    */
   public void stop() {
      if (timer == null)
         return;

      timer.cancel();
      timer = null;
   }

   private abstract class MyTimer implements Runnable {

      protected boolean cancel = false;

      void cancel() {
         this.cancel = true;
      }
   }

   private class MyBusyTimer extends MyTimer {

      @Override
      public void run() {
         long nextWakeup = System.nanoTime();

         while (!cancel) {
            if (System.nanoTime() >= nextWakeup) {
               RealTimeTickSource.super.doTick();
               nextWakeup = nextWakeup + interval;
            }
         }
      }

   }

   private class MyWaitingTimer extends MyTimer {

      private final Object lock = new Object();

      @Override
      public void run() {
         long nextWakeup = System.nanoTime();

         while (!cancel) {
            if (System.nanoTime() >= nextWakeup) {
               RealTimeTickSource.super.doTick();
               nextWakeup = nextWakeup + interval;
            }

            long period = (long) ((nextWakeup - System.nanoTime()) / 4);

            /*
             * don't sync-sleep below 1 ms per sleep slice, since method
             * call overhead will take loner than that (1 ms is very long
             * for a method call, this is a safety margin for slower systems)
             */
            if (period > 1 * 1000000) {
               period = Math.min(period, 10 * 1000000);
               try {
                  synchronized (lock) {
                     lock.wait(period / 1000000, (int) (period % 1000000));
                  }
               } catch (InterruptedException ignore) {}
            }
         }
      }

      void cancel() {
         super.cancel();
         synchronized (lock) {
            lock.notifyAll();
         }
      }

   }

   private class MyMillisecondTimer extends MyTimer {

      private final Object lock = new Object();

      @Override
      public void run() {
         long nextWakeup = System.currentTimeMillis();

         while (!cancel) {
            if (System.currentTimeMillis() >= nextWakeup) {
               RealTimeTickSource.super.doTick();
               nextWakeup = nextWakeup + interval / 1000000;
            }

            long period = (long) ((nextWakeup - System.currentTimeMillis()) / 4);

            /*
             * don't sync-sleep below 1 ms per sleep slice, since method
             * call overhead will take loner than that (1 ms is very long
             * for a method call, this is a safety margin for slower systems)
             */
            if (period > 5) {
               period = Math.min(period, 100);
               try {
                  synchronized (lock) {
                     lock.wait(period);
                  }
               } catch (InterruptedException ignore) {}
            }
         }
      }

      void cancel() {
         super.cancel();
         synchronized (lock) {
            lock.notifyAll();
         }
      }

   }

}


package at.borkowski.spicej.rt;

import java.math.BigDecimal;
import java.math.RoundingMode;

import at.borkowski.spicej.ticks.TickSource;

/**
 * A utility class for calculating parameters necessary for rate limitation of
 * bytes per seconds.
 *
 * The way spiceJ works internally, three parameters are required to set up a
 * byte-rate limited stream:
 *
 *

 *
Tick interval: How many nanoseconds are between two ticks (see
 * {@link TickSource})

 *
Bytes per tick: How many bytes are allowed to be transmitted/received per
 * tick

 *
Prescale: By how much to divide the incoming ticks (
 * 1 - prescale ticks are skipped before actually allowing data to
 * be sent or received). This is a possibility of skipping ticks to allow for
 * very low bitrates without having extensive tick intervals.

 *

 *
 * This class allows for easy calculation of bytes per second to these three
 * parametes while respecting some bounds:
 *
 *

 *
Minimum interval: The interval must not be shorter than
 * {@link #MIN_INTERVAL_NS} nanoseconds to avoid overhead by CPU usage.

 *
Maximum interval: An upper bound must not be exceeded for the tick
 * interval, {@link #MAX_INTERVAL_NS} ns.

 *

 *
 * The error generated by this class is influenced by the scale used in
 * calculations (see {@link #SCALE}) is tested by
 * RateCalculatorTest (in test sources).
 *
 */
public class RateCalculator {

   private RateCalculator() {}

   /**
    * The minimum byte rate representable with our data model (this is not
    * necessarily the exact minimum value, but a value close enough to the
    * minimum lower bound.
    */
   public static final float MIN_RATE = 7.6E-10F;

   /**
    * The highest byte rate representable with our data model (this is not
    * necessarily the exact maximum value, but a value close enough to the
    * maximum upper bound.
    */
   public static final float MAX_RATE = 8.7E+13F;

   /**
    * Nanoseconds per second.
    */
   public static final int NS_PER_S = 1000000000;

   /**
    * The default enforced lower bound for the interval. Intervals lower than
    * this might not be reliably possible on some hardware.
    */
   public static final int MIN_INTERVAL_NS = 100;

   /**
    * The enforced upper bound for the interval. Rates requiring a higher
    * interval will be forced to be realized use prescaling.
    */
   public static final int MAX_INTERVAL_NS = NS_PER_S;

   /**
    * The enforced upper bound for bytes per tick. Higher values result in a
    * bigger buffer and higher memory usage.
    */
   public static final int MAX_BYTES_PER_TICK = 10 * 1024 * 1024;

   /**
    * The scale (see {@link BigDecimal}) used for internal calculations.
    */
   public static final int SCALE = 70;

   /**
    * The rounding mode (see {@link BigDecimal}) used for internal calculation.
    */
   public static final RoundingMode ROUND = RoundingMode.HALF_UP;

   /**
    * The error margin permitted for calculations.
    */
   public static final double MAX_ERROR = 0.005;

   /**
    * Performs a calculation with the default minimal interval (see
    * {@link #MIN_INTERVAL_NS}). See {@link RateCalculator} for details.
    *
    * @param rateBytesPerSecond
    *           The rate in bytes per second to target
    * @return the calculation result
    */
   public static Result calculate(float rateBytesPerSecond) {
      return calculate(rateBytesPerSecond, MIN_INTERVAL_NS);
   }

   /**
    * Performs a calculation with the given minimal interval. See
    * {@link RateCalculator} for details.
    *
    * @param rateBytesPerSecond
    *           The rate in bytes per second to target
    * @param minInterval
    *           The minimal interval in nanoseconds.
    * @return the calculation result
    */
   public static Result calculate(float rateBytesPerSecond, int minInterval) {
      BigDecimal B_MIN = BigDecimal.ONE;
      BigDecimal B_MAX = BigDecimal.valueOf(MAX_BYTES_PER_TICK);
      BigDecimal I_MIN = BigDecimal.valueOf(minInterval);
      BigDecimal I_MAX = BigDecimal.valueOf(MAX_INTERVAL_NS);
      BigDecimal Id_MAX = BigDecimal.valueOf(Integer.MAX_VALUE);

      BigDecimal ONEG = BigDecimal.valueOf(NS_PER_S);
      BigDecimal TWO = BigDecimal.valueOf(2);
      BigDecimal E = BigDecimal.valueOf(Math.E);

      BigDecimal R = BigDecimal.valueOf(rateBytesPerSecond).divide(ONEG, SCALE, ROUND);
      BigDecimal I = I_MAX;

      BigDecimal B = R.multiply(I);

      BigDecimal ERROR;
      BigDecimal ERROR_MAX = BigDecimal.valueOf(MAX_ERROR);

      BigDecimal R_set = BigDecimal.valueOf(rateBytesPerSecond).divide(ONEG, SCALE, ROUND);
      BigDecimal R_eff;

      // bytes per I_MAX <= 1
      if (B.compareTo(B_MIN) <= 0) {
         B = BigDecimal.ONE;
         I = B.divide(R, SCALE, ROUND);

         BigDecimal Id = BigDecimal.ONE;
         while (true) {
            while (I.compareTo(I_MAX) > 0) {
               I = I.divide(E, SCALE, ROUND);
               Id = Id.multiply(E);
            }

            if (Id.compareTo(Id_MAX) > 0)
               throw new IllegalArgumentException("rate too low (" + rateBytesPerSecond + "): prescaler too high");

            BigDecimal B_int = BigDecimal.valueOf(B.setScale(0, ROUND).intValueExact());
            BigDecimal I_int = BigDecimal.valueOf(I.setScale(0, ROUND).intValueExact());
            BigDecimal Id_int = BigDecimal.valueOf(Id.setScale(0, ROUND).intValueExact());

            R_eff = B_int.divide(I_int, SCALE, ROUND).divide(Id_int, SCALE, ROUND);
            ERROR = R_eff.divide(R_set, SCALE, ROUND).subtract(BigDecimal.ONE).abs();
            if (ERROR.compareTo(ERROR_MAX) < 0)
               break;

            I = I.multiply(E);
            B = B.multiply(E);
         }

         return new Result(B.setScale(0, ROUND).intValueExact(), Id.setScale(0, ROUND).intValueExact(), I.setScale(0, ROUND).intValueExact());
      } else {
         BigDecimal Id = BigDecimal.ONE;

         while (true) {
            while (I.compareTo(I_MAX) > 0) {
               I = I.divide(E, SCALE, ROUND);
               Id = Id.multiply(E);
            }

            while (B.compareTo(B_MAX) > 0) {
               B = B.divide(TWO, SCALE, ROUND);
               I = I.divide(TWO, SCALE, ROUND);
            }

            if (I.compareTo(BigDecimal.ONE) < 0)
               throw new IllegalArgumentException("rate too high (" + rateBytesPerSecond + "): interval too low");

            BigDecimal B_int = BigDecimal.valueOf(B.setScale(0, ROUND).intValueExact());
            BigDecimal I_int = BigDecimal.valueOf(I.setScale(0, ROUND).intValueExact());
            BigDecimal Id_int = BigDecimal.valueOf(Id.setScale(0, ROUND).intValueExact());

            R_eff = B_int.divide(I_int, SCALE, ROUND).divide(Id_int, SCALE, ROUND);
            ERROR = R_eff.divide(R_set, SCALE, ROUND).subtract(BigDecimal.ONE).abs();
            if (ERROR.compareTo(ERROR_MAX) < 0)
               break;

            I = I.multiply(E);
            B = B.multiply(E);
         }

         if (I.compareTo(I_MIN) < 0)
            throw new IllegalArgumentException("rate too high (" + rateBytesPerSecond + "): interval too low");

         return new Result(B.setScale(0, ROUND).intValueExact(), Id.setScale(0, ROUND).intValueExact(), I.setScale(0, ROUND).intValueExact());
      }
   }

   public static class Result {
      private final int bytesPerTick;
      private final int prescale;
      private final int tickNanosecondInterval;

      public Result(int bytesPerTick, int prescale, int tickNanosecondInterval) {
         this.bytesPerTick = bytesPerTick;
         this.prescale = prescale;
         this.tickNanosecondInterval = tickNanosecondInterval;
      }

      public int getBytesPerTick() {
         return bytesPerTick;
      }

      public int getPrescale() {
         return prescale;
      }

      public int getTickNanosecondsInterval() {
         return tickNanosecondInterval;
      }
   }
}


package at.borkowski.spicej;

import java.io.InputStream;
import java.io.OutputStream;

import at.borkowski.spicej.streams.DelayedInputStream;
import at.borkowski.spicej.streams.RateLimitInputStream;
import at.borkowski.spicej.streams.RateLimitOutputStream;
import at.borkowski.spicej.ticks.TickSource;

/**
 * Provides helper functions for easy shaping of streams.
 */
public class Streams {
   private Streams() {}

   /**
    * Creates a byte-rate-limited {@link InputStream}. See
    * {@link RateLimitInputStream#RateLimitInputStream(InputStream, TickSource, int, int)}
    * for detailed information.
    *
    * @param base
    *           The raw (underlying) {@link InputStream}
    * @param tickSource
    *           The source of ticks
    * @param bytesPerTick
    *           (see
    *           {@link RateLimitInputStream#RateLimitInputStream(InputStream, TickSource, int, int)}
    *           )
    * @param prescale
    *           (see
    *           {@link RateLimitInputStream#RateLimitInputStream(InputStream, TickSource, int, int)}
    *           )
    * @return the resulting input stream
    */
   public static RateLimitInputStream limitRate(InputStream base, TickSource tickSource, int bytesPerTick, int prescale) {
      return new RateLimitInputStream(base, tickSource, bytesPerTick, prescale);
   }

   /**
    * Creates a byte-rate-limited {@link OutputStream}. See
    * {@link RateLimitOutputStream#RateLimitOutputStream(OutputStream, TickSource, int, int)}
    * for detailed information.
    *
    * @param base
    *           The raw (underlying) {@link OutputStream}
    * @param tickSource
    *           The source of ticks
    * @param bytesPerTick
    *           (see
    *           {@link RateLimitOutputStream#RateLimitOutputStream(OutputStream, TickSource, int, int)}
    *           )
    * @param prescaler
    *           (see
    *           {@link RateLimitOutputStream#RateLimitOutputStream(OutputStream, TickSource, int, int)}
    *           )
    * @return the resulting output stream
    */
   public static RateLimitOutputStream limitRate(OutputStream base, TickSource tickSource, int bytesPerTick, int prescaler) {
      return new RateLimitOutputStream(base, tickSource, bytesPerTick, prescaler);
   }

   /**
    * Creates a delayed {@link InputStream}. See
    * {@link DelayedInputStream#DelayedInputStream(TickSource, InputStream, long, int)}
    * for detailed information.
    *
    * @param base
    *           The raw (underlying) {@link InputStream}.
    * @param tickSource
    *           The source of ticks
    * @param delay
    *           The delay in ticks to add to the stream
    * @param bufferSize
    *           The buffer size to use (see
    *           {@link DelayedInputStream#DelayedInputStream(TickSource, InputStream, long, int)}
    *           )
    * @return the resulting input stream
    */
   public static DelayedInputStream addDelay(InputStream base, TickSource tickSource, long delay, int bufferSize) {
      return new DelayedInputStream(tickSource, base, delay, bufferSize);
   }

}


package at.borkowski.spicej.proxy;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * A stream gobbler, copying data from an {@link InputStream} to an
 * {@link OutputStream}.
 */
public class StreamGobbler implements Runnable {
   private final InputStream is;
   private final OutputStream os;

   private Thread thread;
   private Throwable t = null;
   private boolean finished = false;
   private boolean cancel = false;

   StreamGobbler(InputStream is, OutputStream os) {
      this.is = is;
      this.os = os;
   }

   public void run() {
      thread = Thread.currentThread();
      try {
         byte[] block = new byte[1024];
         while (!cancel) {
            int rd = is.read(block);
            if (rd == -1)
               break;
            os.write(block, 0, rd);
            os.flush();
         }
      } catch (Throwable t) {
         this.t = t;
      } finally {
         try {
            os.close();
         } catch (IOException ignore) {}
         try {
            is.close();
         } catch (IOException ignore) {}

         finished = true;
         synchronized (this) {
            this.notifyAll();
         }
      }
   }

   /**
    * Waits until the gobbler finished. If the gobbler encountered any
    * exception, it is thrown from this method.
    *
    * @throws Throwable
    *            if the gobbler has thrown an exception
    */
   public void waitFor() throws Throwable {
      while (!finished) {
         try {
            synchronized (this) {
               this.wait(100);
            }
         } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
         }
      }

      if (t != null)
         throw t;
   }

   /**
    * Interrupts the gobbler and closes its streams.
    */
   public void close() {
      cancel = true;
      try {
         thread.interrupt();
         waitFor();
      } catch (Throwable ignore) {}

      try {
         is.close();
      } catch (Exception ignore) {}

      try {
         os.close();
      } catch (Exception ignore) {}
   }
}


package at.borkowski.spicej.streams;

import java.io.IOException;
import java.io.OutputStream;

import at.borkowski.spicej.shapers.RateShaper;
import at.borkowski.spicej.streams.RateHelper.IdleNotify;
import at.borkowski.spicej.ticks.TickSource;

/**
 * Provides an {@link OutputStream} with a limited rate of bytes. For a
 * description of blocking mode, see {@link RateLimitInputStream}.
 */
public class RateLimitOutputStream extends OutputStream implements RateShaper {
   private final OutputStream real;

   private final RateHelper rateHelper;

   /**
    * Constructs a byte-rate-limited {@link OutputStream}. See
    * {@link RateLimitInputStream} for a description of the rate parameters
    * (byteRate and prescale).
    *
    * @param real
    *           The raw {@link OutputStream} to send to
    * @param tickSource
    *           The tick source to use
    * @param byteRate
    *           The rate in bytes per tick (before prescaler) to use
    * @param prescale
    *           The prescaler to use (see {@link RateLimitInputStream})
    */
   public RateLimitOutputStream(OutputStream real, TickSource tickSource, int byteRate, int prescale) {
      this.real = real;

      this.rateHelper = new RateHelper(tickSource, byteRate, prescale);
   }

   @Override
   public void setByteRate(int bytesPerTick) {
      rateHelper.setThingsPerTick(bytesPerTick);
   }

   @Override
   public int getByteRate() {
      return rateHelper.getThingsPerTick();
   }

   @Override
   public void write(int b) throws IOException {
      rateHelper.takeOne();
      real.write(b);
   }

   @Override
   public void write(byte[] b, int off, int len) throws IOException {
      int done = 0;
      while (done < len)
         done += realWrite(b, off + done, Math.min(len - done, rateHelper.getThingsPerTick()));
   }

   // len <= num
   private int realWrite(byte[] b, int off, int len) throws IOException {
      int lenToWrite = rateHelper.take(len);

      real.write(b, off, lenToWrite);
      return lenToWrite;
   }

   @Override
   public void write(byte[] b) throws IOException {
      write(b, 0, b.length);
   }

   @Override
   public void close() throws IOException {
      real.close();
      rateHelper.close();
   }

   @Override
   public void flush() throws IOException {
      real.flush();
   }

   void test__SetIdleNotify(IdleNotify target) {
      rateHelper.test__SetIdleNotify(target);
   }

   /**
    * Sets the non-blocking flag.
    *
    * @param nonBlocking
    *           whether the stream should be in non-blocking mode (see
    *           {@link RateLimitInputStream}).
    */
   public void setNonBlocking(boolean nonBlocking) {
      rateHelper.setNonBlocking(nonBlocking);
   }

   @Override
   public int getPrescale() {
      return rateHelper.getPrescale();
   }

   @Override
   public void setPrescale(int prescale) {
      rateHelper.setPrescale(prescale);
   }

   /**
    * Returns the underlying {@link OutputStream}.
    *
    * @return the underlying stream
    */
   public OutputStream getBaseStream() {
      return real;
   }

   /**
    * Returns the {@link TickSource} this stream uses.
    *
    * @return the used tick source
    */
   public TickSource getTickSource() {
      return rateHelper.getTickSource();
   }

}


package com.zandero.utils;

import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Stream;

/**
 * Map manipulation utils
 */
public final class MapUtils {

	private MapUtils() {
		// hide constructor
	}

	/**
	 * Merging single level aggregation maps
	 *
	 * @param stream        source to merge
	 * @param mergeFunction operation
	 * @param mapSupplier   new map supplier
	 * @param <K>           type of key
	 * @param <V>           type of value
	 * @param <M>           type of map supplier
	 * @return new merged map
	 */
	public static <K, V, M extends Map<K, V>> M merge(Stream<? extends Map<K, V>> stream,
	                                                  BinaryOperator<V> mergeFunction,
	                                                  Supplier<M> mapSupplier) {

		Assert.notNull(stream, "Missing map merge function!");
		Assert.notNull(mergeFunction, "Missing map merge function!");
		Assert.notNull(mapSupplier, "Missing map supplier!");

		return stream.collect(mapSupplier,
		                      (a, b) -> b.forEach((k, v) -> a.merge(k, v, mergeFunction)),
		                      Map::putAll);
	}

	/**
	 * Splits map to list of maps
	 * @param map to be split
	 * @param limit max number of items in splitted map
	 * @param <K> key type
	 * @param <V> value type
	 * @return list of maps
	 */
	public static <K, V> List<Map<K, V>> split(Map<K, V> map, int limit) {

		Assert.notNull(map, "Missing map!");
		Assert.isTrue(limit > 0, "Map limit must be > 0!");

		if (map.size() <= limit) {
			return Collections.singletonList(map); // nothing to do
		}

		return map.entrySet().parallelStream().collect(mapSizer(limit));
	}

	/**
	 * Collector splitting map into seperate maps
	 * @param limit max number of items in slitted map
	 * @param <K> key type
	 * @param <V> value type
	 * @return collected map with size less or equal to limit
	 */
	private static <K, V> Collector<Map.Entry<K, V>, ?, List<Map<K, V>>> mapSizer(int limit) {
		return Collector.of(ArrayList::new,
		                    (l, e) -> {
			                    if (l.isEmpty() || l.get(l.size() - 1).size() == limit) {
				                    l.add(new HashMap<>());
			                    }
			                    l.get(l.size() - 1).put(e.getKey(), e.getValue());
		                    },
		                    (l1, l2) -> {
			                    if (l1.isEmpty()) {
				                    return l2;
			                    }
			                    if (l2.isEmpty()) {
				                    return l1;
			                    }
			                    if (l1.get(l1.size() - 1).size() < limit) {
				                    Map<K, V> map = l1.get(l1.size() - 1);
				                    ListIterator<Map<K, V>> mapsIte = l2.listIterator(l2.size());
				                    while (mapsIte.hasPrevious() && map.size() < limit) {
					                    Iterator<Map.Entry<K, V>> ite = mapsIte.previous().entrySet().iterator();
					                    while (ite.hasNext() && map.size() < limit) {
						                    Map.Entry<K, V> entry = ite.next();
						                    map.put(entry.getKey(), entry.getValue());
						                    ite.remove();
					                    }
					                    if (!ite.hasNext()) {
						                    mapsIte.remove();
					                    }
				                    }
			                    }
			                    l1.addAll(l2);
			                    return l1;
		                    }
		);
	}

	/**
	 * Sorts map with comparator
	 *
	 * @param map        to be sorted
	 * @param comparator to apply
	 * @param <K>        type of key
	 * @param <V>        type of value
	 * @return sorted map (LinkedHashMap)
	 */
	public static <K, V> Map<K, V> sort(Map<K, V> map, Comparator<Map.Entry<K, V>> comparator) {

		Assert.notNull(map, "Missing map!");
		Assert.notNull(comparator, "Missing comparator!");

		List<Map.Entry<K, V>> list = new LinkedList<>(map.entrySet());
		Collections.sort(list, comparator);

		Map<K, V> result = new LinkedHashMap<>();
		for (Map.Entry<K, V> entry : list) {
			result.put(entry.getKey(), entry.getValue());
		}
		return result;
	}

	/**
	 * Returns first value in map as given by the iterator or null if empty
	 *
	 * @param map to get first value out
	 * @param <T> object type of result
	 * @return first value in map or null if null or empty
	 */
	public static <T> T firstValue(Map<String, T> map) {

		if (map == null || map.size() == 0) {
			return null;
		}

		String firstKey = map.keySet().iterator().next();
		return map.get(firstKey);
	}

	/**
	 * Compares if two maps hold the same set of keys
	 *
	 * @param mapOne first map
	 * @param mapTwo second map
	 * @param <T>    object type map is holding
	 * @return true if all keys are present in both maps, or they are both empty or null, false otherwise
	 */
	public static <T> boolean equals(Map<String, T> mapOne, Map<String, T> mapTwo) {

		return equals(mapOne, mapTwo, false);
	}

	/**
	 * Compares if two maps hold the same set of keys and same values
	 * comparison of values utilizes the equals call, so make sure equals is implemented
	 *
	 * @param mapOne        first map
	 * @param mapTwo        second map
	 * @param compareValues true to compare also values, false to compare keys only
	 * @param <T>           object type map is holding
	 * @return true if all keys are present in both maps, or they are both empty or null, false otherwise
	 */
	public static <T> boolean equals(Map<String, T> mapOne, Map<String, T> mapTwo, boolean compareValues) {

		boolean firstEmpty = mapOne == null || mapOne.isEmpty();
		boolean secondEmpty = mapTwo == null || mapTwo.isEmpty();

		if (firstEmpty && secondEmpty) {
			return true;
		}

		if (firstEmpty || secondEmpty) {
			return false;
		}

		if (mapOne.size() != mapTwo.size()) {
			return false;
		}

		// compare keys
		for (String key : mapOne.keySet()) {

			if (compareValues) {
				T valueOne = mapOne.get(key);
				T valueTwo = mapTwo.get(key);

				if (valueOne == null && valueTwo == null) {
					continue;
				}

				if (valueOne != null && valueTwo != null && valueTwo.equals(valueOne)) {
					continue;
				}

				return false;
			} else {
				if (!mapTwo.containsKey(key)) {
					return false;
				}
			}
		}

		return true;
	}
}


package com.zandero.utils;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Method parameter check helper
 * add additional checks when needed
 *
 * @author drejc (Andrej Završnik)
 */
public final class Assert {

	private Assert() { // hide constructor
	}

	/**
	 * Will always throw and IlligalArgumentException
	 * @param message fail message aka: "forgot to implement this"
	 */
	public static void always(String message) {

		throw new IllegalArgumentException(message);
	}

	/**
	 * Tests if condition is false
	 *
	 * @param test    must be false
	 * @param message to return in exception
	 * @throws IllegalArgumentException if test is true
	 */
	public static void isFalse(boolean test, String message) {

		if (test) {
			throw new IllegalArgumentException(message);
		}
	}

	/**
	 * Tests if condition is true
	 *
	 * @param test    must be ture
	 * @param message to return in exception
	 * @throws IllegalArgumentException if test is false
	 */
	public static void isTrue(boolean test, String message) {

		isFalse(!test, message);
	}

	/**
	 * Tests if object is null
	 *
	 * @param test    must be null
	 * @param message to return in exception
	 * @param <T>     object type
	 * @throws IllegalArgumentException if object != null
	 */
	public static <T> void isNull(T test, String message) {

		isTrue(test == null, message);
	}

	/**
	 * Tests if object is != null
	 *
	 * @param test    must not be null
	 * @param message to return in exception
	 * @param <T>     object type
	 * @throws IllegalArgumentException if object == null
	 */
	public static <T> void notNull(T test, String message) {

		isFalse(test == null, message);
	}

	/**
	 * Tests if String is null or empty when trimmed
	 *
	 * @param value   must be non empty string
	 * @param message to return in exception
	 * @throws IllegalArgumentException if value == null, value == "" or value.trim() == ""
	 */
	public static void notNullOrEmptyTrimmed(String value, String message) {

		isFalse(StringUtils.isNullOrEmptyTrimmed(value), message);
	}

	/**
	 * Tests if list is null or empty
	 *
	 * @param list    must be have at least one element
	 * @param message to return in exception
	 * @param <T>     object type
	 * @throws IllegalArgumentException if list == null or list.size() == 0
	 */
	public static <T> void notNullOrEmpty(Collection<T> list, String message) {

		isFalse(list == null || list.size() == 0, message);
	}

	/**
	 * Tests if list is null or empty
	 *
	 * @param set     must be have at least one element
	 * @param message to return in exception
	 * @param <T>     object type
	 * @throws IllegalArgumentException if list == null or list.size() == 0
	 */
	public static <T> void notNullOrEmpty(Set<T> set, String message) {

		isFalse(set == null || set.size() == 0, message);
	}

	/**
	 * Tests if list is null or empty
	 *
	 * @param array   must be have at least one element
	 * @param message to return in exception
	 * @param <T>     object type
	 * @throws IllegalArgumentException if list == null or list.size() == 0
	 */
	public static <T> void notNullOrEmpty(T[] array, String message) {

		isFalse(array == null || array.length == 0, message);
	}

	/**
	 * Tests if map is null or empty
	 *
	 * @param map     must be have at least one element
	 * @param message to return in exception
	 * @param <T>     object type
	 * @param <K>     value type
	 * @throws IllegalArgumentException if list == null or list.size() == 0
	 */
	public static <T, K> void notNullOrEmpty(Map<T, K> map, String message) {

		isFalse(map == null || map.size() == 0, message);
	}

	/**
	 * Tests if list is null or empty
	 *
	 * @param list    must be null or empty
	 * @param message to return in exception
	 * @param <T>     object type
	 * @throws IllegalArgumentException if list != null or list.size() greater than 0
	 */
	public static <T> void isNullOrEmpty(List<T> list, String message) {

		isTrue(list == null || list.size() == 0, message);
	}

	/**
	 * Tests if set is null or empty
	 *
	 * @param set     must be null or empty
	 * @param message to return in exception
	 * @param <T>     object type
	 * @throws IllegalArgumentException if list != null or list.size() greater than 0
	 */
	public static <T> void isNullOrEmpty(Set<T> set, String message) {

		isTrue(set == null || set.size() == 0, message);
	}

	/**
	 * Tests if array is null or empty
	 *
	 * @param array   must be null or empty
	 * @param message to return in exception
	 * @param <T>     object type
	 * @throws IllegalArgumentException if list != null or list.size() greater than 0
	 */
	public static <T> void isNullOrEmpty(T[] array, String message) {

		isTrue(array == null || array.length == 0, message);
	}

	/**
	 * Tests if map is null or empty
	 *
	 * @param map     must be null or empty
	 * @param message to return in exception
	 * @param <T>     object type
	 * @param <K>     value type
	 * @throws IllegalArgumentException if list != null or list.size() greater than 0
	 */
	public static <T, K> void isNullOrEmpty(Map<T, K> map, String message) {

		isTrue(map == null || map.size() == 0, message);
	}
}


package com.zandero.utils;

import java.io.*;
import java.net.URL;
import java.util.LinkedHashSet;
import java.util.Scanner;
import java.util.Set;

/**
 * Utility class to read resources
 */
public final class ResourceUtils {

	private static final int BUFFER_SIZE = 100_000;

	private static final String UTF_8 = "UTF-8";

	private ResourceUtils() {
		// hide constructor
	}

	/**
	 * Loads class resource to String
	 *
	 * @param resourceFile to read
	 * @param clazz        to use for resource access
	 * @return String representing the resource or null if resource could not be read
	 */
	@Deprecated
	public static String getResourceAsString(String resourceFile, Class clazz) {

		Assert.notNullOrEmptyTrimmed(resourceFile, "Missing resource file!");

		Scanner scanner = null;

		try {
			InputStream resource = clazz.getResourceAsStream(resourceFile);
			scanner = new Scanner(resource, UTF_8);
			return scanner.useDelimiter("\\A").next();
		}
		catch (Exception e) {
			return null;
		}
		finally {
			if (scanner != null) {
				scanner.close();
			}
		}
	}

	public static String getResourceAsString(String resourceFile) {

		return getResourceAsString(resourceFile, ResourceUtils.class);
	}

	public InputStream getResourceAsStream(String resource) {
		return ResourceUtils.class.getResourceAsStream(resource);
	}

	/**
	 * Loads resource as a set of Strings, where each word is added to the set
	 *
	 * @param resourceFile to read
	 * @param clazz        to use for resource access
	 * @return set of strings (lines) or null if resource could not be read
	 */
	public static Set<String> getResourceWords(String resourceFile, Class clazz) {

		Assert.notNullOrEmptyTrimmed(resourceFile, "Missing resource file!");

		Scanner scanner = null;

		try {
			InputStream resource = clazz.getResourceAsStream(resourceFile);
			scanner = new Scanner(resource, UTF_8);

			Set<String> list = new LinkedHashSet<>();
			while (scanner.hasNext()) {
				String next = scanner.next();
				if (next != null && next.trim().length() > 0) {
					list.add(next);
				}
			}

			return list;
		}
		catch (Exception e) {
			return null;
		}
		finally {
			if (scanner != null) {
				scanner.close();
			}
		}
	}

	/**
	 * Loads resource as a set of Strings, where each word is added to the set
	 *
	 * @param resourceFile to read
	 * @return set of strings (lines) or null if resource could not be read
	 */
	public static Set<String> getResourceWords(String resourceFile) {

		return getResourceWords(resourceFile, ResourceUtils.class);
	}

	/**
	 * Get resource last modified date
	 *
	 * @param resourceFile to read
	 * @param clazz        to use for resource access
	 * @return last modified date or null if resource could not be read
	 */
	@Deprecated
	public static Long getLastModifiedTime(String resourceFile, Class clazz) {

		Assert.notNullOrEmptyTrimmed(resourceFile, "Missing resource file!");

		try {
			URL url = clazz.getResource(resourceFile);
			return url.openConnection().getLastModified(); // get last modified date of resource
		}
		catch (IOException e) {
			return null;
		}
	}

	public static Long getLastModifiedTime(String resourceFile) {
		return getLastModifiedTime(resourceFile, ResourceUtils.class);
	}

	/**
	 * Load input stream into string
	 *
	 * @param is stream
	 * @return String representation of given input
	 */
	public static String getString(final InputStream is) {

		return getString(is, UTF_8);
	}

	/**
	 * Load input stream into string
	 *
	 * @param is       stream
	 * @param encoding to use when reading input stream
	 * @return String representation of given input
	 */
	public static String getString(final InputStream is, String encoding) {

		if (is == null) {
			return null;
		}

		if (StringUtils.isNullOrEmptyTrimmed(encoding)) {
			encoding = UTF_8;
		}

		final char[] buffer = new char[BUFFER_SIZE];
		final StringBuilder out = new StringBuilder();
		try {
			try (Reader in = new InputStreamReader(is, encoding)) {
				for (; ; ) {
					int rsz = in.read(buffer, 0, buffer.length);
					if (rsz < 0) {
						break;
					}
					out.append(buffer, 0, rsz);
				}
			}
		}
		catch (IOException ioe) {
			throw new RuntimeException(ioe);
		}
		return out.toString();
	}

	/**
	 * Load input stream into byte array
	 *
	 * @param is stream
	 * @return byte representation of given input
	 */
	public static byte[] getBytes(InputStream is) {

		if (is == null) {
			return null;
		}

		ByteArrayOutputStream buffer = new ByteArrayOutputStream();

		int nRead;
		byte[] data = new byte[BUFFER_SIZE];
		try {

			while ((nRead = is.read(data, 0, data.length)) != -1) {
				buffer.write(data, 0, nRead);
			}

			buffer.flush();
		}
		catch (IOException ignored) {
		}

		return buffer.toByteArray();
	}

	/**
	 * Reads file into String
	 *
	 * @param file to be read
	 * @return file content
	 * @throws IOException in case file does't exist or is not a file
	 */
	public static String readFileToString(File file) throws IOException {

		Assert.isTrue(file.exists(), "File '" + file + "' does not exist");
		Assert.isFalse(file.isDirectory(), "File '" + file + "' is a directory");
		Assert.isTrue(file.canRead(), "File '" + file + "' cannot be read");

		FileInputStream stream = new FileInputStream(file);
		return getString(stream);
	}

	/**
	 * Gets absolute file path of resource
	 *
	 * @param resource to get absolute file path for
	 * @param clazz    namespace holding resource
	 * @return file path if found
	 * @throws IllegalArgumentException if resource can not be found
	 */
	@Deprecated
	public static String getResourceAbsolutePath(String resource, Class clazz) {

		Assert.notNullOrEmptyTrimmed(resource, "Missing resource name!");

		URL file = clazz.getResource(resource);
		Assert.notNull(file, "Resource: '" + resource + "', not found!");

		return file.getFile();
	}

	public static String getResourceAbsolutePath(String resource) {

		return getResourceAbsolutePath(resource, ResourceUtils.class);
	}
}


package com.zandero.utils;

import java.security.SecureRandom;

/**
 * Generates a random key of desired type and length
 */
public final class KeyGenerator {

	static final String NUMBERS_NO_ZERO = "123456789";

	static final String NUMBERS_NO_NINE_AND_ZERO = "12345678";

	static final String NUMBERS = "0" + NUMBERS_NO_ZERO;

	static final String ELEMENTS = NUMBERS + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

	/**
	 * Generates random string from ELEMENTS set of chars and numbers
	 *
	 * @param length desired length of key greater than 0
	 * @return random string of desired length (min 1, max 100 characters long)
	 */
	public static String generateString(int length) {

		if (length <= 0 || length > 100) {
			throw new IllegalArgumentException("Can't generate random id with length: " + length);
		}

		SecureRandom random = new SecureRandom();
		StringBuilder sb = new StringBuilder(length);
		for (int i = 0; i < length; i++) {
			sb.append(ELEMENTS.charAt(random.nextInt(ELEMENTS.length())));
		}

		return sb.toString();
	}

	/**
	 * Generates non negative long key of maximum length 18
	 *
	 * @param length desired length of key grater than 0 (must consider max possible length of a long value)
	 * @return long key (min 1, max 19 digits long)
	 */
	public static long generateLong(int length) {

		if (length <= 0 || length > 19) {
			throw new IllegalArgumentException("Can't generate random id with length: " + length);
		}

		SecureRandom random = new SecureRandom();
		StringBuilder sb = new StringBuilder(length);

		// 1st digit should  not be a 0 or 9 if desired length is 19 (as max long is: 9223372036854775807)
		if (length == 19) {
			sb.append(NUMBERS_NO_NINE_AND_ZERO.charAt(random.nextInt(NUMBERS_NO_NINE_AND_ZERO.length())));
		}
		else {
			sb.append(NUMBERS_NO_ZERO.charAt(random.nextInt(NUMBERS_NO_ZERO.length())));
		}

		// all other digits can contain a 0
		for (int i = 1; i < length; i++) {
			sb.append(NUMBERS.charAt(random.nextInt(NUMBERS.length())));
		}

		return Long.parseLong(sb.toString());
	}
}


package com.zandero.utils;

import java.lang.reflect.Array;

/**
 *
 */
public final class ArrayUtils {

	private ArrayUtils() {
		// hide constructor
	}

	/**
	 * joins two arrays and preserves array order
	 * array1 items are followed by array2 items as given
	 * @param array1 first array
	 * @param array2 second array
	 * @param <T> class type of object in arrays
	 * @return joined array holding both arrays in same order as given
	 */
	@SafeVarargs
	public static <T> T[] join(final T[] array1, final T... array2) {

		if (isEmpty(array1) && isEmpty(array2)) {
			return null;
		}

		if (isEmpty(array1)) {
			return array2;
		}

		if (isEmpty(array2)) {
			return array1;
		}

		final Class<?> type1 = array1.getClass().getComponentType();

		@SuppressWarnings("unchecked") // OK, because array is of type T
		final T[] joinedArray = (T[]) Array.newInstance(type1, array1.length + array2.length);

		int index = 0;
		for (T item : array1) {
			joinedArray[index++] = item;
		}

		for (T item : array2) {
			joinedArray[index++] = item;
		}

		return joinedArray;
	}

	private static <T> boolean isEmpty(T[] array1) {

		return array1 == null || array1.length == 0;
	}

	// TODO: implement split
}


package com.zandero.utils;

import java.util.*;

/**
 *
 */
public final class SetUtils {

	private SetUtils() {
		// hide constructor
	}

	/**
	 * Splits set in 1..N chunks of maxSize or less
	 *
	 * @param set     to be spitted
	 * @param maxSize of a given chunk
	 * @param <T>     type of class in set
	 * @return list of sets containing all elements of original set without duplicates
	 */
	public static <T> List<Set<T>> split(Set<T> set, int maxSize) {

		Assert.notNull(set, "Missing set to be split!");
		Assert.isTrue(maxSize > 0, "Max size must be > 0!");

		if (set.size() < maxSize) {
			return Collections.singletonList(set);
		}

		List<Set<T>> list = new ArrayList<>();
		Iterator<T> iterator = set.iterator();

		while (iterator.hasNext()) {
			Set<T> newSet = new HashSet<>();
			for (int j = 0; j < maxSize && iterator.hasNext(); j++) {
				T item = iterator.next();
				newSet.add(item);
			}
			list.add(newSet);
		}
		return list;
	}
}


package com.zandero.utils;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAccessor;

/**
 * Java 8 date time utils ..
 * Replacing obsolete DateTimeUtils
 */
public final class InstantTimeUtils {

	public static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd").withZone(ZoneOffset.UTC);
	public static final DateTimeFormatter SHORT_TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").withZone(ZoneOffset.UTC);
	public static final DateTimeFormatter DATE_TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss Z").withZone(ZoneOffset.UTC);

	public static final DateTimeFormatter RFC_2822_DATE_TIME_FORMAT = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss Z").withZone(ZoneOffset.UTC); // RFC-2822

	private InstantTimeUtils() {
		// hide constructor
	}

	/**
	 * Formats time to String
	 *
	 * @param time to be formatted (UTC) in milliseconds
	 * @return date time formatted to yyyy-MM-dd HH:mm:ss Z
	 */
	public static String formatDateTime(long time) {

		Instant instant = Instant.ofEpochMilli(time);
		return formatDateTime(instant);
	}

	/**
	 * Formats time to String
	 *
	 * @param time to be formatted (UTC) in milliseconds
	 * @return date time formatted to yyyy-MM-dd HH:mm:ss Z
	 */
	public static String formatDateTime(Instant time) {
		Assert.notNull(time, "Missing time!");
		return DATE_TIME_FORMAT.format(time);
	}

	/**
	 * Formats time to String
	 *
	 * @param time to be formatted (UTC) in milliseconds
	 * @return date time formatted to yyyy-MM-dd HH:mm
	 */
	public static String formatDateTimeShort(long time) {

		Instant instant = Instant.ofEpochMilli(time);
		return formatDateTimeShort(instant);
	}

	/**
	 * Formats time to String
	 *
	 * @param time to be formatted (UTC) in milliseconds
	 * @return date time formatted to yyyy-MM-dd HH:mm
	 */
	public static String formatDateTimeShort(Instant time) {

		Assert.notNull(time, "Missing time!");
		return SHORT_TIME_FORMAT.format(time);
	}

	/**
	 * Formats time to date only
	 *
	 * @param time to be formatted (UTC) in milliseconds
	 * @return date formatted yyyy-MM-dd
	 */
	public static String formatDate(long time) {

		Instant instant = Instant.ofEpochMilli(time);
		return DATE_FORMAT.format(instant);
	}

	/**
	 * Formats time to date only
	 *
	 * @param time to be formatted (UTC) in milliseconds
	 * @return date formatted yyyy-MM-dd
	 */
	public static String formatDate(Instant time) {

		Assert.notNull(time, "Missing time!");
		return DATE_FORMAT.format(time);
	}

	/**
	 * Custom date time format
	 *
	 * @param time   to be formatted
	 * @param format simple date time format, or null for default yyyy-MM-dd HH:mm:ss Z format
	 * @return formated date time
	 */
	public static String format(long time, DateTimeFormatter format) {

		return format(Instant.ofEpochMilli(time), format);
	}

	/**
	 * Custom date time format
	 *
	 * @param time   to be formatted
	 * @param format simple date time format, or null for default yyyy-MM-dd HH:mm:ss Z format
	 * @return formated date time
	 */
	public static String format(Instant time, DateTimeFormatter format) {

		if (format == null) {
			return formatDateTime(time);
		}

		Assert.notNull(time, "Missing time!");
		return format.format(time);
	}

	/**
	 * Convert any given timestamp string to long
	 * Note that in case conversion fails to produce a result a 0 timestamp is returned!
	 *
	 * @param value   to be converted
	 * @param formats list of formats to try out
	 * @return time stamp or 0 if conversion failed
	 */
	public static Instant getTimestamp(String value, DateTimeFormatter... formats) {

		Assert.notNull(formats, "Missing date time formats");
		Assert.isTrue(formats.length > 0, "Missing date time formats");

		if (StringUtils.isNullOrEmptyTrimmed(value)) {
			return null;
		}

		// OK check if we have 6 digit milliseconds ... if so truncate
		if (value.matches(".*\\.\\d{6}.*")) {
			// remove 3 milliseconds places
			int index = value.indexOf(".");
			value = value.substring(0, index + 4) + value.substring(index + 7);
		}

		// Go over all formats ... and if success return value
		for (DateTimeFormatter format : formats) {

			try {
				TemporalAccessor date = format.parse(value);
				return Instant.from(date);
			}
			catch (DateTimeParseException e) {
				// try next one ...
			}
		}

		return null;
	}

	/**
	 * Converts timestamp into OffsetDatetime
	 *
	 * @param timestamp to be converted
	 * @param zoneId    desired zone or null to take instant zone id
	 * @return OffsetDatetime representation of timestamp
	 */
	public static OffsetDateTime toOffsetDateTime(long timestamp, ZoneId zoneId) {

		Instant time = Instant.ofEpochMilli(timestamp);
		return toOffsetDateTime(time, zoneId);
	}

	/**
	 * Converts timestamp into OffsetDatetime
	 *
	 * @param time   to be converted
	 * @param zoneId desired zone or null to take instant zone id
	 * @return OffsetDatetime representation of timestamp
	 */
	public static OffsetDateTime toOffsetDateTime(Instant time, ZoneId zoneId) {

		Assert.notNull(time, "Missing time!");
		if (zoneId == null) {
			zoneId = ZoneId.from(time);
		}
		return OffsetDateTime.ofInstant(time, zoneId);
	}

	/**
	 * Converts offset date time to long timestamp
	 *
	 * @param timestamp to be converted
	 * @return time stamp in milliseconds
	 */
	public static long fromOffsetToMilliseconds(OffsetDateTime timestamp) {

		Assert.notNull(timestamp, "Missing offset time stamp!");
		return timestamp.toInstant().toEpochMilli();
	}

	/**
	 * Converts offset date time to long timestamp
	 *
	 * @param timestamp to be converted
	 * @return time stamp in milliseconds
	 */
	public static Instant fromOffsetToInstant(OffsetDateTime timestamp) {

		Assert.notNull(timestamp, "Missing offset time stamp!");
		return timestamp.toInstant();
	}

	/**
	 * Gets first millisecond of first day in month
	 *
	 * @param time to get first millisecond
	 * @return first millisecond of month for given time
	 */
	public static Instant getMonthStart(Instant time) {

		Assert.notNull(time, "Missing date time");
		LocalDateTime dateTime = LocalDateTime.ofInstant(time, ZoneOffset.UTC);
		dateTime = dateTime.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).with(ChronoField.MILLI_OF_SECOND, 0);
		return dateTime.toInstant(ZoneOffset.UTC);
	}

	/**
	 * Returns last millisecond of last day in month ... +1 = next first day in month
	 *
	 * @param time to get last second in month
	 * @return last millisecond of month for given time
	 */
	public static Instant getMonthEnd(Instant time) {

		Assert.notNull(time, "Missing date time");
		LocalDateTime dateTime = LocalDateTime.ofInstant(time, ZoneOffset.UTC);
		dateTime = dateTime.withDayOfMonth(1).withHour(23).withMinute(59).withSecond(59).with(ChronoField.MILLI_OF_SECOND, 999);
		dateTime = dateTime.plus(1, ChronoUnit.MONTHS).minus(1, ChronoUnit.DAYS);
		return dateTime.toInstant(ZoneOffset.UTC);
	}

	/**
	 * Check is time periods overlap
	 *
	 * @param startOne start time of first period / null for full
	 * @param endOne   end tme of first period / null for full
	 * @param startTwo start time of second period / null for full
	 * @param endTwo   end time of second period / null for full
	 * @return true if periods overlap, false if they don't
	 * @throws IllegalArgumentException in case start time is after end time of first/second period
	 */
	public static boolean overlaps(Instant startOne, Instant endOne, Instant startTwo, Instant endTwo) {

		// (StartDate1 <= EndDate2) and (StartDate2 <= EndDate1)
		Instant startDate1 = startOne == null ? Instant.MIN : startOne;
		Instant endDate1 = endOne == null ? Instant.MAX : endOne;
		Assert.isTrue(startDate1.isBefore(endDate1), "Start date one can't be after end date one!");

		Instant startDate2 = startTwo == null ? Instant.MIN : startTwo;
		Instant endDate2 = endTwo == null ? Instant.MAX : endTwo;
		Assert.isTrue(startDate2.isBefore(endDate2), "Start date two can't be after end date two!");

		return startDate1.compareTo(endDate2) <= 0 && startDate2.compareTo(endDate1) <= 0;
	}
}