// Simple Set Clipboard System
// Author: Joseph Huckaby

var ZeroClipboard = {
	
	version: "1.0.4",
	clients: {}, // registered upload clients on page, indexed by id
	moviePath: '/Custom/Themes/Picaxe/JS/ZeroClipboard.swf', // URL to movie
	nextId: 1, // ID of next movie
	
	$: function(thingy) {
		// simple DOM lookup utility function
		if (typeof(thingy) == 'string') thingy = document.getElementById(thingy);
		if (!thingy.addClass) {
			// extend element with a few useful methods
			thingy.hide = function() { this.style.display = 'none'; };
			thingy.show = function() { this.style.display = ''; };
			thingy.addClass = function(name) { this.removeClass(name); this.className += ' ' + name; };
			thingy.removeClass = function(name) {
				this.className = this.className.replace( new RegExp("\\s*" + name + "\\s*"), " ").replace(/^\s+/, '').replace(/\s+$/, '');
			};
			thingy.hasClass = function(name) {
				return !!this.className.match( new RegExp("\\s*" + name + "\\s*") );
			}
		}
		return thingy;
	},
	
	setMoviePath: function(path) {
		// set path to ZeroClipboard.swf
		this.moviePath = path;
	},
	
	dispatch: function(id, eventName, args) {
		// receive event from flash movie, send to client		
		var client = this.clients[id];
		if (client) {
			client.receiveEvent(eventName, args);
		}
	},
	
	register: function(id, client) {
		// register new client to receive events
		this.clients[id] = client;
	},
	
	getDOMObjectPosition: function(obj) {
		// get absolute coordinates for dom element
		var info = {
			left: 0, 
			top: 0, 
			width: obj.width ? obj.width : obj.offsetWidth, 
			height: obj.height ? obj.height : obj.offsetHeight
		};

		while (obj) {
			info.left += obj.offsetLeft;
			info.top += obj.offsetTop;
			obj = obj.offsetParent;
		}

		return info;
	},
	
	Client: function(elem) {
		// constructor for new simple upload client
		this.handlers = {};
		
		// unique ID
		this.id = ZeroClipboard.nextId++;
		this.movieId = 'ZeroClipboardMovie_' + this.id;
		
		// register client with singleton to receive flash events
		ZeroClipboard.register(this.id, this);
		
		// create movie
		if (elem) this.glue(elem);
	}
};

