*** empty log message ***
[m17n/m17n-lib-js.git] / xex.js
diff --git a/xex.js b/xex.js
index a726a77..cd440c1 100644 (file)
--- a/xex.js
+++ b/xex.js
-// -* coding: utf-8; -*
+// xex.js -- Xex (XML Expression) interpreter
+// Copyright (C) 2010
+//   National Institute of Advanced Industrial Science and Technology (AIST)
+//   Registration Number H15PRO112
 
-var Xex = {};
+// This file is part of the m17n database; a sub-part of the m17n
+// library.
 
-Xex.Alist = function ()
-{
-  this.count = 0;
-}
+// The m17n library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public License
+// as published by the Free Software Foundation; either version 2.1 of
+// the License, or (at your option) any later version.
 
-Xex.Alist.prototype.put = function (key, val)
-{
-  this.count++;
-  return (this[key] = val);
-}
-Xex.Alist.prototype.clone = function ()
-{
-  var alist = new Xex.Alist ();
-  for (key in this)
-    alist[key] = this[key];
-  return alist;
-}
-Xex.Alist.prototype.toString = function ()
-{
-  var str = 'alist:';
-  for (key in this)
-    str += '"' + key + '"';
-  return str;
-}
+// The m17n library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+
+// You should have received a copy of the GNU Lesser General Public
+// License along with the m17n library; if not, write to the Free
+// Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+// Please note that the code is not yet matured.
+
+var Xex = {};
+
+(function () {                 // Logging
+  // The logging node containing tracing information.
+  var log = null;
+  // Number of lines.
+  var lines;
+  // Style properties of the logging node.
+  var styles = { border: '1px solid black',
+                font: 'normal normal normal small monospace',
+                width: '600px',
+                minHeight: '300px',
+                maxHeight: '300px',
+                overflow: 'auto' };
+  
+  // Toggle logging on and off.  PARENT if non-null specifies the
+  // parent of the log node.  The log node is appended to PARENT.
+  // If PARENT is null, 'body' node is assumed.
+  Xex.LogToggle = function (parent)
+  {
+    if (log)
+      {
+       log.parentNode.removeChild (log);
+       log = null;
+       return;
+      }
+    if (! parent)
+      parent = document.getElementsByTagName ('body')[0];
+    log = document.createElement ('ol');
+    for (var prop in styles)
+      log.style[prop] = styles[prop];
+    parent.appendChild (log);
+    lines = 0;
+    return log;
+  }
 
-// Xex.alist = new Xex.Alist ();
-// Xex.alist.put ('abc', "ABC");
-// alert (Xex.alist['abc']);
+  // Log ARG (string).  INDENT if specified is a number of columns to
+  // indent.  If INDENT is -1, ARG is appended to the last log.
+  Xex.Log = function (arg, indent)
+  {
+    if (! log)
+      return;
+    if (! arg)
+      {
+       while (log.childNodes.length > 0)
+         log.removeChild (log.firstChild);
+       lines = 0;
+      }
+    else
+      {
+       var node;
+       if (indent == -1)
+         log.lastChild.innerText += arg;
+       else
+         {
+           lines++;
+           if (lines >= 256)
+             {
+               node = log.firstElement ();
+               log.start = lines - 254;
+             }
+           else
+             node = document.createElement ('li');
+           if (indent != undefined)
+             node.style.textIndent = (indent + 1) + 'em';
+           else
+             node.style.textIndent = '0px';
+           node.innerText = arg;
+           log.appendChild (node);
+           log.scrollTop = log.scrollHeight;
+         }
+      }
+  }
+}) ();
 
 Xex.Error = {
   UnknownError: "unknown-error",
@@ -45,7 +112,8 @@ Xex.Error = {
 
   UnknownFunction: "unknown-function",
   MacroExpansionError: "macro-expansion-error",
-  NoVariableName: "no-variable-anme",
+  NoVariableName: "no-variable-name",
+  NoFunctionName: "no-funcion-name",
 
   // Run time errors.
   ArithmeticError: "arithmetic-error",
@@ -56,45 +124,52 @@ Xex.Error = {
   UncaughtThrow: "uncaught-throw"
 };
 
-Xex.Variable = function (domain, name, val)
+Xex.Variable = function (name, desc, val, range)
 {
-  this.domain = domain;
-  this.name = name;
+  if (name)
+    this.name = name;
+  if (desc)
+    this.desc = desc;
   this.val = val;
+  if (range)
+    this.range = range;
 }
 
-Xex.Variable.prototype.clone = function () {
-  return new Xex.Variable (this.domain, this.name, this.value);
-}
-    
-Xex.Variable.prototype.Equals = function (obj) {
-  return ((obj instanceof Xex.Variable)
-         && obj.name == this.name);
-}
+Xex.Variable.prototype = {
+  clone: function ()
+  {
+    return new Xex.Variable (this.name, this.desc, this.val, this.range);
+  },
+  equals: function (obj)
+  {
+    return ((obj instanceof Xex.Variable)
+           && obj.name == this.name);
+  },
+  SetValue: function (term)
+  {
+    this.val = term;
+    return term;
+  }
+}  
 
-Xex.Variable.prototype.SetValue = function (term) {
-  this.val = term;
-  return term;
-}
 
-Xex.Function = function (name, with_var, min_args, max_args) {
+Xex.Function = function (name, with_var, min_args, max_args)
+{
   this.name = name;
   this.with_var = with_var;
   this.min_args = min_args;
   this.max_args = max_args;
 };  
 
-Xex.Subrountine = function (builtin, name, with_var, min_args, max_args) {
-  this.name = name;
-  this.with_var = with_var;
-  this.min_args = min_args;
-  this.max_args = max_args;
+Xex.Subrountine = function (builtin, name, with_var, min_args, max_args)
+{
+  Xex.Function.apply (this, [name, with_var, min_args, max_args]);
   this.builtin = builtin;
 }
 
 Xex.Subrountine.prototype.Call = function (domain, vari, args)
 {
-  newargs = new Array ();
+  var newargs = new Array ();
   for (var i = 0; i < args.length; i++)
     {
       newargs[i] = args[i].Eval (domain);
@@ -106,10 +181,7 @@ Xex.Subrountine.prototype.Call = function (domain, vari, args)
 
 Xex.SpecialForm = function (builtin, name, with_var, min_args, max_args)
 {
-  this.name = name;
-  this.with_var = with_var;
-  this.min_args = min_args;
-  this.max_args = max_args;
+  Xex.Function.apply (this, [name, with_var, min_args, max_args]);
   this.builtin = builtin;
 }
 
@@ -120,10 +192,7 @@ Xex.SpecialForm.prototype.Call = function (domain, vari, args)
 
 Xex.Lambda = function (name, min_args, max_args, args, body)
 {
-  this.name = name;
-  this.with_var = with_var;
-  this.min_args = min_args;
-  this.max_args = max_args;
+  Xex.Function.apply (this, [name, false, min_args, max_args]);
   this.args = args;
   this.body = body;
 }
@@ -174,10 +243,7 @@ Xex.Lambda.prototype.Call = function (domain, vari, args)
 
 Xex.Macro = function (name, min_args, max_args, args, body)
 {
-  this.name = name;
-  this.with_var = with_var;
-  this.min_args = min_args;
-  this.max_args = max_args;
+  Xex.Function.apply (this, [name, false, min_args, max_args]);
   this.args = args;
   this.body = body;
 }
@@ -193,9 +259,9 @@ Xex.Macro.prototype.Call = function (domain, vari, args)
       domain.Bind (this.args[i], args[i]);
     try {
       domain.Catch (Xex.CatchTag.Return);
-      for (var term in body)
+      for (var i in this.body)
         {
-         result = term.Eval (domain);
+         result = this.body[i].Eval (domain);
          if (domain.Thrown ())
            break;
        }
@@ -254,7 +320,11 @@ Xex.Domain = function (name, parent, context)
       for (elt in parent.functions)
        this.functions[elt] = parent.functions[elt];
       for (elt in parent.variables)
-       this.variables[elt] = parent.variables[elt];
+       {
+         var vari = parent.variables[elt];
+         this.variables[elt] = new Xex.Variable (vari.name, vari.desc,
+                                                 vari.val, vari.range);
+       }
     }
 
   this.call_stack = new Array ();
@@ -352,7 +422,7 @@ Xex.Domain.prototype = {
     this.functions[name] =  new Xex.Lambda (name, min_args, max_args,
                                            args, body);
   },
-  DefunByFunc: function (func) { this.functions[func.Name] = func; },
+  DefunByFunc: function (func) { this.functions[func.name] = func; },
   Defmacro: function (name, min_args, max_args, args, body)
   {
     this.functions[name] = new Xex.Macro (name, min_args, max_args,
@@ -362,30 +432,20 @@ Xex.Domain.prototype = {
   {
     var func = this.functions[fname];
 
+    if (! func)
+      throw new Xex.ErrTerm (Xex.Error.UnknownFunction, fname);
     if (this.termtypes[alias])
       throw new Xex.ErrTerm (Xex.Error.FunctionConflict,
                           "Already defined as a term type: " + alias);
     if (this.functions[alias])
       throw new Xex.ErrTerm (Xex.Error.FunctionConflict,
                           "Already defined as a function: " + alias);
-    if (! func)
-      throw new Xex.ErrTerm (Xex.Error.UnknownFunction, fname);
     this.functions[alias] = func;
   },
-  Defvar: function (name)
+  Defvar: function (name, desc, val, range)
   {
-    var vari = this.variables[name];
-    if (vari)
-      {
-       if (vari.Typed)
-         throw new Xex.ErrTerm (Xex.Error.VariableTypeConflict,
-                              "Not a non-typed variable: " + name);
-      }
-    else
-      {
-       vari = new Xex.Variable (this, name, Xex.Zero);
-       this.variables[name] = vari;
-      }
+    var vari = new Xex.Variable (name, desc, val, range);
+    this.variables[name] = vari;
     return vari;
   },
   GetFunc: function (name)
@@ -393,7 +453,7 @@ Xex.Domain.prototype = {
     var func = this.functions[name];
     if (! func)
       throw new Xex.ErrTerm (Xex.Error.UnknownFunction,
-                            "Unknown function: " + this + ':' + name);
+                            "Unknown function: " + name);
     return func;
   },
   CopyFunc: function (domain, name)
@@ -411,7 +471,8 @@ Xex.Domain.prototype = {
   {
     var vari = this.variables[name];
     if (! vari)
-      vari = this.variables[name] = new Xex.Variable (this, name, Xex.Zero);
+      vari = this.variables[name] = new Xex.Variable (name, null,
+                                                     Xex.Zero, null);
     return vari;
   },
   GetVar: function (name) { return this.variables[name]; },
@@ -438,64 +499,194 @@ Xex.Term.prototype = {
   IsTrue: function () { return true; },
   Eval: function (domain) { return this.Clone (); },
   Clone: function (domain) { return this; },
-  Equals: function (obj)
+  equals: function (obj)
   {
     return (this.type == obj.type
-           && this.val
+           && this.val != undefined
            && obj.val == this.val);
   },
-  Matches: function (obj) { return this.Equals (obj); },
+  Matches: function (obj) { return this.equals (obj); },
   toString: function ()
   {
     if (this.val != undefined)
       return '<' + this.type + '>' + this.val + '</' + this.type + '>';
     return '<' + this.type + '/>';
-  }
+  },
+  Intval: function () { throw new Xex.ErrTerm (Xex.Error.WrongType,
+                                              "Not an integer"); },
+  Strval: function () { throw new Xex.ErrTerm (Xex.Error.WrongType,
+                                              "Not a string"); }
 };
 
-Xex.ParseTerm = function (domain, node)
+Node.prototype.firstElement = function ()
 {
-  var name = node.nodeName;
-  var parser = domain.termtypes[name];
-
-  if (parser)
-    return parser (domain, node);
-  if (name == 'defun' || name == 'defmacro')
-    {
-      name = parse_defun_head (domain, node);
-      parse_defun_body (domain, node);
-      return new Xex.StrTerm (name);
-    }
-  if (name == 'defvar')
-    {
-      name = parse_defvar (doamin, node);
-      return new Xex.StrTerm (nanme);
-    }
-
-  return new Xex.Funcall.prototype.Parser (domain, node);
+  for (var n = this.firstChild; n; n = n.nextSibling)
+    if (n.nodeType == 1)
+      return n;
+  return null;
 }
 
-Xex.ParseTermList = function (domain, node)
+Node.prototype.nextElement = function ()
 {
-  for (var n = node; n; n = n.nextSibling)
+  for (var n = this.nextSibling; n; n = n.nextSibling)
     if (n.nodeType == 1)
+      return n;
+  return null;
+};
+
+(function () {
+  function parse_defvar (domain, node)
+  {
+    var name = node.attributes['vname'].nodeValue;
+    if (! name)
+      throw new Xex.ErrTerm (Xex.Error.NoVariableName, node, '');
+    var vari = domain.variables[name];
+    var desc, val = null, range;
+    if (vari)
       {
-       if (n.nodeName == 'defun' || n.nodeName == 'defmacro')
-         Xex.parse_defun_head (domain, n);
+       desc = vari.description;
+       val = vari.val;
+       range = vari.range;
       }
-  var terms = new Array ();
-  for (var n = node; n; n = n.nextSibling)
-    if (n.nodeType == 1)
+    node = node.firstElement ();
+    if (node && node.nodeName == 'description')
+      {
+       desc = node.firstChild.nodeValue;
+       node = node.nextElement ();
+      }
+    if (node)
+      {
+       val = Xex.Term.Parse (domain, node);
+       node = node.nextElement ();
+       if (node && node.nodeName == 'possible-values')
+         for (node = node.firstElement (); node; node = node.nextElement ())
+           {
+             var pval;
+             if (node.nodeName == 'range')
+               {
+                 if (! val.IsInt)
+                   throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
+                                          'Range not allowed for ' + name);
+                 pval = new Array ();
+                 for (var n = node.firstElement (); n; n = n.nextElement ())
+                   {
+                     var v = Xex.Term.Parse (domain, n);
+                     if (! v.IsInt)
+                       throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
+                                              'Invalid range value: ' + val);
+                     pval.push (v);
+                   }
+                 }
+             else
+               {
+                 pval = Xex.Term.Parse (domain, node);
+                 if (val.type != pval.type)
+                   throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
+                                          'Invalid possible value: ' + pval);
+               }
+             if (! range)
+               range = new Array ();
+             range.push (pval);
+         }
+      }
+    if (val == null)
+      val = Xex.Zero;
+    domain.Defvar (name, desc, val, range);
+    return name;
+  }
+
+  function parse_defun_head (domain, node)
+  {
+    var name = node.attributes['fname'].nodeValue;
+    if (! name)
+      throw new Xex.ErrTerm (Xex.Error.NoFunctionName, node, '');
+    var args = new Array ();
+    var nfixed = 0, noptional = 0, nrest = 0;
+
+    node = node.firstElement ();
+    if (node && node.nodeName == 'args')
+      {
+       var n;
+       for (n = n.firstElement (); n; n = n.nextElement ())
+         {
+           if (n.nodeName == 'fixed')
+             nfixed++;
+           else if (n.nodeName == 'optional')
+             noptional++;
+           else if (n.nodeName == 'rest')
+             nrest++;
+           else
+             throw new Xex.ErrTerm (Xex.Error.WrongType, n, n.nodeName);
+         }
+       if (nrest > 1)
+         throw new Xex.ErrTerm (Xex.Error.WrongType, n, 'Too many <rest>');
+       for (n = node.firstElement (); n; n = n.nextElement ())
+         args.push (domain.DefVar (n.attributes['vname'].nodeValue));
+      }
+    args.min_args = nfixed;
+    args.max_args = nrest == 0 ? nfixed + noptional : -1;
+
+    if (node.nodeName == 'defun')
+      domain.Defun (name, args, null);
+    else
+      domain.Defmacro (name, args, null);
+    return name;
+  }
+
+  function parse_defun_body (domain, node)
+  {
+    var name = node.attributes['fname'].nodeValue;
+    var func = domain.GetFunc (name);
+    var body;
+    for (node = node.firstElement (); node; node = node.nextElement ())
+      if (node.nodeName != 'description' && node.nodeName != 'args')
+       break;
+    body = Xex.Term.Parse (domain, node, null);
+    func.body = body;
+  }
+
+  Xex.Term.Parse = function (domain, node, stop)
+  {
+    if (arguments.length == 2)
+      {
+       var name = node.nodeName;
+       var parser = domain.termtypes[name];
+
+       if (parser)
+         return parser (domain, node);
+       if (name == 'defun' || name == 'defmacro')
+         {
+           name = parse_defun_head (domain, node);
+           parse_defun_body (domain, node);
+           return new Xex.StrTerm (name);
+         }
+       if (name == 'defvar')
+         {
+           name = parse_defvar (domain, node);
+           return new Xex.StrTerm (name);
+         }
+       return new Xex.Funcall.prototype.Parser (domain, node);
+      }
+    for (var n = node; n && n != stop; n = n.nextElement ())
+      if (n.nodeName == 'defun' || n.nodeName == 'defmacro')
+       parse_defun_head (domain, n);
+    var terms = null;
+    for (var n = node; n && n != stop; n = n.nextElement ())
       {
        if (n.nodeName == 'defun' || n.nodeName == 'defmacro')
-         Xex.parse_defun_body (domain, n);
+         parse_defun_body (domain, n);
        else if (n.nodeName == 'defvar')
-         Xex.parse_defvar (domain, n);
+         parse_defvar (domain, n);
        else
-         terms.push (Xex.ParseTerm (domain, n));
+         {
+           if (! terms)
+             terms = new Array ();
+           terms.push (Xex.Term.Parse (domain, n));
+         }
       }
-  return terms;
-}
+    return terms;
+  }
+}) ();
 
 Xex.Varref = function (vname)
 {
@@ -508,9 +699,9 @@ Xex.Varref = function (vname)
   proto.Clone = function () { return new Xex.Varref (this.val); }
   proto.Eval = function (domain)
   {
-    if (! this.vari || this.vari.domain != domain)
-      this.vari = domain.GetVarCreate (this.val);
-    return this.vari.val;
+    var vari = domain.GetVarCreate (this.val);
+    Xex.Log (this.ToString () + '=>' + vari.val, domain.depth);
+    return vari.val;
   }
 
   proto.Parser = function (domain, node)
@@ -518,15 +709,20 @@ Xex.Varref = function (vname)
     return new Xex.Varref (node.attributes['vname'].nodeValue);
   }
 
+  proto.ToString = function ()
+  {
+    return '<varref vname="' + this.val + '"/>';
+  }
+
   Xex.Varref.prototype = proto;
 }) ();
 
 var null_args = new Array ();
   
-Xex.Funcall = function (func, vari, args)
+Xex.Funcall = function (func, vname, args)
 {
   this.func = func;
-  this.vari = vari;
+  this.vname = vname;
   this.args = args || null_args;
 };
 
@@ -539,20 +735,19 @@ Xex.Funcall = function (func, vari, args)
     var attr;
 
     if (fname == 'funcall')
-      fname = node.attributes['fname']
+      fname = node.attributes['fname'].nodeValue;
     var func = domain.GetFunc (fname);
-    var vari;
+    var vname;
     attr = node.attributes['vname'];
-    vari = attr != undefined ? domain.GetVarCreate (attr.nodeValue) : false;
-    var args = Xex.ParseTermList (domain, node.firstChild);
-    return new Xex.Funcall (func, vari, args);
+    vname = attr != undefined ? attr.nodeValue : null;
+    var args = Xex.Term.Parse (domain, node.firstElement (), null);
+    return new Xex.Funcall (func, vname, args);
   }
 
   proto.New = function (domain, fname, vname, args)
   {
     var func = domain.GetFunc (fname);
-    var vari = vname ? domain.GetVarCreate (vname) : null;
-    var funcall = new Xex.Funcall (func, vari, args);
+    var funcall = new Xex.Funcall (func, vname, args);
     if (func instanceof Xex.Macro)
       funcall = funcall.Eval (domain);
     return funcall;
@@ -560,7 +755,19 @@ Xex.Funcall = function (func, vari, args)
 
   proto.Eval = function (domain)
   {
-    return this.func.Call (domain, this.vari, this.args);
+    Xex.Log (this, domain.depth);
+    var vari;
+    if (this.vname)
+      vari = domain.GetVarCreate (this.vname);
+    domain.depth++;
+    var result;
+    try {
+      result = this.func.Call (domain, vari, this.args);
+    } finally {
+      Xex.Log (' => ' + result, --domain.depth,
+              this.func instanceof Xex.Subrountine);
+    }
+    return result;
   }
 
   proto.Clone = function ()
@@ -568,11 +775,11 @@ Xex.Funcall = function (func, vari, args)
     return new Xex.Funcall (this.func, this.vari, this.args);
   }
 
-  proto.Equals = function (obj)
+  proto.equals = function (obj)
   {
     return (obj.type == 'funcall'
            && obj.func == this.func
-           && obj.vari.Equals (this.vari)
+           && obj.vari.equals (this.vari)
            && obj.args.length == this.func.length);
   }
 
@@ -580,11 +787,18 @@ Xex.Funcall = function (func, vari, args)
   {
     var arglist = ''
     var len = this.args.length;
+    var str = '<' + this.func.name;
+    if (this.vname)
+      str += ' vname="' + this.vname + '"';
     if (len == 0)
-      return '<' + this.func.name + '/>';
-    for (var i = 0; i < len; i++)
-      arglist += this.args[i].toString ();
-    return '<' + this.func.name + '>' + arglist + '</' + this.func.name + '>';
+      return str + '/>';
+    if (this.func instanceof Xex.Subrountine)
+      for (var i = 0; i < len; i++)
+       arglist += this.args[i].toString ();
+    else
+      for (var i = 0; i < len; i++)
+       arglist += '.';
+    return str + '>' + arglist + '</' + this.func.name + '>';
   }
 
   Xex.Funcall.prototype = proto;
@@ -617,7 +831,7 @@ Xex.ErrTerm = function (ename, message, stack)
     return new Xex.ErrTerm (ename, message, false);
   }
 
