/
com/planet_ink/coffee_mud/Abilities/
com/planet_ink/coffee_mud/Abilities/Common/
com/planet_ink/coffee_mud/Abilities/Diseases/
com/planet_ink/coffee_mud/Abilities/Druid/
com/planet_ink/coffee_mud/Abilities/Fighter/
com/planet_ink/coffee_mud/Abilities/Prayers/
com/planet_ink/coffee_mud/Abilities/Properties/
com/planet_ink/coffee_mud/Abilities/Skills/
com/planet_ink/coffee_mud/Abilities/Songs/
com/planet_ink/coffee_mud/Abilities/Spells/
com/planet_ink/coffee_mud/Abilities/Thief/
com/planet_ink/coffee_mud/Abilities/Traps/
com/planet_ink/coffee_mud/Areas/interfaces/
com/planet_ink/coffee_mud/Behaviors/
com/planet_ink/coffee_mud/Behaviors/interfaces/
com/planet_ink/coffee_mud/CharClasses/interfaces/
com/planet_ink/coffee_mud/Commands/
com/planet_ink/coffee_mud/Commands/interfaces/
com/planet_ink/coffee_mud/Exits/interfaces/
com/planet_ink/coffee_mud/Items/Armor/
com/planet_ink/coffee_mud/Items/Basic/
com/planet_ink/coffee_mud/Items/MiscMagic/
com/planet_ink/coffee_mud/Items/Software/
com/planet_ink/coffee_mud/Items/Weapons/
com/planet_ink/coffee_mud/Libraries/
com/planet_ink/coffee_mud/Libraries/interfaces/
com/planet_ink/coffee_mud/Locales/
com/planet_ink/coffee_mud/Locales/interfaces/
com/planet_ink/coffee_mud/MOBS/
com/planet_ink/coffee_mud/Races/
com/planet_ink/coffee_mud/Races/interfaces/
com/planet_ink/coffee_mud/WebMacros/
com/planet_ink/coffee_mud/WebMacros/interfaces/
com/planet_ink/coffee_mud/core/smtp/
com/planet_ink/coffee_mud/core/threads/
com/planet_ink/siplet/applet/
lib/
resources/fakedb/
resources/quests/holidays/
web/
web/admin.templates/
web/admin/grinder/
web/admin/images/
web/pub.templates/
web/pub/images/mxp/
web/pub/sounds/
package com.planet_ink.coffee_mud.core;
import java.util.*;
import java.io.*;

/*
   Copyright 2000-2010 Bo Zimmerman

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/
/**
 * A core singleton class handling various mathematical operations and 
 * functions, especially dealing with explicit type conversions, and 
 * special string conversions and functions.
 */
public class CMath
{
    private CMath(){super();}
    private static CMath inst=new CMath();
    public static CMath instance(){return inst;}
    private static final String[] ROMAN_HUNDREDS={"C","CC","CCC","CD","D","DC","DCC","DCCC","CM","P"};
    private static final String[] ROMAN_TENS={"X","XX","XXX","XL","L","LX","LXX","LXXX","XC","C"};
    private static final String[] ROMAN_ONES={"I","II","III","IV","V","VI","VII","VIII","IX","X"};
    private static final String   ROMAN_ALL="CDMPXLIV";
    private static final java.text.DecimalFormat twoPlaces = new java.text.DecimalFormat("0.#####%");
    private static Random rand = new Random(System.currentTimeMillis());

    /** Convert an integer to its Roman Numeral equivalent
     *
     * Usage: Return=convertToRoman(Number)+".";
     * @param i Integer to convert
     *
     * @return String Converted integer
     */
    public static String convertToRoman(int i)
    {
        StringBuffer roman=new StringBuffer("");
        if(i>1000)
        {
            roman.append("Y");
            i=i%1000;
        }
        if(i>=100)
        {
            int x=i%100;
            int y=(i-x)/100;
            if(y>0)
                roman.append(ROMAN_HUNDREDS[y-1]);
            i=x;
        }
        if(i>=10)
        {
            int x=i%10;
            int y=(i-x)/10;
            if(y>0)
                roman.append(ROMAN_TENS[y-1]);
        }
        i=i%10;
        if(i>0)
            roman.append(ROMAN_ONES[i-1]);
        return roman.toString();
    }

    /**
     * Convert a number from roman numeral to integer.
     * @param s the roman numeral string
     * @return the int
     */
    public static int convertFromRoman(String s)
    {
        int x=0;
        while(s.startsWith("Y"))
            x+=1000;
        for(int i=ROMAN_HUNDREDS.length-1;i>=0;i--)
            if(s.startsWith(ROMAN_HUNDREDS[i]))
            {
                x+=(100*(i+1));
                break;
            }
        for(int i=ROMAN_TENS.length-1;i>=0;i--)
            if(s.startsWith(ROMAN_TENS[i]))
            {
                x+=(10*(i+1));
                break;
            }
        for(int i=ROMAN_ONES.length-1;i>=0;i--)
            if(s.startsWith(ROMAN_ONES[i]))
            {
                x+=i+1;
                break;
            }
        return x;
    }

    /**
     * Return st,nd,rd for a number
     * @param num the number
     * @return the st,nd,rd appendage only
     */
    public static String numAppendage(int num)
	{
        if((num<11)||(num>13))
        {
            String strn=""+num;
            switch(strn.charAt(strn.length()-1))
            {
            case '1': return "st";
            case '2': return "nd";
            case '3': return "rd";
            }
        }
        return "th";
	}

