/**
 * Script:
 *   Lighter.js - Syntax Highlighter written in MooTools.
 *
 * License:
 *   MIT-style license.
 * 
 * Author:
 *   Jose Prado
 *
 * Copyright:
 *   Copyright (�) 2009 [Jose Prado](http://pradador.com/).
 *
 */
(function () {
	Lighter = new Class({	
		Implements: [Options, Events],
		name: 'Lighter',
		options: {
			altLines: '', // Pseudo-selector enabled.
			clipboard: null,
			container: null,
			editable: false,
			flame: 'standard',
			fuel:  'standard',
			id: null,
			indent: -1,
			matchType: "standard",
			mode: "pre",
			path: null,
			strict: false
		},
	
		/***************************
		 * Lighter Initialization
		 **************************/
		initialize: function (codeblock, options) {
			this.setOptions(options);
			this.id = this.options.id || this.name + '_' + $time();
			this.codeblock = $(codeblock);
			this.container = $(this.options.container);
			this.code = chop(this.codeblock.get('html')).replace(/&lt;/gim, '<').replace(/&gt;/gim, '>').replace(/&amp;/gim, '&');
		
			// Indent code if user option is set.
			if (this.options.indent > -1) { this.code = tabToSpaces(this.code, this.options.indent); }
		
			// Figure out path based on script location of Lighter.js or option passed in.
			this.getPath();
			
			// Extract fuel/flame names. Precedence: className > options > 'standard'.
			this.getClass();
			
			// Set builder options.
			this.builder = new Hash({
				'inline': this.createLighter.pass('code', this),
				'pre':    this.createLighter.pass('pre', this),
				'ol':     this.createLighterWithLines.pass([['ol'], ['li']], this),
				'div':    this.createLighterWithLines.pass([['div'], ['div', 'span'], true, 'span'], this),
				'table':  this.createLighterWithLines.pass([['table', 'tbody'], ['tr', 'td'], true, 'td'], this)
			});
		
			// Initialize caches
			Lighter.scripts     = Lighter.scripts || {};
			Lighter.stylesheets = Lighter.stylesheets || {};
		
			// Load fuel/flame to start chain of loads.
			this.loadStylesheet(this.options.flame, 'Flame.'+this.options.flame+'.css');
			this.loadFuel();
		},
		loadFuel: function () {
			var lastLoad = true;
			try {
				this.fuel = new Fuel[this.options.fuel](this.code, {
					matchType: this.options.matchType,
					strict: this.options.strict
				});
				this.light();
			} catch (e) {
				lastLoad = false;
				this.loadScript(this.options.fuel, 'Fuel.'+this.options.fuel+'.js', {
					'load': this.loadFuel.bind(this),
					'error': function () { this.options.fuel = 'standard'; this.loadFuel(); }.bind(this)
				});
			}
			
			if (lastLoad === true) {
				this.fireEvent('readied');
			}
		},
		light: function () {
			// Build highlighted code object.
			this.element = this.toElement();
		
			// Insert lighter in the right spot.
			if (this.container) {
				this.container.empty();
				this.element.inject(this.container);
			} else {
				this.codeblock.setStyle('display', 'none');
				this.element.inject(this.codeblock, 'after');
				if (this.options.clipboard) { this.loadClipboard(); }
			}
		},
		unlight: function() {
			$(this).setStyle('display', 'none');
			this.codeblock.setStyle('display', 'inherit');
		},
		loadClipboard: function () {
			try {
				this.clip = new ZeroClipboard.Client();
				this.clip.setPath(this.options.path);
				this.clip.glue($(this.options.clipboard));
				this.clip.setText(this.code);
				this.clip.addEventListener('complete', function (client, text) {
					var clipMsg = new Element('div', {'class':'cb-msg','html':'Copied to clipboard'}).inject(client.domElement);
					(function() { clipMsg.dispose(); }).delay(3000);
				});
			} catch (e) {
				this.loadScript('clipboard', 'ZeroClipboard.js', {
					'load': this.loadClipboard.bind(this),
					'error': $empty
				});
				return false;
			}
		},
		/***************************
		 * Initialize helper methods
		 **************************/
		getPath: function() {
		  if (!$chk(Lighter.path)) {
		      $$('head script').each(function(el) {
		          var script  = el.src.split('?', 1),
		              pattern = /Lighter(\.full|\.lite)?\.js$/gi;
		          if (script[0].match(pattern)) {
		              Lighter.path = script[0].replace(pattern, '');
		          }
		      })
		  }
		  if (!this.options.path) { this.options.path = Lighter.path; }
		},
		getClass: function() {
            var classNames = this.codeblock.get('class').split(' '),
                ff = [null, null];
            switch (classNames.length) {
                case 0: // No language! Simply wrap in Lighter.js standard Fuel/Flame.
					break;
				case 1: // Single class, assume this is the fuel/flame
					ff = classNames[0].split(':');
					break;
				default: // More than one class, let's give the first one priority for now.
					ff = classNames[0].split(':');
            }
            
            if (ff[0]) { this.options.fuel  = ff[0]; }
            if (ff[1]) { this.options.flame = ff[1]; }
		},
		loadScript: function (holder, fileName, events) {
			if ($chk(Lighter.scripts[holder])) {
				Lighter.scripts[holder].addEvents({
					load: events.load,
					error: events.error,
					readystatechange: function() {
						if (['loaded', 'complete'].contains(this.readyState)) events.load();
					}
				});
			} else {
				Lighter.scripts[holder] = new Element('script', {
					'src': this.options.path+fileName+'?'+$time(),
					'type': 'text/javascript',
					'events': {
						load: events.load,
						error: events.error,
						readystatechange: function() {
							if (['loaded', 'complete'].contains(this.readyState)) events.load();
						}
					}
				}).inject(document.head);
			}
		},
		loadStylesheet: function (holder, fileName) {
			if (!$chk(Lighter.stylesheets[holder])) {
				Lighter.stylesheets[holder] = new Element('link').inject(document.head);
				Lighter.stylesheets[holder].set('rel', 'stylesheet');
				Lighter.stylesheets[holder].set('type', 'text/css');
				Lighter.stylesheets[holder].set('media', 'screen');
				Lighter.stylesheets[holder].set('href', this.options.path+fileName+'?'+$time());
			}
		},
		/***************************
		 * Lighter creation methods
		 **************************/
		createLighter: function (parent) {
			var lighter = new Element(parent, { 'class': this.options.flame + this.name }),
			    pointer = 0;
		    
			// If no matches were found, insert code plain text.
			if (!$defined(this.fuel.wicks[0])) {
				lighter.appendText(this.code);
			} else {
		
				// Step through each match and add unmatched + matched bits to lighter.
				this.fuel.wicks.each(function (match) {
					lighter.appendText(this.code.substring(pointer, match.index));
				
					this.insertAndKeepEl(lighter, match.text, match.type);
					pointer = match.index + match.text.length;
				}, this);
			
				// Add last unmatched code segment if it exists.
				if (pointer < this.code.length) {
					lighter.appendText(this.code.substring(pointer, this.code.length));
				}
			}
		
			//lighter.set('text', lighter.get('html'));
			return lighter;
		},
		createLighterWithLines: function (parent, child, addLines, numType) {
			var lighter = new Element(parent[0], { 'class': this.options.flame + this.name, 'id': this.id }),
			    newLine = new Element(child[0]),
			    lineNum = 1,
			    pointer = 0,
			    text = null;
		
			// Small hack to ensure tables have no ugly styles.
			if (parent[0] == "table") { lighter.set("cellpadding", 0).set("cellspacing", 0).set("border", 0); }
		
			/* If lines need to be wrapped in an inner parent, create that element
			   with this test. (E.g, tbody in a table) */
			if (parent[1]) { lighter = new Element(parent[1]).inject(lighter); }
		
			/* If code needs to be wrapped in an inner child, create that element
			   with this test. (E.g, tr to contain td) */
			if (child[1]) { newLine = new Element(child[1]).inject(newLine); }
			newLine.addClass(this.options.flame + 'line');
			if (addLines) { lineNum = this.insertLineNum(newLine, lineNum, numType); }

			// Step through each match and add matched/unmatched bits to lighter.
			this.fuel.wicks.each(function (match) {
		
				// Create and insert un-matched source code bits.
				if (pointer != match.index) {
					text = this.code.substring(pointer, match.index).split("\n");
					for (var i = 0; i < text.length; i++) {
						if (i < text.length - 1) {
							if (text[i] === '') { text[i] = ' '; }
							newLine = this.insertAndMakeEl(newLine, lighter, text[i], child);
							if (addLines) { lineNum = this.insertLineNum(newLine, lineNum, numType); }
						} else {
							this.insertAndKeepEl(newLine, text[i]);
						}
					}
				}
			
				// Create and insert matched symbol.
				text = match.text.split('\n');
				for (var i = 0; i < text.length; i++) {
					if (i < text.length - 1) {
						newLine = this.insertAndMakeEl(newLine, lighter, text[i], child, match.type);
						if (addLines) { lineNum = this.insertLineNum(newLine, lineNum, numType); }
					} else {
						this.insertAndKeepEl(newLine, text[i], match.type);
					}
				}
			
				pointer = match.end;
			}, this);
		
			// Add last unmatched code segment if it exists.
			if (pointer <= this.code.length) {
				text = this.code.substring(pointer, this.code.length).split('\n');
				for (var i = 0; i < text.length; i++) {
					newLine = this.insertAndMakeEl(newLine, lighter, text[i], child);
					if (addLines) { lineNum = this.insertLineNum(newLine, lineNum, numType); }
				}
			}
		
			// Add alternate line styles based on pseudo-selector.
			if (this.options.altLines !== '') {
				if (this.options.altLines == 'hover') {
					lighter.getElements('.'+this.options.flame+'line').addEvents({
							'mouseover': function () {this.toggleClass('alt');},
							'mouseout':  function () {this.toggleClass('alt');}
					});
				} else {
					if (child[1]) {
						lighter.getChildren(':'+this.options.altLines).getElement('.'+this.options.flame+'line').addClass('alt');
					} else {
						lighter.getChildren(':'+this.options.altLines).addClass('alt');
					}
				}
			}
		
			// Add first/last line classes to correct element based on mode.
			if (child[1]) {
				lighter.getFirst().getChildren().addClass(this.options.flame+'first');
				lighter.getLast().getChildren().addClass(this.options.flame+'last');
			} else {
				lighter.getFirst().addClass(this.options.flame+'first');
				lighter.getLast().addClass(this.options.flame+'last');
			}
		
			// Ensure we return the real parent, not just an inner element like a tbody.
			if (parent[1]) { lighter = lighter.getParent(); }
			return lighter;
		},
		/** Helper function to insert new code segment into existing line. */
		insertAndKeepEl: function (el, text, alias) {
			if (text.length > 0) {
				var span = new Element('span', { 'text': text });
				if (alias) {
					span.addClass(this.fuel.aliases[alias] || alias);
				}
				span.inject(el);
			}
		},
		/** Helper function to insert new code segment into existing line and create new line. */
		insertAndMakeEl: function (el, group, text, child, alias) {
			this.insertAndKeepEl(el, text, alias);
			if (child[1]) { el = el.getParent(); }
			el.inject(group);
		
			var newLine = new Element(child[0]);
			if (child[1]) { newLine = new Element(child[1]).inject(newLine); }
			newLine.addClass(this.options.flame+'line');
			return newLine;
		},
		/** Helper funciton to insert line number into line. */
		insertLineNum: function (el, lineNum, elType) {
			var newNum = new Element(elType, {
				'text':  lineNum++,
				'class': this.options.flame+ 'num'
			});
			newNum.inject(el.getParent(), 'top');
		
			return lineNum;
		},
	
		/******************
		 * Element Methods
		 ******************/
		toElement: function () {
			if (!this.element) {
				this.element = this.builder[this.options.mode]();
				if (this.options.editable) { this.element.set('contenteditable', 'true'); }
			}
		
			return this.element;
		}
	});

	/** Element Native extensions */
	Element.implement({ light: function (options){ return new Lighter(this, options); } });

	/** String functions */
	function chop(str) { return str.replace(/(^\s*\n|\n\s*$)/gi, ''); }	
	function tabToSpaces(str, spaces) {
		for (var i = 0, indent = ''; i < spaces; i++) { indent += ' '; }
		return str.replace(/\t/g, indent);
	}
	
})();


