/* Title: WeeBank
* Author: John P. Spurgeon
* Director's cut: 15 April 2018
* Available at: http://scribbledecobble.blogspot.com/2018/04/wee-bank.html
*
* EXCLAIMER
*
* The names, algorithms, and comments below are the products of the author's memory and
* imagination or are the result of reading books or surfing the internet. Any resemblance
* to actual persons, living or dead, or actual events might be an allusion. No drugs
* (other than caffeine and maybe one or two BEAK BREAKER/BENDERS) were used during the
* production of this program.
*/
// PART 0. IN A GALAXY FAR, FAR AWAY...
// With a little help from our friends
import java.util.Collections;
import java.util.Comparator;
import java.util.Stack;
import java.util.List;
import java.util.LinkedList;
import java.util.ArrayList;
// PART 1. INTRODUCING...
/******************/
/* Insertion Sort */
/******************/
final class InsertionSort
{
// Exercise: Write insertIntoMultiset.
public static <E> boolean insertIntoSet(E element, List<E> sortedSet, Comparator<E> cmp)
{
final int n = sortedSet.size();
int i = 0;
while (i < n)
{
int result = cmp.compare(sortedSet.get(i), element);
if (result == 0) return false;
else if (result > 0) break;
else i++;
}
sortedSet.add(i, element);
return true;
}
}
/*****************/
/* Binary Search */
/*****************/
interface Fun<X, Y>
{
Y apply(X element);
}
/* "Extra, Extra - Read All About It: Nearly All Binary Searches and Mergesorts are Broken"
*
* Posted by Joshua Bloch on Friday, June 02, 2006 at
* https://research.googleblog.com/2006/06/extra-extra-read-all-about-it-nearly.html
*/
final class BinarySearch
{
/* Ponder These:
*
* - When might a simple linear search be better? (What about the size of the list?)
* - What values of the so-called sortedSet parameter could cause this method to fail?
* - What type of List<E> object would you definitely not want to pass to this method?
*/
public static <E, V>
int getIndex(V value, List<E> sortedSet, Fun<E, V> f, Comparator<V> cmp)
{
int i, lower = 0, upper = sortedSet.size() - 1;
while (upper >= lower)
{
i = lower + ((upper - lower) / 2); // Ponder This: Why not (upper + lower) / 2 ?
E element = sortedSet.get(i);
int result = cmp.compare(value, f.apply(element));
if (result == 0) return i;
else if (result < 0) upper = i - 1;
else lower = i + 1;
}
return -1;
}
public static <E, V extends Comparable<V>>
int getIndex(V value, List<E> sortedSet, Fun<E, V> f)
{
Comparator<V> cmp = (V v1, V v2) -> v1.compareTo(v2);
return getIndex(value, sortedSet, f, cmp);
}
}
// PART 2. TWIN SISTERS PICTURES (a virtual company) PRESENTS...
/*******************************/
/* WeeBank: A New Feature Film */
/*******************************/
public class WeeBank // Our motto is too small to matter.
{
public static void main(String[] args)
{
final int n = args.length;
final int numHolders = n == 2 ? Integer.parseInt(args[0]) : 16;
final int numTransactions = n == 2 ? Integer.parseInt(args[1]) : 1024;
final CommandProcessingUnit cpu = new CommandProcessingUnit();
final String[] lines = (n == 0 || n == 2) ?
Writer.getScript(numHolders, numTransactions) : args;
for (String line : lines) // Action!
{
BackupAcct backupAcct = null;
switch(line)
{
case Keywords.CREATE_BANK:
cpu.createBank();
break;
case Keywords.OPEN_EXPOSED_CHECKING:
backupAcct = cpu.openExposedCheckingAcct();
cpu.setBackupAcct(backupAcct);
break;
case Keywords.OPEN_PROTECTED_CHECKING:
cpu.openProtectedCheckingAcct();
cpu.setBackupAcct(null);
break;
case Keywords.OPEN_SAVINGS:
backupAcct = cpu.openSavingsAcct();
cpu.setBackupAcct(backupAcct);
break;
case Keywords.DEPOSIT:
cpu.makeDeposit();
break;
case Keywords.WITHDRAW:
cpu.makeWithdrawal();
break;
default:
cpu.pushString(line);
break;
}
}
Banks.display(); // screening
}
}
// PART 3. STARING...
/*******************************************************************/
/* Banks (the personhood, not the famous metropolis) */
/* See also: https://en.wikipedia.org/wiki/Citizens_United_v._FEC */
/*******************************************************************/
/* We are uncovering better ways of profiting
* by doing it and sabotaging others who do it.
* Through this work we have come to value:
*
* Automated processes and tools over life
* Share holders over account holders
* Executives over managers over customers
* Collecting fees over paying interest
*
* That is, while the items on the right are necessary,
* the items on the left are to die for.
*
* (Not signed or said by dead board misdirectors.)
*/
final class Banks
{
public static final BankComparator bankComparator = new BankComparator();
private static final ArrayList<Bank> sortedBankSet = new ArrayList<Bank>();
public static Bank getBank(Integer routingNum)
{
Fun<Bank, Integer> f = (Bank b) -> (Integer)b.getRoutingNum();
final int i = BinarySearch.getIndex(routingNum, sortedBankSet, f);
if (i < 0) Error.illegalArg("Bad routing number.");
return sortedBankSet.get(i);
}
public static boolean createBank(int routingNum, String bankName)
{
Bank bank = new Bank(routingNum, bankName);
return InsertionSort.insertIntoSet(bank, sortedBankSet, Banks.bankComparator);
}
public static void display()
{
for (Bank bank : sortedBankSet) System.out.println(bank);
}
}
final class Bank
{
/* See: https://en.wikipedia.org/wiki/ABA_routing_transit_number
* See also: https://en.wikipedia.org/wiki/Knuth_reward_check
*/
private final int routingNum;
private final String bankName;
private final List<Account> sortedAcctSet = new ArrayList<Account>();
private final List<Holder> sortedHolderSet = new ArrayList<Holder>();
private final CustomerService customerService;
private final BankManager manager;
public Bank(int routingNum, String bankName)
{
this.bankName = bankName;
this.routingNum = routingNum;
this.customerService = new CustomerService(sortedHolderSet);
this.manager = new BankManager(this, customerService, sortedAcctSet);
}
public final BankManager getManager()
{
return manager;
}
public final int getRoutingNum()
{
return routingNum;
}
public final String getBankName()
{
return bankName;
}
public final boolean equals(Object that)
{
// System.out.println("Comparing " + this.toString() + " and " + that.toString());
if (that == null) return false;
if (!Bank.class.isAssignableFrom(that.getClass())) return false;
final Bank other = (Bank) that;
return this.routingNum == other.routingNum;
}
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("Bank: " + bankName + "\n");
sb.append("Routing number: " + routingNum + "\n");
for (Account acct : sortedAcctSet) sb.append(acct.toString());
return sb.toString();
}
}
final class BankManager
{
private final Bank bank;
private final CustomerService customerService;
private final List<Account> sortedAcctSet;
public BankManager(Bank bank, CustomerService customerService, List<Account> accounts)
{
this.bank = bank;
this.customerService = customerService;
sortedAcctSet = accounts;
}
public final ExposedCheckingAcct
openExposedCheckingAcct(int acctNum, String holderId)
{
Holder holder = customerService.getOrCreateHolder(holderId);
ExposedCheckingAcct acct = new ExposedCheckingAcct(bank, acctNum, holder);
return addAccount(acct, holder) ? acct : null;
}
public final ProtectedCheckingAcct
openProtectedCheckingAcct(int acctNum, String holderId, BackupAcct backup)
{
Holder holder = customerService.getOrCreateHolder(holderId);
ProtectedCheckingAcct acct = new ProtectedCheckingAcct(bank, acctNum, holder, backup);
return addAccount(acct, holder) ? acct : null;
}
public final SavingsAcct
openSavingsAcct(int acctNum, String holderId)
{
Holder holder = customerService.getOrCreateHolder(holderId);
SavingsAcct acct = new SavingsAcct(bank, acctNum, holder);
return addAccount(acct, holder) ? acct : null;
}
public final Account getAccount(Integer acctNum)
{
Fun<Account, Integer> f = (Account a) -> (Integer)a.getAcctNum();
final int i = BinarySearch.getIndex(acctNum, sortedAcctSet, f);
if (i < 0) Error.illegalArg("Bad account number.");
return sortedAcctSet.get(i);
}
private final boolean addAccount(Account acct, Holder holder)
{
if (InsertionSort.insertIntoSet(acct, sortedAcctSet, Accounts.acctComparator))
{
customerService.addHolder(holder);
holder.addAccount(acct);
return true;
}
return false;
}
}
final class CustomerService
{
private final List<Holder> sortedHolderSet;
public CustomerService(List<Holder> holders)
{
sortedHolderSet = holders;
}
public final int getHolderIndex(String holderId)
{
Fun<Holder, String> f = (Holder h) -> h.getId();
return BinarySearch.getIndex(holderId, sortedHolderSet, f);
}
public final boolean addHolder(Holder holder)
{
if (getHolderIndex(holder.getId()) >= 0) return false;
return InsertionSort.insertIntoSet(holder, sortedHolderSet, Holders.holderIdComparator);
}
public final Holder getOrCreateHolder(String holderId)
{
final int i = getHolderIndex(holderId);
return i < 0 ? new Holder(holderId) : sortedHolderSet.get(i);
}
}
// PART 4. AND STARING...
/************/
/* Accounts */
/************/
/* Entourage */
class Accounts
{
public static final Comparator<Account>
acctComparator = new AcctComparator(),
/* For future use... */
acctBalanceComparator = new AcctBalanceComparator(),
reverseAcctBalanceComparator = Collections.reverseOrder(acctBalanceComparator);
}
/** Something (an account) that may be overdrawn and can thereby incur fees. */
interface Overdraftable // This is risky business.
{
int getOverdraftCount();
}
/** An account that may be used for so-called overdraft protection. */
interface BackupAcct // Be sure to charge for this.
{
int getAcctNum();
int getRoutingNum();
boolean hasSufficientFunds(int requestedCents);
boolean withdraw(int cents);
}
/* Leading Actor */
abstract class Account
{
private Holder holder;
private int acctNum;
private int balance;
private Bank bank;
protected Account(Bank bank, int acctNum, Holder holder)
{
if (bank == null) Error.illegalArg("bank cannot be null");
if (holder == null) Error.illegalArg("holder cannot be null");
if (acctNum < 0) Error.illegalArg("account number cannot be negative");
this.bank = bank;
this.acctNum = acctNum;
this.holder = holder;
}
public abstract double getInterestRate();
public Holder getHolder() { return holder; }
public final int getAcctNum() { return acctNum; }
public final int getRoutingNum() { return bank.getRoutingNum(); }
public final int getBalance() { return balance; }
public final boolean hasSufficientFunds(int requestedCents)
{
return balance >= requestedCents;
}
public final void deposit(int cents)
{
if (cents <= 0) Error.illegalArg("Cents must be greater than zero.");
int newBalance = balance + cents;
if (newBalance <= balance) Error.overflow();
balance = newBalance;
}
public boolean withdraw(int cents)
{
if (cents <= 0) Error.illegalArg("Cents must be greater than zero.");
int newBalance = balance - cents;
if (newBalance >= balance) Error.overflow();
balance = newBalance;
return true;
}
public final boolean equals(Object that)
{
// System.out.println("Comparing " + this.toString() + " and " + that.toString());
if (that == null) return false;
if (!Account.class.isAssignableFrom(that.getClass())) return false;
final Account other = (Account) that;
return this.bank.equals(other.bank) && this.acctNum == other.getAcctNum();
}
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("\n" + Strings.TAB + "Account #: " + acctNum);
sb.append("\n" + Strings.TAB + "Account holder: " + holder.getId());
sb.append("\n" + Strings.TAB + "Balance: " + (balance/100.0) + "\n");
return sb.toString();
}
}
/* Account Understudies: Checking Accounts */
abstract class CheckingAcct extends Account implements Overdraftable
{
private int overdraftCount = 0;
protected CheckingAcct(Bank bank, int acctNum, Holder holder)
{
super(bank, acctNum, holder);
}
public final double getInterestRate() { return 0.005; }
public final int getOverdraftCount() { return overdraftCount; }
public boolean withdraw(int cents)
{
boolean succeeded = super.withdraw(cents);
if (succeeded && getBalance() < 0)
{
if (++overdraftCount < 0) Error.overflow();
}
return succeeded;
}
public String toString()
{
return super.toString() + Strings.TAB +
"Overdraft count: " + overdraftCount + "\n";
}
}
final class ExposedCheckingAcct extends CheckingAcct implements BackupAcct
{
public ExposedCheckingAcct(Bank bank, int acctNum, Holder holder)
{
super(bank, acctNum, holder);
}
public final boolean withdraw(int cents)
{
return super.withdraw(cents); // Ponder This: Why bother with this?
}
public String toString()
{
return "\n" + Strings.TAB + "Checking Account" + super.toString();
}
}
final class ProtectedCheckingAcct extends CheckingAcct
{
private final BackupAcct backup; // provides overdraft protection
public ProtectedCheckingAcct(Bank bank, int acctNum, Holder holder, BackupAcct backup)
{
super(bank, acctNum, holder);
if (backup == null) Error.illegalArg("backup cannot be null");
this.backup = backup;
}
public final boolean withdraw(int cents)
{
tryToEnsureSufficientFunds(cents);
return super.withdraw(cents);
}
private final void tryToEnsureSufficientFunds(int requestedCents)
{
final int balance = getBalance();
if (requestedCents > balance)
{
final int deficit = requestedCents - balance;
if (backup.hasSufficientFunds(deficit) && backup.withdraw(deficit))
deposit(deficit);
}
}
public String toString()
{
return "\n" + Strings.TAB + "Checking Account" + super.toString() + Strings.TAB +
"Protected by: " +
backup.getAcctNum() + "\n";
}
}
/* Account Understudies: Savings Account */
final class SavingsAcct extends Account implements BackupAcct
{
public SavingsAcct(Bank bank, int acctNum, Holder holder)
{
super(bank, acctNum, holder);
}
public final double getInterestRate() { return 0.015; }
public final boolean withdraw(int cents)
{
if (!hasSufficientFunds(cents)) return false;
return super.withdraw(cents);
}
public String toString()
{
return "\n" + Strings.TAB + "Savings Account" + super.toString();
}
}
// PART 5. SUPPORTING CHARACTERS...
/*******************/
/* Account Holders */
/*******************/
/* Holders are just extras. They don't do much. */
final class Holders
{
public static Comparator<Holder> holderIdComparator = new HolderIdComparator();
}
class Holder
{
private String holderId;
private List<Account> sortedAcctSet = new LinkedList<Account>();
public Holder(String holderId)
{
if (holderId == null) Error.illegalArg("holder id cannot be null");
if (holderId.length() == 0) Error.illegalArg("holder id length cannot be zero");
this.holderId = holderId;
}
public final boolean addAccount(Account acct)
{
if (acct == null) Error.illegalArg("account cannot be null");
return InsertionSort.insertIntoSet(acct, sortedAcctSet, Accounts.acctComparator);
}
public final String getId() { return holderId; }
}
// PART 6. ROLL CREDITS...
/*******/
/* CPU */
/*******/
/* A gaffer in the motion picture industry and on a television crew is the head electrician,
* responsible for the execution (and sometimes the design) of...
*
* https://en.wikipedia.org/wiki/Gaffer_(filmmaking)
*/
final class CommandProcessingUnit
{
private Stack<String> argStack = new Stack<String>();
private BackupAcct backupAcct;
private int popInt() { return Integer.parseInt(argStack.pop()); }
private String popString() { return argStack.pop(); }
public void pushString(String s) { argStack.push(s); }
public void setBackupAcct(BackupAcct acct) { backupAcct = acct; }
public void createBank()
{
int routingNum = popInt();
String bankName = popString();
Banks.createBank(routingNum, bankName);
}
public BackupAcct openExposedCheckingAcct()
{
int acctNum = popInt();
int routingNum = popInt();
String holderId = popString();
Bank bank = Banks.getBank(routingNum);
return bank.getManager().openExposedCheckingAcct(acctNum, holderId);
}
public void openProtectedCheckingAcct()
{
int acctNum = popInt();
int routingNum = popInt();
String holderId = popString();
Bank bank = Banks.getBank(routingNum);
bank.getManager().openProtectedCheckingAcct(acctNum, holderId, backupAcct);
}
public BackupAcct openSavingsAcct()
{
int acctNum = popInt();
int routingNum = popInt();
String holderId = popString();
Bank bank = Banks.getBank(routingNum);
return bank.getManager().openSavingsAcct(acctNum, holderId);
}
public void makeDeposit()
{
int cents = popInt();
int acctNum = popInt();
int routingNum = popInt();
Bank bank = Banks.getBank(routingNum);
Account acct = bank.getManager().getAccount(acctNum);
acct.deposit(cents);
}
public void makeWithdrawal()
{
int cents = popInt();
int acctNum = popInt();
int routingNum = popInt();
Bank bank = Banks.getBank(routingNum);
Account acct = bank.getManager().getAccount(acctNum);
acct.withdraw(cents);
}
}
/***************/
/* Comparators */
/***************/
/* After the attachment phase is complete..., the physical auditions begin for all of the
* remaining roles. During this time, depending on the budget of the film, they could have
* what is called "pre-screens" where you audition only for a casting director (or associate)
* to see if the actor is right for the material.... The resulting list of actors who were
* selected to play a character for a production, is called a cast list ... A key intern will
* work with many busy casting directors sorting mail, ..., help[ing] actors sign in, and
* keep[ing] the flow of talent going in and out of the casting room as smooth[ly] as possible.
*
* https://en.wikipedia.org/wiki/Casting_(performing_arts)
*/
final class HolderIdComparator implements Comparator<Holder>
{
public int compare(Holder h1, Holder h2)
{
return h1.getId().compareTo(h2.getId());
}
}
final class BankComparator implements Comparator<Bank>
{
public int compare(Bank b1, Bank b2)
{
return Integer.compare(b1.getRoutingNum(), b2.getRoutingNum());
}
}
final class AcctComparator implements Comparator<Account>
{
public int compare(Account a1, Account a2)
{
int result = Integer.compare(a1.getRoutingNum(), a2.getRoutingNum());
if (result == 0)
{
result = Integer.compare(a1.getAcctNum(), a2.getAcctNum());
}
return result;
}
}
final class AcctBalanceComparator implements Comparator<Account>
{
public int compare(Account a1, Account a2)
{
return Integer.compare(a1.getBalance(), a2.getBalance());
}
}
/*******************/
/* Bits and Pieces */
/*******************/
/* Scenic Designers */
final class Keywords
{
public static final String
CREATE_BANK = "create_bank",
DEPOSIT = "deposit",
OPEN_EXPOSED_CHECKING = "open_exposed_checking",
OPEN_PROTECTED_CHECKING = "open_protected_checking",
OPEN_SAVINGS = "open_savings",
WITHDRAW = "withdraw";
}
final class Strings
{
public static final String SEP = ","; // separator
public static final String TAB = " ";
public static final String[] POS_DIGITS = {
"1", "2", "3", "4", "5", "6", "7", "8", "9"
};
public static final String[] TEN_DIGITS = {
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
};
public static final String[] FIRST_NAMES = {
"Alan", "Barbara", "Bob", "David", "Don", "Fran", "John", "Judea",
"Juris", "Ken", "Leslie", "Martin", "Marvin", "Niklaus",
"Tony", "Whitfield"
};
public static final String[] LAST_NAMES = {
"Allen", "Diffie", "Floyd", "Hartmanis", "Hellman", "Hennessy",
"Hoare", "Knuth", "Lamport", "Liskov", "Minsky", "Patterson",
"Pearl", "Perlis", "Thompson", "Wirth"
};
public static final String[] BANK_NAMES = {
"DoA", "MoMoneyChaser", "WellGoFar", "UrbanCollection", "MenNGoldNBags"
};
public static final String[] ROUTING_NUMBERS = {
"503087512", "908170897", "275653426", "154509612", "677765703"
// Ponder This: Which number is missing??
};
public static final String[] TRANSACTIONS = {
Keywords.DEPOSIT, Keywords.WITHDRAW
};
public static final String[] CREATE_EXPOSED_ACCT_COMMANDS = {
/* Keywords.OPEN_EXPOSED_CHECKING, */ Keywords.OPEN_SAVINGS
};
public static final String[] CREATE_CHECKING_ACCT_COMMANDS = {
Keywords.OPEN_EXPOSED_CHECKING, Keywords.OPEN_PROTECTED_CHECKING
};
}
final class Tokens
{
public static String getRandom(String[] strings)
{
return strings[(int)(strings.length * Math.random())];
}
public static String getRandom(List<String> strings)
{
return strings.get((int)(strings.size() * Math.random()));
}
private static String getRandomHolderId()
{
return getRandom(Strings.FIRST_NAMES) + getRandom(Strings.LAST_NAMES);
}
private static String getRandomNum(int n, String[] digits)
{
StringBuilder sb = new StringBuilder();
while (n-- > 0) sb.append(getRandom(digits));
return sb.toString();
}
private static String getRandomCents()
{
int n = (int)(3 * Math.random());
return getRandomNum(3, Strings.POS_DIGITS) +
getRandomNum(n, Strings.TEN_DIGITS);
}
private static String getRandomAcctNum()
{
return getRandomNum(1, Strings.POS_DIGITS) +
getRandomNum(5, Strings.TEN_DIGITS);
}
private static String getRandomRoutingNum()
{
return getRandom(Strings.ROUTING_NUMBERS);
}
public static String getRandomHolderBankInfo()
{
return getRandomHolderId() + Strings.SEP + getRandomRoutingNum();
}
public static String getRandomAccountInfo(String holderBankInfo)
{
/* Ponder These:
*
* - What could go wrong? Hint: getRandomAcctNum().
* - How would you know if it did?
* - What are the odds?
* - What are the consequences?
*
* Exercise: Eliminate the possibility. Hint: getUniqueAcctNum().
*/
return holderBankInfo + Strings.SEP + getRandomAcctNum();
}
public static String getRandomTransaction()
{
return getRandomCents() + Strings.SEP +
getRandom(Strings.TRANSACTIONS);
}
}
/***************/
/* Head Writer */
/***************/
/* Don't Bother Me. I'm creating. */
final class Writer
{
private static List<String> createAcctCommands;
private static List<String> transactionInfo;
private static String getCreateBankCommand(int i)
{
return Strings.BANK_NAMES[i] + Strings.SEP +
Strings.ROUTING_NUMBERS[i] + Strings.SEP + "create_bank";
}
private static String createExposedAcctCommand(String acctInfo)
{
return acctInfo + Strings.SEP +
Tokens.getRandom(Strings.CREATE_EXPOSED_ACCT_COMMANDS);
}
private static String createCheckingAcctCommand(String acctInfo)
{
return acctInfo + Strings.SEP +
Tokens.getRandom(Strings.CREATE_CHECKING_ACCT_COMMANDS);
}
private static void storyboard(int n)
{
createAcctCommands = new LinkedList<String>();
transactionInfo = new LinkedList<String>();
while (--n >= 0)
{
String holderBankInfo = Tokens.getRandomHolderBankInfo();
String a1 = Tokens.getRandomAccountInfo(holderBankInfo);
String t1 = a1.substring(a1.indexOf(Strings.SEP) + 1);
String a2 = Tokens.getRandomAccountInfo(holderBankInfo);
String t2 = a2.substring(a2.indexOf(Strings.SEP) + 1);
createAcctCommands.add(createExposedAcctCommand(a1));
createAcctCommands.add(createCheckingAcctCommand(a2));
transactionInfo.add(t1);
transactionInfo.add(t2);
}
}
private static String getCreateBankCommands()
{
final int len1 = Strings.BANK_NAMES.length;
final int len2 = Strings.ROUTING_NUMBERS.length;
int n = Math.min(len1, len2);
StringBuilder sb = new StringBuilder();
while (--n > 0) sb.append(getCreateBankCommand(n) + Strings.SEP);
if (n == 0) sb.append(getCreateBankCommand(n));
return sb.toString();
}
private static String getCreateAcctCommands()
{
StringBuilder sb = new StringBuilder();
for (String cmd : createAcctCommands)
sb.append(Strings.SEP + cmd);
return sb.toString();
}
private static String getTransactionCommands(int m)
{
StringBuilder sb = new StringBuilder();
while (m-- > 0)
{
String cmd = Strings.SEP + Tokens.getRandom(transactionInfo) + Strings.SEP +
Tokens.getRandomTransaction();
sb.append(cmd);
}
return sb.toString();
}
public static String[] getScript(int numHolders, int numTransactions)
{
StringBuilder sb = new StringBuilder();
storyboard(numHolders);
sb.append(getCreateBankCommands());
sb.append(getCreateAcctCommands());
sb.append(getTransactionCommands(numTransactions));
return sb.toString().split("\\" + Strings.SEP);
}
}
/******************/
/* Error Handling */
/******************/
/* Producer: I'm the only one allowed to say 'Cut!' */
final class Error
{
private static final String CUT = "Cut! ";
public static void illegalArg(String message)
{
throw new IllegalArgumentException(CUT + message);
}
public static void illegalState(String message)
{
throw new IllegalStateException(CUT + message);
}
public static void overflow()
{
Error.overflow("Overflow detected.");
}
public static void overflow(String message)
{
throw new ArithmeticException(CUT + message);
}
}