function hilite(t,ext) {
 if(ext=='css') { return hilitecss(t); }
 if(ext=='html') { return hilitehtml(t); }
 return hilitejs(t);
}

function hilitecss(t) {
  var ruleRE = /([^\{]+)\{([^\}]+)\}/g;
  var pairRE = /([a-z-]+):([^;]+);/gi;
  t = t.replace(ruleRE, function(n,a,b) {
    a = a.replace( /([^#\.]([a-z]\w*)\b)/gi, '<span class="cssselector">$1</span>' );
    a = a.replace( /(#([a-z]\w*)\b)/gi, '<span class="cssid">$1</span>' );
    a = a.replace( /(\.([a-z]\w*)\b)/gi, '<span class="cssclass">$1</span>' );
    return ''+a+'{<span class="cssrule">'+hilitecssrule(b)+'</span>}';
  });
  t = t.replace( /(\/\*[\w\W]*?\*\/)/g, '<span class="comment">$1</span>');
  return t;
}
function hilitecssrule(t) {
  var pairRE = /(([a-z-]+):([^;]+);)/gi; // new RegExp('([a-zA-Z-]+):([^;]+);', 'g');
  t = t.replace(pairRE, '<span class="cssprop">$2</span>:<span class="cssval">$3</span>;');
  return t;
}

function hilitehtml(t) {
 var now=new Date(), dif,old;
 var s, x, y, NV = '', TK='', AT='', IS=0, bas, vat, vl = function(i) { var v=s.substr(i,y-i);
  if(/^on\w+/i.test(AT)) { return i==6 ? hilitejs(v.replace(/\\"/g,'"')).replace(/"/g,'\\"') : hilitejs(v.replace(/\\'/g,"'")).replace(/'/g,"\\'"); }
  return /^style/i.test(AT) ? hilitecssrule(v) : v;
 }, am = 'Q'; while( t.indexOf(am)+1 ) { am += Math.round(Math.random()) ? 'X' : am; }
 var ar1 = [ '&', am, '<', '>', '"' ], ar2 = [ am, '&amp;', '&lt;', '&gt;', '&quot;' ];
 for( x = 0; x < ar1.length; x++ ) { while(t.indexOf(ar1[x])+1) { t= t.replace(ar1[x],ar2[x]); } }
 for( x = 0; x < t.length; x++ ) {
  if(old===x) { y=t.substr(0,x).split(/\n/).length; alert('Highlighting problem on line '+y+':\n\n'+t.split(/\n/)[y-1].replace(/&quot;/g,'"').replace(/&gt;/g,'>').replace(/&lt;/g,'<').replace(/&amp;/g,'&')); NV+=s; break; } s=t.substr(x); old=x;
  dif=new Date()-now; status=dif; if(dif>7000) { NV+=s; break; } // if(!confirm(x+'\n'+NV)) { NV+=s; break;} // safety net
  if((y=s.match(/^\s+/))) {
    NV += y[0]; x+=y[0].length-1;
  }else if(TK) {
    if(s.charAt(0)=='=') {
      NV += '='; IS=1;
    }else if((y=s.match(/^\s*\/?\s*&gt;/))) {
      NV += '<span class=tag>'+y[0]+'</span>'; x+=y[0].length-1; TK=''; IS=0;
    }else if(!IS) {    // atr
      AT=s.replace(/((http-|xml:)\w*)?\W[\w\W]*/i,'$1');
      NV += '<span class=att>'+AT+'<\/span>'; x += AT.length-1;
    }else { IS=0;    // val
      if( s.charAt(0) == "'" ) { bas = 0; //'string'
       for( y = 1; ( bas%2 || s.charAt(y) != "'" ) && y < s.length - 1; y++ ) {
         bas = ( s.substr(y,2) == '\\\\' || s.substr(y,2) == '\\\'' ) ? bas+1 : 0;
       }
       NV += "'<span class=value>"+vl(1)+"</span>'"; x += y;
      } else if( s.substr(0,6) == "&quot;" ) { bas = 0; //"string"
        for( y = 1; ( bas%2 || s.substr(y,6) != "&quot;" ) && y < s.length - 1; y++ ) {
          bas = ( s.substr(y,2) == '\\\\' || s.substr(y,7) == '\\&quot;' ) ? bas+1 : 0;
        }
        NV += '&quot;<span class=value>'+vl(6)+'</span>&quot;'; x += y+5;
      } else{
        y=s.replace(/(&gt;|\s)[\w\W]*/,'');
        vat=(/^\w+=/.test(s.substr(1)))?'att':'value'; // fix empty attributes//broken
        NV += '<span class='+vat+'>'+y+'<\/span>'; x += y.length-1;
      }
    }
  }else if( s.substr(0,4)!='&lt;' ) {
    y=s.replace(/&lt;[\w\W]*/,'');
    NV += y; x += y.length-1;
  }else if((y=s.match(/^&lt;!\s*\[\s*CDATA\s*\[([\w\W]*?)\]\]&gt;/))) { y=y[0];
    NV += '<span class=comment>'+y+'</span>'; x += y.length-1; IS=0;
  }else if((y=s.match(/^&lt;!--[\w\W]*?--&gt;/))) { y=y[0];
    NV += '<span class=comment>'+y+'</span>'; x += y.length-1; IS=0;
  }else if((y=s.match(/^&lt;!DOCTYPE[\w\W]*?&gt;/))) { y=y[0];
    NV += '<span class=comment>'+y+'</span>'; x += y.length-1; IS=0;
  }else if((TK=s.replace(/(&lt;\/?\w+)[\w\W]*/,'$1'))) {    // a tag!
    NV += '<span class=tag>'+TK+'</span>'; x += TK.length-1;
  }else {    // it wasn't a tag after all - no spaces allowed here
    NV += '&lt;'; x += 3;
  }
 }
 return NV;
}

function hilitejs(t) { var now=new Date(),dif,old,
 w1=' for if while switch with typeof void return function ',
 w2=' function var new else return do break continue case default in delete typeof ',
 w3=' null false true ',
 s, x, y, NV = '', TK, bas, am = 'Q'; while( t.indexOf(am) + 1 ) { am += Math.round(Math.random()) ? 'X' : am; }
 var ar1 = ['&',am,'<','>','"'], ar2 = [am,'&amp;','&lt;','&gt;','&quot;'];
 for( x = 0; x < ar1.length; x++ ) { while(t.indexOf(ar1[x])+1) { t= t.replace(ar1[x],ar2[x]); } }
 for( x = 0; x < t.length; x++ ) {
  if(old===x) { y=t.substr(0,x).split(/\n/).length; alert('Highlighting problem on line '+y+':\n\n'+t.split(/\n/)[y-1].replace(/&quot;/g,'"').replace(/&gt;/g,'>').replace(/&lt;/g,'<').replace(/&amp;/g,'&')); NV+=s; break; } s=t.substr(x); old=x;
  dif=new Date()-now; status=dif; if(dif>7000) { NV+=s; break; } // if(!confirm(x+'\n'+NV)) { NV+=s; break;} // safety net
  if( s.charAt(0).replace(/[\w\+\-\*\/%=&\!\|\^~\'\"\?:]/,'') ) { NV += s.charAt(0); } else {
   if( !s.charAt(0).replace(/[a-zA-Z_]/,'') ) { //variable or function or keyword or true/false/null
    TK = s.replace(/\W[\w\W]*/,'');
    x += TK.length - 1;
    if( s.replace(/\w*\s*/,'').charAt(0) == '(' ) { //function/method or ...
     if( w1.indexOf(' '+TK+' ')>-1  ) {
      NV += '<span class=oper>'+TK+'</span>';
     } else { NV += '<span class=func>'+TK+'</span>';
    } } else { //variable or keyword or bool
     if( w2.indexOf(' '+TK+' ')>-1 ) {
      NV += '<span class=oper>'+TK+'</span>';
     } else { if( w3.indexOf(' '+TK+' ')>-1 ) {
       NV += '<span class=num>'+TK+'</span>';
      } else { NV += '<span class=var>'+TK+'</span>'; } } }
   } else { if( !s.charAt(0).replace(/[\d]/,'') ) { //numbers (+ & - signs are operators)
     NV += '<span class=num>'+s.replace(/[^0-9.xE][\w\W]*/,'')+'</span>';
     x += s.replace(/[^0-9.xE][\w\W]*/,'').length - 1;
    } else { //ops, comments, regexp and strings
     if( s.substr(0,2)!=='/*' && s.substr(0,2)!=='//' ) { //ops,regexp,',"
      if( s.charAt(0)==="'" ) { bas = 0; //'string'
       for( y = 1; ( bas%2 || s.charAt(y)!=="'" ) && y < s.length - 1; y++ ) {
        bas = ( s.substr(y,2) == '\\\\' || s.substr(y,2) == '\\\'' ) ? bas+1 : 0;
       }
       NV += "'<span class=string>"+s.substr(1,y-1)+"</span>'"; x += y;
      } else { if( s.substr(0,6) == "&quot;" ) { bas = 0; //"string"
        for( y = 1; ( bas%2 || s.substr(y,6)!=="&quot;" ) && y < s.length - 1; y++ ) {
          bas = ( s.substr(y,2) == '\\\\' || s.substr(y,7) == '\\&quot;' ) ? bas+1 : 0;
        }
        NV += '&quot;<span class=string>'+s.substr(6,y-6)+'</span>&quot;'; x += y+5;
       } else { if( (y=ar(s)) ) { //ops, regexp
         NV += '<span class=oper>'+y+'</span>';
         x += y.length - 1;
        } else { //regexp and /. divide preceeded by word or number or ) then any number of tabs or spaces
         for( y = -1; x + y!==0 && ( ' \t\r\n\f'.indexOf(s.charAt(y))>-1 ); y-- ) { }
         if( !s.charAt(y).replace(/[\)\w\]]/,'') ) { NV += '<span class=oper>/</span>'; //divide
         } else { bas = 0; //regexp
          for( y = 1; ( bas%2 || s.charAt(y) != "/" ) && y < s.length - 1; y++ ) {
           if( s.charAt(y)==='\\' && ( s.charAt(y+1)==='\\' || s.charAt(y+1) == "/" ) ) {
            bas++; } else { bas = 0; }
          } // got the regexp. now catch the flags
          NV += '/<span class=reg>'+s.substr(1,y-1)+'</span>/'; x += y; y = x;
          if( s.charAt(1)==='g' || s.charAt(1)==='i' ) { x++; }
          if( s.charAt(1)==='g' || s.charAt(1)==='i' ) { x++; } if( x > y ) {
           NV += '<span class=reg>'+t.substr(y+1,x-y)+'</span>'; } } } } }
     } else { if( s.substr(0,2)==='/*' ) { //block comments
       y=s.replace(/\*\/[\w\W]*/,''); NV += '<span class=comment>'+y+'*/</span>';
       x += y.length + 1;
      } else { //one-line comments
       y=s.replace(/[\n\r][\w\W]*/,''); NV += '<span class=comment>'+y+'</span>';
       x += y.length - 1; } } } } } }
status='Highlighting done in '+dif/1000+' sec.';setTimeout( 'status=\'\';', 5000 ); return NV;

 function ar(s) {
  var a = [':', '?', '||', '&amp;&amp;', '!', '~', '^', '|', '&amp;', '&gt;&gt;', '&lt;&lt;', '!=', '==', '--', '++', '&lt;=', '&gt;=', '&lt;', '&gt;', '-=', '+=', '=', '%', '*', '-', '+'], i=a.length;
  while( i-- ) { if( s.substr(0,a[i].length) == a[i] ) { return a[i]; } } return false;
 }
}