ZeroClipboard.Client.prototype = {
	
	id: 0, // unique ID for us
	ready: false, // whether movie is ready to receive events or not
	movie: null, // reference to movie object
	clipText: '', // text to copy to clipboard
	handCursorEnabled: true, // whether to show hand cursor, or default pointer cursor
	cssEffects: true, // enable CSS mouse effects on dom container
	handlers: null, // user event handlers
	
	glue: function(elem) {
		// glue to DOM element
		// elem can be ID or actual DOM element object
		this.domElement = ZeroClipboard.$(elem);
		
		// float just above object, or zIndex 99 if dom element isn't set
		var zIndex = 99;
		if (this.domElement.style.zIndex) {
			zIndex = parseInt(this.domElement.style.zIndex) + 1;
		}
		
		// find X/Y position of domElement
		var box = ZeroClipboard.getDOMObjectPosition(this.domElement);
		
		// create floating DIV above element
		this.div = document.createElement('div');
		var style = this.div.style;
		style.position = 'absolute';
		style.left = '' + box.left + 'px';
		style.top = '' + box.top + 'px';
		style.width = '' + box.width + 'px';
		style.height = '' + box.height + 'px';
		style.zIndex = zIndex;
		
		// style.backgroundColor = '#f00'; // debug
		
		// give the div a class attribute so we can find and remove it when tabs change later on - added by Dan Sheerman
		this.div.className = 'zeroClipboard';
				
		var body = document.getElementsByTagName('body')[0];
		body.appendChild(this.div);
		
		this.div.innerHTML = this.getHTML( box.width, box.height );
	},
	
	getHTML: function(width, height) {
		// return HTML for movie
		var html = '';
		var flashvars = 'id=' + this.id + 
			'&width=' + width + 
			'&height=' + height;
			
		if (navigator.userAgent.match(/MSIE/)) {
			// IE gets an OBJECT tag
			var protocol = location.href.match(/^https/i) ? 'https://' : 'http://';
			html += '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="'+protocol+'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="'+width+'" height="'+height+'" id="'+this.movieId+'" align="middle"><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="false" /><param name="movie" value="'+ZeroClipboard.moviePath+'" /><param name="loop" value="false" /><param name="menu" value="false" /><param name="quality" value="best" /><param name="bgcolor" value="#ffffff" /><param name="flashvars" value="'+flashvars+'"/><param name="wmode" value="transparent"/></object>';
		}
		else {
			// all other browsers get an EMBED tag
			html += '<embed id="'+this.movieId+'" src="'+ZeroClipboard.moviePath+'" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="'+width+'" height="'+height+'" name="'+this.movieId+'" align="middle" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="'+flashvars+'" wmode="transparent" />';
		}
		return html;
	},
	
	hide: function() {
		// temporarily hide floater offscreen
		if (this.div) {
			this.div.style.left = '-2000px';
		}
	},
	
	show: function() {
		// show ourselves after a call to hide()
		this.reposition();
	},
	
	destroy: function() {
		// destroy control and floater
		if (this.domElement && this.div) {
			this.hide();
			this.div.innerHTML = '';
			
			var body = document.getElementsByTagName('body')[0];
			try { body.removeChild( this.div ); } catch(e) {;}
			
			this.domElement = null;
			this.div = null;
		}
	},
	
	reposition: function(elem) {
		// reposition our floating div, optionally to new container
		// warning: container CANNOT change size, only position
		if (elem) {
			this.domElement = ZeroClipboard.$(elem);
			if (!this.domElement) this.hide();
		}
		
		if (this.domElement && this.div) {
			var box = ZeroClipboard.getDOMObjectPosition(this.domElement);
			var style = this.div.style;
			style.left = '' + box.left + 'px';
			style.top = '' + box.top + 'px';
		}
	},
	
	setText: function(newText) {
		// set text to be copied to clipboard
		this.clipText = newText;
		if (this.ready) this.movie.setText(newText);
	},
	
	addEventListener: function(eventName, func) {
		// add user event listener for event
		// event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel
		eventName = eventName.toString().toLowerCase().replace(/^on/, '');
		if (!this.handlers[eventName]) this.handlers[eventName] = [];
		this.handlers[eventName].push(func);
	},
	
	setHandCursor: function(enabled) {
		// enable hand cursor (true), or default arrow cursor (false)
		this.handCursorEnabled = enabled;
		if (this.ready) this.movie.setHandCursor(enabled);
	},
	
	setCSSEffects: function(enabled) {
		// enable or disable CSS effects on DOM container
		this.cssEffects = !!enabled;
	},
	
	receiveEvent: function(eventName, args) {
		// receive event from flash
		eventName = eventName.toString().toLowerCase().replace(/^on/, '');
				
		// special behavior for certain events
		switch (eventName) {
			case 'load':
				// movie claims it is ready, but in IE this isn't always the case...
				// bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function
				this.movie = document.getElementById(this.movieId);
				if (!this.movie) {
					var self = this;
					setTimeout( function() { self.receiveEvent('load', null); }, 1 );
					return;
				}
				
				// firefox on pc needs a "kick" in order to set these in certain cases
				if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) {
					var self = this;
					setTimeout( function() { self.receiveEvent('load', null); }, 100 );
					this.ready = true;
					return;
				}
				
				this.ready = true;
				this.movie.setText( this.clipText );
				this.movie.setHandCursor( this.handCursorEnabled );
				break;
			
			case 'mouseover':
				if (this.domElement && this.cssEffects) {
					this.domElement.addClass('hover');
					if (this.recoverActive) this.domElement.addClass('active');
				}
				break;
			
			case 'mouseout':
				if (this.domElement && this.cssEffects) {
					this.recoverActive = false;
					if (this.domElement.hasClass('active')) {
						this.domElement.removeClass('active');
						this.recoverActive = true;
					}
					this.domElement.removeClass('hover');
				}
				break;
			
			case 'mousedown':
				if (this.domElement && this.cssEffects) {
					this.domElement.addClass('active');
				}
				break;
			
			case 'mouseup':
				if (this.domElement && this.cssEffects) {
					this.domElement.removeClass('active');
					this.recoverActive = false;
				}
				break;
		} // switch eventName
		
		if (this.handlers[eventName]) {
			for (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) {
				var func = this.handlers[eventName][idx];
			
				if (typeof(func) == 'function') {
					// actual function reference
					func(this, args);
				}
				else if ((typeof(func) == 'object') && (func.length == 2)) {
					// PHP style object + method, i.e. [myObject, 'myMethod']
					func[0][ func[1] ](this, args);
				}
				else if (typeof(func) == 'string') {
					// name of function
					window[func](this, args);
				}
			} // foreach event handler defined
		} // user defined handler for event
	}
	
};