    /**
     * Return true if the char is a roman numeral digit
     * @param c the char
     * @return true if is roman
     */
    public static boolean isRomanDigit(char c){ return ROMAN_ALL.indexOf(c)>=0;}

    /**
     * Returns true if the string is a roman numeral
     * @param s the string to test
     * @return true if a roman numeral, false otherwise
     */
    public static boolean isRomanNumeral(String s)
    {
        if(s==null) return false;
        s=s.toUpperCase().trim();
        if(s.length()==0) return false;
        for(int c=0;c<s.length();c++)
            if(!isRomanDigit(s.charAt(c)))
                return false;
        return true;
    }

    /**
     * Returns the absolute difference between two numbers
     * @param x the first number
     * @param y the second number
     * @return the absolute difference (x-y)*(-1 if <)
     */
    public static long absDiff(long x, long y)
    {
        long d=x-y;
        if(d<0) return d*-1;
        return d;
    }

    /**
     * Returns true if the string is a number (float or int)
     * @param s the string to test
     * @return true if a number, false otherwise
     */
    public static boolean isNumber(String s)
    {
        if(s==null) return false;
        s=s.trim();
        if(s.length()==0) return false;
        if((s.length()>1)&&(s.startsWith("-")))
            s=s.substring(1);
        for(int i=0;i<s.length();i++)
            if("0123456789.,".indexOf(s.charAt(i))<0)
                return false;
        return true;
    }