/**
 * Script:
 *   Fuel.js - Language definition engine for Lighter.js
 *
 * License:
 *   MIT-style license.
 * 
 * Author:
 *   Jose Prado
 *
 * Copyright:
 *   Copyright (�) 2009 [Jose Prado](http://pradador.com/).
 *
 */
var Fuel = new Class({
	Implements: [Options],
	options: {
		matchType: "standard",
		strict: false
	},
	language: '',
	
	patterns: new Hash(),
	keywords: new Hash(),
	delimiters: new Hash({
		start: null,
		end: null
	}),

	/************************
	 * Common Regex Rules
	 ***********************/
	common: {	
		slashComments: /(?:^|[^\\])\/\/.*$/gm, // Matches a C style single-line comment.
		poundComments: /#.*$/gm,               // Matches a Perl style single-line comment.
		multiComments: /\/\*[\s\S]*?\*\//gm,   // Matches a C style multi-line comment.
		aposStrings:   /'[^'\\]*(?:\\.[^'\\]*)*'/gm, // Matches a string enclosed by single quotes. Legacy.
		quotedStrings: /"[^"\\]*(?:\\.[^"\\]*)*"/gm, // Matches a string enclosed by double quotes. Legacy.
		multiLineSingleQuotedStrings: /'[^'\\]*(?:\\.[^'\\]*)*'/gm, // Matches a string enclosed by single quotes across multiple lines.
		multiLineDoubleQuotedStrings: /"[^"\\]*(?:\\.[^"\\]*)*"/gm, // Matches a string enclosed by double quotes across multiple lines.
		multiLineStrings:   /'[^'\\]*(?:\\.[^'\\]*)*'|"[^"\\]*(?:\\.[^"\\]*)*"/gm, // Matches both.
		singleQuotedString: /'[^'\\\r\n]*(?:\\.[^'\\\r\n]*)*'/gm, // Matches a string enclosed by single quotes.
		doubleQuotedString: /"[^"\\\r\n]*(?:\\.[^"\\\r\n]*)*"/gm, // Matches a string enclosed by double quotes.
		strings: /'[^'\\\r\n]*(?:\\.[^'\\\r\n]*)*'|"[^"\\\r\n]*(?:\\.[^"\\\r\n]*)*"/gm, // Matches both.
		properties:    /\.(\w+)\s*/gi,     // Matches a property: .property style.
		methodCalls:   /\.(\w+)\s*\(/gm,   // Matches a method call: .methodName() style.
		functionCalls: /\b([\w\$_-]+)\s*\(/gm,   // Matches a function call: functionName() style.
		objFunctionCalls: /\b([\w\$_-]+)\s*:\s*function\(/gm,   // Matches a function call: functionName: function( style.
		brackets:      /\{|\}|\(|\)|\[|\]/g, // Matches any of the common brackets.
		numbers:       /\b((?:(\d+)?\.)?[0-9]+|0x[0-9A-F]+)\b/gi // Matches integers, decimals, hexadecimals.
	},
	
	/************************
	 * Fuel Constructor
	 ***********************/
	initialize: function(code, options, wicks) {
		this.setOptions(options);
		this.wicks = wicks || [];
		this.code = code;
		this.aliases = $H();
		this.rules = $H();
		
		// Set builder object for matchType.
		this.builder = new Hash({
			'standard': this.findMatches,
			'lazy':     this.findMatchesLazy
		});
		
		// Add delimiter rules if not in strict mode
		if (!options.strict) {
			if (this.delimiters.start) this.addFuel('delimBeg', this.delimiters.start, 'de1');
			if (this.delimiters.end)   this.addFuel('delimEnd', this.delimiters.end,   'de2');
		}
		
		// Set Keyword Rules from this.keywords object.
		this.keywords.each(function(keywordSet, ruleName) {
			if (keywordSet.csv != '') {
				this.addFuel(ruleName, this.csvToRegExp(keywordSet.csv, keywordSet.mod || "g"), keywordSet.alias);
			}
		}, this);
		
		// Set Rules from this.patterns object.
		this.patterns.each(function(regex, ruleName) {
			this.addFuel(ruleName, regex.pattern, regex.alias);
		}, this);
		
		/** Process source code based on match type. */
		var codeBeg = 0,
		    codeEnd = this.code.length,
		    codeSeg = '',
		    delim   = this.delimiters,
		    matches = [],
		    match   = null,
		    endMatch = null;
		
		if (!options.strict) {
			// Find matches through the complete source code.
			matches.extend(this.builder[options.matchType].pass(this.code, this)());
		} else if (delim.start && delim.end) {
			// Find areas between language delimiters and find matches there.
			while ((match = delim.start.exec(this.code)) != null ) {
				delim.end.lastIndex = delim.start.lastIndex;
				if ((endMatch = delim.end.exec(this.code)) != null ) {
					matches.push(new Wick(match[0], 'de1', match.index));
					codeBeg = delim.start.lastIndex;
					codeEnd = endMatch.index-1;
					codeSeg = this.code.substring(codeBeg, codeEnd);
					matches.extend(this.builder[options.matchType].pass([codeSeg, codeBeg], this)());
					matches.push(new Wick(endMatch[0], 'de2', endMatch.index));
				}
			}
		}
		this.wicks = matches;
	},
	
	/************************
	 * Regex Helper methods.
	 ***********************/
	addFuel: function(fuelName, RegEx, className) {
		this.rules[fuelName] = RegEx;
		this.addAlias(fuelName, className);
	},
	addAlias: function(key, alias) { 
		this.aliases[key] = alias || key; 
	},
	csvToRegExp: function(csv, mod) {
		return new RegExp('\\b(' + csv.replace(/,\s*/g, '|') + ')\\b', mod);
	},
	delimToRegExp: function(beg, esc, end, mod, suffix) {
		beg = beg.escapeRegExp();
		if (esc) esc = esc.escapeRegExp();
		end = (end) ? end.escapeRegExp() : beg;
		var pat = (esc) ? beg+"[^"+end+esc+'\\n]*(?:'+esc+'.[^'+end+esc+'\\n]*)*'+end : beg+"[^"+end+'\\n]*'+end;

		return new RegExp(pat+(suffix || ''), mod || '');
	},
	strictRegExp: function() {
		var regex = '(';
		for (var i = 0; i < arguments.length; i++) {
			regex += arguments[i].escapeRegExp();
			regex += (i < arguments.length - 1) ? '|' : '';
		}
		regex += ')';
		return new RegExp(regex, "gim");
	},
	
	/************************
	 * Match finding Methods
	 ***********************/
	findMatches: function(code, offset) {
		var wicks       = [],
		    startIndex  = 0,
		    matchIndex  = code.length
		    insertIndex = 0,
		    match      = null,
		    type       = null,
		    newWick    = null,
		    rule       = null,
		    rules      = {},
		    currentMatch = null,
		    futureMatch  = null;
		
		offset = offset || 0;
		
		// Create assosciative array of rules for faster access via for...in loop instead of .each().
		this.rules.each(function(regex, rule) {
			rules[rule] = {pattern: regex, nextIndex: 0};
		}, this);
			
		/**
		 * Step through the source code sequentially finding the left-most/earliest matches and then
		 * continuing beyond the end of that match to prevent parser from adding inner matches.
		 */
		while(startIndex < code.length) {
			matchIndex = code.length;
			match      = null;
			
			// Apply each rule at the current startIndex.
			for (rule in rules) {
				rules[rule].pattern.lastIndex = startIndex;
				currentMatch = rules[rule].pattern.exec(code);
				if (currentMatch === null) {
					// Delete rule if there's no matches.
					delete rules[rule];
				} else {
					// Find earliest and longest match, then store relevant info.
					if (currentMatch.index < matchIndex || (currentMatch.index == matchIndex && match[0].length < currentMatch[0].length)) {
						match      = currentMatch;
						type       = rule;
						matchIndex = currentMatch.index;
					}
					// Store index of rules' next match in nextIndex property.
					rules[rule].nextIndex = rules[rule].pattern.lastIndex - currentMatch[0].length;
				}
			}
			/* Create a new Wick out of found match. Otherwise break out of loop since no
			   matches are left. */
			if (match != null) {
			
				// If $1 capture group exists, use $1 instead of full match.
				index = (match[1] && match[0].contains(match[1])) ? match.index + match[0].indexOf(match[1]) : match.index;
				newWick = new Wick(match[1] || match[0], type, index+offset);
				wicks.push(newWick);
				
				/* Find the next match of current rule and store its index. If not done, the nextIndex
				   would be at the start of current match, thus creating an infinite loop*/
				futureMatch = rules[type].pattern.exec(code);
				if (!futureMatch) {
					rules[type].nextIndex = code.length;
				} else {
					rules[type].nextIndex = rules[type].pattern.lastIndex - futureMatch[0].length;
				}
				
				// Cycle through "nextIndex" properties and store earliest position in min variable.
				var min = code.length;
				for (rule in rules) {
					if (rules[rule].nextIndex < min) {
						min = rules[rule].nextIndex;
					}
				}
				/* Set startIndex to the end of current match if min is located behind it. Normally this
				   would signal an inner match. Future upgrades should do this test in the min loop
				   in order to find the actual earliest match. */
				startIndex = Math.max(min, newWick.end - offset);
			} else {
				break;
			}
		}
		return wicks;
	},
	/* Brute force the matches by finding all possible matches from all rules. Then we sort them
	   and cycle through the matches finding and eliminating inner matches. Faster than findMatches,
	   but less robust and prone to erroneous matches. */
	findMatchesLazy: function(code, offset) {
		var wicks = this.wicks,
		    match = null
		    index = 0;
		
		offset = offset || 0;
		
		this.rules.each(function(regex, rule) {
			while ((match = regex.exec(code)) != null) {
				index = (match[1] && match[0].contains(match[1])) ? match.index + match[0].indexOf(match[1]) : match.index;
				wicks.push(new Wick(match[1] || match[0], rule, index + offset));
			}
		}, this);
		return this.purgeWicks(wicks);
	},
	purgeWicks: function(wicks) {
		wicks = wicks.sort(this.compareWicks);
		for (var i = 0, j = 0; i < wicks.length; i++) {
			if (wicks[i] == null) continue;
			for (j = i+1; j < wicks.length && wicks[i] != null; j++) {
				if      (wicks[j] == null)            {continue;}
				else if (wicks[j].isBeyond(wicks[i])) {break;}
				else if (wicks[j].overlaps(wicks[i])) {wicks[i] = null;}
				else if (wicks[i].contains(wicks[j])) {wicks[j] = null;}
			}
		}
		return wicks.clean();
	},
	compareWicks: function(wick1, wick2) {return wick1.index - wick2.index;}
});

Fuel.standard = new Class({ Extends: Fuel, initialize: function(code, options, wicks) { this.parent(code, options, wicks); } });

var Wick = new Class({
	initialize: function(match, type, index) {
		this.text   = match;
		this.type   = type;
		this.index  = index;
		this.length = this.text.length;
		this.end    = this.index + this.length;
	},
	contains: function(wick) { return (wick.index >= this.index && wick.index < this.end); },
	isBeyond: function(wick) { return (this.index >= wick.end); },
	overlaps: function(wick) { return (this.index == wick.index && this.length > wick.length); },
	toString: function() { return this.index+' - '+this.text+' - '+this.end; }
});


var lighter_langs = ['js','css','html','php','shell','sql'];

window.addEvent('load', function() {
	var docXY = $(document.body).getSize();
	$$("pre").each(function(_el) {
		if (_el.get('class') == '' || !lighter_langs.contains((_el.get('class').replace(/(?:\:.+)|(?: .+)$/, '')).toLowerCase())) return;

		var clip_board = null;
		if (!_el.hasClass('no-clipboard')) {
			clip_board = $$('.clipboard')[0].clone();
			clip_board.setStyle('display', 'block').inject(_el, 'before');
		}
		
		var light_props = {
			'mode': 'ol',
			'path':'/library/code/js/lighter/',
			'onReadied': function() {
				var codeXY = $(this.id).getPosition();
				if ($(this.element)) {
					if (clip_board) { clip_board.inject(this.element, 'before'); }

					var sWidth = _el.getScrollSize().x, oWidth = this.element.getStyle('width').toInt();
					if (sWidth > oWidth) {
						this.element.store('swidth',(docXY.x-codeXY.x-25)).store('owidth',oWidth)
						.addEvents({
							'mouseenter': function() {
								this.tween('width', this.retrieve('swidth'));
							},
							'mouseleave': function() {
								this.tween('width', this.retrieve('owidth'));
							}
						});
					}

					this.element.addEvents({
						'mouseup': function() {
							var userSelection;
							if (window.getSelection) {
								userSelection = window.getSelection();
							}
							else if (document.selection) { // should come last; Opera!
								userSelection = document.selection.createRange();
							}
							var selectedCode = userSelection.toString().trim().replace(/^#/gm, '');
							if (selectedCode != '') {
								var cbWindow = window.open(null, 'cbw', 'resizable,width=650,height=450');
								cbWindow.document.open();
								cbWindow.document.title = 'Copied Code Block';
								cbWindow.document.write('<html><body style="margin:0;padding:0;border:0;"><textarea id="ta" style="width:100%;height:100%;position:absolute;left:0;top:0;right:0;bottom:0">' + selectedCode + '</textarea>');
								cbWindow.document.write('<a href="javascript:void(window.close())" style="display:block;position:fixed;_position:absolute;right:5px;bottom:5px;background:rgba(255,255,255,0.8);padding:5px">CLOSE</a>');
								cbWindow.document.write('<script>window.onload=function(){var ga=document.body.firstChild;ga.select();ga.focus();};</script></body></html>');
								cbWindow.document.close();
							}
						}
					});
				}
			}
		};
		
		if (clip_board !== null) {
			light_props['clipboard'] = clip_board;
		}

		_el.light(light_props);
	});
});