/* Copyright (C) 2007, 2008 gnombat@users.sourceforge.net */
/* License: http://shjs.sourceforge.net/doc/gplv3.html */

/*
SHJS - Syntax Highlighting in JavaScript
Copyright (C) 2007, 2008 gnombat@users.sourceforge.net
License: http://shjs.sourceforge.net/doc/gplv3.html
*/

if (! this.sh_languages) {
  this.sh_languages = {};
}
var sh_requests = {};

function sh_isEmailAddress(url) {
  if (/^mailto:/.test(url)) {
    return false;
  }
  return url.indexOf('@') !== -1;
}

function sh_setHref(tags, numTags, inputString) {
  var url = inputString.substring(tags[numTags - 2].pos, tags[numTags - 1].pos);
  if (url.length >= 2 && url.charAt(0) === '<' && url.charAt(url.length - 1) === '>') {
    url = url.substr(1, url.length - 2);
  }
  if (sh_isEmailAddress(url)) {
    url = 'mailto:' + url;
  }
  tags[numTags - 2].node.href = url;
}

/*
Konqueror has a bug where the regular expression /$/g will not match at the end
of a line more than once:

  var regex = /$/g;
  var match;

  var line = '1234567890';
  regex.lastIndex = 10;
  match = regex.exec(line);

  var line2 = 'abcde';
  regex.lastIndex = 5;
  match = regex.exec(line2);  // fails
*/
function sh_konquerorExec(s) {
  var result = [''];
  result.index = s.length;
  result.input = s;
  return result;
}