    /**
     * Divide a by b, making sure both are cast to doubles
     * and that the return is precisely double.
     * @param a the dividend
     * @param b the divisor
     * @return the quotient
     */
    public static double div(double a, double b)
    {
        return a/b;
    }
    /**
     * Divide a by b, making sure both are cast to doubles
     * and that the return is precisely double.
     * @param a the dividend
     * @param b the divisor
     * @return the quotient
     */
    public static double div(double a, int b)
    {
        return a/((double)b);
    }
    /**
     * Divide a by b, making sure both are cast to doubles
     * and that the return is precisely double.
     * @param a the dividend
     * @param b the divisor
     * @return the quotient
     */
    public static double div(int a, double b)
    {
        return ((double)a)/b;
    }
    /**
     * Divide a by b, making sure both are cast to doubles
     * and that the return is precisely double.
     * @param a the dividend
     * @param b the divisor
     * @return the quotient
     */
    public static double div(double a, long b)
    {
        return a/((double)b);
    }
    /**
     * Divide a by b, making sure both are cast to doubles
     * and that the return is precisely double.
     * @param a the dividend
     * @param b the divisor
     * @return the quotient
     */
    public static double div(long a, double b)
    {
        return ((double)a)/b;
    }
    /**
     * Multiply a and b, making sure both are cast to doubles
     * and that the return is precisely double.
     * @param a the first number
     * @param b the second number
     * @return the retult of multiplying a and b
     */
    public static double mul(double a, double b)
    {
        return a*b;
    }
    /**
     * Multiply a and b, making sure both are cast to doubles
     * and that the return is precisely double.
     * @param a the first number
     * @param b the second number
     * @return the retult of multiplying a and b
     */
    public static double mul(double a, int b)
    {
        return a*((double)b);
    }
    /**
     * Multiply a and b, making sure both are cast to doubles
     * and that the return is precisely double.
     * @param a the first number
     * @param b the second number
     * @return the retult of multiplying a and b
     */
    public static double mul(int a, double b)
    {
        return ((double)a)*b;
    }
    /**
     * Multiply a and b, making sure both are cast to doubles
     * and that the return is precisely double.
     * @param a the first number
     * @param b the second number
     * @return the retult of multiplying a and b
     */
    public static double mul(double a, long b)
    {
        return a*((double)b);
    }
    /**
     * Multiply a and b, making sure both are cast to doubles
     * and that the return is precisely double.
     * @param a the first number
     * @param b the second number
     * @return the retult of multiplying a and b
     */
    public static double mul(long a, double b)
    {
        return ((double)a)*b;
    }
    /**
     * Multiply a and b, making sure both are cast to doubles
     * and that the return is precisely double.
     * @param a the first number
     * @param b the second number
     * @return the retult of multiplying a and b
     */
    public static long mul(long a, long b)
    {
        return a*b;
    }
    /**
     * Multiply a and b, making sure both are cast to doubles
     * and that the return is precisely double.
     * @param a the first number
     * @param b the second number
     * @return the retult of multiplying a and b
     */
    public static int mul(int a, int b)
    {
        return a*b;
    }
    /**
     * Divide a by b, making sure both are cast to doubles
     * and that the return is precisely double.
     * @param a the dividend
     * @param b the divisor
     * @return the quotient
     */
    public static double div(long a, long b)
    {
        return ((double)a)/((double)b);
    }
    /**
     * Divide a by b, making sure both are cast to doubles
     * and that the return is precisely double.
     * @param a the dividend
     * @param b the divisor
     * @return the quotient
     */
    public static double div(int a, int b)
    {
        return ((double)a)/((double)b);
    }
    /**
     * Raises x to the y power, making sure both are cast to doubles
     * and that the return is rounded off.
     * @param x the base number
     * @param y the power
     * @return x to the y power, rounded off
     */
    public static long pow(long x, long y)
    {
        return Math.round(Math.pow(((double)x),((double)y)));
    }
    /**
     * Returns x, squared, after being case to a double
     * @param x the number to square
     * @return x, squared, and rounded off.
     */
    public static int squared(int x)
    {
        return (int)Math.round(Math.pow(((double)x),2.0));
    }
    /**
     * Returns true if the given number has the bits
     * represented by the given bitmask set.
     * @param num the number
     * @param bitmask the bit mask
     * @return true if the bits are set, false otherwise
     */
    public static boolean bset(short num, short bitmask)
    {
        return ((num&bitmask)==bitmask);
    }
    /**
     * Returns true if the given number has the bits
     * represented by the given bitmask set.
     * @param num the number
     * @param bitmask the bit mask
     * @return true if the bits are set, false otherwise
     */
    public static boolean bset(int num, int bitmask)
    {
        return ((num&bitmask)==bitmask);
    }
    /**
     * Returns true if the given number has the bits
     * represented by the given bitmask set.
     * @param num the number
     * @param bitmask the bit mask
     * @return true if the bits are set, false otherwise
     */
    public static boolean bset(long num, long bitmask)
    {
        return ((num&bitmask)==bitmask);
    }
    /**
     * Returns true if the given number has the bits
     * represented by the given bitmask set.
     * @param num the number
     * @param bitmask the bit mask
     * @return true if the bits are set, false otherwise
     */
    public static boolean bset(long num, int bitmask)
    {
        return ((num&bitmask)==bitmask);
    }
    /**
     * Returns the given number, after having set the
     * bits represented by the given bit mask.
     * @param num the number
     * @param bitmask the bitmask
     * @return the number | the bitmask
     */
    public static int setb(int num, int bitmask)
    {
        return num|bitmask;
    }
    /**
     * Returns true if any of the bits represented
     * by the given bitmask are set in the given
     * number.
     * @param num the given number
     * @param bitmask the bitmask of bits to check
     * @return true if any bits from the mask are set
     */
    public static boolean banyset(int num, int bitmask)
    {
        return ((num&bitmask)>0);
    }
    /**
     * Returns true if any of the bits represented
     * by the given bitmask are set in the given
     * number.
     * @param num the given number
     * @param bitmask the bitmask of bits to check
     * @return true if any bits from the mask are set
     */
    public static boolean banyset(long num, long bitmask)
    {
        return ((num&bitmask)>0);
    }
    /**
     * Returns true if any of the bits represented
     * by the given bitmask are set in the given
     * number.
     * @param num the given number
     * @param bitmask the bitmask of bits to check
     * @return true if any bits from the mask are set
     */
    public static boolean banyset(long num, int bitmask)
    {
        return ((num&bitmask)>0);
    }
    /**
     * Returns the given number, after having set the
     * bits represented by the given bit mask.
     * @param num the number
     * @param bitmask the bitmask
     * @return the number | the bitmask
     */
    public static long setb(long num, int bitmask)
    {
        return num|bitmask;
    }
    /**
     * Returns the given number, after having set the
     * bits represented by the given bit mask.
     * @param num the number
     * @param bitmask the bitmask
     * @return the number | the bitmask
     */
    public static long setb(long num, long bitmask)
    {
        return num|bitmask;
    }
    /**
     * Unsets those bits in the given number which are
     * turned ON in the given bitmask.
     * @param num the given number
     * @param bitmask the given bitmask
     * @return the number without the bitmasks bits turned on.
     */
    public static int unsetb(int num, int bitmask) { return num & (~bitmask);}
    /**
     * Unsets those bits in the given number which are
     * turned ON in the given bitmask.
     * @param num the given number
     * @param bitmask the given bitmask
     * @return the number without the bitmasks bits turned on.
     */
    public static long unsetb(long num, long bitmask) { return num & (~bitmask);}
    /**
     * Unsets those bits in the given number which are
     * turned ON in the given bitmask.
     * @param num the given number
     * @param bitmask the given bitmask
     * @return the number without the bitmasks bits turned on.
     */
    public static long unsetb(long num, int bitmask) { return num & (~bitmask);}
    /**
     * Returns true if the bitnumberth bit (0...) is set 
     * in the given number
     * @param number the given number
     * @param bitnumber the bit to check (0,1,2...)
     * @return true if the given bitnumberth bit is set
     */
    public static boolean isSet(int number, int bitnumber)
    {
    	int mask=(int)pow(2,bitnumber);
    	return ((number&mask)==mask);
    }
    /**
     * Returns true if the given string represents a 
     * percentage in the form X% where X is any real
     * number.
     * @param s the string to check
     * @return true if it is a percentage, false otherwise
     */
    public static boolean isPct(String s)
    {
        if(s==null) return false;
        s=s.trim();
        if(!s.endsWith("%")) return false;
        return CMath.isNumber(s.substring(0,s.length()-1));
    }
    /**
     * Converts the given string to a floating
     * point number, 1>=N>=0, representing 
     * the whole percentage of the string.  The
     * string format is either X or X%, where 100>=X>=0
     * If the format is bad, 0.0 is returned.
     * @param s the string to convert
     * @return the string converted to a real number 
     */
    public static double s_pct(String s)
    {
    	if(s==null) return 0.0;
    	while(s.trim().endsWith("%")) s=s.trim().substring(0,s.length()-1).trim();
    	return s_double(s)/100.0;
    }
    
    /**
     * Converts a percentage 1>d>0 to a string.
     * @param d the number to convert
     * @return the percentage string.
     */
    public static String toPct(double d)
    {
        String s=twoPlaces.format(d);
        if(s.endsWith("%%")) return s.substring(0,s.length()-1);
        return s;

    }
    
