/* This bit of Javascript is meant to be used with Ubiquity, see 
   http://labs.mozilla.com/2008/08/introducing-ubiquity/
*/
CmdUtils.CreateCommand({
  names: ["calc2"],
  author: { name: "Jean-Philippe Martin", email: "pandamail@fastmail.fm"},
  contributors: ["JP Martin"],
  license: "BSD",
  homepage: "http://www.jpemartin.com/ubiq/calc2.html",
  icon: "chrome://ubiquity/content/icons/calculator.png",
  description: "A simple calculator",
  help: "Understands +,-,*,/,**,pi,e,ln,!,sin,xor and similar, as well as ( ) and operator precedence.",

  arguments: [{role: 'object', nountype: noun_arb_text}],

  preview: function( pblock, args ) {
    var theShout = args.object;
    if (theShout!=null && theShout.text!=null && theShout.text=='selftest') {
       // special case: self-test
       pblock.innerHTML = 'Self-test result:<br/>'+this.selftest();
       return;
    }
    var ret = this._calc( theShout.text)
    if (isNaN(ret) || ret=='NaN') ret = '?';    
    pblock.innerHTML = theShout.text+ " = " + ret+".<br/>"+this.help;
  },

  execute: function( args ) {
    var theShout = args.object;
    var ret = this._calc( theShout.text)
    if (isNaN(ret) || ret=='NaN') ret = '?';
    var lret = theShout.text+" = "+ret
    displayMessage( ret );
    if (CmdUtils.getSelection().length>0)
       CmdUtils.setSelection( lret );
  },

  // return a string describing the outcome
  selftest: function() {
     var t = {"1+1":2, "2*3+4":10, "2*(3+4)":14, "(2*3)+4":10,
         " 1+2":3, "1 + 2":3, "1+ 2":3, "1 +2":3, "1  +   2":3,
         "1+2 ":3, " 1+2 ":3, "(1+2)":3, "(1+ 2 ) ":3,
         "2*( 3+4 )":14, "2 * (3+4 )":14,
         "2*3*4*5+6":126, "(2*3*4)*5+6":126, "2*3*4*(5+6)":264,
         "2+3+4+5*6":39, "(2+3+4)+5*6":39, "2+3+4+(5*6)":39, 
         "2+(3+4)+(5*6)":39, "(2+(3+(4+5*6)))":39, "(2+3+4+5)*6":84,
         "(2+(3+(4+5)))*6":84, "(0)":0, "(1)":1, "(-1)":-1,
         "2*3+4*5+6":32,
         "1E1":10, "1E2+3":103, "1E-1":0.1, "0.12":0.12, 
         "0.12E2":12, "-1E1":-10, "-1.12E-1":-0.112,
         "0":0, "100":100,
         "ln(e)":1, "ln(e**2)":2, "pi":Math.PI, "π":Math.PI, "PI":Math.PI, 
         "2pi":2*Math.PI, "2π":2*Math.PI,
         "cos(0)":1, "cos(π)":-1, "cos(2π)":1, "cos(pi/2)":0, "cos(3pi/2)":0,
         "sin(0)":0, "sin(π)":0, "sin(2π)":0, "sin(pi/2)":1, "sin(3pi/2)":-1,
         "sin(pi/4)-sqrt(2)/2":0, "sin(0.4) squared + cos(0.4) squared":1,
         "cos(pi)*2":-2,
         "degToRad(90)-pi/2":0, "radToDeg(pi)":180,
         "3!":6, "4!":24, "1+4!":25, "2*4!":48, "1+2*4!":49,
         "3!+2":8, "4!*2":48, 
         "3 xor 5":3^5, "1 or 6":1|6, "2 and 3":2&3,
         "3 ^ 5":3^5, "1 | 6":1|6, "2 & 3":2&3,
         "1-6":-5, "-5":-5, "-1":-1, "-1E1":-10, "-π":-Math.PI, 
         "2**3":8, "3**2":9, "3 ** 2":9, "3** 2":9, "3 **2":9,
         "1<<1":2, "1<<2":4, "3<<1":6, "3 << 1":6, "3<< 1":6, "3 <<1":6,
         "twenty-one":21, "twenty - one":19, "20-1":19, "20 - 1":19,
         "one hundred and ten":110, "hundred ten":110, "hundred minus ten":90,
         "one":1, "nine hundred and ninety-nine":999,
         "minus three":-3,"one minus three":-2, "two times (minus three)":-6,
         "sin(3 pi / 2)":-1,"3*(1+2.5)":10.5,"3**2":9,"12!":479001600,"1E3+24":1024,
         "8 or 1 xor 3":10, "11 % 5":1, "π":Math.PI, "c/1000":299792.458,
         "1<<4 or 1":17, "sin(degToRad(90))":1, "2 plus 3 squared":11,
         "ln( fourty-two )":3.7376696182833684, "one hundred and two plus five":107,
};
     var res=0;
     var correct=0;
     var failed=0;
     var fres = [];
     for (x in t) {
       res = this._calc(x);
       if (Math.abs(res-t[x])<1E-10) correct++;
       else { failed++;
              fres.push(""+x+" = "+t[x]+", but calculator said: "+res);
            }
     }
     if (failed==0) return "All "+(correct+failed)+" tests passed.";
     var ret = ""+failed+" tests failed out of "+(correct+failed)+".";
     for (res=0; res<fres.length; res++)
         ret += '<br/>'+fres[res];
     return ret;
  },

  // return an array where the English numbers have been replaced
  // with their counterparts. This works OK now.
  // tricky: twenty-one (21) vs twenty - one (19)
  // tricky: hundred and ten (bitwise and) vs hundred and ten (110)
  _engToNumber:function(array) {
     var dic = new Object();
     dic.ZERO=0; dic.ONE=1; dic.TWO=2; dic.THREE=3; dic.FOUR=4;
     dic.FIVE=5; dic.SIX=6; dic.SEVEN=7; dic.EIGHT=8; dic.NINE=9;
     dic.TEN=10; dic.ELEVEN=11; dic.TWELVE=12; dic.THIRTEEN=13;
     dic.FOURTEEN=14; dic.FIFTEEN=15; dic.SIXTEEN=16; dic.SEVENTEEN=17;
     dic.EIGHTEEN=18; dic.NINETEEN=19; 
     dic.TWENTY=20; dic.THIRTY=30; dic.FOURTY=40; dic.FIFTY=50; dic.SIXTY=60;
     dic.SEVENTY=70; dic.EIGHTY=80; dic.NINETY=90; 
     var TEXT=1
     var OTHER=0
     var a = new Array()
     var i=0
     for (i=0; i<array.length; i++) {
        var X=(''+array[i]).toUpperCase()
        var j = a.length
        if (dic[X]!=null) {
           if (dic[X]<10 && dic[X]>=1 && j>1 && a[j-1][0]=='-' && a[j-2][1]==TEXT && a[j-2][0]%10==0) {
              a.pop();
              var prev = a.pop()[0];
              a.push([ dic[X]+prev, TEXT ])
           } else if (j>1 && a[j-1][0]==' ' && a[j-2][1]==TEXT && a[j-2][0]>=100) {
             // hundred fifty
             a.pop()
             var prev = a.pop()[0]
             a.push( [prev + dic[X], TEXT] ) 
           } else {
             a.push( [dic[X],TEXT] )
           }
        } else if (X=='HUNDRED') {
            // five hundred?
           if ((j>0 && a[j-1][1]==TEXT) || (j>1 && a[j-1][0]==' ' && a[j-2][1]==TEXT)) {
              var prev = a.pop()[0]
              if (prev==' ') prev = a.pop()[0]
              a.push([ prev*100, TEXT ])
           } else {
              a.push([100,TEXT])
           }
        } else if (X=='AND' && ((j>1 && a[j-1][0]==' ' && a[j-2][1]==TEXT) 
                               || (j>0 && a[j-1][0]!=' ' && a[j-1][1]==TEXT))) {
           // "one hundred and twenty-five"
           // don't push at all, so "and" goes away
           if (a[j-1][0]==' ') {a.pop();}
        } else {
           a.push( [array[i],OTHER])
        }
     }
     var b = new Array()
     for (i=0;i<a.length;i++)
        b.push(a[i][0]);
     return b;
  },

  _oneNumber:function(array,index) {
    var skip=0
    if (''+array[index]==' ') skip++;
    var x = array[index+skip];
    var X = (""+x).toUpperCase();
    var lhs2 = parseFloat(x);
    if (!isNaN(lhs2)) return [lhs2,skip];
    if (X=='PI' || x=='π') return [Math.PI,skip];
    // the golden ratio
    if (X=='PHI' || x=='φ') return [ (Math.sqrt(5)+1)/2,skip]
    // Planck constant
    if (x=='ℎ') return [6.626068E-34,skip]
    if (x=='ℏ') return [6.626068E-34/(2*Math.PI),skip]
    // the speed of light
    if (x=='c') return [299792458,skip]
    if (X=='E') return [Math.E,skip];
    if (X=='LN') {
       var v = this._oneNumber(array,index+1)
       return [Math.log(v[0]),v[1]+1+skip]
    }
    if (X=='EXP') {
       var v = this._oneNumber(array,index+1)
       return [Math.exp(v[0]),v[1]+1+skip]
    }
    if (X=='SIN') {
       var v= this._oneNumber(array,index+1) 
       return [Math.sin(v[0]),v[1]+1+skip]
    }
    if (X=='COS') {
       var v= this._oneNumber(array,index+1) 
       return [Math.cos(v[0]),v[1]+1+skip]
    }
    if (X=='TAN') {
       var v= this._oneNumber(array,index+1) 
       return [Math.tan(v[0]),v[1]+1+skip]
    }
    if (X=='ASIN') {
       var v= this._oneNumber(array,index+1) 
       return [Math.asin(v[0]),v[1]+1+skip]
    }
    if (X=='ACOS') {
       var v= this._oneNumber(array,index+1) 
       return [Math.acos(v[0]),v[1]+1+skip]
    }
    if (X=='ATAN') {
       var v= this._oneNumber(array,index+1) 
       return [Math.atan(v[0]),v[1]+1+skip]
    }
    if (X=='SQRT') {
       var v= this._oneNumber(array,index+1) 
       return [Math.sqrt(v[0]),v[1]+1+skip]
    }
    if (X=='SQR') {
       var v= this._oneNumber(array,index+1) 
       return [v[0]*v[0],v[1]+1+skip]
    }    
    if (X=='DEG2RAD' || X=='DEGTORAD') {
       var v= this._oneNumber(array,index+1) 
       return [v[0]*Math.PI/180.0,v[1]+1+skip]
    }
    if (X=='RAD2DEG' || X=='RADTODEG') {
       var v= this._oneNumber(array,index+1) 
       return [v[0]/Math.PI*180.0,v[1]+1+skip]
    }  
    return [x,skip]; // give up
  },

  _factorial:function(n) {
    var ret=1;
    var i=1;
    for (i=2;i<=n;i++) ret *= i;
    return ret;
  },

  _calc:function(exprstr) {
    var x = exprstr.split(/([-+*&^|/!// /(/)])/);
    var a = new Array();
    var i=0
    // skip initial "calc2" or "#"
    if (x.length>i && (x[i]==' ')) i++
    if (x.length>i && (x[i]=='#')) i++
    if (x.length>i && (x[i]==' ')) i++
    if (x.length>i && (x[i]==this.name || x[i]=='calc2')) i++
    // fix "2 pi" 

    // deal with twenty-one vs twenty - one before we remove spaces
    x = this._engToNumber(x);

    // constants, "<<"/">>" without spaces
    var re = /^([0-9]+)([^0-9]+)([0-9]*)$/; 
    for (; i<x.length; i++) {
      if (x[i]==' ') continue
      var X = (""+x[i]).toUpperCase();
      var parts = (''+x[i]).match(re);
      // pi only. 1E2 must become 100, not 1*e
      if ((X=='PI') && a.length>0) {
         var oa = a.pop()
         var oax = parseFloat(oa)
         if (isNaN(oax)) {
            a.push(oa)
            a.push(x[i])
         } else {
            // 2 pi -> 2*pi  
            a.push(oa); a.push('*'); a.push(x[i]);
         }
      } else if (x[i].length>2 && (x[i].substring(0,2)=='>>'||x[i].substring(0,2)=='<<')) {
          // 1 <<2
          a.push(x[i].substring(0,2));
          a.push(x[i].substring(2)); 
      } else if (null!=parts && parts[2]!=null && 
                   (parts[2].toUpperCase()=='PI'||parts[2]=='π'
                    ||parts[2]=='<<'||parts[2]=='>>'||parts[1]=='<<'||parts[1]=='>>') ) {
        // fix 2pi, or 1<<4
        a.push(parts[1])
        if ( (""+parts[2]).toUpperCase()=='PI' || (""+parts[2]).toUpperCase()=='E' || parts[2]=='π')
           a.push('*');
        a.push(parts[2])
        if (parts.length>3 && parts[3]!=null) a.push(parts[3])
      } else if (x[i]=='-' && i>0 && i+1<x.length) {
         // test for 1E-2: must be 0.01, not e - 2
         var v = (''+x[i-1]).toUpperCase();
         if (v.length>1 && v.substring(v.length-1)=='E') {
            // must be 1E-2 or similar
            v = a.pop();
            a.push(''+v+x[i]+x[i+1])
         } else a.push(x[i]);

      } else { a.push(x[i]) }
    }
    
    return this._deparen(a,0,0)[0];
  },

  // find innermost paren, apply innercalc to it, repeat
  _deparen:function(x,index,level) {
    var i=index;
    if (level>10) return -999; // debug
    var a = new Array();
    // first: parens
    for (i=index;i<x.length;i++) {
        if (x[i]==' ') continue;
        if (x[i]=='') continue;
        if (x[i]=='(') {
           var v = this._deparen(x,i+1,level+1);
           if (v[1]>i) i=v[1]; // sanity check    
           a.push(v[0]);
        }
        else if (x[i]==')') {
           if (a.length==0) return [null,i+1];
           return [this._innercalc(a),i+1];
        } else {
          a.push(x[i])
        }
    }

    //return ["a[0]='"+a+"' (length "+a.length+")",x.length];
    return [this._innercalc(a), x.length];
  }, 

  // evaluate an array of symbols (but no "(" or ")")
  _innercalc:function(x) {
    var i=0;
    var a = new Array();
    
    for (i=0;i<x.length;i++) {
        var X = (""+x[i]).toUpperCase();   
        if ((x[i]=='-' || (''+x[i]).toUpperCase()=='MINUS') && i==0) {
           // -2 -> -1 * 2
           a.push("-1");
           a.push("*");
           continue;
        }
        if (x[i]=='!') {
           var v = parseFloat(a.pop())
           a.push(this._factorial(v))
        }
        else if (X=='SQUARED') {
           var v = parseFloat(a.pop())
           a.push(v*v)
        }
        else if (X=='CUBED') {
           var v = parseFloat(a.pop())
           a.push(v*v*v)
        }
        else {
          var xyz=this._oneNumber(x,i)
          i += xyz[1]
          a.push( xyz[0] );          
        }
    }
    // now same for next-level functions
    x = a;
    a = new Array();
    
    for (i=0;i<x.length;i++) {
        // b**c = b raised to the cth power
        if (x[i]=='*' && x[i-1]=='*') {
           var b=parseFloat(x[i-2])
           var xyz=this._oneNumber(x,i+1)
           var c = xyz[0]
           i += xyz[1]+1
           a.pop();
           a.pop();
           a.push( Math.pow(b,c) ) 
        }
        else {
          a.push( x[i] );          
        }
    }
    // now same for next-level functions
    x = a;
    a = new Array();

    for (i=0;i<x.length;i++) {
        var X = (""+x[i]).toUpperCase();    
        if (['*','/','TIMES','%','MODULO'].indexOf(X)>-1) {
           var zop = X;
           var cmd = a.pop();
           var lhs = cmd; //parseFloat(cmd);
           var rhs = parseFloat(x[i+1]);
           //var xyz = this._oneNumber(x,i+1);
           //var rhs=xyz[0];
           i += xyz[1]+1; // +1 because of the "*"
           if (zop=='*' || zop=='TIMES')
             a.push(lhs*rhs);
           else if (zop=='%' || zop=='MODULO')
             a.push(lhs%rhs);
           else
             a.push(lhs/rhs);
        }
        else {  
          a.push(x[i]);
        }
    }
    // now same for next-level functions
    x = a;
    a = new Array();

    for (i=0;i<x.length;i++) {
        // without the conversion to string, if x[i]=0
        // then it somehow also equals " "  (WTH?)
        if ((''+x[i])==' ') continue;
        var X = (""+x[i]).toUpperCase();
    
        if (['+','PLUS','-','MINUS'].indexOf(X)>-1) {
           var cmd = a.pop();
           var lhs = cmd;
           var rhs = parseFloat(x[i+1]);
           if (x[i]=='+' || X=='PLUS')
             a.push(lhs+rhs);
           else if (x[i]=='-' || X=='MINUS')
             a.push(lhs-rhs);           
           i++;
        }
        else {
          a.push(x[i]);
        }
    }
    // now same for next-level functions
    x = a;
    a = new Array();
    for (i=0;i<x.length;i++) {
        if (['<<','>>'].indexOf(x[i])>-1) {
           var cmd = a.pop();
           var lhs = cmd;
           var rhs = parseFloat(x[i+1]);
           if (x[i]=='<<')
             a.push(lhs<<rhs);
           else if (x[i]=='>>')
             a.push(lhs>>rhs);           
           i++;
        }
        else {
          a.push( x[i] );
        }
    }
    // now same for next-level functions
    x = a;
    a = new Array();
    for (i=0;i<x.length;i++) {
        var X = (""+x[i]).toUpperCase();    
        if (['XOR','^','OR','|','AND','&'].indexOf(X)>-1) {
           var cmd = a.pop();
           var lhs = cmd;
           var rhs = parseFloat(x[i+1]);
           if (X=='XOR' || X=='^')
             a.push(lhs^rhs);
           else if (X=='OR' || X=='|')
             a.push(lhs|rhs);
           else if (X=='AND' || X=='&')
             a.push(lhs&rhs);
           i++;
        }
        else {
          a.push( x[i] )
        }
    }
    return a[0];
  }
})
/* this would be nice, but it doesn't work right
var noun_cust_country = {
  _name: "country name",

  suggest: function( text, html ) {
         
    var suggestions  = [];
    var i=0;
    if (null!=flag_verb_cached_countries)
      for (i=0;i<flag_verb_cached_countries.length;i++) {
        var name = flag_verb_cached_countries[i];
        if (name.match(text, "i"))
	   suggestions.push( CmdUtils.makeSugg(name) );
      }

    // Return a list of input objects, limited to at most five:
    suggestions = suggestions.splice(0, 6);
    // if we don't return at least one suggestion, the verb doesn't work.
    // that's too bad, because I really want to just wait until we've loaded stuff
    if (suggestions.length<1) suggestions.push( CmdUtils.makeSugg(text) );
    return suggestions;
  }
};
*/

var flag_verb_cached_countries = null;

CmdUtils.CreateCommand({
  names: ["flag"],
  author: { name: "Jean-Philippe Martin", email: "pandamail@fastmail.fm"},
  contributors: ["JP Martin"],
  license: "BSD",
  description: "Country -&gt; its flag",
  homepage: "http://www.jpemartin.com/ubiq/",

  //takes: {"country":noun_arb_text},
  //takes: {"country":noun_cust_country},
  arguments: [{role: 'object', nountype: noun_arb_text}],

  _cachedK: null,
  _cachedV: null,
  _page: null,

  preview: function( pblock, args ) {
    var arg = args.object
    if (null==arg || null==arg.text || arg.text.length<1) {
       pblock.innerHTML='';
       return;
    }
    var baseUrl = "http://www.flags.net/index"+arg.text[0].toLowerCase()+'.htm';   
    pblock.innerHTML='Looking for flag for '+arg.text+'... <div id="result" style="display:none">...</div>'
    if (this._cachedK==null || this._cachedK!=baseUrl) {
       this._loadIndex(baseUrl,pblock,arg.text,this);
    } else {
       this._pageLoaded(pblock,arg.text,this);
    }
  },

/* can't load the flag div without pblock :(
  execute: function(arg) {
    this._pageLoaded(null,arg.text,this);
    if (null!=this._page)
      Application.activeWindow.open(Utils.url(this._page));
    else
      displayMessage('Flag not found; page='+this._page);
  },
*/

  _stripVowelAccent:function(str) {
    var s=str;

    var rExps=[ /[\xC0-\xC2]/g, /[\xE0-\xE2]/g,
      /[\xC8-\xCA]/g, /[\xE8-\xEB]/g,
      /[\xCC-\xCE]/g, /[\xEC-\xEE]/g,
      /[\xD2-\xD4]/g, /[\xF2-\xF4]/g,
      /[\xD9-\xDB]/g, /[\xF9-\xFB]/g ];

    var repChar=['A','a','E','e','I','i','O','o','U','u'];

    for(var i=0; i<rExps.length; i++)
      s=s.replace(rExps[i],repChar[i]);

    return s;
  },

  _pageLoaded:function(pblock, name, zis) {
      //displayMessage('pageLoaded')
      var res = pblock.getElementsByTagName('div');
      res.item(0).innerHTML=this._cachedV;
      var r2 = res.item(0).getElementsByTagName('img');
      //displayMessage('there are '+r2.length+' images');
      var i=0;
      var ret = null;
      var flagDesc = '';
      flag_verb_cached_countries = new Array();
      for (i=0;i<r2.length;i++) {
        var x = r2[i].alt;
        var boo='Flag of';
        if (x!=null && x.length>boo.length && x.substr(0,boo.length)==boo) x=x.substring(boo.length,x.length)
        x=x.replace('>','&gt;');
        x=x.replace('<','&lt;');
        if (null!=x && x.substr(0,1).toLowerCase()==name[0].toLowerCase())
           flag_verb_cached_countries.push(x); 
        if (this._stripVowelAccent(r2[i].alt.toUpperCase()).indexOf(this._stripVowelAccent(name.toUpperCase()))>=0) {
           flagDesc = r2[i].alt;
           //displayMessage('found');
           //displayMessage(r2[i].src);
           ret = r2[i].src;
        }
      }
      var ret2=null;
      // now search for links, for the action
      var r2 = res.item(0).getElementsByTagName('a');
      for (i=0;i<r2.length;i++) {
        var x = r2[i].title;
        if (this._stripVowelAccent(x.toUpperCase()).indexOf(this._stripVowelAccent(name.toUpperCase()))>=0) {
           ret2 = r2[i].href;
           ret2 = ret2.replace('chrome://ubiquity/content/','')
           ret2 = 'http://www.flags.net/'+ret2;                            
        }
      }
      this._page = ret2;
      if (null!=ret2) flagDesc = '<a href="'+ret2+'">'+flagDesc+'</a>'
      if (null!=ret) {
         var prefix='chrome://ubiquity/content/'
         if (ret.length>prefix.length && ret.substring(0,prefix.length)==prefix) ret = ret.substring(prefix.length, ret.length);
         //displayMessage('Final: '+ret)
         if (null!=pblock) pblock.innerHTML=flagDesc+' <img src="http://www.flags.net/'+ret+'"/> <br/>image courtesy of http://www.flags.net/';
      } else {
         if (null1=pblock) pblock.innerHTML+='Sorry, no flag found for '+name;
      }
  },

  _loadIndex:function(url, pblock, name, zis) {
    //displayMessage('loadIndex('+url+')')
    jQuery.get( url, {}, function( page ) {
      //displayMessage("page loaded");
      zis._cachedV=page;
      zis._cachedK=url;
      zis._pageLoaded(pblock, name, zis);
    });
  },

})
CmdUtils.CreateCommand({
  name: "pause-TSO",
  author: { name: "Jean-Philippe Martin", email: "pandamail@fastmail.fm"},
  contributors: ["JP Martin"],
  license: "BSD",
  description: "pause/restarts the music from TheSixtyOne.com",
  homepage: "http://www.jpemartin.com/ubiq/pause-TSO.html",
  //help: '',

  preview: function(pbox,arg) {
    var text = 'Press ENTER to ';
    var v = this._findT61();
    if (v==null) return this._say(pbox,text+"(try to) pause the current song."); 
    v = v.current_song;
    if (v==null) return this._say(pbox,text+"(try to) pause the current song.");
    if (v.playing) text += 'pause ';
    else text += 'resume ';
    text += '"'+v.name+'" by '+v.artist;
    if (null!=v.photo_base_url) text += '<br/><img src="'+v.photo_base_url+'_small"/>'
    this._say(pbox, text); 
  },

  _say:function(pbox, text) {
    pbox.innerHTML = text;
  },

  execute: function() {
     var v = this._findT61(); //CmdUtils.getWindowInsecure().t61;
     if (null==v) { displayMessage("Could not find TheSixtyOne.com web page"); return; }
     var song = v.current_song;
     if (null==song) return; // already stopped
     if (song.playing) song.pause();
     else song.play();
  },

  _findT61:function() {
     var v = CmdUtils.getWindowInsecure().t61;
     //if (null!=v) return v;
     for( var j=0; j < Application.windows.length; j++ ) {
       var window = Application.windows[j];
       v = window.t61;
       if (null!=v) return v;
       for (var i = 0; i < window.tabs.length; i++) {
         var scope = window.tabs[i].document.defaultView.wrappedJSObject;
         v = scope.t61;
         if (null!=v) return v;
       }
     }
     return null; // not found
  },

});

noun_type_emote = new CmdUtils.NounType( "emote",
  [":)",':D',';)',':))',':p',':s',':(','D:','>(',':!',':o',':|','O_o',":'",'8)'] 
  );


CmdUtils.CreateCommand({
  names: ["smiley"],
  arguments: [{role: 'object', nountype: noun_arb_text,label: 'emote'}],

  author: { name: "Jean-Philippe Martin", email: "pandamail@fastmail.fm"},
  contributors: ["JP Martin"],
  license: "BSD",
  description: "Smilies!",
  homepage: "http://www.jpemartin.com/ubiq/smiley.html",
  help: 'Select a smiley, press enter to paste it into your email or web page. Thanks for <a href="http://openclipart.org/media/people/Chrisdesign">Chrisdesign</a> for the graphics.',

  preview: function(pbox,args) {
    pbox.innerHTML = this._makeImg(args.object.text)
  },

  execute: function(arg) { 
    CmdUtils.setSelection(this._makeImg(arg.object.text)); 
  },

_makeImg:function(emote) {
  // smileys from: http://openclipart.org/people/Chrisdesign/Chrisdesign_Glossy_Smiley_Set_1.jpg
  var data = {':)':
"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",':D':
"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", ';)':
   "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"
+"\n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",':))':
   "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"
+"\n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",':P':
   "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"
+"\n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",':S':
   "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"
+"\n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"
+"\nv//Z",':(':
  "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"
+"\n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",'D:':
  "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"
+"\n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"
+"\nEj0IojylL+RmtKScFQ+Do0aNHoNf/9k=",'>(':
  "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"
+"\n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",':!':
   "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"
+"\n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"
+"\ncbwwCogkaNGjXXYQhH//2Q==",':O':
 "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"
+"\n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"
+"\nJNaJ17AHsU/to0aNWBxURxX/2Q==",':|':
   "/9j/4AAQSkZJRgABAQEA1QDVAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoM"
+"\nDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsN"
+"\nFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAAR"
+"\nCAAkACQDASIAAhEBAxEB/8QAGQAAAwEBAQAAAAAAAAAAAAAAAAYIBwkF/8QAMBAAAQMDAwMD"
+"\nAgQHAAAAAAAAAQIDBAUGEQAHCBIhQRMiMQlRMkJSYRcjNGJxkdH/xAAaAQACAwEBAAAAAAAA"
+"\nAAAAAAADBgEEBwIF/8QAJhEAAgEDAwMEAwAAAAAAAAAAAQIDAAQRBRIhEzFhQVGBkaGxwf/a"
+"\nAAwDAQACEQMRAD8Asrlvy3p3G6lUyk0umOXZuPcBLVDtuKr3LOSPXeI7paSR/lRBAwApSZn/"
+"\nAIB7t77zo0nfLe+dbcipgvRrKtWUmGy2gdykJCv5vSCMkhah3yo/Ol7jnWGt9t/b93wrWJap"
+"\n9UfpdvpeGRGpzA6WwgH4Kk9OSMe5Kz+Y5xHlFxT3l3E5R1G5aE0qoU6oymHoNZE1tlMBCEJw"
+"\nlQKwpv0yDjA93yMkkaSJdZjuL2WzWYRiPuT6n1Hx45pnj054IEuDHuL/AIFUnWeBFJ29joqV"
+"\npb2XfY1VDgRHlOVcttrdV8JV7klRJH4Qe/76YNt+XG5HHG/aXYHIxUerW9UnUxaVuJDbDSEu"
+"\nE+1M0DCQCPzgApwSeodSk4P9Qjj5ufvPc9n1O1mnLppsCmCA7EbdbaU1I9RRW/0KUkYcBQD0"
+"\n/HpjOBjWyM7NPVTiPb23N+yEVKqxqcIr0gEOlheSW0oX8EtAoAIOD6Sdec2uJp1vHdNPvUnl"
+"\nSckD355++KtDTWu5Gg6e0jsf57V0MSvrSFIwtJGQQex0akb6du9z9z8b4lGu2ooFwWdUpFry"
+"\nXX1e50R+gtknzhtxtGfPRk986NaOo6ih15BpQYbCVbGRUt8K302zsZU49UK4L9n1GoR6qhLa"
+"\nlOMraUXXPakFRwknsBklOADp0gfUP2OQ0n16tVUq/tpTpGf9a9rkNalT4b8gqtu5TqZIqW0d"
+"\n7PIVc7EJouLpE/P9WU/ocUoqJ8qWsfPpg0/tpuTbt60GHWaDVYlYpkkAtyorocQf2Jz2I8g4"
+"\nI899YpqGjW9jqk014jFJWyCDgDPcHg858jinyLVJrizjjt2AKDB9/wB1Kbv1E9h1JIFXq2T9"
+"\n6S7/AM0w7fb62ZyHbqq7NmTJKKV6apCZMRxnHX1BJHUMH8Ch2+PPzqwahccRbAASkHB74xqL"
+"\nOSm+cvcevHZbZ0puPcOuhUWbKiKKo1DjH2vPvOpyEKSDg+U5/UUpVUvNHsdRYWlgrMzY53cA"
+"\neueO3zXVrqdzanrTkADx3P3S3wl2hqe7VpbjXVS5DkemVC+am7FUl3oS82UskLT9xkkZ+6To"
+"\n1eWwWzVJ2A2htmw6MouxqRFDbkkp6VSX1EqeeI8FbilKx4zjxo1ucKdGNYgOFAH1SLJN1HZy"
+"\nO5zTtUadFqtPkQpsZqZDkoUy/HkIC23UKGFJUk9iCCQQe2oD5S8LLG2Yos2/ts6rc+29SfkJ"
+"\nQ9AtqqmPBc6gST6SkqI/ZKSEjwkaNGpkRXXawyKGjFdpB5qc+MlpXBynvNq1743QvxdGeU42"
+"\n9Hp9XDIdQj4SsFshQPnI11H2R477fcdbeVR7DtyNRmnQkyZXdyVLUD2LrysqXjJIBOE5OAB2"
+"\n0aNDihjhG2JQo8DFTI7Pjcc1pqRkaNGjRsUI1//Z",'O_O':
  "/9j/4AAQSkZJRgABAQEA1QDVAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoM"
+"\nDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsN"
+"\nFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAAR"
+"\nCAAkACQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAgGBwkE/8QANhAAAQIFBAAF"
+"\nAQIPAAAAAAAAAQIDBAUGBxEACBIhExQxQVEigvAJFRYXIyQzQlJhcYGRocH/xAAaAQADAAMB"
+"\nAAAAAAAAAAAAAAACBgcBAwQF/8QAJhEAAQMEAgEDBQAAAAAAAAAAAQIDEQAEBRIxQZEhInET"
+"\nUWGx0f/aAAwDAQACEQMRAD8Ac3dru4le2qSy2Bgpauqbgz5RakdNw5+p1Q6LzpHaWknHfqo9"
+"\nDGFKSi1Sz6a3Nq1Eu3Dbl/yLmcWUqFF0vEqhYSB5AFKH1oyhJGR+2PIevIgg6lFjJu3fzcVX"
+"\nl6p0rzbL83dktPh1OUw0vY+lBSPYrGM4/eLn8R0g96LF3IlN5KglswpubzaZxsxeeZi4aFdf"
+"\nTHhxxSg6hQB5cs5+Qcg4II0opyiMhfvWTbugaiYiSe+eAPM0wmyVaWzdwpGxX4A/prSKP2FS"
+"\nChYNmdUne2rqJmCuPl5j+OOLTrih9OTyTyCvjl36fI1IaB3YXN2xVxKaH3FLhp5SszdTCyq4"
+"\n0C34aULJwERiRhIGMZVgFPZJWMqSo+4napeSrbZ2ehIJlyolyGQJl0ZK24psKgoguFWfqUAo"
+"\neGppolJOPA76I01Ujs4/G7O5PbS4T6JlMGJb5d97IdMOsrUppKFehU0lSEgg4/RjXluZlrHN"
+"\nJfL+6SYImTH3nnzXYnHrvFlr6Wpj0MR+q0EZdQ62laFBaFDKVJPSh8jRpN/we1+0R23hmnK2"
+"\nm6WKhoyaRNMPOPqyp1EPwLZJ9+KHEt59/D0afEr3AUk+hpUUNFFKuRS67FZO/CWxjqbiE+Xm"
+"\n1OT6Ml0a16LQ8leTkfax9nToySnlvtJ8RIKjggn3+D/z++l13IUdNNn+4CZXllMriJnaitHW"
+"\nxVcLAtFxyUx2T+ucfZCySSr05LWDgqbBviDjaC3EWojJaY5moaRn0N4Lzkvi1IK0EgkckEFC"
+"\ngcZScEeih6jULzGDNpmHLlwkNumdvnr5qg2+WU9YtsoHuQIipQ9SiUtEgdY7+/3/AM6gtWyN"
+"\n5SOCSW0g5I7yevf/AFrmsxtQtDt3qKMqKiJPGQE2iYNUE49ETJ59PhKUlZHFSuPZQnsjIx6j"
+"\nJzUu5O/EVXE7/MzZwJqO5M95QkQ/BK5Q8lhz9Lr7zqchCkg/1TnJ74pVx3mCbv3k22PWVhXJ"
+"\n6A7mjtcq7bS6+Iiq52l2Snl6pPcmqpG+6zKYquJl5dbbiW0vI4skLAJ7zy9fkHRrQrb3ZWUb"
+"\nfbPU1QcqKYhmVQwS9FKTxMTEKJW88Rk45LUogZOAQPbRq+stpZbS3E6gDxU9dWXXFOHszU/m"
+"\nEDDTSDeg4yHai4OIaU29DvoC23UKGFJUk9EEEgg6QXdLsooSz8hmNwbazSprbzV19KXYKmJq"
+"\nYaCc5ZyfCKVFP8kpISPZI0aNGpKVjVYkUCVFJBSYpbtttK1FuerZql61ulXqpO46tlxmAnCW"
+"\nfESnPSstkHOO8jWo1kNuVvducgXKaDp2Hk6HuPmowkuxcWQDguvKypXZJAzxGTgDRo1lllpn"
+"\n2tpCR+BFEpa1kbGasorOjRo1uTwKGv/Z",":'":
   "/9j/4AAQSkZJRgABAQEA1QDVAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoM"
+"\nDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsN"
+"\nFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAAR"
+"\nCAAkACQDASIAAhEBAxEB/8QAGgAAAgMBAQAAAAAAAAAAAAAAAAgGBwkDBP/EAC8QAAIBBAEE"
+"\nAQMDAgcAAAAAAAECAwQFBhEHAAgSITETQWEVIkIyUQkkM1JicYH/xAAZAQADAQEBAAAAAAAA"
+"\nAAAAAAACBgcDBAD/xAAoEQACAQMDAgUFAAAAAAAAAAABAgMABBEFITFBUQYiYZGxEjKBwdH/"
+"\n2gAMAwEAAhEDEQA/AHR7tO7a0dtGP26mp7dJk+eX1jDY8bpW/fO4+ZZSPaRKdAnWyTofyZc4"
+"\neTubb1k3JMdh7heasmxupn+m9TjWCwGG22lZEDok7BwZD4uCdLKw3/V1bfDd0j597mM/5kvJ"
+"\nFZAt4ksGOrMAVpqCn9Aqp3ouCCT/AHaT/cevRzl2AYpzZzBNnEuT11kS4Oklzt0FMkn12RVT"
+"\ncchYfSJCgnav7JPreukOfxFbG/ls2kKrHsSOS3OPQD564prg0mYWqXCL9TNvvwB3qAdwnFfF"
+"\nvaYtmqqHmbkexZNdENRQ/oNWZ2ZAQPrP+9B9Mn/ntvegdHVvcC99ea8VSYpS8zXGlzLjXJwq"
+"\nWPk2gg+iY2LFQlbHoBdEEMSAylW2X9levdB2Z413HzY3Vx3ubFbhZKRbdFJDSipjkpVYssZQ"
+"\nspHiS2iG/kdg+tSu4cEYjae2hOJ/B6uwUlI0KTzhWmMruXaYetB/qOzDXwSPsOuEeJLa1iSQ"
+"\nSFjnzA9B3BPX810HSJp3ZWTHYj+CnoinSaNZEdWRwGVlOwQfgg9HSU/4f/cRT03AC4nnd5Sm"
+"\nv2FXWqxkvMT5TQ0/gYj8/CrIIx+I/wD3o6oyOjqGXg0nspVip5FUD2N2OegwK+4tUgw3bG8i"
+"\nrbbWxt/qJKjjfkPne9jf4I+3Tp2PH5KiJTIhLn5P9/z0vHctht37Sefq/m2y2uouvFuXGNMv"
+"\noqGMvJbKsEha0KP4sSST8eTSA6806ZTi3k3G85x6kvePXWkvNpnUFKmjkDr8AlWHyrDftToj"
+"\n76PUI1rQntNXkuJMiOU5z0yeQaoNvqzTWKQp9yDGK9U+KiGIkjx/JB6gmXWOZovBdxov2HyT"
+"\n107gu2LijuRu9rvOaWqqrLhbqU0cElLcJoFEfmX0VVvH+pid62d+ydDS7cl5xa8SsFq7cu3y"
+"\nmkveZVcb0MQgqXqI7HBI7Gaeeck+DKXYgE/s3vQ/arY3WhwagVt7KQuzHfA2A75z+q9a6tNa"
+"\nkzTjAFQTtv4OyDnGHknKcdL/AKTLmtxihkjkVFlAWEhx5H2CGHv8f99HWjvblwjbO3bhvG8D"
+"\ntT/XS2Qf5mr8dGqqXJeaYg7I8nZtAn0ND4HR1eIYRDEsY4AA9qQJpDLI0nck+9WDV0cFxo56"
+"\nSrgjqqWdGimgnQOkiMNMrKfRBBI0fWukM7pOyXAeJ7FduQ+OLjkvG14MoWWjxe6GmopfIE7M"
+"\nRVvED7KhVRv0Ojo60dVdcMM0CMVKkGlk7c8dyXuazqnxTMuUs9NnmleGWK33gQmRFBIDbjIb"
+"\nevewetSOCe23jvt0sDWzBMcp7SZlUVVcxMtXVkewZZm2zDZJC7CjZ8QOjo6COKOHyxKFHoMf"
+"\nFHK7M2CasxXIVT69gHo6OjoiTmsa/9k=",'8)':
   "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"
+"\n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"


}
  return '<img src="data:image/png;base64,'+data[emote.toUpperCase()]+'"/>'
},
})
/* This bit of Javascript is meant to be used with Ubiquity, see 
   http://labs.mozilla.com/2008/08/introducing-ubiquity/
*/
noun_type_tempunit = new CmdUtils.NounType( "Unit",
  ["C", "F", "K", "Celsius", "Farenheit", "Kelvin"] 
  );


CmdUtils.CreateCommand({
  names: ["temp"],
  author: { name: "Jean-Philippe Martin", email: "pandamail@fastmail.fm"},
  contributors: ["JP Martin"],
  license: "BSD",
  description: "temperature converter",
  homepage: "http://www.jpemartin.com/ubiq/temp.html",
  help: "try 25C",

  //takes: {"temperature": noun_arb_text},
  //modifiers: {"in": noun_type_tempunit},

  arguments: [{role: 'object', nountype: noun_arb_text, label: 'temperature'},
              {role: 'format', nountype: noun_arb_text, label: 'unit'}],



  preview: function( pblock, args ) {
    var v = this._conv(args)
    // image thanks to the Open Clipart Library, based on art from "twb"
    if (v[1].length>1) {
      v[1]=' = '+v[1] 
      var data = "iVBORw0KGgoAAAANSUhEUgAAAAsAAAAaCAYAAABhJqYYAAAAAXNSR0IArs4c6QAAAAZiS0dE\n"
+"AP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9gIHhclJ+afj/YAAAAZ\n"
+"dEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAABXUlEQVQ4y43TQUtUURjG8d/c\n"
+"q42YoDhlUISbQXTdrn2QubGNBi1a5iK/Tx+gDESxIaSoteRCpNqE0k5CpJkbg1hTw8xtMQ3c\n"
+"uZ7ReeDAy3v+PLzvczj0agazLlO5XH60tbXZqlRet+bmZp9cCK+sPF1PkmqaJNV0dfVZJcQM\n"
+"dYsoiuJu3Wj8uYa7OXZ3KOQQx/Ff1HLtNAgXi1fOcNB3jNOXa47evgM/arVx3ME+0nNwu17X\n"
+"rNdBk2GU+jpnNUoV7weCW2HnJAg3mAxEtx2Er3KCN/l+FILbxBgbCP7NFO7n7/uNcYyNgdJI\n"
+"KegkklUzCJ9xE8u59loQHuM7Xgy0YD914dGY6cwit0PRgXu82iHd+38+ks6zGXK+/oClYqY5\n"
+"jAUe4lYenhwPzD7Ria+Uh7994SgPf+o8zNee74b0kM8lFqcZaeMDp895/IvDLFzI1DcmWCgQ\n"
+"/WRbx7lH/wBJDFmOvG90hQAAAABJRU5ErkJggg=="
      pblock.innerHTML = '<img src="data:image/png;base64,'+data+'"> '+v[0]+v[1]+".";
    } else {
      pblock.innerHTML = '';
    }
  },
  execute: function( args ) {
    var v = this._conv( args )
    var lret = v[0]+" = "+v[1]+".";
    
    if (CmdUtils.getSelection().length>0) {
       CmdUtils.setSelection( v[1] );
       lret += '<br/>(changed page body)'
    }
    displayMessage( lret );

  },

  _conv:function(args) {
     var txt = args.object.text;
     var mods = '';
     if (null!=args.format) mods = args.format.text;
     var ending = /[0-9] ?(C|F|K|c|f|k)[ ]*(to C|to F|to K|to c|to f|to k)?$/;
     var beginning = /^[0-9]+ ?(C|F|K|c|f|k)/;
     var num = parseFloat(txt)
     var unit = null
     var destUnit = 'x'
     var v = txt.match(ending);
     if (null==v) {
        // no match, try another way to get the unit
        v = txt.match(beginning);
     }
     if (null!=v) {
        num = parseFloat( txt.substring(0,txt.length-1) )
        unit=v[1].toUpperCase()
     }
     destUnit = mods.in.text
     if (destUnit=='' || destUnit==' ') destUnit=null;
     if (null!=destUnit && destUnit!='') destUnit = destUnit.substring(0,1).toUpperCase()

     if (destUnit==null && null!=v && v.length>2) { 
        var vv=v[2];
        if (null!=vv) destUnit = vv.substr(vv.length-1,1).toUpperCase()
     }
     if (destUnit!=null && ['C','F','K'].indexOf(destUnit)<0) destUnit=null;
     if (null==destUnit && unit!=null) {
        destUnit = (unit=='C'?'F':'C')
     }
     if (destUnit!=null && unit==null) {
        if (destUnit=='C') unit='F'
        else if (destUnit=='F') unit='C'
        else if (destUnit=='K') unit='C'
     }
     if (unit==null && num!=null) {
        // return [txt,"?"];
        // guess at the unit!
        if (num<-50) { unit='K'; destUnit='C'; }
        else if (num<50) { unit='C'; destUnit='F'; }
        else { unit='F'; destUnit='C'; }
     }

     var k;
     if (unit=='C') k = num+273.15;
     else if (unit=='F') k = (num+459.67)*5/9.0;
     else k = num

     var res=0
     if (destUnit=='C') res = k-273.15;
     else if (destUnit=='F') res = (k*9/5.0)-459.67;
     else { res = k; destUnit='K'; }

     if (isNaN(num)) return [this.help,'']
     return [num+" "+unit, res.toFixed(2)+" "+destUnit]
  }
})
/* This bit of Javascript is meant to be used with Ubiquity, see 
   http://labs.mozilla.com/2008/08/introducing-ubiquity/
*/

/*
Based on CoolClock code by Simon Baird (simon dot baird at gmail dot com)
See http://simonbaird.com/coolclock/

CoolClock is Copyright (c) Simon Baird 2006-2008
time.js is Copyright (c) Jean-Philippe Martin 2008

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.

Neither the name of the Simon Baird nor the names of other contributors may be
used to endorse or promote products derived from this software without specific
prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/

noun_time_style = new CmdUtils.NounType( "style",
  ["swissrail", "chunkyswiss", "chunkyswissonblack", 
   "fancy", "classic", "machine", "modern", "simple",
   "securephp", "lev", "tes2", "sand", "sun", "tor", "cold",
   "babosa", "tumb", "stone", "disc"] 
  );

/* matches GMT-23 to GMT+23, GMT, EST, and other common timezone names */
var noun_time_timezone = {
  _name: "timezone",

  _knownTZ: {GMT:0,
             BST:+1,
                 WET:+0,
                 WEST:+1,
                 CET:+1,
                 CEST:+2,
                 EET:+2,
                 EEST:+3,
                 MSK:+3,
                 MSD:+4,
                 NST:-3.5,
NDT:-2.5,
AST:-4,
ADT:-3,
EST:-5,
EDT:-4,
CST:-6,
CDT:-5,
MST:-7,
MDT:-6,
PST:-8,
PDT:-7,
AKST:-9,
AKDT:-8,
HAST:-10,
HADT:-9,
AEST:+10,
AEDT:+11,
ACST:+9.5,
ACDT:+10.5,
AWST:+8,
AWDT:+9,
CXT:+7,
},

  suggest: function( text, html ) {
    
    var suggestions  = [];
    var i=0;    

    if (null==text) return;

    if (text.indexOf('+')<0 && text.indexOf('-')<0) {
       for (var k in this._knownTZ) {
          var sk = k.substring(0,text.length)
          if (sk==text) suggestions.push(CmdUtils.makeSugg(k));
       }
    }

    if (text=='GMT') {
       suggestions.push(CmdUtils.makeSugg(text));
       suggestions.push(CmdUtils.makeSugg(text+"+"));
       suggestions.push(CmdUtils.makeSugg(text+"-"));
       return suggestions;
    }

    // XYZZY+2 should only work for XYZZY==GMT
    if ((text.indexOf('+')>=0 || text.indexOf('-')>=0) && text.substring(0,3)!='GMT') {
       suggestions.push(CmdUtils.makeSugg("GMT"));
       return suggestions;
    }

    if (text.substring(0,3)!='GMT') return suggestions;

    // propose +offset or -offset for GMT

    var num=0;
    if (text.length>4) {
      num = parseFloat( text.substring(4) ); 
    }
    if (isNaN(num)) num=0;

    suggestions.push(CmdUtils.makeSugg(text)); 
    for (i=0; i<5; i++) {
        var x = num*10+i;
        if (x<24) 
           suggestions.push(CmdUtils.makeSugg(text+""+i)); 
    }

    // Return a list of input objects, limited to at most five:
    return suggestions.splice(0, 5);
  },

  // returns offset from GMT, or NaN if it doesn't recognize the timestring
  // this should accept everything that suggest can output. 
  // e.g. GMT-6 returns -6 
  interpret:function(text) {
    if (null!=this._knownTZ[text]) return this._knownTZ[text];
    if (text=='GMT') return 0;
    if (text.length<=3) return parseFloat('NaN');
    if (text.length==4 && (text[3]=='+' || text[3]=='-')) return 0;
    var num = parseFloat( text.substring(3) ); 
    return num; 
  },
}



// hopefully this will improve later
CmdUtils.CreateCommand({
  names: ["time"],
  author: { name: "Jean-Philippe Martin", email: "pandamail@fastmail.fm"},
  contributors: ["JP Martin"],
  license: "BSD",
  description: "A pretty clock that shows the current time. Thanks to Simon Baird, http://randomibis.com/coolclock/",
  homepage: "http://www.jpemartin.com/ubiq/time.html",
  help: 'The clock will keep the last style you gave it. Based on CoolClock code by Simon Baird. See: <a href="http://randomibis.com/coolclock/">http://randomibis.com/coolclock/</a>',

  arguments: [ {role: 'object', nountype: noun_arb_text, label: 'style'},
               {role: 'object', nountype: noun_arb_text, label: 'at'} ],
  //modifiers: {"style": noun_time_style, "at": noun_time_timezone},
  ctx: "",

  preview: function( pblock, args ) {
    var mods = args;
    pblock.innerHTML = '<canvas id="can1" width="200" height="200"></canvas><br/>';
    //if (mods.city!=null) pblock.innerHTML+='<br/>Sorry, city offset not implemented yet'
    var d = new Date();

    if (null==mods || null==mods.style || null==mods.style.text || mods.style.text.length<1) {
        this.skinChoice = this.getKey();
    } else {
        this.skinChoice = mods.style.text;
        this.setKey(this.skinChoice);
    }
    skin = this.skins[this.skinChoice];
    if (null==skin) {
       displayMessage('Skin not found: '+this.skinChoice)
       skin = this.skins.swissrail;
       this.setKey('modern');
    } 
    var off=0;
    if (mods.at!=null && mods.at.text!=null) {
       off = noun_time_timezone.interpret(mods.at.text);
       // that is (UTC time)-(local time). So if you're at UTC+1, this'll return -60
       var offHere = d.getTimezoneOffset()/60.0;
       off = (off+offHere);
    }
    if (isNaN(off)) off=0;
    if (0==off) pblock.innerHTML += 'local time';
    else {
       pblock.innerHTML += mods.at.text; 
    }

    var canvas = pblock.getElementsByTagName("canvas")[0]; 
    this.ctx = canvas.getContext('2d');
    this.render(d.getHours()+off,d.getMinutes(),d.getSeconds(),skin);
    

  },

	setKey:function(value){
		if (!Application.prefs.has("ubiq_time_panda_style")) {
                    Application.prefs.setValue("ubiq_time_panda_style", value);
                } else {
                    var new_key = Application.prefs.get("ubiq_time_panda_style");
                    new_key.value = value;
                    return new_key.value;
                }

	},

	getKey:function(){
                var x = Application.prefs.get("ubiq_time_panda_style");
                if (null==x) return null;
		return x.value;
	},

  renderRadius: 100,

  skinChoice: 'chunkyswissonblack',
  skins:	{
		// more skins in moreskins.js
		// try making your own...

		swissrail: {
			outerBorder: { lineWidth: 1, radius:95, color: "black", alpha: 1, fillColor: "white" },
			smallIndicator: { lineWidth: 2, startAt: 89, endAt: 93, color: "black", alpha: 1 },
			largeIndicator: { lineWidth: 4, startAt: 80, endAt: 93, color: "black", alpha: 1 },
			hourHand: { lineWidth: 8, startAt: -15, endAt: 50, color: "black", alpha: 1 },
			minuteHand: { lineWidth: 7, startAt: -15, endAt: 75, color: "black", alpha: 1 },
			secondHand: { lineWidth: 1, startAt: -20, endAt: 85, color: "red", alpha: 1 },
			secondDecoration: { lineWidth: 1, startAt: 70, radius: 4, fillColor: "red", color: "red", alpha: 1 }
		},
		chunkyswiss: {
			outerBorder: { lineWidth: 4, radius:97, color: "black", alpha: 1, fillColor: "white" },
			smallIndicator: { lineWidth: 4, startAt: 89, endAt: 93, color: "black", alpha: 1 },
			largeIndicator: { lineWidth: 8, startAt: 80, endAt: 93, color: "black", alpha: 1 },
			hourHand: { lineWidth: 12, startAt: -15, endAt: 60, color: "black", alpha: 1 },
			minuteHand: { lineWidth: 10, startAt: -15, endAt: 85, color: "black", alpha: 1 },
			secondHand: { lineWidth: 4, startAt: -20, endAt: 85, color: "red", alpha: 1 },
			secondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: "red", color: "red", alpha: 1 }
		},
		chunkyswissonblack: {
			outerBorder: { lineWidth: 4, radius:97, color: "white", alpha: 1, fillColor: "black " },
			smallIndicator: { lineWidth: 4, startAt: 89, endAt: 93, color: "white", alpha: 1 },
			largeIndicator: { lineWidth: 8, startAt: 80, endAt: 93, color: "white", alpha: 1 },
			hourHand: { lineWidth: 12, startAt: -15, endAt: 60, color: "white", alpha: 1 },
			minuteHand: { lineWidth: 10, startAt: -15, endAt: 85, color: "white", alpha: 1 },
			secondHand: { lineWidth: 4, startAt: -20, endAt: 85, color: "red", alpha: 1 },
			secondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: "red", color: "red", alpha: 1 }
		},

        fancy: {
		outerBorder: { lineWidth: 5, radius:95, color: "green", alpha: 0.7 },
		smallIndicator: { lineWidth: 1, startAt: 80, endAt: 93, color: "black", alpha: 0.4 },
		largeIndicator: { lineWidth: 1, startAt: 30, endAt: 93, color: "black", alpha: 0.5 },
		hourHand: { lineWidth: 8, startAt: -15, endAt: 50, color: "blue", alpha: 0.7 },
		minuteHand: { lineWidth: 7, startAt: -15, endAt: 92, color: "red", alpha: 0.7 },
		secondHand: { lineWidth: 10, startAt: 80, endAt: 85, color: "blue", alpha: 0.3 },
		secondDecoration: { lineWidth: 1, startAt: 30, radius: 50, fillColor: "blue", color: "red", alpha: 0.15 }
	},

	machine: {
		outerBorder: { lineWidth: 60, radius:55, color: "#dd6655", alpha: 1 },
		smallIndicator: { lineWidth: 4, startAt: 80, endAt: 95, color: "white", alpha: 1 },
		largeIndicator: { lineWidth: 14, startAt: 77, endAt: 92, color: "#dd6655", alpha: 1 },
		hourHand: { lineWidth: 18, startAt: -15, endAt: 40, color: "white", alpha: 1 },
		minuteHand: { lineWidth: 14, startAt: 24, endAt: 100, color: "#771100", alpha: 0.5 },
		secondHand: { lineWidth: 3, startAt: 22, endAt: 83, color: "green", alpha: 0 },
		secondDecoration: { lineWidth: 1, startAt: 52, radius: 26, fillColor: "#ffcccc", color: "red", alpha: 0.5 }
	},

	// these three created by bonstio from http://bonstio.net
	classic/*was gIG*/: {
		outerBorder: { lineWidth: 185, radius:1, color: "#E5ECF9", alpha: 1 },
		smallIndicator: { lineWidth: 2, startAt: 89, endAt: 94, color: "#3366CC", alpha: 1 },
		largeIndicator: { lineWidth: 4, startAt: 83, endAt: 94, color: "#3366CC", alpha: 1 },
		hourHand: { lineWidth: 5, startAt: 0, endAt: 60, color: "black", alpha: 1 },
		minuteHand: { lineWidth: 4, startAt: 0, endAt: 80, color: "black", alpha: 1 },
		secondHand: { lineWidth: 1, startAt: -20, endAt: 85, color: "red", alpha: .85 },
		secondDecoration: { lineWidth: 3, startAt: 0, radius: 2, fillColor: "black", color: "black", alpha: 1 }
	},

	modern/*was gIG2*/: {
		outerBorder: { lineWidth: 185, radius:1, color: "#E5ECF9", alpha: 1 },
		smallIndicator: { lineWidth: 5, startAt: 88, endAt: 94, color: "#3366CC", alpha: 1 },
		largeIndicator: { lineWidth: 5, startAt: 88, endAt: 94, color: "#3366CC", alpha: 1 },
		hourHand: { lineWidth: 8, startAt: 0, endAt: 60, color: "black", alpha: 1 },
		minuteHand: { lineWidth: 8, startAt: 0, endAt: 80, color: "black", alpha: 1 },
		secondHand: { lineWidth: 5, startAt: 80, endAt: 85, color: "red", alpha: .85 },
		secondDecoration: { lineWidth: 3, startAt: 0, radius: 4, fillColor: "black", color: "black", alpha: 1 }
	},

	simple/*was gIG3*/: {
		outerBorder: { lineWidth: 185, radius:1, color: "#E5ECF9", alpha: 1 },
		smallIndicator: { lineWidth: 10, startAt: 90, endAt: 94, color: "#3366CC", alpha: 1 },
		largeIndicator: { lineWidth: 10, startAt: 90, endAt: 94, color: "#3366CC", alpha: 1 },
		hourHand: { lineWidth: 8, startAt: 0, endAt: 60, color: "black", alpha: 1 },
		minuteHand: { lineWidth: 8, startAt: 0, endAt: 80, color: "black", alpha: 1 },
		secondHand: { lineWidth: 5, startAt: 80, endAt: 85, color: "red", alpha: .85 },
		secondDecoration: { lineWidth: 3, startAt: 0, radius: 4, fillColor: "black", color: "black", alpha: 1 }
	},

	// these two by securephp
	securephp: {
		outerBorder: { lineWidth: 100, radius:0.45, color: "#669900", alpha: 0.3 },
		smallIndicator: { lineWidth: 2, startAt: 80, endAt:90 , color: "green", alpha: 1 },
		largeIndicator: { lineWidth: 8.5, startAt: 20, endAt:40 , color: "green", alpha: 0.4 },
		hourHand: { lineWidth: 3, startAt: 0, endAt: 60, color: "black", alpha: 1 },
		minuteHand: { lineWidth: 2, startAt: 0, endAt: 75, color: "black", alpha: 1 },
		secondHand: { lineWidth: 1, startAt: -10, endAt: 80, color: "blue", alpha: 0.8 },
		secondDecoration: { lineWidth: 1, startAt: 70, radius: 4, fillColor: "blue", color: "red", alpha: 1 }
	},

	tes2: {
		outerBorder: { lineWidth: 4, radius:95, color: "black", alpha: 0.5 },
		smallIndicator: { lineWidth: 1, startAt: 10, endAt:50 , color: "#66CCFF", alpha: 1 },
		largeIndicator: { lineWidth: 8.5, startAt: 60, endAt: 70, color: "#6699FF", alpha: 1 },
		hourHand: { lineWidth: 5, startAt: -15, endAt: 60, color: "black", alpha: 0.7 },
		minuteHand: { lineWidth: 3, startAt: -25, endAt: 75, color: "black", alpha: 0.7 },
		secondHand: { lineWidth: 1.5, startAt: -20, endAt: 88, color: "red", alpha: 1 },
		secondDecoration: { lineWidth: 1, startAt: 20, radius: 4, fillColor: "blue", color: "red", alpha: 1 }
	},


	lev: {
	outerBorder: { lineWidth:10, radius:95, color: "#CCFF33", alpha: 0.65 },
	smallIndicator: { lineWidth: 5, startAt: 84, endAt: 90, color: "#996600", alpha: 1 },
	largeIndicator: { lineWidth: 40, startAt: 25, endAt: 95, color: "#336600", alpha: 0.55 },
	hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 0.9 },
	minuteHand: { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 0.85 },
	secondHand: { lineWidth: 1, startAt: 0, endAt: 85, color: "black", alpha: 1 },
	secondDecoration: { lineWidth: 2, startAt: 5, radius: 10, fillColor: "black", color: "black", alpha: 1 }
	},

	sand: {
	outerBorder: { lineWidth:1, radius:70, color: "black", alpha: 0.5 },
	smallIndicator: { lineWidth: 3, startAt: 50, endAt: 70, color: "#0066FF", alpha: 0.5 },
	largeIndicator: { lineWidth: 200, startAt: 80, endAt: 95, color: "#996600", alpha: 0.75 },
	hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 0.9 },
	minuteHand: { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 0.85 },
	secondHand: { lineWidth: 1, startAt: 0, endAt: 85, color: "black", alpha: 1 },
	secondDecoration: { lineWidth: 2, startAt: 5, radius: 10, fillColor: "black", color: "black", alpha: 1 }
	},

	sun: {
	outerBorder: { lineWidth:100, radius:140, color: "#99FFFF", alpha: 0.2 },
	smallIndicator: { lineWidth: 300, startAt: 50, endAt: 70, color: "black", alpha: 0.1 },
	largeIndicator: { lineWidth: 5, startAt: 80, endAt: 95, color: "black", alpha: 0.65 },
	hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 0.9 },
	minuteHand: { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 0.85 },
	secondHand: { lineWidth: 1, startAt: 0, endAt: 90, color: "black", alpha: 1 },
	secondDecoration: { lineWidth: 2, startAt: 5, radius: 10, fillColor: "black", color: "black", alpha: 1 }
	},

	tor: {
	outerBorder: { lineWidth:10, radius:88, color: "#996600", alpha: 0.9 },
	smallIndicator: { lineWidth: 6, startAt: -10, endAt: 73, color: "green", alpha: 0.3 },
	largeIndicator: { lineWidth: 6, startAt: 73, endAt: 100, color: "black", alpha: 0.65 },
	hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 1 },
	minuteHand: { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 1 },
	secondHand: { lineWidth: 1, startAt: -73, endAt: 73, color: "black", alpha: 0.8 },
	secondDecoration: { lineWidth: 2, startAt: 5, radius: 10, fillColor: "black", color: "black", alpha: 1 }
	},

	cold: {
	outerBorder: { lineWidth:15, radius:90, color: "black", alpha: 0.3 },
	smallIndicator: { lineWidth: 15, startAt: -10, endAt: 95, color: "blue", alpha: 0.1 },
	largeIndicator: { lineWidth: 3, startAt: 80, endAt: 95, color: "blue", alpha: 0.65 },
	hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 1 },
	minuteHand: { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 1 },
	secondHand: { lineWidth: 1, startAt: 0, endAt: 85, color: "black", alpha: 0.8 },
	secondDecoration: { lineWidth: 5, startAt: 30, radius: 10, fillColor: "black", color: "black", alpha: 1 }
	},

	babosa: {
	outerBorder: { lineWidth: 100, radius:25, color: "blue", alpha: 0.25 },
	smallIndicator: { lineWidth: 3, startAt: 90, endAt: 95, color: "#3366CC", alpha: 1 },
	largeIndicator: { lineWidth: 4, startAt: 75, endAt: 95, color: "#3366CC", alpha: 1 },
	hourHand: { lineWidth: 4, startAt: 0, endAt: 60, color: "black", alpha: 1 },
	minuteHand: { lineWidth: 3, startAt: 0, endAt: 85, color: "black", alpha: 1 },
	secondHand: { lineWidth: 12, startAt: 75, endAt: 90, color: "red", alpha: 0.8 },
	secondDecoration: { lineWidth: 3, startAt: 0, radius: 4, fillColor: "black", color: "black", alpha: 1 }
	},

	tumb: {
	outerBorder: { lineWidth:105, radius:5, color: "green", alpha: 0.4 },
	smallIndicator: { lineWidth: 1, startAt: 93, endAt: 98, color: "green", alpha: 1 },
	largeIndicator: { lineWidth: 50, startAt: 0, endAt: 89, color: "red", alpha: 0.14 },
	hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 1 },
	minuteHand: { lineWidth: 3, startAt: 0, endAt: 80, color: "black", alpha: 1 },
	secondHand: { lineWidth: 1, startAt: 0, endAt: 85, color: "black", alpha: 0.8 },
	secondDecoration: { lineWidth: 5, startAt: 50, radius: 90, fillColor: "black", color: "black", alpha: 0.05 }
	},

	stone: {
	outerBorder: { lineWidth:15, radius:80, color: "#339933", alpha: 0.5 },
	smallIndicator: { lineWidth: 2, startAt: 70, endAt: 90, color: "#FF3300", alpha: 0.7 },
	largeIndicator: { lineWidth: 15, startAt: 0, endAt: 29, color: "#FF6600", alpha: 0.3 },
	hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 1 },
	minuteHand: { lineWidth: 3, startAt: 0, endAt: 75, color: "black", alpha: 1 },
	secondHand: { lineWidth: 1, startAt: 0, endAt: 85, color: "black", alpha: 0.8 },
	secondDecoration: { lineWidth: 5, startAt: 50, radius: 90, fillColor: "black", color: "black", alpha: 0.05 }
	},

	disc: {
	outerBorder: { lineWidth:105, radius:1, color: "#666600", alpha: 0.2 },
	smallIndicator: { lineWidth: 1, startAt: 58, endAt: 95, color: "#669900", alpha: 0.8 },
	largeIndicator: { lineWidth: 6, startAt: 25, endAt: 35, color: "#666600", alpha: 1 },
	hourHand: { lineWidth: 4, startAt: 0, endAt: 65, color: "black", alpha: 1 },
	minuteHand: { lineWidth: 3, startAt: 0, endAt: 75, color: "black", alpha: 1 },
	secondHand: { lineWidth: 1, startAt: -75, endAt: 75, color: "#99CC00", alpha: 0.8 },
	secondDecoration: { lineWidth: 5, startAt: 50, radius: 90, fillColor: "#00FF00", color: "green", alpha: 0.05 }
	}


	},



       fullCircle: function(skin) {
		this.fullCircleAt(this.renderRadius,this.renderRadius,skin);
	},

	fullCircleAt: function(x,y,skin) {
		with (this.ctx) {
			save();
			globalAlpha = skin.alpha;
			lineWidth = skin.lineWidth;
			//if (!document.all)
				beginPath();
			//if (document.all)
			//	// excanvas doesn't scale line width so we will do it here
			//	lineWidth = lineWidth * this.scale;
			arc(x, y, skin.radius, 0, 2*Math.PI, false);
			//if (document.all)
			//	// excanvas doesn't close the circle so let's color in the gap
			//	arc(x, y, skin.radius, -0.1, 0.1, false);
			if (skin.fillColor) {
				fillStyle = skin.fillColor
				fill();
			}
			else {
				// XXX why not stroke and fill
				strokeStyle = skin.color;
				stroke();
			}
			restore();
		}
	},

	radialLineAtAngle: function(angleFraction,skin) {
		with (this.ctx) {
			save();
			translate(this.renderRadius,this.renderRadius);
			rotate(Math.PI * (2 * angleFraction - 0.5));
			globalAlpha = skin.alpha;
			strokeStyle = skin.color;
			lineWidth = skin.lineWidth;
			//if (document.all)
			//	// excanvas doesn't scale line width so we will do it here
			//	lineWidth = lineWidth * this.scale;
			if (skin.radius) {
				this.fullCircleAt(skin.startAt,0,skin)
			}
			else {
				beginPath();
				moveTo(skin.startAt,0)
				lineTo(skin.endAt,0);
				stroke();
			}
			restore();
		}
	},

        render: function(hour,min,sec,skin) {
		//var skin = CoolClock.config.skins[this.skinId];
		this.ctx.clearRect(0,0,this.renderRadius*2,this.renderRadius*2);

		this.fullCircle(skin.outerBorder);

		for (var i=0;i<60;i++)
			this.radialLineAtAngle(i/60,skin[ i%5 ? "smallIndicator" : "largeIndicator"]);
				
		this.radialLineAtAngle((hour+min/60)/12,skin.hourHand);
		this.radialLineAtAngle((min+sec/60)/60,skin.minuteHand);
		if (this.showSecondHand) {
			this.radialLineAtAngle(sec/60,skin.secondHand);
			if (!document.all)
				// decoration doesn't render right in IE so lets turn it off
				this.radialLineAtAngle(sec/60,skin.secondDecoration);
		}
	},


})