/**
Highlights all elements containing source code in a text string.  The return
value is an array of objects, each representing an HTML start or end tag.  Each
object has a property named pos, which is an integer representing the text
offset of the tag. Every start tag also has a property named node, which is the
DOM element started by the tag. End tags do not have this property.
@param  inputString  a text string
@param  language  a language definition object
@return  an array of tag objects
*/
function sh_highlightString(inputString, language) {
  if (/Konqueror/.test(navigator.userAgent)) {
    if (! language.konquered) {
      for (var s = 0; s < language.length; s++) {
        for (var p = 0; p < language[s].length; p++) {
          var r = language[s][p][0];
          if (r.source === '$') {
            r.exec = sh_konquerorExec;
          }
        }
      }
      language.konquered = true;
    }
  }

  var a = document.createElement('a');
  var span = document.createElement('span');

  // the result
  var tags = [];
  var numTags = 0;

  // each element is a pattern object from language
  var patternStack = [];

  // the current position within inputString
  var pos = 0;

  // the name of the current style, or null if there is no current style
  var currentStyle = null;

  var output = function(s, style) {
    var length = s.length;
    // this is more than just an optimization - we don't want to output empty <span></span> elements
    if (length === 0) {
      return;
    }
    if (! style) {
      var stackLength = patternStack.length;
      if (stackLength !== 0) {
        var pattern = patternStack[stackLength - 1];
        // check whether this is a state or an environment
        if (! pattern[3]) {
          // it's not a state - it's an environment; use the style for this environment
          style = pattern[1];
        }
      }
    }
    if (currentStyle !== style) {
      if (currentStyle) {
        tags[numTags++] = {pos: pos};
        if (currentStyle === 'sh_url') {
          sh_setHref(tags, numTags, inputString);
        }
      }
      if (style) {
        var clone;
        if (style === 'sh_url') {
          clone = a.cloneNode(false);
        }
        else {
          clone = span.cloneNode(false);
        }
        clone.className = style;
        tags[numTags++] = {node: clone, pos: pos};
      }
    }
    pos += length;
    currentStyle = style;
  };

  var endOfLinePattern = /\r\n|\r|\n/g;
  endOfLinePattern.lastIndex = 0;
  var inputStringLength = inputString.length;
  while (pos < inputStringLength) {
    var start = pos;
    var end;
    var startOfNextLine;
    var endOfLineMatch = endOfLinePattern.exec(inputString);
    if (endOfLineMatch === null) {
      end = inputStringLength;
      startOfNextLine = inputStringLength;
    }
    else {
      end = endOfLineMatch.index;
      startOfNextLine = endOfLinePattern.lastIndex;
    }

    var line = inputString.substring(start, end);

    var matchCache = [];
    for (;;) {
      var posWithinLine = pos - start;

      var stateIndex;
      var stackLength = patternStack.length;
      if (stackLength === 0) {
        stateIndex = 0;
      }
      else {
        // get the next state
        stateIndex = patternStack[stackLength - 1][2];
      }

      var state = language[stateIndex];
      var numPatterns = state.length;
      var mc = matchCache[stateIndex];
      if (! mc) {
        mc = matchCache[stateIndex] = [];
      }
      var bestMatch = null;
      var bestPatternIndex = -1;
      for (var i = 0; i < numPatterns; i++) {
        var match;
        if (i < mc.length && (mc[i] === null || posWithinLine <= mc[i].index)) {
          match = mc[i];
        }
        else {
          var regex = state[i][0];
          regex.lastIndex = posWithinLine;
          match = regex.exec(line);
          mc[i] = match;
        }
        if (match !== null && (bestMatch === null || match.index < bestMatch.index)) {
          bestMatch = match;
          bestPatternIndex = i;
          if (match.index === posWithinLine) {
            break;
          }
        }
      }

      if (bestMatch === null) {
        output(line.substring(posWithinLine), null);
        break;
      }
      else {
        // got a match
        if (bestMatch.index > posWithinLine) {
          output(line.substring(posWithinLine, bestMatch.index), null);
        }

        var pattern = state[bestPatternIndex];

        var newStyle = pattern[1];
        var matchedString;
        if (newStyle instanceof Array) {
          for (var subexpression = 0; subexpression < newStyle.length; subexpression++) {
            matchedString = bestMatch[subexpression + 1];
            output(matchedString, newStyle[subexpression]);
          }
        }
        else {
          matchedString = bestMatch[0];
          output(matchedString, newStyle);
        }

        switch (pattern[2]) {
        case -1:
          // do nothing
          break;
        case -2:
          // exit
          patternStack.pop();
          break;
        case -3:
          // exitall
          patternStack.length = 0;
          break;
        default:
          // this was the start of a delimited pattern or a state/environment
          patternStack.push(pattern);
          break;
        }
      }
    }

    // end of the line
    if (currentStyle) {
      tags[numTags++] = {pos: pos};
      if (currentStyle === 'sh_url') {
        sh_setHref(tags, numTags, inputString);
      }
      currentStyle = null;
    }
    pos = startOfNextLine;
  }

  return tags;
}

////////////////////////////////////////////////////////////////////////////////
// DOM-dependent functions

function sh_getClasses(element) {
  var result = [];
  var htmlClass = element.className;
  if (htmlClass && htmlClass.length > 0) {
    var htmlClasses = htmlClass.split(' ');
    for (var i = 0; i < htmlClasses.length; i++) {
      if (htmlClasses[i].length > 0) {
        result.push(htmlClasses[i]);
      }
    }
  }
  return result;
}

function sh_addClass(element, name) {
  var htmlClasses = sh_getClasses(element);
  for (var i = 0; i < htmlClasses.length; i++) {
    if (name.toLowerCase() === htmlClasses[i].toLowerCase()) {
      return;
    }
  }
  htmlClasses.push(name);
  element.className = htmlClasses.join(' ');
}

/**
Extracts the tags from an HTML DOM NodeList.
@param  nodeList  a DOM NodeList
@param  result  an object with text, tags and pos properties
*/
function sh_extractTagsFromNodeList(nodeList, result) {
  var length = nodeList.length;
  for (var i = 0; i < length; i++) {
    var node = nodeList.item(i);
    switch (node.nodeType) {
    case 1:
      if (node.nodeName.toLowerCase() === 'br') {
        var terminator;
        if (/MSIE/.test(navigator.userAgent)) {
          terminator = '\r';
        }
        else {
          terminator = '\n';
        }
        result.text.push(terminator);
        result.pos++;
      }
      else {
        result.tags.push({node: node.cloneNode(false), pos: result.pos});
        sh_extractTagsFromNodeList(node.childNodes, result);
        result.tags.push({pos: result.pos});
      }
      break;
    case 3:
    case 4:
      result.text.push(node.data);
      result.pos += node.length;
      break;
    }
  }
}