-  proto.Equals = function (obj)
+  proto.equals = function (obj)
   {
     return (obj.IsError
            && obj.ename == ename && obj.message == message
@@ -642,6 +856,7 @@ Xex.IntTerm = function (num) { this.val = num; };
 (function () {
   var proto = new Xex.Term ('integer');
   proto.IsInt = true;
+  proto.Intval = function () { return this.val; };
   proto.IsTrue = function () { return this.val != 0; }
   proto.Clone = function () { return new Xex.IntTerm (this.val); }
   proto.Parser = function (domain, node)
@@ -659,11 +874,12 @@ Xex.StrTerm = function (str) { this.val = str; };
 (function () {
   var proto = new Xex.Term ('string');
   proto.IsStr = true;
+  proto.Strval = function () { return this.val; };
   proto.IsTrue = function () { return this.val.length > 0; }
   proto.Clone = function () { return new Xex.StrTerm (this.val); }
   proto.Parser = function (domain, node)
   {
-    return new Xex.StrTerm (node.firstChild.nodeValue);
+    return new Xex.StrTerm (node.firstChild ? node.firstChild.nodeValue : '');
   }
   Xex.StrTerm.prototype = proto;
 }) ();
@@ -688,20 +904,20 @@ Xex.LstTerm = function (list) { this.val = list; };
   proto.IsTrue = function () { return this.val.length > 0; }
   proto.Clone = function () { return new Xex.LstTerm (this.val.slice (0)); }
 
-  proto.Equals = function (obj)
+  proto.equals = function (obj)
   {
     if (obj.type != 'list' || obj.val.length != this.val.length)
       return false;
     var i, len = this.val.length;
     for (i = 0; i < len; i++)
-      if (! this.val[i].Equals (obj.val[i]))
+      if (! this.val[i].equals (obj.val[i]))
        return false;
     return true;
   }
 
   proto.Parser = function (domain, node)
   {
-    var list = Xex.ParseTermList (domain, node.firstChild);
+    var list = Xex.Term.Parse (domain, node.firstElement (), null);
     return new Xex.LstTerm (list);
   }
 
@@ -724,27 +940,128 @@ Xex.LstTerm = function (list) { this.val = list; };
 
   function Fset (domain, vari, args)
   {
-    return vari.SetValue (args[0]);
+    if (! vari)
+      throw new Xex.ErrTerm (Xex.Error.NoVariableName,
+                            'No variable name to set');
+    vari.SetValue (args[0]);
+    return args[0];
+  }
+
+  function Fnot (domain, vari, args)
+  {
+    return (args[0].IsTrue () ? Xex.Zero : Xex.One);
   }
 
   function maybe_set_intvar (vari, n)
   {
     var term = new Xex.IntTerm (n);
-    if (vari != null)
+    if (vari)
       vari.SetValue (term);
     return term;
   }
 
   function Fadd (domain, vari, args)
   {
-    var n = vari ? vari.val.val : 0;
+    var n = vari ? vari.val.Intval () : 0;
     var len = args.length;
 
     for (var i = 0; i < len; i++)
-      n += args[i].val;
+      n += args[i].Intval ();
+    return maybe_set_intvar (vari, n);
+  }
+
+  function Fmul (domain, vari, args)
+  {
+    var n = vari ? vari.val.Intval () : 1;
+    for (var i = 0; i < args.length; i++)
+      n *= args[i].Intval ();
+    return maybe_set_intvar (vari, n);
+  }
+
+  function Fsub (domain, vari, args)
+  {
+    var n, i;
+
+    if (! vari)
+      {
+       n = args[0].Intval ();
+       i = 1;
+      }
+    else
+      {
+       n = vari.val.Intval ();
+       i = 0;
+      }
+    while (i < args.length)
+      n -= args[i++].Intval ();
+    return maybe_set_intvar (vari, n);
+  }
+
+  function Fdiv (domain, vari, args)
+  {
+    var n, i;
+
+    if (! vari == null)
+      {
+       n = args[0].Intval ();
+       i = 1;
+      }
+    else
+      {
+       n = vari.val.Intval ();
+       i = 0;
+      }
+    while (i < args.length)
+      n /= args[i++].Intval ();
+    return maybe_set_intvar (vari, n);
+  }
+
+  function Fmod (domain, vari, args)
+  {
+    return maybe_set_intvar (vari, args[0].Intval () % args[1].Intval ());
+  }
+
+  function Flogior (domain, vari, args)
+  {
+    var n = vari == null ? 0 : vari.val;
+    for (var i = 0; i < args.length; i++)
+      n |= args[i].val;
+    return maybe_set_intvar (vari, n);
+  }
+
+  function Flogand (domain, vari, args)
+  {
+    var n, i;
+    if (vari == null)
+      {
+       Xex.Log ("logand arg args[0]" + args[0]);
+       n = args[0].Intval ()
+       i = 1;
+      }
+    else
+      {
+       Xex.Log ("logand arg var " + vari);
+       n = vari.val.Intval ();
+       i = 0;
+      }
+    while (n > 0 && i < args.length)
+      {
+       Xex.Log ("logand arg " + args[i]);
+       n &= args[i++].val;
+      }
     return maybe_set_intvar (vari, n);
   }
 
+  function Flsh (domain, vari, args)
+  {
+    return maybe_set_intvar (vari, args[0].Intval () << args[1].Intval ());
+  }
+
+  function Frsh (domain, vari, args)
+  {
+    return maybe_set_intvar (vari, args[0].Intval () >> args[1].Intval ());
+  }
+
   function Fand (domain, vari, args)
   {
     var len = args.length;
@@ -753,7 +1070,7 @@ Xex.LstTerm = function (list) { this.val = list; };
       var result = args[i].Eval (domain);
       if (domain.Thrown ())
        return result;
-      if (! result.IsTrue)
+      if (! result.IsTrue ())
        return Xex.Zero;
     }
     return Xex.One;
@@ -767,12 +1084,78 @@ Xex.LstTerm = function (list) { this.val = list; };
       var result = args[i].Eval (domain);
       if (domain.Thrown ())
        return result;
-      if (result.IsTrue)
+      if (result.IsTrue ())
        return Xex.One;
     }
     return Xex.Zero;
   }
 
+  function Feq (domain, vari, args)
+  {
+    for (var i = 1; i < args.length; i++)
+      if (! args[i - 1].equals (args[i]))
+       return Xex.Zero;
+    return Xex.One;
+  }
+
+  function Fnoteq (domain, vari, args)
+  {
+    return (Feq (domain, vari, args) == Xex.One ? Xex.Zero : Xex.One);
+  }
+
+  function Flt (domain, vari, args)
+  {
+    var n = args[0].Intval ();
+
+    for (var i = 1; i < args.length; i++)
+      {
+       var n1 = args[i].Intval ();
+       if (n >= n1)
+         return Xex.Zero;
+       n = n1;
+      }
+    return Xex.One;
+  }
+
+  function Fle (domain, vari, args)
+  {
+    var n = args[0].Intval ();
+    for (var i = 1; i < args.length; i++)
+      {
+       var n1 = args[i].Intval ();
+       if (n > n1)
+         return Xex.Zero;
+       n = n1;
+      }
+    return Xex.One;
+  }
+
+  function Fgt (domain, vari, args)
+  {
+    var n = args[0].Intval ();
+    for (var i = 1; i < args.length; i++)
+      {
+       var n1 = args[i].Intval ();
+       if (n <= n1)
+         return Xex.Zero;
+       n = n1;
+      }
+    return Xex.One;
+  }
+
+  function Fge (domain, vari, args)
+  {
+    var n = args[0].Intval ();
+    for (var i = 1; i < args.length; i++)
+      {
+       var n1 = args[i].Intval ();
+       if (n < n1)
+         return Xex.Zero;
+       n = n1;
+      }
+    return Xex.One;
+  }
+
   function Fprogn (domain, vari, args)
   {
     var result = Xex.One;
@@ -793,13 +1176,35 @@ Xex.LstTerm = function (list) { this.val = list; };
 
     if (domain.Thrown ())
       return result;
-    if (result.IsTrue)
+    if (result.IsTrue ())
       return args[1].Eval (domain);
-    if (args.Length == 2)
-      return Zero;
+    if (args.length == 2)
+      return Xex.Zero;
     return args[2].Eval (domain);
   }
 
+  function Fcond (domain, vari, args)
+  {
+    for (var i = 0; i < args.length; i++)
+      {
+       var list = args[i];
+       var result = list.val[0].Eval (domain);
+       if (result.IsTrue ())
+         {
+           for (var j = 1; j < list.val.length; j++)
+             {
+               domain.depth++;
+               result = list.val[j].Eval (domain);
+               domain.depth--;
+               if (domain.Thrown ())
+                 return result;
+               }
+           return result;
+         }
+      }
+    return Xex.Zero;
+  }
+
   function eval_terms (domain, terms, idx)
   {
     var result = Xex.Zero;
@@ -871,14 +1276,65 @@ Xex.LstTerm = function (list) { this.val = list; };
   Xex.BasicDomain = basic;
 
   basic.DefSubr (Fset, "set", true, 1, 1);
+  basic.DefAlias ("=", "set");
+  basic.DefSubr (Fnot, "not", false, 1, 1);
+  basic.DefAlias ("!", "not");
   basic.DefSubr (Fadd, "add", true, 1, -1);
+  basic.DefSubr (Fmul, "mul", true, 1, -1);
+  basic.DefAlias ("*", "mul");
+  basic.DefSubr (Fsub, "sub", true, 1, -1);
+  basic.DefAlias ("-", "sub");
+  basic.DefSubr (Fdiv, "div", true, 1, -1);
+  basic.DefAlias ("/", "div");
+  basic.DefSubr (Fmod, "mod", true, 1, 2);
+  basic.DefAlias ("%", "mod");
+  basic.DefSubr (Flogior, "logior", true, 1, -1);
+  basic.DefAlias ('|', "logior");
+  basic.DefSubr (Flogand, "logand", true, 1, -1);
+  basic.DefAlias ("&", "logand");
+  basic.DefSubr (Flsh, "lsh", true, 1, 2);
+  basic.DefAlias ("<<", "lsh");
+  basic.DefSubr (Frsh, "rsh", true, 1, 2);
+  basic.DefAlias (">>", "rsh");
+  basic.DefSubr (Feq, "eq", false, 2, -1);
+  basic.DefAlias ("==", "eq");
+  basic.DefSubr (Fnoteq, "noteq", false, 2, 2);
+  basic.DefAlias ("!=", "noteq");
+  basic.DefSubr (Flt, "lt", false, 2, -1);
+  basic.DefAlias ("<", "lt");
+  basic.DefSubr (Fle, "le", false, 2, -1);
+  basic.DefAlias ("<=", "le");
+  basic.DefSubr (Fgt, "gt", false, 2, -1);
+  basic.DefAlias (">", "gt");
+  basic.DefSubr (Fge, "ge", false, 2, -1);
+  basic.DefAlias (">=", "ge");
   basic.DefSubr (Fthrow, "throw", false, 1, 2);
 
+  //basic.DefSubr (Fappend, "append", true, 0, -1);
+  //basic.DefSubr (Fconcat, "concat", true, 0, -1);
+  //basic.DefSubr (Fnth, "nth", false, 2, 2);
+  //basic.DefSubr (Fcopy, "copy", false, 1, 1);
+  //basic.DefSubr (Fins, "ins", true, 2, 2);
+  //basic.DefSubr (Fdel, "del", true, 2, 2);
+  //basic.DefSubr (Feval, "eval", false, 1, 1);
+  //basic.DefSubr (Fbreak, "break", false, 0, 1);
+  //basic.DefSubr (Freturn, "return", false, 0, 1);
+  //basic.DefSubr (Fthrow, "throw", false, 1, 2);
+
   basic.DefSpecial (Fand, "and", false, 1, -1);
+  basic.DefAlias ("&&", "and");
   basic.DefSpecial (For, "or", false, 1, -1);
-  basic.DefAlias ("=", "set");
+  basic.DefAlias ("||", "or");
   basic.DefSpecial (Fprogn, "progn", false, 1, -1);
+  basic.DefAlias ("expr", "progn");
   basic.DefSpecial (Fif, "if", false, 2, 3);
+  //basic.DefSpecial (Fwhen, "when", false, 1, -1);
+  //basic.DefSpecial (Floop, "loop", false, 1, -1);
+  //basic.DefSpecial (Fwhile, "while", false, 1, -1);
+  basic.DefSpecial (Fcond, "cond", false, 1, -1);
+  //basic.DefSpecial (Fforeach, "foreach", true, 2, -1);
+  //basic.DefSpecial (Fquote, "quote", false, 1, 1);
+  //basic.DefSpecial (Ftype, "type", false, 1, 1);
   basic.DefSpecial (Fcatch, "catch", true, 2, -1);
 
   basic.DefType (Xex.Funcall.prototype);
@@ -893,1308 +1349,46 @@ Xex.LstTerm = function (list) { this.val = list; };
 
 Xex.Zero = new Xex.IntTerm (0);
 Xex.One = new Xex.IntTerm (1);
+Xex.nil = new Xex.SymTerm ('nil');
 
-Xex.Load = function (server, file)
-{
-  var obj = new XMLHttpRequest ();
-  var url = server ? server + '/' + file : file;
-  obj.open ('GET', url, false);
-  obj.overrideMimeType ('text/xml');
-  obj.send ('');
-  return obj.responseXML.firstChild;
-}
+(function () {
+  var queue = new Array ();
+  var iframe = null;
 
-var MIM = {
-  // URL of the input method server.
-  server: "http://www.m17n.org/common/mim-js",
-  // Boolean flag to tell if MIM is active or not.
-  enabled: true,
-  // Boolean flag to tell if MIM is running in debug mode or not.
-  debug: false,
-  // List of registered input methods.
-  im_list: {},
-  // Global input method data
-  im_global: null,
-  // Currently selected input method.
-  current: false,
-
-  // enum
-  LoadStatus: { NotLoaded:0, Loading:1, Loaded:2, Error:-1 },
-  ChangedStatus: {
-    None:      0x00,
-    StateTitle:        0x01,
-    PreeditText:0x02,
-    CursorPos: 0x04,
-    CandidateList:0x08,
-    CandidateIndex:0x10,
-    CandidateShow:0x20,
-    Preedit:   0x06,           // PreeditText | CursorPos
-    Candidate: 0x38 // CandidateList | CandidateIndex | CandidateShow
-  },
-  KeyModifier: {
-    SL:        0x00400000,
-    SR:        0x00800000,
-    S: 0x00C00000,
-    CL:        0x01000000,
-    CR:        0x02000000,
-    C: 0x03000000,
-    AL:        0x04000000,
-    AR:        0x08000000,
-    A: 0x0C000000,
-    ML:        0x04000000,
-    MR:        0x08000000,
-    M: 0x0C000000,
-    G: 0x10000000,
-    s: 0x20000000,
-    H: 0x40000000,
-    High:      0x70000000,
-    All:       0x7FC00000
-  },
-  Error: {
-    ParseError: "parse-error"
-  }
-};
-  
-(function () {
-  var keysyms = new Array ();
-  keysyms["bs"]        = "backspace";
-  keysyms["lf"]        = "linefeed";
-  keysyms["cr"]        = keysyms["enter"] = "return";
-  keysyms["esc"] = "escape";
-  keysyms["spc"] = "space";
-  keysyms["del"] = "delete";
-
-  function decode_keysym (str) {
-    var parts = str.split ("-");
-    var len = parts.length, i;
-    var has_modifier = len > 1;
-
-    for (i = 0; i < len - 1; i++)
-      if (! MIM.KeyModifier.hasOwnProperty (parts[i]))
-       return false;
-    var key = parts[len - 1];
-    if (key.length > 1)
-      {
-       key = keysyms[key.toLowerCase ()];
-       if (key)
-         {
-           if (len > 1)
-             {
-               str = parts[0];
-               for (i = 1; i < len - 1; i++)
-                 str += '-' + parts[i];
-               str += '-' + key;
-             }
-           else
-             str = key;
-         }
-      }
-    if (has_modifier)
-      {
-       parts = new Array ();
-       parts.push (str);
-       return parts;
-      }
-    return str;
-  }
-
-  MIM.Key = function (val)
+  function receiver (event)
   {
-    this.key;
-    this.has_modifier = false;
-    if (typeof val == 'string' || val instanceof String)
+    var request = queue.shift ();
+    //alert ('received: ' + request[0]);
+    var parser = new DOMParser ();
+    var xml = parser.parseFromString (event.data, 'text/xml');
+    if (queue.length > 0)
       {
-       this.key = decode_keysym (val);
-       if (! this.key)
-         throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid key: " + val);
-       if (this.key instanceof Array)
-         {
-           this.key = this.key[0];
-           this.has_modifier = true;
-         }
+       document.getElementsByTagName ('body')[0].removeChild (iframe);
+       iframe.src = queue[0][0];
+       document.getElementsByTagName ('body')[0].appendChild (iframe);
       }
-    else if (typeof val == 'number' || val instanceof Number)
-      this.key = String.fromCharCode (val);
     else
-      throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid key: " + val);
-  }
-
-  MIM.Key.prototype.toString = function () { return this.key; };
-}) ();
-
-(function () {
-  MIM.KeySeq = function (seq)
-  {
-    this.val = new Array ();
-    this.has_modifier = false;
-
-    if (seq)
-      {
-       if (seq.IsList)
-         {
-           var len = seq.val.length;
-           for (var i = 0; i < len; i++)
-             {
-               var v = seq.val[i];
-               if (v.type != 'string' && v.type != 'integer'
-                   && v.type != 'symbol')
-                 throw new Xex.ErrTerm (MIM.Error.ParseError,
-                                        "Invalid key: " + v);
-               var key = new MIM.Key (v.val);
-               this.val.push (key);
-               if (key.has_modifier)
-                 this.has_modifier = true;
-             }
-         }
-       else if (seq.IsStr)
-         {
-           var len = seq.val.length;
-           for (var i = 0; i < len; i++)
-             this.val.push (new MIM.Key (seq.val.charCodeAt (i)));
-         }
-       else
-         throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid key: " + seq);
-      }
-  }
-
-  var proto = new Xex.Term ('keyseq');
-  proto.Clone = function () { return this; }
-  proto.Parser = function (domain, node)
-  {
-    var seq = new Array ();
-    for (node = node.firstChild; node; node = node.nextSibling)
-      if (node.nodeType == 1)
-       {
-         var term = Xex.ParseTerm (domain, node);
-         return new MIM.KeySeq (term);
-       }
-    throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid keyseq");
-  }
-  proto.toString = function ()
-  {
-    var len = this.val.length;
-    if (len == 0)
-      return '<keyseq/>';
-    var first = true;
-    var str = '<keyseq>';
-    for (var i = 0; i < len; i++)
-      {
-       if (first)
-         first = false;
-       else if (this.has_modifier)
-         str += ' ';
-       str += this.val[i].toString ();
-      }
-    return str + '</keyseq>';
-  }
-
-  MIM.KeySeq.prototype = proto;
-}) ();
-
-(function () {
-  MIM.Marker = function () { }
-  MIM.Marker.prototype = new Xex.Term ('marker');
-  MIM.Marker.prototype.CharAt = function (ic)
-  {
-    var p = this.Position (ic);
-    if (p < 0)
-      return ic.GetSurroundingChar (p);
-    else if (pos >= ic.preedit.length)
-      return ic.GetSurroundingChar (p - ic.preedit.length);
-    return ic.preedit.charCodeAt (p);
-  }
-
-  MIM.NamedMarker = function (name) { this.val = name; }
-  MIM.NamedMarker.prototype = new MIM.Marker ();
-  MIM.NamedMarker.prototype.Position = function (ic)
-  {
-    var p = ic.marker_positions[this.val];
-    return (p == undefined ? 0 : p);
-  }
-  MIM.NamedMarker.prototype.Mark = function (ic)
-  {
-    ic.marker_positions[this.val] = ic.cursor_pos;
-  }
-
-  MIM.PredefinedMarker = function (name) { this.val = name; }
-  MIM.PredefinedMarker.prototype = new MIM.Marker ();
-  MIM.PredefinedMarker.prototype.Position = function (ic)
-  {
-    if (typeof this.pos == 'number')
-      return this.pos;
-    return this.pos (ic);
-  }
-
-  var predefined = { }
-
-  function def_predefined (name, position)
-  {
-    predefined[name] = new MIM.PredefinedMarker (name);
-    predefined[name].pos = position;
-  }
-
-  def_predefined ('@<', 0);
-  def_predefined ('@>', function (ic) { return ic.preedit.length; });
-  def_predefined ('@-', function (ic) { return ic.cursor_pos - 1; });
-  def_predefined ('@+', function (ic) { return ic.cursor_pos + 1; });
-  def_predefined ('@[', function (ic) {
-    if (ic.cursor_pos > 0)
-      {
-       var pos = ic.cursor_pos;
-       return ic.preedit.FindProp ('candidates', pos - 1).from;
-      }
-    return 0;
-  });
-  def_predefined ('@]', function (ic) {
-    if (ic.cursor_pos < ic.preedit.length - 1)
-      {
-       var pos = ic.cursor_pos;
-       return ic.preedit.FindProp ('candidates', pos).to;
-      }
-    return ic.preedit.length;
-  });
-  for (var i = 0; i < 10; i++)
-    def_predefined ("@" + i, i);
-  predefined['@first'] = predefined['@<'];
-  predefined['@last'] = predefined['@>'];
-  predefined['@previous'] = predefined['@-'];
-  predefined['@next'] = predefined['@+'];
-  predefined['@previous-candidate-change'] = predefined['@['];
-  predefined['@next-candidate-change'] = predefined['@]'];
-
-  MIM.SurroundMarker = function (name)
-  {
-    this.val = name;
-    this.distance = parseInt (name.slice (2));
-    if (isNaN (this.distance))
-      throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid marker: " + name);
-  }
-  MIM.SurroundMarker.prototype = new MIM.Marker ();
-  MIM.SurroundMarker.prototype.Position = function (ic)
-  {
-    return ic.cursor_pos + this.distance;
-  }
-
-  MIM.Marker.prototype.Parser = function (domain, node)
-  {
-    var name = node.firstChild.nodeValue;
-    if (name.charAt (0) == '@')
-      {
-       var n = predefined[name];
-       if (n)
-         return n;
-       if (name.charAt (1) == '-')
-         return new MIM.SurroundMarker (name);
-       throw new Xex.ErrTerm (MIM.Error.ParseError,
-                              "Invalid marker: " + name);
-      }
-    return new MIM.NamedMarker (name);
-  }
-}) ();
-
-MIM.Selector = function (name)
-{
-  this.val = name;
-}
-MIM.Selector.prototype = new Xex.Term ('selector');
-(function () {
-  var selectors = {};
-  selectors["@<"] = selectors["@first"] = new MIM.Selector ('@<');
-  selectors["@="] = selectors["@current"] = new MIM.Selector ('@=');
-  selectors["@>"] = selectors["@last"] = new MIM.Selector ('@>');
-  selectors["@-"] = selectors["@previous"] = new MIM.Selector ('@-');
-  selectors["@+"] = selectors["@next"] = new MIM.Selector ('@+');
-  selectors["@["] = selectors["@previous-candidate-change"]
-    = new MIM.Selector ('@[');
-  selectors["@]"] = selectors["@next-candidate-change"]
-    = new MIM.Selector ('@]');
-
-  MIM.Selector.prototype.Parser = function (domain, node)
-  {
-    var name = node.firstChild.nodeValue;
-    var s = selectors[name];
-    if (! s)
-      throw new Xex.ErrTerm (MIM.Error.ParseError,
-                            "Invalid selector: " + name);
-    return s;
-  }
-}) ();
-
-MIM.Rule = function (keyseq, actions)
-{
-  this.keyseq = keyseq;
-  this.actions = actions;
-}
-MIM.Rule.prototype = new Xex.Term ('rule');
-MIM.Rule.prototype.Parser = function (domain, node)
-{
-  var n;
-  for (n = node.firstChild; n && n.nodeType != 1; n = n.nextSibling);
-  if (! n)
-    throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid rule:" + node);
-  var keyseq = Xex.ParseTerm (domain, n);
-  if (keyseq.type != 'keyseq')
-    throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid rule:" + node);
-  var actions = Xex.ParseTermList (domain, n.nextSibling);
-  return new MIM.Rule (keyseq, actions);
-}
-MIM.Rule.prototype.toString = function ()
-{
-  return '<rule/>';
-}
-
-MIM.Map = function (name)
-{
-  this.name = name;
-  this.rules = new Array ();
-};
-(function () {
-  var proto = new Xex.Term ('map');
-
-  proto.Parser = function (domain, node)
-  {
-    var name = node.attributes['mname'].nodeValue;
-    if (! name)
-      throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid map");
-    var map = new MIM.Map (name);
-    for (var n = node.firstChild; n; n = n.nextSibling)
-      if (n.nodeType == 1)
-       map.rules.push (Xex.ParseTerm (domain, n));
-    return map;
-  }
-
-  proto.toString = function ()
-  {
-    var str = '<map mname="' + this.name + '">';
-    var len = this.rules.length;
-    for (i = 0; i < len; i++)
-      str += this.rules[i];
-    return str + '</map>';
-  }
-
-  MIM.Map.prototype = proto;
-}) ();
-
-Xex.CatchTag._mimtag = new Xex.SymTerm ('@mimtag');
-
-MIM.Action = function (domain, terms)
-{
-  var args = new Array ();
-  args.push (Xex.CatchTag_.mimtag);
-  for (var i = 0; i < terms.length; i++)
-    args.push (terms[i]);
-  this.action = Xex.Funcall.prototype.New (domain, 'catch', null, args);
-}
-
-MIM.Action.prototype.Run = function (domain)
-{
-  var result = this.action.Eval (domain);
-  if (result.type == 'error')
-    {
-      domain.context.Error = result.toString ();
-      return false;
-    }
-  return (result != Xex.CatchTag._mimtag);
-}
-
-MIM.Keymap = function ()
-{
-  this.submaps = null;
-  this.actions = null;
-};
-(function () {
-  var proto = {};
-
-  function add_rule (keymap, rule)
-  {
-    var keyseq = rule.keyseq;
-    var len = keyseq.val.length;
-
-    for (var i = 0; i < len; i++)
-      {
-       var key = keyseq.val[i];
-       var sub = false;
-
-       if (! keymap.submaps)
-         keymap.submaps = {};
-       else
-         sub = keymap.submaps[key.key];
-       if (! sub)
-         keymap.submaps[key.key] = sub = new MIM.Keymap ();
-       keymap = sub;
-      }
-    keymap.actions = rule.actions;
-  }
-
-  proto.Add = function (map)
-  {
-    var rules = map.rules;
-    var len = rules.length;
-
-    for (var i = 0; i < len; i++)
-      add_rule (this, rules[i]);
-  }
-  proto.Lookup = function (keys, index)
-  {
-    var sub;
-
-    if (index < keys.val.length && this.submaps
-       && (sub = this.submaps[keys.val[index].key]))
-      {
-       index++;
-       return sub.Lookup (keys, index);
-      }
-    return { map: this, index: index };
-  }
-
-  MIM.Keymap.prototype = proto;
-}) ();
-
-MIM.State = function (name)
-{
-  this.name = name;
-  this.keymap = new MIM.Keymap ();
-};
-(function () {
-  var proto = new Xex.Term ('state');
-
-  proto.Parser = function (domain, node)
-  {
-    var map_list = domain.map_list;
-    var name = node.attributes['sname'].nodeValue;
-    if (! name)
-      throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid map");
-    var state = new MIM.State (name);
-    for (node = node.firstChild; node; node = node.nextSibling)
-      {
-       if (node.nodeType != 1)
-         continue;
-       if (node.nodeName == 'branch')
-         {
-           state.keymap.Add (map_list[node.attributes['mname'].nodeValue]);
-           state.keymap.actions = Xex.ParseTermList (domain, node.firstChild);
-         }
-       else if (node.nodeName == 'state-hook')
-         state.enter_actions = Xex.ParseTermList (domain, node.firstChild);
-       else if (node.nodeName == 'catch-all-branch')
-         state.fallback_actions = Xex.ParseTermList (domain, node.firstChild);
-       else if (node.nodeName == 'title')
-         state.title = node.firstChild.nodeValue;
-      }
-    return state;
-  }
-
-  proto.toString = function ()
-  {
-    return '<state sname="' + this.name + '">' + this.keymap + '</state>';
-  }
-
-  MIM.State.prototype = proto;
-}) ();
-
-MIM.im_domain = new Xex.Domain ('input-method', null, null);
-MIM.im_domain.DefType (MIM.KeySeq.prototype);
-MIM.im_domain.DefType (MIM.Marker.prototype);
-MIM.im_domain.DefType (MIM.Selector.prototype);
-MIM.im_domain.DefType (MIM.Rule.prototype);
-MIM.im_domain.DefType (MIM.Map.prototype);
-MIM.im_domain.DefType (MIM.State.prototype);
-
-(function () {
-  var im_domain = MIM.im_domain;
-
-  function Finsert (domain, vari, args)
-  {
-    domain.context.insert (args[0].val, null);
-  }
-
-  im_domain.DefSubr (Finsert, "insert", false, 1, 1);
-}) ();
-
-(function () {
-  var parsers = { };
-  parsers['description'] = function (node)
-  {
-    this.description = node.firstChild.nodeValue;
-  }
-  parsers['title'] = function (node)
-  {
-    this.title = node.firstChild.nodeValue;
-  }
-  parsers['map-list'] = function (node)
-  {
-    for (node = node.firstChild; node; node = node.nextSibling)
-      {
-       if (node.nodeType != 1 || node.nodeName != 'map')
-         continue;
-       var map = Xex.ParseTerm (this.domain, node);
-       this.map_list[map.name] = map;
-      }
-  }
-  parsers['state-list'] = function (node)
-  {
-    this.domain.map_list = this.map_list;
-    for (node = node.firstChild; node; node = node.nextSibling)
-      {
-       if (node.nodeType != 1 || node.nodeName != 'state')
-         continue;
-       var state = Xex.ParseTerm (this.domain, node);
-       if (! state.title)
-         state.title = this.title;
-       if (! this.initial_state)
-         this.initial_state = state;
-       this.state_list[state.name] = state;
-      }
-    delete this.domain.map_list;
-  }
-
-  MIM.IM = function (lang, name, extra_id, file)
-  {
-    this.lang = lang;
-    this.name = name;
-    this.extra_id = extra_id;
-    this.file = file;
-    this.load_status = MIM.LoadStatus.NotLoaded;
-    this.domain = new Xex.Domain (this.lang + '-' + this.name,
-                                 MIM.im_domain, null);
-  }
-
-  var proto = {
-    Load: function ()
-    {
-      var node = Xex.Load (null, this.file);
-      if (! node)
-       {
-         this.load_status = MIM.LoadStatus.Error;
-         return false;
-       }
-      this.map_list = {};
-      this.initial_state = null;
-      this.state_list = {};
-      for (node = node.firstChild; node; node = node.nextSibling)
-        {
-         if (node.nodeType != 1)
-           continue;
-         var name = node.nodeName;
-         var parser = parsers[name];
-         if (parser)
-           parser.call (this, node);
-       }
-      this.load_status = MIM.LoadStatus.Loaded;
-      return true;
-    }
-  }
-
-  MIM.IM.prototype = proto;
-
-  MIM.IC = function (im)
-  {
-    if (im.load_status == MIM.LoadStatus.NotLoaded)
-      im.Load ();
-    if (im.load_status != MIM.LoadStatus.Loaded)
-      alert ('im:' + im.name + ' error:' + im.load_status);
-    this.im = im;
-    this.domain = new Xex.Domain ('context', im.domain, this);
-    this.active = true;
-    this.reset ();
-    this.spot = 0;
-  }
-
-  MIM.CandidateTable = function ()
-  {
-    this.table = new Array ();
-  }
-
-  MIM.CandidateTable.prototype.get = function (from)
-  {
-    for (var i = 0; i < this.table.length; i++)
       {
-       var elt = this.table[i];
-       if (elt.from <= from && elt.to > from)
-         return elt.val;
+       window.removeEventListener ('message', receiver, false);
+       document.getElementsByTagName ('body')[0].removeChild (iframe);
       }
-  }
-
-  MIM.CandidateTable.prototype.put = function (from, to, candidates)
-  {
-    for (var i = 0; i < this.table.length; i++)
-      {
-       var elt = this.table[i];
-       if (elt.from >= from && elt.from < to
-           || elt.to >= from && elt.to < to)
-         {
-           elt.from = from;
-           elt.to = to;
-           elt.val = candidates;
-           return;
-         }
-      }
-    this.table.push ({ from: from, to: to, val: candidates });
-  }
-
-  MIM.CandidateTable.prototype.adjust = function (from, to, inserted)
-  {
-    var diff = inserted - (to - from);
-    for (var i = 0; i < this.table.length; i++)
-      {
-       var elt = this.table[i];
-       if (elt.from >= to)
-         {
-           elt.from += diff;
-           elt.to += diff;
-         }
-      }
-  }
-
-  MIM.CandidateTable.prototype.clear = function ()
-  {
-    this.table.length = 0;
-  }
-
-  function set_cursor (prefix, pos)
-  {
-    this.cursor_pos = pos;
-    if (pos > 0)
-      this.candidates = this.candidate_table.get (pos - 1);
-    else
-      this.candidates = null;
-  }
-
-  function save_state ()
-  {
-    this.state_var_values = this.domain.SaveValues ();
-    this.state_preedit = this.preedit;
-    this.state_key_head = this.key_head;
-    this.state_pos = this.cursor_pos;
-  }
+    request[1] (xml.firstElement (), request[2]);
+    event.preventDefault ();
+  };
 
-  function restore_state ()
+  Xex.Load = function (server, file, callback, arg)
   {
-    this.domain.RestoreValues (this.state_var_values);
-    this.preedit = this.state_preedit;
-    set_cursor.call (this, "restore", this.state_pos);
-  }
-
-  function handle_key ()
-  {
-    var out = this.keymap.Lookup (this.keys, this.key_head);
-    var sub = out.map;
-
-    alert ('handling ' + this.keys.val[this.key_head]);
-    this.key_head = out.index;
-    if (sub != this.keymap)
-      {
-       restore_state.call (this);
-       this.keymap = sub;
-       alert ('submap found, taking map actions:' + sub.actions);
-       if (this.keymap.actions != null)
-         {
-           if (! this.take_actions (this.keymap.actions))
-             return false;
-         }
-       else if (this.keymap.submaps != null)
-         {
-           for (var i = this.state_key_head; i < this.key_head; i++)
-             this.preedit_replace (this.cursor_pos, this.cursor_pos,
-                                   this.keys.val[i].key, null);
-         }
-       if (this.keymap.submaps == null)
-         {
-           if (this.keymap.branch_actions != null)
-             {
-               if (! this.take_actions (this.keymap.branch_actions))
-                 return false;
-             }
-           if (this.keymap != this.state.keymap)
-             this.shift (this.state);
-         }
-      }
-    else
+    var url = server + '/loadxml.html#' + file;
+    //alert ('loading file:' + file);
+    queue.push ([url, callback, arg]);
+    if (queue.length == 1)
       {
-       var current_state = this.state;
-
-       if (this.keymap.branch_actions != null)
-         {
-           if (! this.take_actions (this.keymap.branch_actions))
-             return false;
-         }
-       if (this.state == current_state)
-         {
-           if (this.state == this.initial_state
-               && this.key_head < this.keys.val.length)
-             return false;
-           if (this.keymap != this.state.keymap)
-             this.shift (this.state);
-           else if (this.keymap.branch_actions == null)
-             this.shift (this.initial_state);
-         }
+       window.addEventListener ('message', receiver, false);
+       iframe = document.createElement ('iframe');
+       iframe.style.display = 'none';
+       iframe.src = url;
+       //alert ('iframe created');
+       document.getElementsByTagName ('body')[0].appendChild (iframe);
       }
-    return true;
-  }
-
-  proto = {
-    init: function ()
-    {
-      this.produced = null;
-      this.preedit = '';
-      this.cursor_pos = 0;
-      this.marker_positions = {};
-      this.candidates = null;
-      this.candidate_show = false;
-      this.state = null;
-      this.prev_state = null;
-      this.initial_state = this.im.initial_state;
-      this.title = this.initial_state.title;
-      this.state_preedit = '';
-      this.state_key_head = 0;
-      this.state_var_values = {};
-      this.state_pos = 0;
-      this.keymap = null;
-      this.keys = new MIM.KeySeq ();
-      this.key_head = 0;
-      this.key_unhandled = false;
-      this.unhandled_key = null;
-      this.changed = MIM.ChangedStatus.None;
-      this.error_message = '';
-      this.title = this.initial_state.title;
-      this.produced = null;
-      this.preedit = '';
-      this.marker_positions = {};
-      this.candidate_table = new MIM.CandidateTable ();
-      this.candidates = null;
-      this.candidate_show = false;
-    },
-
-    reset: function ()
-    {
-      this.init ();
-      this.state_var_values = {};
-      this.shift (this.initial_state);
-    },
-
-    catch_args: new Array (Xex.CatchTag._mimtag, null),
-
-    take_actions: function (actions)
-    {
-      var func_progn = this.domain.GetFunc ('progn');
-      var func_catch = this.domain.GetFunc ('catch');
-      this.catch_args[1] = new Xex.Funcall (func_progn, null, actions);
-      var term = new Xex.Funcall (func_catch, null, this.catch_args);
-      term = term.Eval (this.domain);
-      return (! term.IsSymbol || term.val != '@mimtag');
-    },
-
-    GetSurroundingChar: function (pos)
-    {
-      if (pos < 0 ? this.caret_pos < - pos : this.target.value.length < pos)
-       return 0;
-      return this.target.value.charCodeAt (this.caret_pos + pos);
-    },
-    
-    adjust_markers: function (from, to, inserted)
-    {
-      var diff = inserted - (to - from);
-
-      for (var m in this.marker_positions)
-       if (this.marker_positions[m] > from)
-         this.marker_positions[m] = (this.marker_positions[m] >= to
-                                     ? pos + diff : from);
-      if (this.cursor_pos >= to)
-       set_cursor.call (this, 'adjust', this.cursor_pos + diff);
-      else if (this.cursor_pos > from)
-       set_cursor.call (this, 'adjust', from)
-    },
-
-    preedit_replace: function (from, to, text, candidates)
-    {
-      this.preedit = (this.preedit.substring (0, from)
-                     + text + this.preedit.substring (to));
-      this.adjust_markers (from, to, text.length);
-      this.candidate_table.adjust (from, to, text.length);
-      if (candidates)
-       this.candidate_table.put (from, from + text.length, candidates)
-    },
-
-    insert: function (text, candidates)
-    {
-      this.preedit_replace (this.cursor_pos, this.cursor_pos, text, candidates);
-      this.changed = MIM.ChangedStatus.Preedit | MIM.ChangedStatus.CursorPos;
-    },
-
-    del: function (pos)
-    {
-      if (pos < 0)
-       {
-         this.DelSurroundText (pos);
-         pos = 0;
-       }
-      else if (pos > this.preedit.length)
-       {
-         this.DelSurroundText (pos - this.preedit.length);
-         pos = this.preedit.length;
-       }
-      if  (pos < this.cursor_pos)
-       this.preedit = (this.predit.substring (0, pos)
-                       + this.preedit.substring (this.cursor_pos));
-      else
-       this.preedit = (this.preedit.substring (0, this.cursor_pos)
-                       + this.predit.substring (pos));
-    },
-
-    show: function ()
-    {
-      this.candidate_show = true;
-      this.changed |= MIM.ChangedStatus.CandidateShow;
-    },
-
-    hide: function ()
-    {
-      this.candidate_show = false;
-      this.changed |= MIM.ChangedStatus.CandidateShow;
-    },
-
-    move: function (pos)
-    {
-      if (pos < 0)
-       pos = 0;
-      else if (pos > this.preedit.length)
-       pos = this.preedit.length;
-      if (pos != this.cursor_pos)
-       {
-         set_cursor.call (this, 'move', pos);
-         this.changed |= MIM.ChangedStatus.Preedit;
-       }
-    },
-
-    pushback: function (n)
-    {
-      if (n instanceof MIM.KeySeq)
-       {
-         if (this.key_head > 0)
-           this.key_head--;
-         if (this.key_head < this.keys.val.length)
-           this.keys.val.splice (this.key_head,
-                                 this.keys.val.length - this.key_head);
-         for (var i = 0; i < n.val.length; i++)
-           this.keys.val.push (n.val[i]);
-         return;
-       }
-      if (n > 0)
-       {
-         this.key_head -= n;
-         if (this.key_head < 0)
-           this.key_head = 0;
-       }
-      else if (n == 0)
-       this.key_head = 0;
-      else
-      {
-       this.key_head = - n;
-       if (this.key_head > this.keys.val.length)
-         this.key_head = this.keys.val.length;
-      }
-    },
-
-    pop: function ()
-    {
-      if (this.key_head < this.keys.val.length)
-       this.keys.val.splice (this.key_head, 1);
-    },
-
-    commit: function ()
-    {
-      if (this.preedit.length > 0)
-      {
-       this.candidate_table.clear ();
-       this.produced += this.preedit;
-       this.preedit_replace.call (this, 0, this.preedit.Length, '', null);
-      }
-    },
-
-    shift: function (state)
-    {
-      if (state == null)
-      {
-       if (this.prev_state == null)
-         return;
-       state = this.prev_state;
-      }
-
-      if (state == this.initial_state)
-        {
-         this.commit ();
-         this.keys.val.splice (0, this.key_head);
-         this.key_head = 0;
-         if (state != this.state)
-           {
-             this.domain.RestoreValues (this.state_initial_var_values);
-             if (state.enter_actions != null)
-               take_actions.call (state.enter_actions);
-           }
-         this.prev_state = null;
-       }
-      else
-        {
-         if (state != this.state && state.enter_actions != null)
-           take_actions.call (state.enter_actions);
-         this.prev_state = this.state;
-       }
-      save_state.call (this);
-      if (! this.state || this.state.title != state.title)
-       this.changed |= MIM.ChangedStatus.StateTitle;
-      this.state = state;
-      this.keymap = state.keymap;
-    },
-
-    Filter: function (key)
-    {
-      if (! this.active)
-       {
-         this.key_unhandled = true;
-         this.unhandled_key = key;
-         return false;
-       }
-      if (key.key == '_reload')
-       return true;
-      this.changed = MIM.ChangedStatus.None;
-      this.produced = '';
-      this.key_unhandled = false;
-      this.keys.val.push (key);
-      var count = 0;
-      while (this.key_head < this.keys.val.length)
-       {
-         if (! handle_key.call (this))
-           {
-             this.unhandled_key = this.keys.val[this.key_head++];
-             this.key_unhandled = true;
-             break;
-           }
-         if (++count == 10)
-           break;
-       }
-      this.keys.val.splice (0, this.key_head);
-      this.key_head = 0;
-      return (! this.key_unhandled && this.produced.length == 0);
-    }
-  }
-
-  MIM.IC.prototype = proto;
-
-  var node = Xex.Load (null, "imlist.xml");
-  for (node = node.firstChild; node; node = node.nextSibling)
-    if (node.nodeName == 'input-method')
-      {
-       var lang, name, extra_id, file;
-
-       for (var n = node.firstChild; n; n = n.nextSibling)
-         {
-           if (n.nodeName == 'language')
-             lang = n.firstChild.nodeValue;
-           else if (n.nodeName == 'name')
-             name = n.firstChild.nodeValue;
-           else if (n.nodeName == 'extra-id')
-             extra_id = n.firstChild.nodeValue;
-           else if (n.nodeName == 'filename')
-             file = n.firstChild.nodeValue;
-         }
-       if (! MIM.im_list[lang])
-         MIM.im_list[lang] = {};
-       MIM.im_list[lang][name] = new MIM.IM (lang, name, extra_id, file);
-      }
-  node = undefined;
-}) ();
-
-(function () {
-  var keys = new Array ();
-  keys[0x09] = 'tab';
-  keys[0x08] = 'backspace';
-  keys[0x0D] = 'return';
-  keys[0x1B] = 'escape';
-  keys[0x20] = 'space';
-  keys[0x21] = 'pageup';
-  keys[0x22] = 'pagedown';
-  keys[0x23] = 'end';
-  keys[0x24] = 'home';
-  keys[0x25] = 'left';
-  keys[0x26] = 'up';
-  keys[0x27] = 'right';
-  keys[0x28] = 'down';
-  keys[0x2D] = 'insert';
-  keys[0x2E] = 'delete';
-  for (var i = 1; i <= 12; i++)
-    keys[111 + i] = "f" + i;
-  keys[0x90] = "numlock";
-  keys[0xF0] = "capslock";
-
-  MIM.decode_key_event = function (event)
-  {
-    var key = ((event.type == 'keydown' || event.keyCode) ? event.keyCode
-              : event.charCode ? event.charCode
-              : false);
-    if (! key)
-      return false;
-    if (event.type == 'keydown')
-      {
-       key = keys[key];
-       if (! key)
-         return false;
-       if (event.shiftKey) key = "S-" + key ;
-      }
-    else
-      key = String.fromCharCode (key);
-    if (event.altKey) key = "A-" + key ;
-    if (event.ctrlKey) key = "C-" + key ;
-    return new MIM.Key (key);
   }
 }) ();
-
-MIM.add_event_listener
-  = (window.addEventListener
-     ? function (target, type, listener) {
-       target.addEventListener (type, listener, false);
-     }
-     : window.attachEvent
-     ? function (target, type, listener) {
-       target.attachEvent ('on' + type,
-                          function() {
-                            listener.call (target, window.event);
-                          });
-     }
-     : function (target, type, listener) {
-       target['on' + type]
-        = function (e) { listener.call (target, e || window.event); };
-     });
-
-MIM.debug_print = function (event, ic)
-{
-  if (! MIM.debug)
-    return;
-  if (! MIM.debug_nodes)
-    {
-      MIM.debug_nodes = new Array ();
-      MIM.debug_nodes['keydown'] = document.getElementById ('keydown');
-      MIM.debug_nodes['keypress'] = document.getElementById ('keypress');
-      MIM.debug_nodes['status0'] = document.getElementById ('status0');
-      MIM.debug_nodes['status1'] = document.getElementById ('status1');
-      MIM.debug_nodes['keyseq0'] = document.getElementById ('keyseq0');
-      MIM.debug_nodes['keyseq1'] = document.getElementById ('keyseq1');
-      MIM.debug_nodes['range0'] = document.getElementById ('range0');
-      MIM.debug_nodes['range1'] = document.getElementById ('range1');
-    }
-  var target = event.target;
-  var code = event.keyCode;
-  var ch = event.type == 'keydown' ? 0 : event.charCode;
-  var key = MIM.decode_key_event (event);
-  var index;
-
-  MIM.debug_nodes[event.type].innerHTML = "" + code + "/" + ch + " : " + key;
-  index = (event.type == 'keydown' ? '0' : '1');
-  MIM.debug_nodes['status' + index].innerHTML = ic.im.load_status;
-  MIM.debug_nodes['keyseq' + index].innerHTML = ic.keys;
-  MIM.debug_nodes['preedit' + index].innerHTML = ic.preedit;
-};
-
-MIM.get_range = function (target, range)
-{
-  if (target.selectionStart != null) // for Mozilla
-    {
-      range[0] = target.selectionStart;
-      range[1] = target.selectionEnd;
-    }
-  else                         // for IE
-    {
-      var r = document.selection.createRange ();
-      var rr = r.duplicate ();
-
-      rr.moveToElementText (target);
-      rr.setEndPoint ('EndToEnd', range);
-      range[0] = rr.text.length - r.text.length;
-      range[1] = rr.text.length;
-    }
-}
-
-MIM.set_caret = function (target, ic)
-{
-  if (target.selectionStart != null) // Mozilla
-    {
-      target.focus ();
-      target.setSelectionRange (ic.spot, ic.spot + ic.preedit.length);
-    }
-  else                         // IE
-    {
-      var range = target.createTextRange ();
-      range.move ('character', pos);
-      range.select ();
-    }
-};
-
-(function () {
-  var range = new Array ();
-
-  MIM.check_range = function (target, ic)
-  {
-    MIM.get_range (target, range);
-    if (range[0] != ic.spot || range[1] - range[0] != ic.preedit.length)
-      {
-       ic.reset ();
-       ic.spot = range[0];
-      }
-  }
-};
-
-MIM.produce = function (target, ic)
-{
-  target.value = (text.substring (0, ic.spot)
-                 + ic.produced
-                 + text.substring (ic.));
-  ic.range[1] = ic.range[0] + insert.length;
-  MIM.set_caret (ic.target, ic.range[1]);
-};
-
-MIM.reset_ic = function (event)
-{
-  var ic = event.target.mim_ic;
-  if (ic)
-    ic.reset ();
-};
-
-MIM.keydown = function (event)
-{
-  var target = event.target;
-  if (! (target.type == "text" || target.type == "textarea"))
-    return;
-
-  var ic = target.mim_ic;
-  if (! ic || ic.im != MIM.current)
-    {
-      ic = new MIM.IC (MIM.current_im);
-      target.mim_ic = ic;
-      MIM.add_event_listener (target, 'blur', MIM.reset_ic);
-    }
-  if (ic.im.load_status != MIM.LoadStatus.Loaded)
-    return;
-  MIM.check_range (target, ic);
-  MIM.debug_print (event, ic);
-  ic.key = MIM.decode_key_event (event);
-};
-
-MIM.keypress = function (event)
-{
-  if (! (event.target.type == "text" || event.target.type == "textarea"))
-    return;
-
-  var ic = event.target.mim_ic;
-  var i;
-
-  try {
-    if (ic.im.loaded != MIM.LoadStatus.Loaded)
-      return;
-    if (! ic.key)
-      ic.key = MIM.decode_key_event (event);
-    if (! ic.key)
-      {
-       ic.reset ();
-       return;
-      }
-    if (ic.Filter (ic.key))
-      MIM.set_caret (target, ic);
-    else
-      {
-       if (ic.preedit.length > 0)
-         {
-           MIM.insert
-
-         }
-      }
-
-
-    if (ic.im.status == 1) // Still loading.
-      return;
-    MIM.handle_keyseq (event, ic);
-  } finally {
-    MIM.debug_print (event, ic);
-  }
-  return;
-};
-
-MIM.select_im = function (event)
-{
-  var target = event.target.parentNode;
-  while (target.tagName != "SELECT")
-    target = target.parentNode;
-  var idx = 0;
-  var im = false;
-  for (var lang in MIM.list)
-    for (var name in MIM.list[lang])
-      if (idx++ == target.selectedIndex)
-       {
-         im = MIM.list[lang][name];
-         break;
-       }
-  document.getElementsByTagName ('body')[0].removeChild (target);
-  target.target.focus ();
-  if (im && im != MIM.current_im)
-    MIM.current_im = MIM.load_sync (im);
-};
-
-MIM.destroy_menu = function (event)
-{
-  if (event.target.tagName == "SELECT")
-    document.getElementsByTagName ('body')[0].removeChild (event.target);
-};
-
-MIM.select_menu = function (event)
-{
-  var target = event.target;
-
-  if (! ((target.type == "text" || target.type == "textarea")
-        && event.which == 1 && event.ctrlKey))
-    return;
-
-  var sel = document.createElement ('select');
-  sel.onclick = MIM.select_im;
-  sel.onmouseout = MIM.destroy_menu;
-  sel.style.position='absolute';
-  sel.style.left = (event.clientX - 10) + "px";
-  sel.style.top = (event.clientY - 10) + "px";
-  sel.target = target;
-  var idx = 0;
-  for (var lang in MIM.list)
-    for (var name in MIM.list[lang])
-      {
-       var option = document.createElement ('option');
-       var imname = lang + "-" + name;
-       option.appendChild (document.createTextNode (imname));
-       option.value = imname;
-       sel.appendChild (option);
-       if (MIM.list[lang][name] == MIM.current_im)
-         sel.selectedIndex = idx;
-       idx++;
-      }
-  sel.size = idx;
-  document.getElementsByTagName ('body')[0].appendChild (sel);
-};
-
-
-
-MIM.test = function ()
-{
-  var im = MIM.im_list['t']['latn-post'];
-  var ic = new MIM.IC (im);
-
-  ic.Filter (new MIM.Key ('a'));
-  ic.Filter (new MIM.Key ("'"));
-
-  if (true)
-    document.getElementById ('text').value = ic.produced + ic.preedit;
-  else {
-    try {
-      document.getElementById ('text').value
-       = Xex.ParseTerm (domain, body).Eval (domain).toString ();
-    } catch (e) {
-      if (e instanceof Xex.ErrTerm)
-       alert (e);
-      throw e;
-    }
-  }
-}