/**
   * Determines the version of the underlying maxima version.
   *
   * @return An array of 3 elements, containing, major, minor and build version number,
   *     respectively.
   * @throws MaximaTimeoutException
   */
  private int[] determineMaximaVersion() throws MaximaTimeoutException {
    String buildinfo = ggbMaxima.executeCall("build_info();");

    int[] retval = new int[3];
    Pattern p = Pattern.compile("Maxima version: (\\d+).(\\d+).(\\d+)");
    Matcher m = p.matcher(buildinfo);
    if (!m.find()) retval[0] = retval[1] = retval[2] = -1;
    else {
      retval[0] = Integer.parseInt(m.group(1));
      retval[1] = Integer.parseInt(m.group(2));
      retval[2] = Integer.parseInt(m.group(3));
    }
    return retval;
  }
  private void initMyMaximaFunctions()
      throws MaximaTimeoutException, geogebra.cas.jacomax.MaximaTimeoutException {

    // turn auto-simplification off, so a+a gives a+a
    // with this setting ev( a+a, simp ) is needed to get 2*a
    ggbMaxima.executeCall("simp:false;");

    // variable ordering: then factor(a^2-b^2) gives (a-b)*(b+a) instead of �(b-a)(b+a)
    // see http://www.geogebra.org/trac/ticket/281
    ggbMaxima.executeCall("ordergreat(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,z);");

    // set line length of "terminal"
    // we don't want lines broken
    ggbMaxima.executeCall("linel:10000;");

    // make sure results are returned
    ggbMaxima.executeCall("display2d:false;");

    // make sure integral(1/x) = log(abs(x))
    ggbMaxima.executeCall("logabs:true;");

    // make sure algsys (solve) doesn't return complex roots
    ggbMaxima.executeCall("realonly:true;");

    // eg x^-1 displayed as 1/x
    ggbMaxima.executeCall("exptdispflag:true;");

    // suppresses the printout of the message informing the user of the conversion of floating point
    // numbers to rational numbers
    ggbMaxima.executeCall("ratprint:false;");

    // When true, r some rational number, and x some expression, %e^(r*log(x)) will be simplified
    // into x^r . It should be noted that the radcan command also does this transformation, and more
    // complicated transformations of this ilk as well. The logcontract command "contracts"
    // expressions containing log.
    ggbMaxima.executeCall("%e_to_numlog:true;");

    // define custom functions
    ggbMaxima.executeCall("log10(x) := log(x) / log(10);");
    ggbMaxima.executeCall("log2(x) := log(x) / log(2);");
    ggbMaxima.executeCall("cbrt(x) := x^(1/3);");

    // needed to define lcm()
    ggbMaxima.executeCall("load(functs)$");

    // needed for degree()
    ggbMaxima.executeCall("load(powers)$");

    // needed for ???
    ggbMaxima.executeCall("load(format)$");

    // turn {x=3} into {3} etc
    ggbMaxima.executeCall(
        "stripequals(ex):=block("
            + "if atom(ex) then return(ex)"
            + "else if op(ex)=\"=\" then return(stripequals(rhs(ex)))"
            + "else apply(op(ex),map(stripequals,args(ex)))"
            + ")$");

    /* This function takes an expression ex and returns a list of coefficients of v */
    ggbMaxima.executeCall(
        "coefflist(ex,v):= block([deg,kloop,cl],"
            + "cl:[],"
            + "ex:ev(expand(ex),simp),"
            + "deg:degree(ex,v),"
            + "ev(for kloop:0 thru deg do\n"
            + "cl:append(cl,[coeff(ex,v,kloop)]),simp),"
            + "cl"
            + ")$");

    /*
     * Tests if a given symbol is a function-symbol (function name)
     * Implemented as LISP-function as you cannot do this with maxima-functions
     */
    ggbMaxima.executeCall(
        ":lisp (defun $myfun (sym) " + "(cond ((fboundp sym)) ((get sym 'mprops) t) (t nil)))");

    /*
     * Takes a symbol and tests if a it is already bound to something.
     * ( = bound to a function-name or a variable-name).
     *  Note: weird formal parameter name as due to maxima's dynamic scoping rules
     *        using a "normal" formal parameter just doesn't work.
     *        (just try changing "ggbnsrphdbgse5tfd" and then call "issymbolbound('x)")
     */
    ggbMaxima.executeCall(
        "issymbolbound(ggbnsrphdbgse5tfd):= "
            + "myfun(ggbnsrphdbgse5tfd) "
            + "or ?boundp(ggbnsrphdbgse5tfd);");

    /*
     * eg integrate(x^n,x) asks if n+1 is zero
     * this disables the interactivity
     * but we get:
     * if equal(n+1,0) then log(abs(x)) else x^(n+1)/(n+1)
     * TODO: change to ggb syntax
     */
    ggbMaxima.executeCall("load(\"noninteractive\");");

    // define Degree
    ggbMaxima.executeCall("Degree:180/%pi;");
  }