/**
Extracts the tags from the text of an HTML element. The extracted tags will be
returned as an array of tag objects. See sh_highlightString for the format of
the tag objects.
@param  element  a DOM element
@param  tags  an empty array; the extracted tag objects will be returned in it
@return  the text of the element
@see  sh_highlightString
*/
function sh_extractTags(element, tags) {
  var result = {};
  result.text = [];
  result.tags = tags;
  result.pos = 0;
  sh_extractTagsFromNodeList(element.childNodes, result);
  return result.text.join('');
}

/**
Merges the original tags from an element with the tags produced by highlighting.
@param  originalTags  an array containing the original tags
@param  highlightTags  an array containing the highlighting tags - these must not overlap
@result  an array containing the merged tags
*/
function sh_mergeTags(originalTags, highlightTags) {
  var numOriginalTags = originalTags.length;
  if (numOriginalTags === 0) {
    return highlightTags;
  }

  var numHighlightTags = highlightTags.length;
  if (numHighlightTags === 0) {
    return originalTags;
  }

  var result = [];
  var originalIndex = 0;
  var highlightIndex = 0;

  while (originalIndex < numOriginalTags && highlightIndex < numHighlightTags) {
    var originalTag = originalTags[originalIndex];
    var highlightTag = highlightTags[highlightIndex];

    if (originalTag.pos <= highlightTag.pos) {
      result.push(originalTag);
      originalIndex++;
    }
    else {
      result.push(highlightTag);
      if (highlightTags[highlightIndex + 1].pos <= originalTag.pos) {
        highlightIndex++;
        result.push(highlightTags[highlightIndex]);
        highlightIndex++;
      }
      else {
        // new end tag
        result.push({pos: originalTag.pos});

        // new start tag
        highlightTags[highlightIndex] = {node: highlightTag.node.cloneNode(false), pos: originalTag.pos};
      }
    }
  }

  while (originalIndex < numOriginalTags) {
    result.push(originalTags[originalIndex]);
    originalIndex++;
  }

  while (highlightIndex < numHighlightTags) {
    result.push(highlightTags[highlightIndex]);
    highlightIndex++;
  }

  return result;
}

/**
Inserts tags into text.
@param  tags  an array of tag objects
@param  text  a string representing the text
@return  a DOM DocumentFragment representing the resulting HTML
*/
function sh_insertTags(tags, text) {
  var doc = document;

  var result = document.createDocumentFragment();
  var tagIndex = 0;
  var numTags = tags.length;
  var textPos = 0;
  var textLength = text.length;
  var currentNode = result;

  // output one tag or text node every iteration
  while (textPos < textLength || tagIndex < numTags) {
    var tag;
    var tagPos;
    if (tagIndex < numTags) {
      tag = tags[tagIndex];
      tagPos = tag.pos;
    }
    else {
      tagPos = textLength;
    }

    if (tagPos <= textPos) {
      // output the tag
      if (tag.node) {
        // start tag
        var newNode = tag.node;
        currentNode.appendChild(newNode);
        currentNode = newNode;
      }
      else {
        // end tag
        currentNode = currentNode.parentNode;
      }
      tagIndex++;
    }
    else {
      // output text
      currentNode.appendChild(doc.createTextNode(text.substring(textPos, tagPos)));
      textPos = tagPos;
    }
  }

  return result;
}

/**
Highlights an element containing source code.  Upon completion of this function,
the element will have been placed in the "sh_sourceCode" class.
@param  element  a DOM <pre> element containing the source code to be highlighted
@param  language  a language definition object
*/
function sh_highlightElement(element, language) {
  sh_addClass(element, 'sh_sourceCode');
  var originalTags = [];
  var inputString = sh_extractTags(element, originalTags);
  var highlightTags = sh_highlightString(inputString, language);
  var tags = sh_mergeTags(originalTags, highlightTags);
  var documentFragment = sh_insertTags(tags, inputString);
  while (element.hasChildNodes()) {
    element.removeChild(element.firstChild);
  }
  element.appendChild(documentFragment);
}

function sh_getXMLHttpRequest() {
  if (window.ActiveXObject) {
    return new ActiveXObject('Msxml2.XMLHTTP');
  }
  else if (window.XMLHttpRequest) {
    return new XMLHttpRequest();
  }
  throw 'No XMLHttpRequest implementation available';
}