    /**
     * Converts the string to a double percentage and then
     * converts that back to a percentage.
     * @param s the string number
     * @return the percentage %
     */
    public static String toPct(String s) { return toPct(s_pct(s)); }

    /**
     * Returns true if the bitnumberth bit (0...) is set 
     * in the given number
     * @param number the given number
     * @param bitnumber the bit to check (0,1,2...)
     * @return true if the given bitnumberth bit is set
     */
    public static boolean isSet(long number, int bitnumber)
    {
        if((number&(pow(2,bitnumber)))==(pow(2,bitnumber)))
            return true;
        return false;
    }
    
    /**
     * Returns whether the given string is a valid
     * math expression (5 + 7)/2, etc. Does this
     * by evaluating the expression and returning
     * false if an error is found.  No variables
     * are allowed.
     * @param st the possible math expression
     * @return true if it is a math expression
     */
    public static boolean isMathExpression(String st){
        if((st==null)||(st.length()==0)) return false;
        try{ parseMathExpression(st);}catch(Exception e){ return false;}
        return true;
    }
    /**
     * Returns whether the given string is a valid
     * math expression (@x1 + 7)/2, etc. Does this
     * by evaluating the expression and returning
     * false if an error is found.  All necessary
     * variables MUST be included (@x1=vars[0])
     * @param st the possible math expression
     * @param vars the 0 based variables
     * @return true if it is a math expression
     */
    public static boolean isMathExpression(String st, double[] vars){
        if((st==null)||(st.length()==0)) return false;
        try{ parseMathExpression(st,vars);}catch(Exception e){ return false;}
        return true;
    }
    /**
     * Returns the result of evaluating the given math
     * expression.  An expression can be a double or int
     * number, or a full expression using ()+-/*?<>.
     * Variable @xx will refer to current computed value.
     * Returns 0.0 on any parsing error
     * @param st a full math expression string
     * @return the result of the expression
     */
    public static double s_parseMathExpression(String st){ try{ return parseMathExpression(st);}catch(Exception e){ return 0.0;}}
    /**
     * Returns the result of evaluating the given math
     * expression.  An expression can be a double or int
     * number, or a full expression using ()+-/*?<>.
     * Variables are included as @x1, etc.. The given
     * variable values list is 0 based, so @x1 = vars[0].
     * Variable @xx will refer to current computed value.
     * Returns 0.0 on any parsing error
     * @param st a full math expression string
     * @param vars the 0 based variables
     * @return the result of the expression
     */
    public static double s_parseMathExpression(String st, double[] vars){ try{ return parseMathExpression(st,vars);}catch(Exception e){ return 0.0;}}
    /**
     * Returns the result of evaluating the given math
     * expression.  An expression can be a double or int
     * number, or a full expression using ()+-/*?<>.
     * Variable @xx will refer to current computed value.
     * Rounds the result to a long.
     * Returns 0 on any parsing error
     * @param st a full math expression string
     * @return the result of the expression
     */
    public static long s_parseLongExpression(String st){ try{ return parseLongExpression(st);}catch(Exception e){ return 0;}}
    /**
     * Returns the result of evaluating the given math
     * expression.  An expression can be a double or int
     * number, or a full expression using ()+-/*?<>.
     * Variables are included as @x1, etc.. The given
     * variable values list is 0 based, so @x1 = vars[0].
     * Variable @xx will refer to current computed value.
     * Rounds the result to a long.
     * Returns 0 on any parsing error
     * @param st a full math expression string
     * @param vars the 0 based variables
     * @return the result of the expression
     */
    public static long s_parseLongExpression(String st, double[] vars){ try{ return parseLongExpression(st,vars);}catch(Exception e){ return 0;}}
    /**
     * Returns the result of evaluating the given math
     * expression.  An expression can be a double or int
     * number, or a full expression using ()+-/*?<>.  
     * Variable @xx will refer to current computed value.
     * Round the result to an integer.
     * Returns 0 on any parsing error
     * @param st a full math expression string
     * @return the result of the expression
     */
    public static int s_parseIntExpression(String st){ try{ return parseIntExpression(st);}catch(Exception e){ return 0;}}
    /**
     * Returns the result of evaluating the given math
     * expression.  An expression can be a double or int
     * number, or a full expression using ()+-/*?<>.
     * Variables are included as @x1, etc.. The given
     * variable values list is 0 based, so @x1 = vars[0].
     * Variable @xx will refer to current computed value.
     * Rounds the result to an integer.
     * Returns 0 on any parsing error
     * @param st a full math expression string
     * @param vars the 0 based variables
     * @return the result of the expression
     */
    public static int s_parseIntExpression(String st, double[] vars){ try{ return parseIntExpression(st,vars);}catch(Exception e){ return 0;}}

