Reverse Polish Notation Calculator : Calculator « Page Components « JavaScript DHTML

JavaScript DHTML
1. Ajax Layer
2. Data Type
3. Date Time
4. Development
5. Document
6. Dojo toolkit
7. Event
8. Event onMethod
9. Ext JS
10. Form Control
11. GUI Components
12. HTML
13. Javascript Collections
14. Javascript Objects
15. Javascript Properties
16. jQuery
17. Language Basics
18. Mochkit
19. Mootools
20. Node Operation
21. Object Oriented
22. Page Components
23. Rico
24. Scriptaculous
25. Security
26. SmartClient
27. Style Layout
28. Table
29. Utilities
30. Window Browser
31. YUI Library
Java
Java Tutorial
Java Source Code / Java Documentation
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
JavaScript DHTML » Page Components » Calculator 
Reverse Polish Notation Calculator

<html>
  <head>
    <title>rpnjcalc a javascript RPN Calculator</title>
<style type="text/css">
input.btn {align:center;color:#000000;width:50;height:22;vertical-align:middle;font-size:12}
input.bigbtn {align:center;color:#000000;width:100;height:22;vertical-align:middle;font-size:12}
</style>

<script type="text/javascript" language="JavaScript">

<!-- hide this script contents from old browsers

// keep track of whether we just computed display.value
var computed = true;
var dgmode = 1// rad mode is default
var enterpressed = false;
var undostack=new Array(5);
var lastxvalue=0;

// init:
undostack[4]=0;
undostack[3]=0;
undostack[2]=0;
undostack[1]=0;
undostack[0]=0;


// f=form object
function pushStack(f)
{
    f.stack3.value = f.stack2.value;
    f.stack2.value = f.stack1.value;
    f.stack1.value = f.stack.value;
    f.stack.value = f.display.value;
}
// for the pop button: role down all.
// f=form object
function popStackDisplay(f)
{
    f.display.value = f.stack.value;
    f.stack.value = f.stack1.value;
    f.stack1.value = f.stack2.value;
    f.stack2.value = f.stack3.value;
    computed = true;
}
// pop just the upper stack
// f=form object
function popStack(f)
{
    f.stack.value = f.stack1.value;
    f.stack1.value = f.stack2.value;
    f.stack2.value = f.stack3.value;
}
// f=form object
function fillundostack(f)
{
    undostack[4]=f.stack3.value;
    undostack[3]=f.stack2.value;
    undostack[2]=f.stack1.value;
    undostack[1]=f.stack.value;
    undostack[0]=f.display.value;
    lastxvalue=f.display.value;
}

// f=form object
function undoall(f)
{
    f.stack3.value= undostack[4];
    f.stack2.value= undostack[3];
    f.stack1.value= undostack[2];
    f.stack.value = undostack[1];
    f.display.value=undostack[0];
    computed=true;
}

// f=form object
function lastx(f)
{
    f.display.value=lastxvalue;
    computed=true;
}

// make sure we have a number in the display
function isnotafinatenumber(f)
{
    var tmp;
    tmp=parseFloat(f.display.value);
    if(isNaN(tmp|| ! isFinite(tmp)){
        return(true);
    }
    return(false);
}

// the enter button
// f=form object
function enterx(f)
{
    fillundostack(f);
    if(isnotafinatenumber(f)){
        f.display.value="0";
    }else{
        pushStack(f);
    }
    enterpressed = true;
    computed = false;
}
// the C (clear) button
// f=form object
function cx(f)
{
    fillundostack(f);
    f.display.value = ;
    computed = false;
}

// recall X
// f=form object
function rcl1(f)
{
    fillundostack(f);
    // auto-push the stack if the last value was computed
    if(computed) {
        if(isnotafinatenumber(f)){
            f.display.value="0";
        }
        pushStack(f);
    }
    if(isNaN(f.mem1.value|| ! isFinite(f.mem1.value)){
        f.mem1.value=0;
    }
    f.display.value=f.mem1.value;
    computed = true;
}

// recall X
// f=form object
function rcl2(f)
{
    fillundostack(f);
    // auto-push the stack if the last value was computed
    if(computed) {
        if(isnotafinatenumber(f)){
            f.display.value="0";
        }
        pushStack(f);
    }
    if(isNaN(f.mem2.value|| ! isFinite(f.mem2.value)){
        f.mem2.value=0;
    }
    f.display.value=f.mem2.value;
    computed = true;
}

// recall X
// f=form object
function rcl3(f)
{
    fillundostack(f);
    // auto-push the stack if the last value was computed
    if(computed) {
        if(isnotafinatenumber(f)){
            f.display.value="0";
        }
        pushStack(f);
    }
    if(isNaN(f.mem3.value|| ! isFinite(f.mem3.value)){
        f.mem3.value=0;
    }
    f.display.value=f.mem3.value;
    computed = true;
}

// recall X
// f=form object
function rcl4(f)
{
    fillundostack(f);
    // auto-push the stack if the last value was computed
    if(computed) {
        if(isnotafinatenumber(f)){
            f.display.value="0";
        }
        pushStack(f);
    }
    if(isNaN(f.mem4.value|| ! isFinite(f.mem4.value)){
        f.mem4.value=0;
    }
    f.display.value=f.mem4.value;
    computed = true;
}

// store X
// f=form object
function sto1(f)
{
    f.mem1.value=f.display.value;
}

// store X
// f=form object
function sto2(f)
{
    f.mem2.value=f.display.value;
}

// store X
// f=form object
function sto3(f)
{
    f.mem3.value=f.display.value;
}

// store X
// f=form object
function sto4(f)
{
    f.mem4.value=f.display.value;
}

// add a new character to the display
// object passed is the form object and the character(s)
function addChar(f, character)
{
    var tmpvar;
    if (computed || enterpressed) {
        fillundostack(f);
    }
    // auto-push the stack if the last value was computed
    if(computed) {
        if(isnotafinatenumber(f)){
            f.display.value="0";
        }
        pushStack(f);
        f.display.value = "";
        computed = false;
    }
    if(enterpressed) {
            f.display.value = "";
            computed = false;
            enterpressed = false;
    }
    tmpvar=f.display.value;

    // make sure f.display.value is a string
    if(tmpvar.match(/^[0-9\.\-eE]+$/)){
        f.display.value += character;
    }else{
        f.display.value = character;
    }
}

// f=form object
function deleteChar(f)
{
    if (computed || enterpressed) {
        fillundostack(f);
        f.display.value = 0;
        computed = false;
        enterpressed = false;
    }else{
        f.display.value = f.display.value.substring(0, f.display.value.length - 1);
    }
}

function powxy(f)
{
    var tmpvar;
    fillundostack(f);
    tmpvar = Math.pow(parseFloat(f.stack.value),parseFloat(f.display.value));
    f.display.value = tmpvar;
    computed = true;
    popStack(f);
}

function square(f)
{
    fillundostack(f);
    f.display.value = parseFloat(f.display.value* parseFloat(f.display.value);
    computed = true;
}

function sqrtx(f)
{
    fillundostack(f);
    f.display.value = Math.sqrt(parseFloat(f.display.value));
    computed = true;
}

function expx(f)
{
    fillundostack(f);
    f.display.value = Math.exp(parseFloat(f.display.value));
    computed = true;
}

function lnx(f)
{
    fillundostack(f);
    f.display.value = Math.log(parseFloat(f.display.value));
    computed = true;
}

// the 0.000...1 is to handle rounding errors better
function log10(f)
{
    fillundostack(f);
    f.display.value = Math.log(parseFloat(f.display.value))/(Math.LN10 - 0.00000000000000001);
    computed = true;
}

// ln(gamma(x))
// x is the actual value not a form object
function internal_loggamma(x)
{
    with(Math) {
        var v=1;
        var w=0
        var z=0
        while x<) { v*=x; x++ }
        w=1/(x*x)
        return ((((((((-3617/122400)*w + 7/1092)*w
         -691/360360)*w + 5/5940)*w
         -1/1680)*w + 1/1260)*w
         -1/360)*w + 1/12)/x + 0.5 * log(2*PI)-log(v)-x+(x-0.5)*log(x;
     
}

// gamma function
// x is the actual value not a form object
function internal_gamma(x
{  
    with(Math) {
        if x <= ) {
            if (abs(x)-floor(abs(x))==)
                // should be complex infinity but we do not have
                // complex numbers
                return Number.POSITIVE_INFINITY; 
            else 
                return PI/sin(PI*x* expinternal_loggamma(1-x) ) );
        }else 
            return exp(internal_loggamma(x)) ;
    
}

// calculate the factorial including non integer factorial
// Integer factorial is: n!= n* (n-1)!
// Non interger is: n!=gamma(n+1)
function internal_factorial(n)
{  
  with(Math) {
      if (n<0)  /* if negative */
        return internal_gamma(n+1);
      else if ((n == 0|| (n == 1))
        return 1;
      else if (abs(n)-floor(abs(n))==) { // positive integer
        var buf = 1;
        var i;
        for (i=1;i<=n;i++) {
            buf = buf*i;
        }
        return buf;
      }else         // if non-integer 
        return internal_gamma(n+1);
  
}

// this function can be used directly from the gui
function factx(f)
{
    fillundostack(f);
    if(isnotafinatenumber(f)){
        f.display.value =Number.NaN;
    }else{
        f.display.value = internal_factorial(parseFloat(f.display.value));
        computed = true;
    }
}
    
// toggle the mode between deg and rad
function changedegrad(button)
{
    ifdgmode == "1.0" ) {
        button.value = " deg";
        dgmode = Math.PI/180.0;
    else {
        button.value = " rad ";
        dgmode = 1.0;
    }
}

function sin(f){
    fillundostack(f);
    f.display.value = Math.sin(parseFloat(f.display.value)*dgmode);
    computed = true;
}

function asin(f){
    fillundostack(f);
    f.display.value = Math.asin(parseFloat(f.display.value))/dgmode;
    computed = true;
}

function cos(f){
    fillundostack(f);
    f.display.value = Math.cos(parseFloat(f.display.value)*dgmode);
    computed = true;
}

function acos(f){
    fillundostack(f);
    f.display.value = Math.acos(parseFloat(f.display.value))/dgmode;
    computed = true;
}

function tan(f){
    fillundostack(f);
    f.display.value = Math.tan(parseFloat(f.display.value)*dgmode);
    computed = true;
}

function atan(f){
    fillundostack(f);
    f.display.value = Math.atan(parseFloat(f.display.value))/dgmode;
    computed = true;
}

// put pi (3.1415... into x)
function pix(f){
    fillundostack(f);
    if(computed) {
        if(isnotafinatenumber(f)){
            f.display.value = Math.PI;
        }else{
            pushStack(f);
            f.display.value = Math.PI;
        }
    }else{
        f.display.value = Math.PI;
    }
    computed = true;
}

function onebyx(f)
{
    var tmpvar;
    fillundostack(f);
    tmpvar = parseFloat(f.display.value);
    if (isNaN(tmpvar|| tmpvar == 0){
        f.display.value =Number.NaN;
        computed = false;
    }else{
        f.display.value = / tmpvar;
        computed = true;
    }
}

function swapxy(f)
{
    var tmpvar;
    fillundostack(f);
    tmpvar = f.display.value;
    if(isNaN(tmpvar|| tmpvar == "" ){
        tmpvar="0";
    }
    f.display.value = f.stack.value;
    f.stack.value = tmpvar;
    computed = true;
}

function add(f)
{
    fillundostack(f);
    f.display.value = parseFloat(f.stack.value)
                       + parseFloat(f.display.value);
    computed = true;
    popStack(f);
}

function subtract(f)
{
    fillundostack(f);
    f.display.value = f.stack.value - f.display.value;
    computed = true;
    popStack(f);
}

function multiply(f)
{
    fillundostack(f);
    f.display.value = f.stack.value * f.display.value;
    computed = true;
    popStack(f);
}

function divide(f)
{
    fillundostack(f);
    var divisor = parseFloat(f.display.value);
    if(divisor == 0) {
        f.display.value = Number.POSITIVE_INFINITY;
    }else{
        f.display.value = f.stack.value / divisor;
    }
    computed = true;
    popStack(f);
}

// object passed is form
function changeSign(f)
{
    fillundostack(f);
    // we could use f.display.value = 0 - f.display.value but
    // we might get rounding errors
    if(f.display.value.substring(01== "-")
        f.display.value = f.display.value.substring(1, f.display.value.length);
    else
        f.display.value = "-" + f.display.value;
}

// keyboard interface

// handle the differences between MSIE and Netscape
function getkey(e)
{
if (window.event)
    return window.event.keyCode;
else if (e)
    return e.which;
else
    return null;
}

// http://www.faqs.org/docs/htmltut/forms/_INPUT_onKeyPress.html
function chkkey(e)
{
    var key, keychar;
    key = getkey(e);
    if (key == nullreturn true;
    if (key == 13){
        // enter pressed
        enterx(document.rpncal);
    }else if (key == 8){
        // backspace
        deleteChar(document.rpncal);
    }else{
        // get character
        keychar = String.fromCharCode(key);
        if ((("0123456789.").indexOf(keychar> -1)){
            addChar(document.rpncal,keychar);
        }else if (keychar == "e" ){
            expx(document.rpncal);
        }else if (keychar == "l" ){
            lnx(document.rpncal);
        }else if (keychar == "^" ){
            powxy(document.rpncal);
        }else if (keychar == "r" ){
            onebyx(document.rpncal);
        }else if (keychar == "d" ){
            // d or backspace = &lt;-
            deleteChar(document.rpncal);
        }else if (keychar == "C" ){
            cx(document.rpncal);
        }else if (keychar == "c" ){
            changeSign(document.rpncal);
        }else if (keychar == "s" ){
            // s = swap
            swapxy(document.rpncal);
        }else if (keychar == "p" ){
            // p = pop
            popStackDisplay(document.rpncal);
        }else if (keychar == "-" ){
            subtract(document.rpncal);
        }else if (keychar == "+" ){
            add(document.rpncal);
        }else if (keychar == "*" ){
            multiply(document.rpncal);
        }else if (keychar == "/" ){
            divide(document.rpncal);
        }
        // c = +/-
    }
}

function printkey(e)
{
var key, keychar;
key = getkey(e);
if (key == nullreturn true;
// get character
keychar = String.fromCharCode(key);
keychar = keychar.toLowerCase();
alert("key is: "+ key + "c: "+keychar);
}

//<!-- done hiding from old browsers -->

</script>
  </head>

  <body>
    <h1><font color="darkblue">Reverse Polish Notation
    Calculator</font></h1>

    <p>This calculator uses postfix notation also known as Reverse
    Polish Notation (RPN). This notation has many advantages over
    Algebraic notation. One advantage is that you can calculate 
    even
    complicated terms without braces.</p>

    <p>An example: Suppose you want calculate (4)<br>
     Press the following keys on the calculator: 5, enter, 3,
    enter. The and did go into the calculator's memory, the
    stack. Now you type and press + to add. After this you just
    press * to multiply.</p>

    <p>You can either operate this calculator with mouse clicks or
    <b><font color="#008800">you can use the keyboard</font></b>.
    However some web-browsers have keyboard shortcuts which may
    conflict with the keys used by this calculator. Therefore you
    need to place the mouse over the text area below
    as this avoids the browsers keyboard shortcuts to take
    effect. The keyboard interface was tested with Mozilla, MS IE and Opera.
    It does not work with Netscape 4.</p>

    <p>rpnjcalc comes with a small manual which you can find here:
<a href="rpnjcalc-help-0.1.html">rpnjcalc-help-0.1.html</a></p>
<hr>

    <center>
      <form name="rpncal" method="post">
        <table border="4" cellpadding="0" cellspacing="1" bgcolor=
        "#CCCCCC" summary="calculator">
          <tr>
            <td colspan="7" align="center"><font color="#0000AA">
              rpnjcalc version 1.6</font></td>
          </tr>

          <tr>
            <td colspan="4"><input type="button" value="stoX"
            onclick="sto4(this.form)"> <input name="mem4" value="0"
            size="14"> <input type="button" value="rclX" onclick=
            "rcl4(this.form)"> </td>

            <td colspan="3" bgcolor="#AAAABB">C:<input name=
            "stack3" value="0" size="23" readonly>&nbsp;</td>
          </tr>

          <tr>
            <td colspan="4"><input type="button" value="stoX"
            onclick="sto3(this.form)"> <input name="mem3" value="0"
            size="14"> <input type="button" value="rclX" onclick=
            "rcl3(this.form)"> </td>

            <td colspan="3" bgcolor="#AAAABB">B:<input name=
            "stack2" value="0" size="23" readonly>&nbsp;</td>
          </tr>

          <tr>
            <td colspan="4"><input type="button" value="stoX"
            onclick="sto2(this.form)"> <input name="mem2" value="0"
            size="14"> <input type="button" value="rclX" onclick=
            "rcl2(this.form)"> </td>

            <td colspan="3" bgcolor="#AAAABB">A:<input name=
            "stack1" value="0" size="23" readonly>&nbsp;</td>
          </tr>

          <tr>
            <td colspan="4"><input type="button" value="stoX"
            onclick="sto1(this.form)"> <input name="mem1" value="0"
            size="14"> <input type="button" value="rclX" onclick=
            "rcl1(this.form)"> </td>

            <td colspan="3" bgcolor="#AAAABB">Y:<input name="stack"
            value="0" size="23" readonly>&nbsp;</td>
          </tr>

          <tr>
            <td><input type="button" class="btn" value="undo" onclick=
            "undoall(this.form)"> </td>
            <td><input type="button" class="btn" value="lastX" onclick=
            "lastx(this.form)"> </td>
            <td><input type="button" class="btn" value="swap" onclick=
            "swapxy(this.form)"> </td>
      <td colspan="1">&nbsp;</td>
            <!-- the display line should be writable so you
                            can do copy and paste -->

            <td colspan="3" bgcolor="#AAAABB">X:<input name=
            "display" value="0" size="23">&nbsp;</td>
          </tr>

          <tr>
            <td><input type="button" class="btn" value=" sin " onclick=
            "sin(this.form)"> </td>

            <td><input type="button" class="btn" value="asin " onclick=
            "asin(this.form)"> </td>

            <td><input type="button" class="btn" value=" PI " onclick=
            "pix(this.form)"> </td>

            <td><input type="button" class="btn" value=" 1/x  " onclick=
            "onebyx(this.form)"> </td>

            <td><input type="button" class="btn" value=" y^x  " onclick=
            "powxy(this.form)"> </td>

            <td><input type="button" class="btn" value="  log " onclick=
            "log10(this.form)"> </td>

            <td><input type="button" class="btn" value=" E " onclick=
            "addChar(this.form, 'E')"> </td>
          </tr>

          <tr>
            <td><input type="button" class="btn" value=" cos " onclick=
            "cos(this.form)"> </td>

            <td><input type="button" class="btn" value="acos" onclick=
            "acos(this.form)"> </td>

            <td><input type="button" class="btn" value=" 7 " onclick=
            "addChar(this.form, '7')"> </td>

            <td><input type="button" class="btn" value=" 8 " onclick=
            "addChar(this.form, '8')"> </td>

            <td><input type="button" class="btn" value=" 9 " onclick=
            "addChar(this.form, '9')"> </td>

            <td><input type="button" class="btn" value=" / " onclick=
            "divide(this.form)"> </td>

            <td><input type="button" class="btn" value=" E- " onclick=
            "addChar(this.form, 'E-')"> </td>
          </tr>

          <tr>
            <td><input type="button" class="btn" value=" tan " onclick=
            "tan(this.form)"> </td>

            <td><input type="button" class="btn" value="atan " onclick=
            "atan(this.form)"> </td>

            <td><input type="button" class="btn" value=" 4 " onclick=
            "addChar(this.form, '4')"> </td>

            <td><input type="button" class="btn" value=" 5 " onclick=
            "addChar(this.form, '5')"> </td>

            <td><input type="button" class="btn" value=" 6 " onclick=
            "addChar(this.form, '6')"> </td>

            <td><input type="button" class="btn" value=" * " onclick=
            "multiply(this.form)"> </td>

            <td><input type="button" class="btn" value=" x! " onclick=
            "factx(this.form)"> </td>
          </tr>

          <tr>
            <td><input type="button" class="btn" value=" ^2 " onclick=
            "square(this.form)"> </td>

            <td><input type="button" class="btn" value="  sqrt  " onclick=
            "sqrtx(this.form)"> </td>

            <td><input type="button" class="btn" value=" 1 " onclick=
            "addChar(this.form, '1')"> </td>

            <td><input type="button" class="btn" value=" 2 " onclick=
            "addChar(this.form, '2')"> </td>

            <td><input type="button" class="btn" value=" 3 " onclick=
            "addChar(this.form, '3')"> </td>

            <td><input type="button" class="btn" value=" - " onclick=
            "subtract(this.form)"> </td>

      <td>&nbsp;</td>
          </tr>

          <tr>
            <td><input type="button" class="btn" value=" e^x " onclick=
            "expx(this.form)"> </td>

            <td><input type="button" class="btn" value=" ln  " onclick=
            "lnx(this.form)"> </td>

            <td><input type="button" class="btn" value=" 0 " onclick=
            "addChar(this.form, '0')"> </td>

            <td><input type="button" class="btn" value=" . " onclick=
            "addChar(this.form, '.')"> </td>

            <td><input type="button" class="btn" value=" +/-  " onclick=
            "changeSign(this.form)"> </td>

            <td><input type="button" class="btn" value=" + " onclick=
            "add(this.form)"> </td>

      <td>&nbsp;</td>
          </tr>

          <tr>
            <td>mode:</td>

            <td><input type="button" class="btn" name="mode" value="  rad  "
            onclick="changedegrad(this)"> </td>

            <td><input type="button" class="btn" value=" C " onclick=
            "cx(this.form)"> </td>

            <td><input type="button" class="btn" value=" &lt;- " onclick=
            "deleteChar(this.form)"> </td>

            <td><input type="button" class="btn" value=" pop " onclick=
            "popStackDisplay(this.form)"> </td>

            <td colspan="2"><input type="button" class="bigbtn" value=" Enter "
            name=" enter " onclick="enterx(this.form)"> </td>
          </tr>
        </table>
      </form>
      <br>
      <form name="kbdfrom" onkeypress="javascript:chkkey(event)">
        <small><textarea cols="76" rows="4" name="dummy" readonly
        onclick="this.style.backgroundColor='#BDBDBD'" onmouseout=
        "this.style.backgroundColor='#FFFFFF'">
          For keyboard usage leave mouse cursor on this field and
          click once. Keys: 0-9.=numbers, return=enter, c=+/-, C=clear, 
                      s=swap, d=&lt;-, p=pop, ^=y^x, l=ln, e=e^x, r=1/x 
        </textarea></small>
      </form>
    </center>
    <br>
    <hr>
    <br>
    <!-- version is also written up in the table -->
     rpnjcalc was written by Guido Socher, guido at linuxfocus dot
    org, Copyright: GPL <!-- history:
    1997-04-03 first version
    2000-06-08 v0.8 several updateds
    2003-10-12 v0.9 html faults removed. Tested on opera, mozilla, IE
    2003-10-13 v1.0 more functions added
    2003-10-16 v1.1 code cleanup 
                    Keyboard interface added.
    2003-10-16 v1.2 more math functions added (trigonometry)
    2003-10-17 v1.3 factorial added
    2003-10-20 v1.4 undo/lastx/sto and rcl registers
    2003-10-21 v1.5 fine tuning. Added help text.
    2003-12-18 v1.6 autopush stack when pressing rcl

    nice links: http://www.hpmuseum.org/
                http://www.hp.com/calculators/
    -->
  </body>
</html>
<!--  vim: set sw=ts=et: -->

           
       
Related examples in the same category
1. JavaScript (sCal-05m) Calculator
2. JavaScript Calculator - sCal
3. A JavaScript Calculator
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.