function sh_load(language, element, prefix, suffix) {
  if (language in sh_requests) {
    sh_requests[language].push(element);
    return;
  }
  sh_requests[language] = [element];
  var request = sh_getXMLHttpRequest();
  var url = prefix + 'sh_' + language + suffix;
  request.open('GET', url, true);
  request.onreadystatechange = function () {
    if (request.readyState === 4) {
      try {
        if (! request.status || request.status === 200) {
          eval(request.responseText);
          var elements = sh_requests[language];
          for (var i = 0; i < elements.length; i++) {
            sh_highlightElement(elements[i], sh_languages[language]);
          }
        }
        else {
          throw 'HTTP error: status ' + request.status;
        }
      }
      finally {
        request = null;
      }
    }
  };
  request.send(null);
}

/**
Highlights all elements containing source code on the current page. Elements
containing source code must be "pre" elements with a "class" attribute of
"sh_LANGUAGE", where LANGUAGE is a valid language identifier; e.g., "sh_java"
identifies the element as containing "java" language source code.
*/
function sh_highlightDocument(prefix, suffix) {
  var nodeList = document.getElementsByTagName('pre');
  for (var i = 0; i < nodeList.length; i++) {
    var element = nodeList.item(i);
    var htmlClasses = sh_getClasses(element);
    for (var j = 0; j < htmlClasses.length; j++) {
      var htmlClass = htmlClasses[j].toLowerCase();
      if (htmlClass === 'sh_sourcecode') {
        continue;
      }
      if (htmlClass.substr(0, 3) === 'sh_') {
        var language = htmlClass.substring(3);
        if (language in sh_languages) {
          sh_highlightElement(element, sh_languages[language]);
        }
        else if (typeof(prefix) === 'string' && typeof(suffix) === 'string') {
          sh_load(language, element, prefix, suffix);
        }
        else {
          throw 'Found <pre> element with class="' + htmlClass + '", but no such language exists';
        }
        break;
      }
    }
  }
}





/* DEFINE A LANGUAGE */