    private static double parseMathExpression(StreamTokenizer st, boolean inParen, double[] vars, double previous)
        throws ArithmeticException
    {
        if(!inParen) {
            st.ordinaryChar('/');
            st.ordinaryChar('x');
            st.ordinaryChar('X');
        }
        double finalValue=0;
        try{
            int c=st.nextToken();
            char lastOperation='+';
            while(c!=StreamTokenizer.TT_EOF)
            {
                double curValue=0.0;
                switch(c)
                {
                case StreamTokenizer.TT_NUMBER:
                    curValue=st.nval;
                    break;
                case '(':
                    curValue=parseMathExpression(st,true,vars,finalValue);
                    break;
                case ')':
                    if(!inParen)
                        throw new ArithmeticException("')' is an unexpected token.");
                    return finalValue;
                case '@':
                {
                    c=st.nextToken();
                    if((c!='x')&&(c!='X'))
                        throw new ArithmeticException("'"+c+"' is an unexpected token after @.");
                    c=st.nextToken();
                    if((c=='x')||(c=='X'))
                    	curValue=previous;
                    else
                    {
	                    if(c!=StreamTokenizer.TT_NUMBER)
	                        throw new ArithmeticException("'"+c+"' is an unexpected token after @x.");
	                    if(vars==null)
	                        throw new ArithmeticException("vars have not been defined for @x"+st.nval);
	                    if((st.nval>vars.length)||(st.nval<1.0))
	                        throw new ArithmeticException("'"+st.nval+"/"+vars.length+"' is an illegal variable reference.");
	                    curValue=vars[((int)st.nval)-1];
                    }
                    break;
                }
                case '+':
                case '<':
                case '>':
                case '-':
                case '*':
                case '\\':
                case '/':
                case '?':
                {
                    lastOperation=(char)c;
                    c=st.nextToken();
                    continue;
                }
                default:
                    throw new ArithmeticException("'"+c+"' is an illegal expression.");
                }
                switch(lastOperation)
                {
                case '<': finalValue = finalValue < curValue? finalValue : curValue; break;
                case '>': finalValue = finalValue > curValue? finalValue : curValue; break;
                case '+': finalValue+=curValue; break;
                case '-': finalValue-=curValue; break;
                case '*': finalValue*=curValue; break;
                case '/':
                case '\\': finalValue/=curValue; break;
                case '?': finalValue= ((curValue-finalValue+0.5) * rand.nextDouble()) + finalValue; break;
                }
                c=st.nextToken();
            }
        }
        catch(IOException e){}
        if(inParen)
            throw new ArithmeticException("')' was missing from this expression");
        return finalValue;
    }

    /**
     * A class representing a single piece of a compiled operation.  Optomized for
     * speed of execution rather than the obvious wastefulness of storage.
     */
    public static final class CompiledOperation
    {
    	public static final int OPERATION_VARIABLE=0;
    	public static final int OPERATION_VALUE=1;
    	public static final int OPERATION_OPERATION=2;
    	public static final int OPERATION_LIST=3;
    	public static final int OPERATION_PREVIOUSVALUE=4;
    	public int type = -1;
    	public int variableIndex = 0;
    	public double value = 0.0;
    	public char operation = ' ';
    	public LinkedList<CompiledOperation> list = null;
    	public CompiledOperation(int variableIndex) { type = OPERATION_VARIABLE; this.variableIndex = variableIndex;}  
    	public CompiledOperation(double value) { type = OPERATION_VALUE; this.value = value;}  
    	public CompiledOperation(LinkedList<CompiledOperation> list) { type = OPERATION_LIST; this.list = list;}  
    	public CompiledOperation(char operation) { type = OPERATION_OPERATION; this.operation = operation;}  
    	public CompiledOperation() { type = OPERATION_PREVIOUSVALUE;}  
    }
    
    /**
     * Pre-compiles an expression for faster evaluation later on.
     * @see CMath#parseMathExpression(LinkedList, double[])
     * @param st the math expression as a string
     * @returns the pre-compiled expression
     * @throws ArithmeticException
     */
    public static LinkedList<CompiledOperation> compileMathExpression(String formula)
    {return compileMathExpression(new StreamTokenizer(new InputStreamReader(new ByteArrayInputStream(formula.getBytes()))),false);}
    
    /**
     * Pre-compiles an expression for faster evaluation later on.
     * @see CMath#parseMathExpression(LinkedList, double[])
     * @param st the tokenized expression
     * @param inParen whether or not you are in parenthesis mode 
     * @returns the pre-compiled expression
     * @throws ArithmeticException
     */
    private static LinkedList<CompiledOperation> compileMathExpression(StreamTokenizer st, boolean inParen)
    	throws ArithmeticException
	{
	    if(!inParen) {
	        st.ordinaryChar('/');
	        st.ordinaryChar('x');
	        st.ordinaryChar('X');
	    }
	    LinkedList<CompiledOperation> list = new LinkedList<CompiledOperation>();
	    
	    try{
	        int c=st.nextToken();
	        char lastOperation='+';
	        while(c!=StreamTokenizer.TT_EOF)
	        {
	            switch(c)
	            {
	            case StreamTokenizer.TT_NUMBER:
	            	list.add(new CompiledOperation(st.nval));
	                break;
	            case '(':
	            	list.add(new CompiledOperation(compileMathExpression(st,true)));
	                break;
	            case ')':
	                if(!inParen)
	                    throw new ArithmeticException("')' is an unexpected token.");
	                return list;
	            case '@':
	            {
	                c=st.nextToken();
	                if((c!='x')&&(c!='X'))
	                    throw new ArithmeticException("'"+c+"' is an unexpected token after @.");
	                c=st.nextToken();
                    if((c=='x')||(c=='X'))
		                list.add(new CompiledOperation());
                    else
                    {
		                if(c!=StreamTokenizer.TT_NUMBER)
		                    throw new ArithmeticException("'"+c+"' is an unexpected token after @x.");
		                if((st.nval>11)||(st.nval<1.0))
		                    throw new ArithmeticException("'"+st.nval+"/11' is an illegal variable reference.");
		                list.add(new CompiledOperation(((int)st.nval)-1));
                    }
	                break;
	            }
	            case '+':
	            case '-':
	            case '*':
	            case '\\':
	            case '/':
	            case '?':
                case '<':
                case '>':
	            {
	                lastOperation=(char)c;
	                c=st.nextToken();
	                continue;
	            }
	            default:
	                throw new ArithmeticException("'"+(char)c+"' ("+(int)c+") is an illegal expression.");
	            }
	            switch(lastOperation)
	            {
	            case '+':
	            case '-':
	            case '*':
	            case '?':
                case '<':
                case '>':
	            	list.add(new CompiledOperation(lastOperation));
	            	break;
	            case '/':
	            case '\\':
	            	list.add(new CompiledOperation('/'));
	            	break;
	            }
	            c=st.nextToken();
	        }
	    }
	    catch(IOException e){}
	    if(inParen)
	        throw new ArithmeticException("')' was missing from this expression");
	    return list;
	}

    /**
     * Parse a pre-compiled expression.  Requires a vars variable of at least 10 entries
     * to ensure NO exceptions (other than /0).
     * @see CMath#compileMathExpression(StreamTokenizer, boolean)
     * @param list the pre-compiled expression
     * @param vars the variable values
     * @return the final value
     */
    public static double parseMathExpression(LinkedList<CompiledOperation> list, double[] vars, double previous)
	{
        double finalValue=0.0;
        double curValue=0.0;
    	for(CompiledOperation o : list)
    		switch(o.type)
    		{
    			case CompiledOperation.OPERATION_VALUE: 
    				curValue = o.value; break;
    			case CompiledOperation.OPERATION_VARIABLE: 
    				curValue = vars[o.variableIndex]; break;
    			case CompiledOperation.OPERATION_LIST: 
    				curValue = parseMathExpression(o.list,vars,finalValue); break;
    			case CompiledOperation.OPERATION_PREVIOUSVALUE: 
    				curValue = previous; break;
    			case CompiledOperation.OPERATION_OPERATION:
    				switch(o.operation)
    				{
    	                case '+': finalValue+=curValue; break;
    	                case '-': finalValue-=curValue; break;
    	                case '*': finalValue*=curValue; break;
    	                case '/': finalValue/=curValue; break;
    	                case '?': finalValue= ((curValue-finalValue+0.5) * rand.nextDouble()) + finalValue; break;
    	                case '<': finalValue = finalValue < curValue? finalValue : curValue; break;
    	                case '>': finalValue = finalValue > curValue? finalValue : curValue; break;
    				}
    				break;
    		}
    	return finalValue;
	}
    
	
    /**
     * Returns the result of evaluating the given math
     * expression.  An expression can be a double or int
     * number, or a full expression using ()+-/*?<>.
     * Variable @xx will refer to current computed value.
     * Rounds the result to a long
     * Throws an exception on any parsing error
     * @param formula a full math expression string
     * @return the result of the expression
     */
    public static long parseLongExpression(String formula)
    {return Math.round(parseMathExpression(new StreamTokenizer(new InputStreamReader(new ByteArrayInputStream(formula.getBytes()))),false,null,0));}
    /**
     * Returns the result of evaluating the given math
     * expression.  An expression can be a double or int
     * number, or a full expression using ()+-/*?<>.
     * Variables are included as @x1, etc.. The given
     * variable values list is 0 based, so @x1 = vars[0].
     * Variable @xx will refer to current computed value.
     * Rounds the result to a long
     * Throws an exception on any parsing error
     * @param formula a full math expression string
     * @param vars the 0 based variables
     * @return the result of the expression
     */
    public static long parseLongExpression(String formula, double[] vars)
    {return Math.round(parseMathExpression(new StreamTokenizer(new InputStreamReader(new ByteArrayInputStream(formula.getBytes()))),false,vars,0));}

    /**
     * Returns the result of evaluating the given math
     * expression.  An expression can be a double or int
     * number, or a full expression using ()+-/*?<>.
     * Variable @xx will refer to current computed value.
     * Rounds the result to an integer.
     * Throws an exception on any parsing error
     * @param formula a full math expression string
     * @return the result of the expression
     */
    public static int parseIntExpression(String formula) throws ArithmeticException
    {return (int)Math.round(parseMathExpression(new StreamTokenizer(new InputStreamReader(new ByteArrayInputStream(formula.getBytes()))),false,null,0));}
    /**
     * Returns the result of evaluating the given math
     * expression.  An expression can be a double or int
     * number, or a full expression using ()+-/*?<>.
     * Variables are included as @x1, etc.. The given
     * variable values list is 0 based, so @x1 = vars[0].
     * Variable @xx will refer to current computed value.
     * Rounds the result to an integer.
     * Throws an exception on any parsing error
     * @param formula a full math expression string
     * @param vars the 0 based variables
     * @return the result of the expression
     */
    public static int parseIntExpression(String formula, double[] vars) throws ArithmeticException
    {return (int)Math.round(parseMathExpression(new StreamTokenizer(new InputStreamReader(new ByteArrayInputStream(formula.getBytes()))),false,vars,0));}
    /**
     * Returns the result of evaluating the given math
     * expression.  An expression can be a double or int
     * number, or a full expression using ()+-/*?<>.
     * Variable @xx will refer to current computed value.
     * Throws an exception on any parsing error
     * @param formula a full math expression string
     * @return the result of the expression
     */
    public static double parseMathExpression(String formula) throws ArithmeticException
    {return parseMathExpression(new StreamTokenizer(new InputStreamReader(new ByteArrayInputStream(formula.getBytes()))),false,null,0);}
    /**
     * Returns the result of evaluating the given math
     * expression.  An expression can be a double or int
     * number, or a full expression using ()+-/*?<>.
     * Variables are included as @x1, etc.. The given
     * variable values list is 0 based, so @x1 = vars[0].
     * Variable @xx will refer to current computed value.
     * Throws an exception on any parsing error
     * @param formula a full math expression string
     * @param vars the 0 based variables
     * @return the result of the expression
     */
    public static double parseMathExpression(String formula, double[] vars) throws ArithmeticException
    {return parseMathExpression(new StreamTokenizer(new InputStreamReader(new ByteArrayInputStream(formula.getBytes()))),false,vars,0);}