if (! this.sh_languages) {
  this.sh_languages = {};
}
sh_languages['picaxe'] = [
  [
    [
      /\b(?:adcconfig|backward|bcdtoascii|bcdtobin|bintoascii|bintobcd|booti2c|branch|button|calibadc|calibadc10|calibfreq|call|case|clearbit|compsetup|count|daclevel|dacsetup|data|debug|dec|disablebod|disabletime|disconnect|do|doze|eeprom|else|elseif|enablebod|enabletime|end|endif|endselect|exit|for|forward|fvrsetup|get|gosub|goto|halt|hi2cin|hi2cout|hi2csetup|hibernate|high|hintsetup|hpwm|hpwmduty|hpwmout|hserin|hserout|hsersetup|hshin|hshout|hspiin|hspiout|hspisetup|i2cmaster|i2cread|i2cslave|i2cwrite|if|inc|infrain|infrain2|infraout|input|inputtype|irin|irout|kbin|kbled|keyin|keyled|let|lookdown|lookup|loop|low|nap|next|off|on|output|owin|owout|pause|pauseus|peek|peeksfr|play|poke|pokesfr|porta|portb|portc|portd|pot|pullup|pulsin|pulsout|put|pwm|pwmdiv4|pwmdiv16|pwmdiv64|pwmduty|pwmout|random|read|readadc|readadc10|readdac|readdac10|readfirmware|readi2c|readinternaltemp|readmem|readoutputs|readowclk|readowsn|readpinsc|readportc|readrevision|readsilicon|readtable|readtemp|readtemp12|reconnect|reset|resetowclk|restart|resume|return|reverse|rfin|rfout|run|select|sensor|serin|serout|serrxd|sertxd|servo|servopos|setbit|setfreq|setint|setintflags|settimer|shiftin|shiftout|shin|shout|sleep|sound|spiin|spiout|srlatch|srreset|srset|step|stop|suspend|swap|switch|switchoff|switchon|symbol|table|tablecopy|then|tmr3setup|to|toggle|togglebit|touch|touch16|tune|uniin|uniout|until|vartoascii|wait|while|word|write|writei2c|writemem)\b/gi,
      'sh_keyword',
      -1
    ],
    [
      /\b(?:a\.0|a\.1|a\.2|a\.3|a\.4|a\.5|a\.6|a\.7|b\.0|b\.1|b\.2|b\.3|b\.4|b\.5|b\.6|b\.7|c\.0|c\.1|c\.2|c\.3|c\.4|c\.5|c\.6|c\.7|d\.0|d\.1|d\.2|d\.3|d\.4|d\.5|d\.6|d\.7|b300_4|b300_8|b300_16|b300_20|b300_32|b300_40|b300_64|b600_4|b600_8|b600_16|b600_20|b600_32|b600_40|b600_64|b1200_4|b1200_8|b1200_16|b1200_20|b1200_32|b1200_40|b1200_64|b2400_4|b2400_8|b2400_16|b2400_20|b2400_32|b2400_40|b2400_64|b4800_4|b4800_8|b4800_16|b4800_20|b4800_32|b4800_40|b4800_64|b9600_4|b9600_8|b9600_16|b9600_20|b9600_32|b9600_40|b9600_64|b14400_4|b14400_8|b14400_16|b14400_20|b14400_32|b14400_40|b14400_64|b19200_4|b19200_8|b19200_16|b19200_20|b19200_32|b19200_40|b19200_64|b28800_4|b28800_8|b28800_16|b28800_20|b28800_32|b28800_40|b28800_64|b31250_4|b31250_8|b31250_16|b31250_20|b31250_32|b31250_40|b31250_64|b38400_4|b38400_8|b38400_16|b38400_20|b38400_32|b38400_40|b38400_64|b57600_4|b57600_8|b57600_16|b57600_20|b57600_32|b57600_40|b57600_64|b76800_4|b76800_8|b76800_16|b76800_20|b76800_32|b76800_40|b76800_64|b115200_4|b115200_8|b115200_16|b115200_20|b115200_32|b115200_40|b115200_64|cls|cr|em4|em8|em16|em20|em32|em40|em64|fvr1024|fvr2048|fvr4096|i2cbyte|i2cword|i2cfast|i2cfast4|i2cfast8|i2cfast16|i2cfast20|i2cfast32|i2cfast40|i2cfast64|i2cfast_4|i2cfast_8|i2cfast_16|i2cfast_20|i2cfast_32|i2cfast_40|i2cfast_64|i2cslow|i2cslow4|i2cslow8|i2cslow16|i2cslow20|i2cslow32|i2cslow40|i2cslow64|i2cslow_4|i2cslow_8|i2cslow_16|i2cslow_20|i2cslow_32|i2cslow_40|i2cslow_64|it_raw_h|it_raw_l|it_5v0|it_4v5|it_3v5|it_4v0|it_3v3|it_3v0|k31|k62|k125|k250|k500|lf|lsbfirst|lsbfirst_h|lsbfirst_l|lsbpost|lsbpost_h|lsbpost_l|lsbpre|lsbpre_h|lsbpre_l|msbfirst_h|msbfirst_l|msbfirst|msbpost|msbpost_h|msbpost_l|msbpre|msbpre_h|msbpre_l|m1|m2|m4|m8|m16|m32|m64|n300|n300_4|n600|n600_4|n600_8|n1200|n1200_4|n1200_8|n2400|n2400_4|n2400_8|n2400_16|n4800|n4800_4|n4800_8|n4800_16|n4800_32|n9600|n9600_8|n9600_16|n9600_32|n9600_64|n19200|n19200_16|n19200_32|n19200_64|n38400|n38400_32|n38400_64|n76800|n76800_64|output0|output1|output2|output3|output4|output5|output6|output7|ownoreset|ownoreset_bit|owresetafter|owresetafter_bit|owresetbefore|owresetbefore_bit|owresetboth|owresetboth_bit|owresetfirst|owresetfirst_bit|pwmfull_f|pwmfull_r|pwmhalf|pwmsingle|pwmhhhh|pwmhlhl|pwmlhlh|pwmllll|spifast|spimedium|spislow|spimode00|spimode00e|spimode01|spimode01e|spimode10|spimode10e|spimode11|spimode11e|t1s_4|t1s_8|t1s_16|t1s_20|t1s_32|t1s_40|t1s_64|t300|t300_4|t600|t600_4|t600_8|t1200|t1200_4|t1200_8|t2400|t2400_4|t2400_8|t2400_16|t4800|t4800_4|t4800_8|t4800_16|t4800_32|t9600|t9600_8|t9600_16|t9600_32|t9600_64|t19200|t19200_16|t19200_32|t19200_64|t38400|t38400_32|t38400_64|t76800|t76800_64|uni_crrd|uni_eral|uni_rdsr|uni_read|uni_setal|uni_wren|uni_wrdi|uni_write|uni_wrsr|a|b|c|d)\b/gi,
      'sh_predef_var',
      -1
    ],
    [
      /@bptr|@bptrdec|@bptrinc|@ptr|@ptrdec|@ptrinc|adcsetup|adcsetup2|b0|b1|b2|b3|b4|b5|b6|b7|b8|b9|b10|b11|b12|b13|bit0|bit1|bit2|bit3|bit4|bit5|bit6|bit7|bit8|bit9|bit10|bit11|bit12|bit13|bit14|bit15|bit16|bit17|bit18|bit19|bit20|bit21|bit22|bit23|bit24|bit25|bit26|bit27|bit28|bit29|bit30|bit31|bptr|bptr0|bptr1|bptr2|bptr3|bptr4|bptr5|bptr6|bptr7|bptrdec|bptrinc|compflag|compvalue|dir0|dir1|dir2|dir3|dir4|dir5|dir6|dir7|dira\.0|dira\.1|dira\.2|dira\.3|dira\.4|dira\.5|dira\.6|dira\.7|dirb\.0|dirb\.1|dirb\.2|dirb\.3|dirb\.4|dirb\.5|dirb\.6|dirb\.7|dirc\.0|dirc\.1|dirc\.2|dirc\.3|dirc\.4|dirc\.5|dirc\.6|dirc\.7|dird\.0|dird\.1|dird\.2|dird\.3|dird\.4|dird\.5|dird\.6|dird\.7|dirs|dirsa|dirsb|dirsc|dirsd|flag0|flag1|flag2|flag3|flag4|flag5|flag6|flag7|flag8|flag9|flag10|flag11|flag12|flag13|flag14|flag15|flags|flagsh|flagsl|hi2cflag|hi2clast|hint0flag|hint1flag|hint2flag|hintflag|hserflag|hserinflag|hserinptr|hserptr|infra|input0|input1|input2|input3|input4|input5|input6|input7|keyvalue|outpin0|outpin1|outpin2|outpin3|outpin4|outpin5|outpin6|outpin7|outpina\.0|outpina\.1|outpina\.2|outpina\.3|outpina\.4|outpina\.5|outpina\.6|outpina\.7|outpinb\.0|outpinb\.1|outpinb\.2|outpinb\.3|outpinb\.4|outpinb\.5|outpinb\.6|outpinb\.7|outpinc\.0|outpinc\.1|outpinc\.2|outpinc\.3|outpinc\.4|outpinc\.5|outpinc\.6|outpinc\.7|outpind\.0|outpind\.1|outpind\.2|outpind\.3|outpind\.4|outpind\.5|outpind\.6|outpind\.7|outpins|outpinsa|outpinsb|outpinsc|outpinsd|pin0|pin1|pin2|pin3|pin4|pin5|pin6|pin7|pina\.0|pina\.1|pina\.2|pina\.3|pina\.4|pina\.5|pina\.6|pina\.7|pinb\.0|pinb\.1|pinb\.2|pinb\.3|pinb\.4|pinb\.5|pinb\.6|pinb\.7|pinc\.0|pinc\.1|pinc\.2|pinc\.3|pinc\.4|pinc\.5|pinc\.6|pinc\.7|pind\.0|pind\.1|pind\.2|pind\.3|pind\.4|pind\.5|pind\.6|pind\.7|pins|pinsa|pinsb|pinsc|pinsd|port|ptr|ptr0|ptr1|ptr2|ptr3|ptr4|ptr5|ptr6|ptr7|ptr8|ptr9|ptr10|ptr11|ptr12|ptr13|ptr14|ptr15|ptrh|ptrl|ptrdec|ptrinc|s_w0|s_w1|s_w2|s_w3|s_w4|s_w5|s_w6|s_w7|task|time|timer|timer3|toflag|trisc|w0|w1|w2|w3|w4|w5|w6|w7/gi,
      'sh_symbol',
      -1
    ],
    [
      /;/g,
      'sh_comment',
      1
    ],
    [
      /\b(?:andnot|and|atan|bit|clear|cos|dcd|dig|inv|is|max|min|mod|nand|ncd|nob|nor|not|ornot|or|rev|set|sin|sqr|xnor|xornot|xor)\b/gi,
      'sh_predef_func',
      -1
    ]
  ],
  [
    [
      /$/g,
      null,
      -2
    ]
  ]
];