    /**
     * Returns the long value of a string without crashing
     *
     * <br><br><b>Usage:</b> lSize = WebIQBase.s_long(WebIQBase.getRes(AttStatsRes,"BlobSize"));
     * @param LONG String to convert
     * @return long Long value of the string
     */
    public static long s_long(String LONG)
    {
        long slong=0;
        try{ slong=Long.parseLong(LONG); }
        catch(Exception e){ return 0;}
        return slong;
    }

    /**
     * Returns the floating point value of a string without crashing
     *
     * <br><br><b>Usage:</b> lSize = WebIQBase.s_float(WebIQBase.getRes(AttStatsRes,"BlobSize"));
     * @param FLOAT String to convert
     * @return Float value of the string
     */
    public static float s_float(String FLOAT)
    {
        float sfloat=(float)0.0;
        try{ sfloat=Float.parseFloat(FLOAT); }
        catch(Exception e){ return 0;}
        return sfloat;
    }

    /**
     * Returns the double value of a string without crashing
     *
     * <br><br><b>Usage:</b> dSize = WebIQBase.s_double(WebIQBase.getRes(AttStatsRes,"BlobSize"));
     * @param DOUBLE String to convert
     * @return double Double value of the string
     */
    public static double s_double(String DOUBLE)
    {
        double sdouble=0;
        try{ sdouble=Double.parseDouble(DOUBLE); }
        catch(Exception e){ return 0;}
        return sdouble;
    }


    /**
     * Returns the absolute value (X>=0) of the
     * given number
     * @param val the number
     * @return the absolute value of the number
     */
    public static int abs(int val)
    {
        if(val>=0) return val;
        return val*-1;
    }

    /**
     * Returns the absolute value (X>=0) of the
     * given number
     * @param val the number
     * @return the absolute value of the number
     */
    public static long abs(long val)
    {
        if(val>=0) return val;
        return val*-1;
    }

    /**
     * Returns the boolean value of a string without crashing
     *
     * <br><br><b>Usage:</b> int num=s_bool(CMD.substring(14));
     * @param BOOL Boolean value of string
     * @return int Boolean value of the string
     */
    public static boolean s_bool(String BOOL)
    {
        return Boolean.valueOf(BOOL).booleanValue();
    }

    /**
     * Returns whether the given string is a boolean value
     *
     * <br><br><b>Usage:</b> if(isBool(CMD.substring(14)));
     * @param BOOL Boolean value of string
     * @return whether it is a boolean
     */
    public static boolean isBool(String BOOL)
    {
        return BOOL.equalsIgnoreCase("true")||BOOL.equalsIgnoreCase("false");
    }

    /**
     * Returns the integer value of a string without crashing
     *
     * <br><br><b>Usage:</b> int num=s_int(CMD.substring(14));
     * @param INT Integer value of string
     * @return int Integer value of the string
     */
    public static int s_int(String INT)
    {
        int sint=0;
        try{ sint=Integer.parseInt(INT); }
        catch(Exception e){ return 0;}
        return sint;
    }
    /**
     * Returns the short value of a string without crashing
     *
     * <br><br><b>Usage:</b> int num=s_short(CMD.substring(14));
     * @param SHORT Short value of string
     * @return short Short value of the string
     */
    public static short s_short(String SHORT)
    {
    	short sint=0;
        try{ sint=Short.parseShort(SHORT); }
        catch(Exception e){ return 0;}
        return sint;
    }

    /**
     * Returns whether the given string is a long value
     *
     * <br><br><b>Usage:</b> if(isLong(CMD.substring(14)));
     * @param LONG Long value of string
     * @return whether it is a long
     */
    public static boolean isLong(String LONG){return isInteger(LONG);}
    
    /**
     * Returns whether the given string is a int value
     *
     * <br><br><b>Usage:</b> if(isInteger(CMD.substring(14)));
     * @param INT Integer value of string
     * @return whether it is a int
     */
    public static boolean isInteger(String INT)
    {
        if(INT==null) return false;
        if(INT.length()==0) return false;
        int i=0;
        if(INT.charAt(0)=='-')
            if(INT.length()>1)
                i++;
            else
                return false;
        for(;i<INT.length();i++)
            if(!Character.isDigit(INT.charAt(i)))
                return false;
        return true;
    }
    
    /**
     * Returns whether the given string is a float value
     *
     * <br><br><b>Usage:</b> if(isFloat(CMD.substring(14)));
     * @param DBL float value of string
     * @return whether it is a float
     */
    public static boolean isFloat(String DBL){return isDouble(DBL);}
    
    /**
     * Returns a int representing either the given value, or 
     * the 2^ power of the comma separated values in the order
     * they appear in the given string list.
     *
     * <br><br><b>Usage:</b> if(s_parseBitIntExpression(CMDS,CMD.substring(14)));
     * @param bits the ordered string values from 0-whatever.
     * @param val the expression, or list of string values
     * @return the int value, or 0
     */
    public static int s_parseBitIntExpression(String[] bits, String val)
    {
    	return (int)s_parseBitLongExpression(bits,val);
    }
    
    /**
     * Returns a long representing either the given value, or 
     * the 2^ power of the comma separated values in the order
     * they appear in the given string list.
     *
     * <br><br><b>Usage:</b> if(s_parseBitLongExpression(CMDS,CMD.substring(14)));
     * @param bits the ordered string values from 0-whatever.
     * @param val the expression, or list of string values
     * @return the long value, or 0
     */
    public static long s_parseBitLongExpression(String[] bits, String val)
    {
    	if((val==null)||(val.trim().length()==0)||(CMath.isMathExpression(val)))
    		return CMath.s_parseLongExpression(val);
    	StringTokenizer tokens=new StringTokenizer(val,",");
    	long l=0;
    	while(tokens.hasMoreElements())
    	{
    		val=tokens.nextToken().trim();
    		if((val.length()==0)||(CMath.isMathExpression(val)))
    			l|=CMath.s_parseLongExpression(val);
    		else
    		for(int x=0;x<bits.length;x++)
    			if(bits[x].equalsIgnoreCase(val))
	    		{
    				l+=pow(2,x-1);
	    			break;
	    		}
    	}
    	return l;
    }
    
    /**
     * Replaces the internal Random object with the one
     * passed in.  Intended to be used for debugging purposes
     * only.
     * @param rand the random object to use
     */
    public static void setRand(Random rand)
    {
    	CMath.rand = rand;
    }
    
    /**
     * Returns a long representing either the given value, or 
     * the index of the value in the order
     * they appear in the given string list.
     *
     * <br><br><b>Usage:</b> if(s_parseListLongExpression(CMDS,CMD.substring(14)));
     * @param descs the ordered string values from 0-whatever.
     * @param val the expression, or list of string values
     * @return the long value, or 0
     */
    public static long s_parseListLongExpression(String[] descs, String val)
    {
    	if((val==null)||(val.trim().length()==0)||(CMath.isMathExpression(val)))
    		return CMath.s_parseLongExpression(val);
		for(int x=0;x<descs.length;x++)
			if(descs[x].equalsIgnoreCase(val))
				return x;
		return 0;
    }
    
    /**
     * Returns a int representing either the given value, or 
     * the index of the value in the order
     * they appear in the given string list.
     *
     * <br><br><b>Usage:</b> if(s_parseListIntExpression(CMDS,CMD.substring(14)));
     * @param descs the ordered string values from 0-whatever.
     * @param val the expression, or list of string values
     * @return the int value, or 0
     */
    public static int s_parseListIntExpression(String[] descs, String val)
    { return (int)s_parseListLongExpression(descs,val);}
    
    /**
     * Returns whether the given string is a double value
     *
     * <br><br><b>Usage:</b> if(isDouble(CMD.substring(14)));
     * @param DBL double value of string
     * @return whether it is a double
     */
    public static boolean isDouble(String DBL)
    {
        if(DBL==null) return false;
        if(DBL.length()==0) return false;
        int i=0;
        if(DBL.charAt(0)=='-')
            if(DBL.length()>1)
                i++;
            else
                return false;
        boolean alreadyDot=false;
        for(;i<DBL.length();i++)
            if(!Character.isDigit(DBL.charAt(i)))
            {
                if(DBL.charAt(i)=='.')
                {
                    if(alreadyDot)
                        return false;
                    alreadyDot=true;
                }
                else
                    return false;
            }
        return alreadyDot;
    }

    /**
     * @see java.lang.Math#round(double)
     * @param d the real number
     * @return the rounded number as a long
     */
    public long round(double d){return Math.round(d);}
    /**
     * @see java.lang.Math#round(float)
     * @param d the real number
     * @return the rounded number as a long
     */
    public long round(float d){return Math.round(d);}
    /**
     * @see java.lang.Math#abs(double)
     * @param d the real number
     * @return the absolute value of the number
     */
    public double abs(double d){return Math.abs(d);}
    /**
     * @see java.lang.Math#abs(float)
     * @param d the real number
     * @return the absolute value of the number
     */
    public float abs(float d){return Math.abs(d);}
    /**
     * @see java.lang.Math#random()
     * @return a random number
     */
    public double random(){return rand.nextDouble();}
    /**
     * @see java.lang.Math#floor(double)
     * @param d the number to get the floor of
     * @return the floor of the given number
     */
    public double floor(double d){return Math.floor(d);}
    /**
     * @see java.lang.Math#floor(float)
     * @param d the number to get the floor of
     * @return the floor of the given number
     */
    public float floor(float d){return (float)Math.floor(d);}
    /**
     * @see java.lang.Math#floor(double)
     * @param d the number to get the ceiling of
     * @return the ceiling of the given number
     */
    public double ceiling(double d){return Math.ceil(d);}
    /**
     * @see java.lang.Math#floor(float)
     * @param d the number to get the ceiling of
     * @return the ceiling of the given number
     */
    public float ceiling(float d){return (float)Math.ceil(d);}
    /**
     * @see java.lang.Math#sqrt(double)
     * @param d the number to get the square root of
     * @return the square root of the given number
     */
    public double sqrt(double d){return Math.sqrt(d);}
    /**
     * @see java.lang.Math#sqrt(float)
     * @param d the number to get the square root of
     * @return the square root of the given number
     */
    public float sqrt(float d){return (float)Math.sqrt(d);}
}