Ext.ns('Ext.ux');
// vim: ts=4:sw=4:nu:fdc=2:nospell
/**
  * Ext.ux.IconCombo Extension Class for Ext 2.x Library
  *
  * @author  Ing. Jozef Sakalos
  * @version $Id: Ext.ux.IconCombo.js 617 2007-12-20 11:29:56Z jozo $
  *
  * @class Ext.ux.IconCombo
  * @extends Ext.form.ComboBox
  */
Ext.ux.IconCombo = Ext.extend(Ext.form.ComboBox, {
    initComponent:function() {
 
        Ext.apply(this, {
            tpl:  '<tpl for=".">'
                + '<div class="x-combo-list-item ux-icon-combo-item '
                + '{' + this.iconClsField + '}">'
                + '{' + this.displayField + '}'
                + '</div></tpl>'
        });
 
        // call parent initComponent
        Ext.ux.IconCombo.superclass.initComponent.call(this);
 
    }, // end of function initComponent
 
    onRender:function(ct, position) {
        // call parent onRender
        Ext.ux.IconCombo.superclass.onRender.call(this, ct, position);
 
        // adjust styles
        this.wrap.applyStyles({position:'relative'});
        this.el.addClass('ux-icon-combo-input');
 
        // add div for icon
        this.icon = Ext.DomHelper.append(this.el.up('div.x-form-field-wrap'), {
            tag: 'div', style:'position:absolute'
        });
    }, // end of function onRender

	afterRender:function() {
		Ext.ux.IconCombo.superclass.afterRender.apply(this, arguments);
		if(undefined !== this.value) {
			this.setValue(this.value);
		}
	},// end of function afterRender
 
    setIconCls:function() {
        var rec = this.store.query(this.valueField, this.getValue()).itemAt(0);
        if(rec && this.icon) {
            this.icon.className = 'ux-icon-combo-icon ' + rec.get(this.iconClsField);
        }
    }, // end of function setIconCls
 
    setValue: function(value) {
        Ext.ux.IconCombo.superclass.setValue.call(this, value);
        this.setIconCls();
    }, // end of function setValue

	clearValue:function() {
		 Ext.ux.IconCombo.superclass.clearValue.call(this);
		if(this.icon) {
				this.icon.className = '';
		}
	}
});
 
// register xtype
Ext.reg('iconcombo', Ext.ux.IconCombo);// vim: ts=4:sw=4:nu:fdc=4:nospell
/**
 * Ext.ux.form.LovCombo, List of Values Combo
 *
 * @author    Ing. Jozef Sakáloš
 * @copyright (c) 2008, by Ing. Jozef Sakáloš
 * @date      16. April 2008
 * @version   $Id: Ext.ux.form.LovCombo.js 285 2008-06-06 09:22:20Z jozo $
 *
 * @license Ext.ux.form.LovCombo.js is licensed under the terms of the Open Source
 * LGPL 3.0 license. Commercial use is permitted to the extent that the 
 * code/component(s) do NOT become part of another Open Source or Commercially
 * licensed development library or toolkit without explicit permission.
 * 
 * License details: http://www.gnu.org/licenses/lgpl.html
 */
 
/*global Ext */
// add RegExp.escape if it has not been already added
if('function' !== typeof RegExp.escape) {
	RegExp.escape = function(s) {
		if('string' !== typeof s) {
			return s;
		}
		// Note: if pasting from forum, precede ]/\ with backslash manually
		return s.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
	}; // eo function escape
}

// create namespace
Ext.ns('Ext.ux.form');
 
/**
 *
 * @class Ext.ux.form.LovCombo
 * @extends Ext.form.ComboBox
 */
Ext.ux.form.LovCombo = Ext.extend(Ext.form.ComboBox, {

	// {{{
    // configuration options
	/**
	 * @cfg {String} checkField name of field used to store checked state.
	 * It is automatically added to existing fields.
	 * Change it only if it collides with your normal field.
	 */
	 checkField:'checked'

	/**
	 * @cfg {String} separator separator to use between values and texts
	 */
    ,separator:','

	/**
	 * @cfg {String/Array} tpl Template for items. 
	 * Change it only if you know what you are doing.
	 */
	// }}}
    // {{{
    ,initComponent:function() {
        
		// template with checkbox
		if(!this.tpl) {
			this.tpl = 
				 '<tpl for=".">'
				+'<div class="x-combo-list-item">'
				+'<img class="ux-lovcombo-icon ux-lovcombo-icon-'
				+'{[values.' + this.checkField + '?"checked":"unchecked"' + ']}">'
				+'<div class="ux-lovcombo-item-text">{' + (this.displayField || 'text' )+ '}</div>'
				+'</div>'
				+'</tpl>'
			;
		}
 
        // call parent
        Ext.ux.form.LovCombo.superclass.initComponent.apply(this, arguments);

		// install internal event handlers
		this.on({
			 scope:this
			,beforequery:this.onBeforeQuery
			,blur:this.onRealBlur
		});

		// remove selection from input field
		this.onLoad = this.onLoad.createSequence(function() {
			if(this.el) {
				var v = this.el.dom.value;
				this.el.dom.value = '';
				this.el.dom.value = v;
			}
		});
 
    } // e/o function initComponent
    // }}}
	// {{{
	/**
	 * Disables default tab key bahavior
	 * @private
	 */
	,initEvents:function() {
		Ext.ux.form.LovCombo.superclass.initEvents.apply(this, arguments);

		// disable default tab handling - does no good
		this.keyNav.tab = false;

	} // eo function initEvents
	// }}}
	// {{{
	/**
	 * clears value
	 */
	,clearValue:function() {
		this.value = '';
		this.setRawValue(this.value);
		this.store.clearFilter();
		this.store.each(function(r) {
			r.set(this.checkField, false);
		}, this);
		if(this.hiddenField) {
			this.hiddenField.value = '';
		}
		this.applyEmptyText();
	} // eo function clearValue
	// }}}
	// {{{
	/**
	 * @return {String} separator (plus space) separated list of selected displayFields
	 * @private
	 */
	,getCheckedDisplay:function() {
		var re = new RegExp(this.separator, "g");
		return this.getCheckedValue(this.displayField).replace(re, this.separator + ' ');
	} // eo function getCheckedDisplay
	// }}}
	// {{{
	/**
	 * @return {String} separator separated list of selected valueFields
	 * @private
	 */
	,getCheckedValue:function(field) {
		field = field || this.valueField;
		var c = [];

		// store may be filtered so get all records
		var snapshot = this.store.snapshot || this.store.data;

		snapshot.each(function(r) {
			if(r.get(this.checkField)) {
				c.push(r.get(field));
			}
		}, this);

		return c.join(this.separator);
	} // eo function getCheckedValue
	// }}}
	// {{{
	/**
	 * beforequery event handler - handles multiple selections
	 * @param {Object} qe query event
	 * @private
	 */
	,onBeforeQuery:function(qe) {
		qe.query = qe.query.replace(new RegExp(this.getCheckedDisplay() + '[ ' + this.separator + ']*'), '');
	} // eo function onBeforeQuery
	// }}}
	// {{{
	/**
	 * blur event handler - runs only when real blur event is fired
	 */
	,onRealBlur:function() {
		this.list.hide();
		var rv = this.getRawValue();
		var rva = rv.split(new RegExp(RegExp.escape(this.separator) + ' *'));
		var va = [];
		var snapshot = this.store.snapshot || this.store.data;

		// iterate through raw values and records and check/uncheck items
		Ext.each(rva, function(v) {
			snapshot.each(function(r) {
				if(v === r.get(this.displayField)) {
					va.push(r.get(this.valueField));
				}
			}, this);
		}, this);
		this.setValue(va.join(this.separator));
		this.store.clearFilter();
	} // eo function onRealBlur
	// }}}
	// {{{
	/**
	 * before blur event - is empty function as all logic goes in onRealblur
	 */
	,beforeBlur: Ext.emptyFn
	// }}}
	// {{{
	/**
	 * Combo's onSelect override
	 * @private
	 * @param {Ext.data.Record} record record that has been selected in the list
	 * @param {Number} index index of selected (clicked) record
	 */
	,onSelect:function(record, index) {
        if(this.fireEvent('beforeselect', this, record, index) !== false){

			// toggle checked field
			record.set(this.checkField, !record.get(this.checkField));

			// display full list
			if(this.store.isFiltered()) {
				this.doQuery(this.allQuery);
			}
			// set (update) value and fire event
			this.setValue(this.getCheckedValue());
            this.fireEvent('select', this, record, index);
        }
	} // eo function onSelect
	// }}}
	// {{{
	/**
	 * Sets the value of the LovCombo
	 * @param {Mixed} v value
	 */
	,setValue:function(v) {
		if(v) {
			v = '' + v;
			if(this.valueField) {
				this.store.clearFilter();
				this.store.each(function(r) {
					var checked = !(!v.match(
						 '(^|' + this.separator + ')' + RegExp.escape(r.get(this.valueField))
						+'(' + this.separator + '|$)'))
					;

					r.set(this.checkField, checked);
				}, this);
				this.value = this.getCheckedValue();
				this.setRawValue(this.getCheckedDisplay());
				if(this.hiddenField) {
					this.hiddenField.value = this.value;
				}
			}
			else {
				this.value = v;
				this.setRawValue(v);
				if(this.hiddenField) {
					this.hiddenField.value = v;
				}
			}
			if(this.el) {
				this.el.removeClass(this.emptyClass);
			}
		}
		else {
			this.clearValue();
		}
	} // eo function setValue
	// }}}
	// {{{
	/**
	 * Selects all items
	 */
	,selectAll:function() {
        this.store.each(function(record){
            // toggle checked field
            record.set(this.checkField, true);
        }, this);

        //display full list
        this.doQuery(this.allQuery);
        this.setValue(this.getCheckedValue());
    } // eo full selectAll
	// }}}
	// {{{
	/**
	 * Deselects all items. Synonym for clearValue
	 */
    ,deselectAll:function() {
		this.clearValue();
    } // eo full deselectAll 
	// }}}

}); // eo extend
 
// register xtype
Ext.reg('lovcombo', Ext.ux.form.LovCombo); 
// eof
/*-------------------------------------------------------------------
 Ext.ux.form.TinyMCETextArea

 ExtJS form field - a text area with integrated TinyMCE WYSIWYG Editor

 Version: 4.0.1
 Release date: 17.12.2013
 ExtJS Version: 4.2.1
 TinyMCE Version: 4.0.11
 License: LGPL v2.1 or later, Sencha License

 Author: Oleg Schildt
 E-Mail: Oleg.Schildt@gmail.com

 Copyright (c) 2013 Oleg Schildt

 Enhanced by Steve Drucker (sdrucker@figleaf.com):
 ExtJS Version: 4.2.1
 TinyMCE Version: 4.0.20

 Re-Enhanced by Bhavin Bathani (bhavin.gir@gmail.com):
 ExtJS Version: 3.4
 TinyMCE Version: 4.1.0

 Following issues are covered:

 - Make the whole class compitible with ExtJS Version 3.4
 - Avoid using callparent function.
 - Using the way for inherit class which is supported in ExtJS Version 3.4
 - Avoid uaing 'alias' config to declare xtype.
 - add 'getInputId' function.
 - 'withEd' function is added to reschedule function call after editor will be initialized.
 - 'getEditor' function is added to reduce code duplication to get the editor instance.
 - 'insertAtCursor' function is added.
 - Enabling and disabling of the WYSIWYG editor controls without reinitialize the whole editor.
 - Removed all the configuration overhead for tinymce plugin inclusion.
 - Proper API code commenting is followed for better understanding.
 -------------------------------------------------------------------*/

Ext.ux.form.TinyMCETextArea = Ext.extend(Ext.form.TextArea, {
	/**
	 * Flag for tracking the initialization state.
	 * @property
	 * @type Boolean
	 */
	wysiwygIntialized: false,

	/**
	 * Indicates if the initialization of this editor is in progress.
	 * @property
	 * @type Boolean
	 */
	intializationInProgress: false,

	/**
	 * The height of the editor applied previously.
	 * @property
	 * @type Number
	 */
	lastHeight: null,

	/**
	 * The height of the editor iframe applied previously.
	 * @property
	 * @type Number
	 */
	lastFrameHeight: null,

	/**
	 * This properties enables starting without WYSIWYG editor.
	 * The user can activate it later if he wants.
	 * @property
	 * @type Boolean
	 */
	noWysiwyg: false,

	/**
	 * @cfg {Object} tinyMCEConfig Configuration object for the TinyMCE configuration options
	 */
	tinyMCEConfig: {},

	/**
	 * This property holds the editor instance.
	 * @property
	 * @type Object
	 */
	editor : undefined,

	/**
	 * @cfg {Boolean} disabled Render this component disabled (default is false).
	 */
	disableEditor : false,

	/**
	 * @constructor
	 * @param {Object} config The configuration options.
	 */
	constructor: function(config)
	{
		config = config || {};

		Ext.applyIf(config, {
			hideMode: 'offsets'
		});

		// Apply some required tinymce config
		Ext.applyIf(config.tinyMCEConfig, {
			hideMode: 'offsets',
			mode : 'exact',
			resize : false
		});

		Ext.ux.form.TinyMCETextArea.superclass.constructor.call(this, config);
	},

	/**
	 * Function called after the editor has been rendered
	 * @private
	 */
	afterRender: function()
	{
		var me = this;

		Ext.ux.form.TinyMCETextArea.superclass.afterRender.call(this, arguments);

		// Rendering is completed, now the target textarea element is available which is required to create TinyMce editor.
		this.initEditor();

		me.on('blur', function(elm, ev, eOpts) {
			var ctrl = document.getElementById(me.getInputId());

			if (me.wysiwygIntialized) {
				var ed = me.getEditor();

				// In the HTML text modus, the contents should be
				// synchronized upon the blur event.
				if (ed && ed.isHidden()) {
					if (ctrl) {
						me.positionBeforeBlur = {
							start: ctrl.selectionStart,
							end: ctrl.selectionEnd
						};
					}

					ed.load();
				}
			} else {
				if (ctrl) {
					me.positionBeforeBlur = {
						start: ctrl.selectionStart,
						end: ctrl.selectionEnd
					};
				}
			}
		}, me);

		// Synchronize the tinymce editor height whenever base-textarea gets resized.
		me.on('resize', function(elm, width, height, oldWidth, oldHeight, eOpts) {
			me.syncEditorHeight(height);
		}, me);
	},

	/**
	 * Sets the height of the editor iframe.
	 * The toolbar/menubar/statusbar height needs to be subtracted from
	 * total height to find out the iframe height.
	 * @param {Mixed} height The new height to set.
	 * @private
	 */
	syncEditorHeight: function(height)
	{
		var me = this;

		me.lastHeight = height;

		// if the editor is not initialized/ rendered than simply return.
		if (!me.wysiwygIntialized || !me.rendered) {
			return;
		}

		var ed = tinymce.get(me.getInputId());

		// if the editor is not available at all than simply return.
		if(!ed){
			return;
		}

		// if the editor is hidden, we do not synchronize
		// because the size values of the hidden editor are calculated wrong.
		if (ed.isHidden()) {
			return;
		}

		var edIframe = Ext.get(me.getInputId() + "_ifr");

		var parent = edIframe.up(".mce-edit-area");
		parent = parent.up(".mce-container-body");

		var newHeight = height;

		var edToolbar = parent.down(".mce-toolbar-grp");
		if (edToolbar)
			newHeight -= edToolbar.getHeight();

		var edMenubar = parent.down(".mce-menubar");
		if (edMenubar)
			newHeight -= edMenubar.getHeight();

		var edStatusbar = parent.down(".mce-statusbar");
		if (edStatusbar)
			newHeight -= edStatusbar.getHeight();

		me.lastFrameHeight = newHeight - 3;

		edIframe.setHeight(newHeight - 3);
	},

	/**
	 * If ed (local editor instance) is already initialized, calls specified function directly.
	 * Otherwise reschedule that particular function call on {@link tinymce.Editor.init init} event.
	 * @param {Function} func The function definition which is to be called while editor is completely ready.
	 * @private
	 */
	withEd: function(func)
	{
		var me = this;
		var ed = this.getEditor();

		// check If editor instance is available or not
		if (ed){
			// if editor is created but not initialized then reschedule the function call on init event.
			if(!ed.initialized){
				ed.on("init", function() { me.withEd(func); }, me);
			} else if(ed.initialized){
				me.editor = ed;
				func.call(me);
			}
		}
	},

	/**
	 * @return {String} Returns the input id for this field. If none was specified via the {@link #inputId} config,
	 * then an id will be automatically generated.
	 */
	getInputId: function()
	{
		return this.inputId || (this.inputId = this.id);
	},

	/**
	 * Method to determine whether this Component is currently disabled.
	 * @return {Boolean} the disabled state of this Component.
	 */
	isDisabled : function()
	{
		return this.disabled;
	},

	/**
	 * Inserts the passed text at the current cursor position. The editor must be initialized
	 * to insert text.
	 * @param {String} value Text which needs to be inserted
	 */
	insertAtCursor: function(value)
	{
		// Call tiny MCE insert content function
		var ed = this.getEditor();
		ed.execCommand('mceInsertContent', false, value);
		ed.undoManager.clear();
	},

	/**
	 * Initialized the editor.
	 * Assign necessary {@link #tinyMCEConfig} options and register necessary events to handle content
	 * and height of editor.
	 * Will call {@link tinymce.Editor.init init} method to setup iframe and create theme and plugin instances.
	 * @private
	 */
	initEditor: function()
	{
		var me = this;

		if (me.noWysiwyg || me.intializationInProgress || me.wysiwygIntialized) {
			return;
		}

		me.intializationInProgress = true;

		me.tinyMCEConfig.selector = 'textarea#' + me.getInputId();

		if (me.lastFrameHeight) {
			me.tinyMCEConfig.height = me.lastFrameHeight;
		} else {
			me.tinyMCEConfig.height = 30;
		}

		// We have to override the setup method of the TinyMCE.
		// If the user has define own one, we shall not loose it.
		// Store it and call it after our specific actions.
		var user_setup = null;

		if (me.tinyMCEConfig.setup) {
			user_setup = me.tinyMCEConfig.setup;
		}

		// BEGIN: setup
		me.tinyMCEConfig.setup = function(ed) {

			if(!Ext.isDefined(me.editor)) {
				me.editor = ed;
			}
			
			// Themes will dynamically load their stylesheets into the DOM.
			// We will overwrite the loadCSS function to add listeners for 
			// the loading. This way we make sure that all css has been loaded
			// before we resize the editor.
			var origTinymceDOMloadCSS = tinymce.DOM.loadCSS;
			// We will store the urls of all stylesheets that are loading in this array
			var cssFilesLoading = [];
			tinymce.DOM.loadCSS = function(url){
				if (!url) {
					url = '';
				}

				Ext.each(url.split(','), function(url){
					if ( Ext.isEmpty(url) ){
						return;
					}
					// Store the url in the array, so we can check if we are still
					// loading css files
					cssFilesLoading.push(url);
					// Create an element to load the stylesheet
					var el = document.createElement('link');
					// Add the element to the DOM, or it will not fire events
					document.head.appendChild(el);
					// Add a handler for the load event
					el.addEventListener('load', function(){
						// Remove the url from the array
						cssFilesLoading.splice(cssFilesLoading.indexOf(url), 1);
						// Remove the element from the DOM because tiny will have added it also
						// and we don't need it twice
						document.head.removeChild(el);
						me.fireEvent('stylesheetloaded', url);
					});
					// Add a handler for the error event
					el.addEventListener('error', function(){
						// Remove the url from the array
						cssFilesLoading.splice(cssFilesLoading.indexOf(url), 1);
						me.fireEvent('stylesheetloaded', url);
					});
					el.setAttribute('rel', 'stylesheet');
					el.setAttribute('type', 'text/css');
					el.setAttribute('href', url);
					
				});

				return origTinymceDOMloadCSS.apply(this, arguments);
			};
			
			ed.on('init', function(e) {
				// Restore the original loadCSS function
				tinymce.DOM.loadCSS = origTinymceDOMloadCSS;

				me.wysiwygIntialized = true;
				me.intializationInProgress = false;

				if (me.disableEditor || me.isDisabled()) {
					me.disable();
				}

				me.fireEvent('initialized', me, ed, {});
				
				// A wrapper function for syncEditorHeight(). It will check
				// if all css has been loaded before calling syncEditorHeight()
				function setEditorHeight(){
					if ( cssFilesLoading.length>0 ){
						me.on('stylesheetloaded', function(){
							setEditorHeight();
						}, this);
					} else {
						me.syncEditorHeight(me.lastHeight || me.height);
					}
				}
				
				if (me.lastHeight || me.height) {
					setEditorHeight();
				}
			});

			if (user_setup) {
				user_setup(ed);
			}
		};

		tinymce.init(me.tinyMCEConfig);

		me.intializationInProgress = false;
		me.wysiwygIntialized = true;
	},

	/**
	 * Retrieves the editor instance if the value of {@link #editor} property is empty.
	 * @return {Object} the editor instance.
	 */
	getEditor: function()
	{
		return tinymce.get(this.getInputId());
	},

	/**
	 * Returns true/false if the editor is hidden or not.
	 * @return {Boolean} the hidden state of an editor.
	 */
	isEditorHidden: function()
	{
		var me = this;

		if (!me.wysiwygIntialized) {
			return true;
		}

		var ed = me.getEditor();
		if (!ed) {
			return true;
		}

		return ed.isHidden();
	},

	/**
	 * Shows the editor and call {@link #initEditor} method if the editor is not initialized.
	 */
	showEditor: function()
	{
		var me = this;

		me.storedCursorPosition = null;

		if (!me.wysiwygIntialized) {
			me.noWysiwyg = false;
			me.initEditor();
			return;
		}

		var ed = me.getEditor();
		if (!ed) {
			return;
		}

		ed.show();

		ed.nodeChanged();

		if (me.lastHeight) {
			me.syncEditorHeight(me.lastHeight);
		}
	},

	/**
	 * Hides the editor.
	 */
	hideEditor: function()
	{
		var me = this;

		if (!me.wysiwygIntialized) {
			return;
		}

		var ed = me.getEditor();
		if (!ed) {
			return;
		}

		var node = ed.selection.getNode();

		if (!node || node.nodeName === "#document" || node.nodeName === "BODY" || node.nodeName === "body") {
			ed.hide();

			return;
		}

		// otherwise try to position the cursor

		var marker = '<a id="_____sys__11223___"></a>';
		ed.selection.collapse(true);
		ed.execCommand('mceInsertContent', 0, marker);

		ed.hide();

		var ctrl = document.getElementById(me.getInputId());

		var pos = -1;
		var txt = "";

		if (ctrl) {
			txt = ctrl.value;
			pos = txt.indexOf(marker);
		}

		if (pos !== -1) {
			var re = new RegExp(marker, "g");
			txt = txt.replace(re, "");
			ctrl.value = txt;

			if (ctrl.setSelectionRange) {
				ctrl.focus();
				ctrl.setSelectionRange(pos, pos);
			}
		}
	},

	/**
	 * Shows/Hides the editor, will call {@link #hideEditor} or {@link #showEditor}.
	 */
	toggleEditor: function()
	{
		var me = this;

		if (!me.wysiwygIntialized) {
			me.showEditor();
			return;
		}

		var ed = me.getEditor();

		if (ed.isHidden()) {
			me.showEditor();
		} else {
			me.hideEditor();
		}
	},

	/**
	 * Destroys the editor instance by removing all events, element references.
	 * @return {Object} me the current scope or container instance.
	 */
	removeEditor: function()
	{
		var me = this;

		if (me.intializationInProgress) {
			return me;
		}

		if (!me.wysiwygIntialized) {
			return me;
		}

		var ed = me.getEditor();
		if (ed) {
			ed.save();
			ed.destroy(false);
		}

		me.wysiwygIntialized = false;

		return me;
	},

	/**
	 * Sets a data value into the field and runs the validation.
	 * @param {String} v The value to set
	 * @return {String} Value which was set
	 */
	setValue: function(v)
	{
		var me = this;

		if (me.wysiwygIntialized) {
			// The editor does some preformatting of the HTML text
			// entered by the user.
			// The method setValue sets the value of the textarea.
			// We have to load the text into editor for the
			// preformatting and then to save it back to the textarea.
			if (this.value !== v) {
				this.value = v;
				if (this.rendered) {
					var ed = me.getEditor();
					if(!ed){
						tinyMCE.EditorManager.on("AddEditor", function() {
							me.withEd(function(){
								var ed = me.getEditor();
								// if selected editor is dirty then dont call setContent function.
								if(!ed.isDirty()) {
									me.setContent(ed, v);
								}
							});
						}, this);
					} else {
						me.setContent(ed, v);
					}
				}
			}
		}
		return this.value;
	},
	
	/**
	 * Function is used to set the content in HTML Editor.
	 * @param {Object} editor the HTML Editor Object
	 * @param {String} value the value which is going to set in editor.
	 */
	setContent : function(editor, value)
	{
		editor.setContent(value === null || value === undefined ? '' : value, { format: 'raw' });
		editor.startContent = editor.getContent({ format: 'raw' }); 
	},

	/**
	 * Returns the current data value of the editor.
	 * @return {String} v The field value
	 */
	getValue: function(some)
	{
		var ed = this.getEditor();
		if(!ed){
			return;
		}
		if(!this.rendered || !ed.initialized )
			return Ext.value( this.value, '' );

		var v = ed.getContent();
		if( v === this.emptyText || v === undefined ){
			v = '';
		}
		return v;
	},

	/**
	 * Returns the raw data value which may or may not be a valid, defined value.
	 * @return {Mixed} v The field value
	 */
	getRawValue : function(){

		var ed = this.getEditor();
		if(!ed){
			return;
		}

		if( !this.rendered || !ed.initialized )
			return Ext.value( this.value, '' );

		var v = ed.getContent({format : 'raw'});
		if(v === this.emptyText){
			v = '';
		}
		return v;
	},

	/**
	 * Initializes the field's value based on the initial config.
	 */
	initValue: function()
	{
		if (!this.rendered)
			Ext.ux.TinyMCE.superclass.initValue.call(this);
		else {
			if (this.value !== undefined) {
				this.setValue(this.value);
			}
			else {
				var v = this.getEl().value;
				if ( v )
					this.setValue( v );
			}
		}
	},

	/**
	 * Focuses/activates the editor. This will set this editor as the activeEditor in the tinymce collection.
	 * If the editor is not initialized yet than Try to focus this component.
	 * @param {Boolean} selectText (optional) If applicable, true to also select the text in this component.
	 * @param {Boolean/Number} delay (optional) Delay the focus this number of milliseconds (true for 10 milliseconds)
	 * @return {Ext.Component} me
	 */
	focus: function(selectText, delay)
	{
		var me = this;

		if (me.isDisabled()) {
			return me;
		}

		if (delay) {
			if (isNaN(delay)) {
				delay = 10;
			}

			setTimeout(function() {
				me.focus.call(me, selectText, false);
			}, delay);
			return me;
		}

		if (!me.wysiwygIntialized) {
			return Ext.ux.form.TinyMCETextArea.superclass.focus.call(this, arguments);
		}

		var ed = me.getEditor();

		if (ed && !ed.isHidden()) {
			Ext.ux.form.TinyMCETextArea.superclass.focus.call(this, arguments);

			ed.focus();
		} else {
			return Ext.ux.form.TinyMCETextArea.superclass.focus.call(this, arguments);
		}

		return me;
	},

	/**
	 * Enable this component.
	 * @return {Ext.Component} this
	 */
	enable: function()
	{
		var me = this;
		var result  = Ext.ux.form.TinyMCETextArea.superclass.enable.call(this, arguments);

		if (!result) {
			return result;
		}

		var ed = me.getEditor();
		if(ed) {
			ed.theme.panel.find('*').disabled(false);
			this.getEditorBody().setAttribute('contenteditable', true);
		}

		return me;
	},

	/**
	 * Disable this component.
	 * @param {Boolean} silent true to prevent fire 'disable' event
	 * @return {Ext.Component} this
	 */
	disable: function(silent)
	{
		var me = this;
		var result = Ext.ux.form.TinyMCETextArea.superclass.disable.call(this, arguments);

		if (!result) {
			return result;
		}

		var ed = me.getEditor();
		if(ed) {
			ed.theme.panel.find('*').disabled(true);
			this.getEditorBody().setAttribute('contenteditable', false);
		}

		return me;
	},

	/**
	 * Hide this component.
	 * @return {Ext.Component} this
	 */
	hide: function()
	{
		var me = this;

		Ext.ux.form.TinyMCETextArea.superclass.hide.call(this, arguments);

		var ed = me.getEditor();
		if(ed){
			ed.hide();
		} else {
			tinyMCE.EditorManager.on("AddEditor", function() {
				me.withEd(function() {
					var ed = me.getEditor();
					ed.hide();
				});
			}, this);
		}

		return me;
	},

	/**
	 * Show this component.
	 * @return {Ext.Component} this
	 */
	show: function()
	{
		var me = this;

		Ext.ux.form.TinyMCETextArea.superclass.show.call(this, arguments);

		var ed = me.getEditor();
		if(ed){
			ed.show();
		}

		return me;
	},

	/**
	 * Keep bookmark location for the current selection in a class property named into {@link #storedCursorPosition}.
	 * which can be used to restore the selection after some content modification to the document.
	 */
	storeCurrentSelection: function()
	{
		var me = this;

		var wwg_mode = false;

		var ed = me.getEditor();

		if (me.wysiwygIntialized) {
			if (ed && !ed.isHidden()) {
				wwg_mode = true;
			}
		}

		var ctrl = document.getElementById(me.getInputId());

		if (wwg_mode) {
			me.storedCursorPosition = ed.selection.getBookmark('simple');
		} else if (ctrl) {
			me.storedCursorPosition = me.positionBeforeBlur;
		}
	},

	/**
	 * Restores the selection to the specified bookmark stored into {@link #storedCursorPosition} property.
	 */
	restoreCurrentSelection: function()
	{
		var me = this;

		if (!me.storedCursorPosition) {
			return;
		}

		var wwg_mode = false;

		var ed = me.getEditor();

		if (me.wysiwygIntialized) {
			if (ed && !ed.isHidden()) {
				wwg_mode = true;
			}
		}

		var ctrl = document.getElementById(me.getInputId());

		if (wwg_mode) {
			ed.selection.moveToBookmark(me.storedCursorPosition);
		} else if (ctrl) {
			ctrl.setSelectionRange(me.storedCursorPosition.start, me.storedCursorPosition.end);
		}
	},

	/**
	 * Insert text at the cursor position by executing 'mceInsertContent' tinymce command
	 * if the editor is initialized and not hidden. Otherwise, it will get the size of
	 * existing content up till the cursor position of the editor and append the text.
	 * @param {String} txt the text which needs to be inserted
	 */
	insertText: function(txt)
	{
		var me = this;

		var wwg_mode = false;

		var ed = me.getEditor();

		if (me.wysiwygIntialized) {
			if (ed && !ed.isHidden()) {
				wwg_mode = true;
			}
		}

		var ctrl = document.getElementById(me.getInputId());

		if (wwg_mode) {
			ed.focus();
			ed.execCommand('mceInsertContent', 0, txt);
		} else if (ctrl) {
			ctrl.focus();

			var start = ctrl.selectionStart + txt.length;

			ctrl.value = ctrl.value.slice(0, ctrl.selectionStart) + txt + ctrl.value.slice(ctrl.selectionEnd);

			ctrl.setSelectionRange(start, start);
		}
	}
});
Ext.reg('zarafa.tinymcetextarea', Ext.ux.form.TinyMCETextArea);// XRegExp 1.5.0
// (c) 2007-2010 Steven Levithan
// MIT License
// <http://xregexp.com>
// Provides an augmented, extensible, cross-browser implementation of regular expressions,
// including support for additional syntax, flags, and methods

var XRegExp;

if (XRegExp) {
    // Avoid running twice, since that would break references to native globals
    throw Error("can't load XRegExp twice in the same frame");
}

// Run within an anonymous function to protect variables and avoid new globals
(function () {

    //---------------------------------
    //  Constructor
    //---------------------------------

    // Accepts a pattern and flags; returns a new, extended `RegExp` object. Differs from a native
    // regular expression in that additional syntax and flags are supported and cross-browser
    // syntax inconsistencies are ameliorated. `XRegExp(/regex/)` clones an existing regex and
    // converts to type XRegExp
    XRegExp = function (pattern, flags) {
        var output = [],
            currScope = XRegExp.OUTSIDE_CLASS,
            pos = 0,
            context, tokenResult, match, chr, regex;

        if (XRegExp.isRegExp(pattern)) {
            if (flags !== undefined)
                throw TypeError("can't supply flags when constructing one RegExp from another");
            return clone(pattern);
        }
        // Tokens become part of the regex construction process, so protect against infinite
        // recursion when an XRegExp is constructed within a token handler or trigger
        if (isInsideConstructor)
            throw Error("can't call the XRegExp constructor within token definition functions");

        flags = flags || "";
        context = { // `this` object for custom tokens
            hasNamedCapture: false,
            captureNames: [],
            hasFlag: function (flag) {return flags.indexOf(flag) > -1;},
            setFlag: function (flag) {flags += flag;}
        };

        while (pos < pattern.length) {
            // Check for custom tokens at the current position
            tokenResult = runTokens(pattern, pos, currScope, context);

            if (tokenResult) {
                output.push(tokenResult.output);
                pos += (tokenResult.match[0].length || 1);
            } else {
                // Check for native multicharacter metasequences (excluding character classes) at
                // the current position
                if (match = real.exec.call(nativeTokens[currScope], pattern.slice(pos))) {
                    output.push(match[0]);
                    pos += match[0].length;
                } else {
                    chr = pattern.charAt(pos);
                    if (chr === "[")
                        currScope = XRegExp.INSIDE_CLASS;
                    else if (chr === "]")
                        currScope = XRegExp.OUTSIDE_CLASS;
                    // Advance position one character
                    output.push(chr);
                    pos++;
                }
            }
        }

        regex = RegExp(output.join(""), real.replace.call(flags, flagClip, ""));
        regex._xregexp = {
            source: pattern,
            captureNames: context.hasNamedCapture ? context.captureNames : null
        };
        return regex;
    };


    //---------------------------------
    //  Public properties
    //---------------------------------

    XRegExp.version = "1.5.0";

    // Token scope bitflags
    XRegExp.INSIDE_CLASS = 1;
    XRegExp.OUTSIDE_CLASS = 2;


    //---------------------------------
    //  Private variables
    //---------------------------------

    var replacementToken = /\$(?:(\d\d?|[$&`'])|{([$\w]+)})/g,
        flagClip = /[^gimy]+|([\s\S])(?=[\s\S]*\1)/g, // Nonnative and duplicate flags
        quantifier = /^(?:[?*+]|{\d+(?:,\d*)?})\??/,
        isInsideConstructor = false,
        tokens = [],
        // Copy native globals for reference ("native" is an ES3 reserved keyword)
        real = {
            exec: RegExp.prototype.exec,
            test: RegExp.prototype.test,
            match: String.prototype.match,
            replace: String.prototype.replace,
            split: String.prototype.split
        },
        compliantExecNpcg = real.exec.call(/()??/, "")[1] === undefined, // check `exec` handling of nonparticipating capturing groups
        compliantLastIndexIncrement = function () {
            var x = /^/g;
            real.test.call(x, "");
            return !x.lastIndex;
        }(),
        compliantLastIndexReset = function () {
            var x = /x/g;
            real.replace.call("x", x, "");
            return !x.lastIndex;
        }(),
        hasNativeY = RegExp.prototype.sticky !== undefined,
        nativeTokens = {};

    // `nativeTokens` match native multicharacter metasequences only (including deprecated octals,
    // excluding character classes)
    nativeTokens[XRegExp.INSIDE_CLASS] = /^(?:\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|c[A-Za-z]|[\s\S]))/;
    nativeTokens[XRegExp.OUTSIDE_CLASS] = /^(?:\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\d*|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|c[A-Za-z]|[\s\S])|\(\?[:=!]|[?*+]\?|{\d+(?:,\d*)?}\??)/;


    //---------------------------------
    //  Public methods
    //---------------------------------

    // Lets you extend or change XRegExp syntax and create custom flags. This is used internally by
    // the XRegExp library and can be used to create XRegExp plugins. This function is intended for
    // users with advanced knowledge of JavaScript's regular expression syntax and behavior. It can
    // be disabled by `XRegExp.freezeTokens`
    XRegExp.addToken = function (regex, handler, scope, trigger) {
        tokens.push({
            pattern: clone(regex, "g" + (hasNativeY ? "y" : "")),
            handler: handler,
            scope: scope || XRegExp.OUTSIDE_CLASS,
            trigger: trigger || null
        });
    };

    // Accepts a pattern and flags; returns an extended `RegExp` object. If the pattern and flag
    // combination has previously been cached, the cached copy is returned; otherwise the newly
    // created regex is cached
    XRegExp.cache = function (pattern, flags) {
        var key = pattern + "/" + (flags || "");
        return XRegExp.cache[key] || (XRegExp.cache[key] = XRegExp(pattern, flags));
    };

    // Accepts a `RegExp` instance; returns a copy with the `/g` flag set. The copy has a fresh
    // `lastIndex` (set to zero). If you want to copy a regex without forcing the `global`
    // property, use `XRegExp(regex)`. Do not use `RegExp(regex)` because it will not preserve
    // special properties required for named capture
    XRegExp.copyAsGlobal = function (regex) {
        return clone(regex, "g");
    };

    // Accepts a string; returns the string with regex metacharacters escaped. The returned string
    // can safely be used at any point within a regex to match the provided literal string. Escaped
    // characters are [ ] { } ( ) * + ? - . , \ ^ $ | # and whitespace
    XRegExp.escape = function (str) {
        return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
    };

    // Accepts a string to search, regex to search with, position to start the search within the
    // string (default: 0), and an optional Boolean indicating whether matches must start at-or-
    // after the position or at the specified position only. This function ignores the `lastIndex`
    // property of the provided regex
    XRegExp.execAt = function (str, regex, pos, anchored) {
        regex = clone(regex, "g" + ((anchored && hasNativeY) ? "y" : ""));
        regex.lastIndex = pos = pos || 0;
        var match = regex.exec(str);
        if (anchored)
            return (match && match.index === pos) ? match : null;
        else
            return match;
    };

    // Breaks the unrestorable link to XRegExp's private list of tokens, thereby preventing
    // syntax and flag changes. Should be run after XRegExp and any plugins are loaded
    XRegExp.freezeTokens = function () {
        XRegExp.addToken = function () {
            throw Error("can't run addToken after freezeTokens");
        };
    };

    // Accepts any value; returns a Boolean indicating whether the argument is a `RegExp` object.
    // Note that this is also `true` for regex literals and regexes created by the `XRegExp`
    // constructor. This works correctly for variables created in another frame, when `instanceof`
    // and `constructor` checks would fail to work as intended
    XRegExp.isRegExp = function (o) {
        return Object.prototype.toString.call(o) === "[object RegExp]";
    };

    // Executes `callback` once per match within `str`. Provides a simpler and cleaner way to
    // iterate over regex matches compared to the traditional approaches of subverting
    // `String.prototype.replace` or repeatedly calling `exec` within a `while` loop
    XRegExp.iterate = function (str, origRegex, callback, context) {
        var regex = clone(origRegex, "g"),
            i = -1, match;
        while (match = regex.exec(str)) {
            callback.call(context, match, ++i, str, regex);
            if (regex.lastIndex === match.index)
                regex.lastIndex++;
        }
        if (origRegex.global)
            origRegex.lastIndex = 0;
    };

    // Accepts a string and an array of regexes; returns the result of using each successive regex
    // to search within the matches of the previous regex. The array of regexes can also contain
    // objects with `regex` and `backref` properties, in which case the named or numbered back-
    // references specified are passed forward to the next regex or returned. E.g.:
    // var xregexpImgFileNames = XRegExp.matchChain(html, [
    //     {regex: /<img\b([^>]+)>/i, backref: 1}, // <img> tag attributes
    //     {regex: XRegExp('(?ix) \\s src=" (?<src> [^"]+ )'), backref: "src"}, // src attribute values
    //     {regex: XRegExp("^http://xregexp\\.com(/[^#?]+)", "i"), backref: 1}, // xregexp.com paths
    //     /[^\/]+$/ // filenames (strip directory paths)
    // ]);
    XRegExp.matchChain = function (str, chain) {
        return function recurseChain (values, level) {
            var item = chain[level].regex ? chain[level] : {regex: chain[level]},
                regex = clone(item.regex, "g"),
                matches = [], i;
            for (i = 0; i < values.length; i++) {
                XRegExp.iterate(values[i], regex, function (match) {
                    matches.push(item.backref ? (match[item.backref] || "") : match[0]);
                });
            }
            return ((level === chain.length - 1) || !matches.length) ?
                matches : recurseChain(matches, level + 1);
        }([str], 0);
    };


    //---------------------------------
    //  New RegExp prototype methods
    //---------------------------------

    // Accepts a context object and arguments array; returns the result of calling `exec` with the
    // first value in the arguments array. the context is ignored but is accepted for congruity
    // with `Function.prototype.apply`
    RegExp.prototype.apply = function (context, args) {
        return this.exec(args[0]);
    };

    // Accepts a context object and string; returns the result of calling `exec` with the provided
    // string. the context is ignored but is accepted for congruity with `Function.prototype.call`
    RegExp.prototype.call = function (context, str) {
        return this.exec(str);
    };


    //---------------------------------
    //  Overriden native methods
    //---------------------------------

    // Adds named capture support (with backreferences returned as `result.name`), and fixes two
    // cross-browser issues per ES3:
    // - Captured values for nonparticipating capturing groups should be returned as `undefined`,
    //   rather than the empty string.
    // - `lastIndex` should not be incremented after zero-length matches.
    RegExp.prototype.exec = function (str) {
        var match = real.exec.apply(this, arguments),
            name, r2;
        if (match) {
            // Fix browsers whose `exec` methods don't consistently return `undefined` for
            // nonparticipating capturing groups
            if (!compliantExecNpcg && match.length > 1 && indexOf(match, "") > -1) {
                r2 = RegExp(this.source, real.replace.call(getNativeFlags(this), "g", ""));
                // Using `str.slice(match.index)` rather than `match[0]` in case lookahead allowed
                // matching due to characters outside the match
                real.replace.call(str.slice(match.index), r2, function () {
                    for (var i = 1; i < arguments.length - 2; i++) {
                        if (arguments[i] === undefined)
                            match[i] = undefined;
                    }
                });
            }
            // Attach named capture properties
            if (this._xregexp && this._xregexp.captureNames) {
                for (var i = 1; i < match.length; i++) {
                    name = this._xregexp.captureNames[i - 1];
                    if (name)
                       match[name] = match[i];
                }
            }
            // Fix browsers that increment `lastIndex` after zero-length matches
            if (!compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index))
                this.lastIndex--;
        }
        return match;
    };

    // Don't override `test` if it won't change anything
    if (!compliantLastIndexIncrement) {
        // Fix browser bug in native method
        RegExp.prototype.test = function (str) {
            // Use the native `exec` to skip some processing overhead, even though the overriden
            // `exec` would take care of the `lastIndex` fix
            var match = real.exec.call(this, str);
            // Fix browsers that increment `lastIndex` after zero-length matches
            if (match && this.global && !match[0].length && (this.lastIndex > match.index))
                this.lastIndex--;
            return !!match;
        };
    }

    // Adds named capture support and fixes browser bugs in native method
    String.prototype.match = function (regex) {
        if (!XRegExp.isRegExp(regex))
            regex = RegExp(regex); // Native `RegExp`
        if (regex.global) {
            var result = real.match.apply(this, arguments);
            regex.lastIndex = 0; // Fix IE bug
            return result;
        }
        return regex.exec(this); // Run the altered `exec`
    };

    // Adds support for `${n}` tokens for named and numbered backreferences in replacement text,
    // and provides named backreferences to replacement functions as `arguments[0].name`. Also
    // fixes cross-browser differences in replacement text syntax when performing a replacement
    // using a nonregex search value, and the value of replacement regexes' `lastIndex` property
    // during replacement iterations. Note that this doesn't support SpiderMonkey's proprietary
    // third (`flags`) parameter
    String.prototype.replace = function (search, replacement) {
        var isRegex = XRegExp.isRegExp(search),
            captureNames, result, str;

        // There are many combinations of search/replacement types/values and browser bugs that
        // preclude passing to native `replace`, so just keep this check relatively simple
        if (isRegex && typeof replacement.valueOf() === "string" && replacement.indexOf("${") === -1 && compliantLastIndexReset)
            return real.replace.apply(this, arguments);

        if (!isRegex)
            search = search + ""; // Type conversion
        else if (search._xregexp)
            captureNames = search._xregexp.captureNames; // Array or `null`

        if (typeof replacement === "function") {
            result = real.replace.call(this, search, function () {
                if (captureNames) {
                    // Change the `arguments[0]` string primitive to a String object which can store properties
                    arguments[0] = new String(arguments[0]);
                    // Store named backreferences on `arguments[0]`
                    for (var i = 0; i < captureNames.length; i++) {
                        if (captureNames[i])
                            arguments[0][captureNames[i]] = arguments[i + 1];
                    }
                }
                // Update `lastIndex` before calling `replacement`
                if (isRegex && search.global)
                    search.lastIndex = arguments[arguments.length - 2] + arguments[0].length;
                return replacement.apply(null, arguments);
            });
        } else {
            str = this + ""; // Type conversion, so `args[args.length - 1]` will be a string (given nonstring `this`)
            result = real.replace.call(str, search, function () {
                var args = arguments; // Keep this function's `arguments` available through closure
                return real.replace.call(replacement, replacementToken, function ($0, $1, $2) {
                    // Numbered backreference (without delimiters) or special variable
                    if ($1) {
                        switch ($1) {
                            case "$": return "$";
                            case "&": return args[0];
                            case "`": return args[args.length - 1].slice(0, args[args.length - 2]);
                            case "'": return args[args.length - 1].slice(args[args.length - 2] + args[0].length);
                            // Numbered backreference
                            default:
                                // What does "$10" mean?
                                // - Backreference 10, if 10 or more capturing groups exist
                                // - Backreference 1 followed by "0", if 1-9 capturing groups exist
                                // - Otherwise, it's the string "$10"
                                // Also note:
                                // - Backreferences cannot be more than two digits (enforced by `replacementToken`)
                                // - "$01" is equivalent to "$1" if a capturing group exists, otherwise it's the string "$01"
                                // - There is no "$0" token ("$&" is the entire match)
                                var literalNumbers = "";
                                $1 = +$1; // Type conversion; drop leading zero
                                if (!$1) // `$1` was "0" or "00"
                                    return $0;
                                while ($1 > args.length - 3) {
                                    literalNumbers = String.prototype.slice.call($1, -1) + literalNumbers;
                                    $1 = Math.floor($1 / 10); // Drop the last digit
                                }
                                return ($1 ? args[$1] || "" : "$") + literalNumbers;
                        }
                    // Named backreference or delimited numbered backreference
                    } else {
                        // What does "${n}" mean?
                        // - Backreference to numbered capture n. Two differences from "$n":
                        //   - n can be more than two digits
                        //   - Backreference 0 is allowed, and is the entire match
                        // - Backreference to named capture n, if it exists and is not a number overridden by numbered capture
                        // - Otherwise, it's the string "${n}"
                        var n = +$2; // Type conversion; drop leading zeros
                        if (n <= args.length - 3)
                            return args[n];
                        n = captureNames ? indexOf(captureNames, $2) : -1;
                        return n > -1 ? args[n + 1] : $0;
                    }
                });
            });
        }

        if (isRegex && search.global)
            search.lastIndex = 0; // Fix IE bug

        return result;
    };

    // A consistent cross-browser, ES3 compliant `split`
    String.prototype.split = function (s /* separator */, limit) {
        // If separator `s` is not a regex, use the native `split`
        if (!XRegExp.isRegExp(s))
            return real.split.apply(this, arguments);

        var str = this + "", // Type conversion
            output = [],
            lastLastIndex = 0,
            match, lastLength;

        // Behavior for `limit`: if it's...
        // - `undefined`: No limit
        // - `NaN` or zero: Return an empty array
        // - A positive number: Use `Math.floor(limit)`
        // - A negative number: No limit
        // - Other: Type-convert, then use the above rules
        if (limit === undefined || +limit < 0) {
            limit = Infinity;
        } else {
            limit = Math.floor(+limit);
            if (!limit)
                return [];
        }

        // This is required if not `s.global`, and it avoids needing to set `s.lastIndex` to zero
        // and restore it to its original value when we're done using the regex
        s = XRegExp.copyAsGlobal(s);

        while (match = s.exec(str)) { // Run the altered `exec` (required for `lastIndex` fix, etc.)
            if (s.lastIndex > lastLastIndex) {
                output.push(str.slice(lastLastIndex, match.index));

                if (match.length > 1 && match.index < str.length)
                    Array.prototype.push.apply(output, match.slice(1));

                lastLength = match[0].length;
                lastLastIndex = s.lastIndex;

                if (output.length >= limit)
                    break;
            }

            if (s.lastIndex === match.index)
                s.lastIndex++;
        }

        if (lastLastIndex === str.length) {
            if (!real.test.call(s, "") || lastLength)
                output.push("");
        } else {
            output.push(str.slice(lastLastIndex));
        }

        return output.length > limit ? output.slice(0, limit) : output;
    };


    //---------------------------------
    //  Private helper functions
    //---------------------------------

    // Supporting function for `XRegExp`, `XRegExp.copyAsGlobal`, etc. Returns a copy of a `RegExp`
    // instance with a fresh `lastIndex` (set to zero), preserving properties required for named
    // capture. Also allows adding new flags in the process of copying the regex
    function clone (regex, additionalFlags) {
        if (!XRegExp.isRegExp(regex))
            throw TypeError("type RegExp expected");
        var x = regex._xregexp;
        regex = XRegExp(regex.source, getNativeFlags(regex) + (additionalFlags || ""));
        if (x) {
            regex._xregexp = {
                source: x.source,
                captureNames: x.captureNames ? x.captureNames.slice(0) : null
            };
        }
        return regex;
    };

    function getNativeFlags (regex) {
        return (regex.global     ? "g" : "") +
               (regex.ignoreCase ? "i" : "") +
               (regex.multiline  ? "m" : "") +
               (regex.extended   ? "x" : "") + // Proposed for ES4; included in AS3
               (regex.sticky     ? "y" : "");
    };

    function runTokens (pattern, index, scope, context) {
        var i = tokens.length,
            result, match, t;
        // Protect against constructing XRegExps within token handler and trigger functions
        isInsideConstructor = true;
        // Must reset `isInsideConstructor`, even if a `trigger` or `handler` throws
        try {
            while (i--) { // Run in reverse order
                t = tokens[i];
                if ((scope & t.scope) && (!t.trigger || t.trigger.call(context))) {
                    t.pattern.lastIndex = index;
                    match = t.pattern.exec(pattern); // Running the altered `exec` here allows use of named backreferences, etc.
                    if (match && match.index === index) {
                        result = {
                            output: t.handler.call(context, match, scope),
                            match: match
                        };
                        break;
                    }
                }
            }
        } catch (err) {
            throw err;
        } finally {
            isInsideConstructor = false;
        }
        return result;
    };

    function indexOf (array, item, from) {
        if (Array.prototype.indexOf) // Use the native array method if available
            return array.indexOf(item, from);
        for (var i = from || 0; i < array.length; i++) {
            if (array[i] === item)
                return i;
        }
        return -1;
    };


    //---------------------------------
    //  Built-in tokens
    //---------------------------------

    // Augment XRegExp's regular expression syntax and flags. Note that when adding tokens, the
    // third (`scope`) argument defaults to `XRegExp.OUTSIDE_CLASS`

    // Comment pattern: (?# )
    XRegExp.addToken(
        /\(\?#[^)]*\)/,
        function (match) {
            // Keep tokens separated unless the following token is a quantifier
            return real.test.call(quantifier, match.input.slice(match.index + match[0].length)) ? "" : "(?:)";
        }
    );

    // Capturing group (match the opening parenthesis only).
    // Required for support of named capturing groups
    XRegExp.addToken(
        /\((?!\?)/,
        function () {
            this.captureNames.push(null);
            return "(";
        }
    );

    // Named capturing group (match the opening delimiter only): (?<name>
    XRegExp.addToken(
        /\(\?<([$\w]+)>/,
        function (match) {
            this.captureNames.push(match[1]);
            this.hasNamedCapture = true;
            return "(";
        }
    );

    // Named backreference: \k<name>
    XRegExp.addToken(
        /\\k<([\w$]+)>/,
        function (match) {
            var index = indexOf(this.captureNames, match[1]);
            // Keep backreferences separate from subsequent literal numbers. Preserve back-
            // references to named groups that are undefined at this point as literal strings
            return index > -1 ?
                "\\" + (index + 1) + (isNaN(match.input.charAt(match.index + match[0].length)) ? "" : "(?:)") :
                match[0];
        }
    );

    // Empty character class: [] or [^]
    XRegExp.addToken(
        /\[\^?]/,
        function (match) {
            // For cross-browser compatibility with ES3, convert [] to \b\B and [^] to [\s\S].
            // (?!) should work like \b\B, but is unreliable in Firefox
            return match[0] === "[]" ? "\\b\\B" : "[\\s\\S]";
        }
    );

    // Mode modifier at the start of the pattern only, with any combination of flags imsx: (?imsx)
    // Does not support x(?i), (?-i), (?i-m), (?i: ), (?i)(?m), etc.
    XRegExp.addToken(
        /^\(\?([imsx]+)\)/,
        function (match) {
            this.setFlag(match[1]);
            return "";
        }
    );

    // Whitespace and comments, in free-spacing (aka extended) mode only
    XRegExp.addToken(
        /(?:\s+|#.*)+/,
        function (match) {
            // Keep tokens separated unless the following token is a quantifier
            return real.test.call(quantifier, match.input.slice(match.index + match[0].length)) ? "" : "(?:)";
        },
        XRegExp.OUTSIDE_CLASS,
        function () {return this.hasFlag("x");}
    );

    // Dot, in dotall (aka singleline) mode only
    XRegExp.addToken(
        /\./,
        function () {return "[\\s\\S]";},
        XRegExp.OUTSIDE_CLASS,
        function () {return this.hasFlag("s");}
    );


    //---------------------------------
    //  Backward compatibility
    //---------------------------------

    // Uncomment the following block for compatibility with XRegExp 1.0-1.2:
    /*
    XRegExp.matchWithinChain = XRegExp.matchChain;
    RegExp.prototype.addFlags = function (s) {return clone(this, s);};
    RegExp.prototype.execAll = function (s) {var r = []; XRegExp.iterate(s, this, function (m) {r.push(m);}); return r;};
    RegExp.prototype.forEachExec = function (s, f, c) {return XRegExp.iterate(s, this, f, c);};
    RegExp.prototype.validate = function (s) {var r = RegExp("^(?:" + this.source + ")$(?!\\s)", getNativeFlags(this)); if (this.global) this.lastIndex = 0; return s.search(r) === 0;};
    */

})();

/*
 * #dependsFile client/third-party/xregexp/xregexp.js
 */

/*
XRegExp Unicode plugin base 0.5
(c) 2008-2010 Steven Levithan
MIT License
<http://xregexp.com>
Uses the Unicode 5.2 character database

The Unicode plugin base adds support for the \p{L} token only (Unicode category Letter). Plugin
packages are available that add support for the remaining Unicode categories, as well as Unicode
scripts and blocks.

All Unicode tokens can be inverted by using an uppercase P; e.g., \P{L} matches any character not
in Unicode's Letter category. Negated Unicode tokens are not supported within character classes.

Letter case, spaces, hyphens, and underscores are ignored when comparing Unicode token names.
*/

var XRegExp;

if (!XRegExp) {
    throw ReferenceError("XRegExp must be loaded before the Unicode plugin");
}

(function () {

    var unicode = {}; // protected storage for package tokens

    XRegExp.addUnicodePackage = function (pack) {
        var codePoint = /\w{4}/g,
            clip = /[- _]+/g,
            name, p;
        for (p in pack) {
            if (pack.hasOwnProperty(p)) {
                name = p.replace(clip, "").toLowerCase();
                // disallow overriding properties that have already been added
                if (!unicode.hasOwnProperty(name)) {
                    unicode[name] = pack[p].replace(codePoint, "\\u$&");
                }
            }
        }
    };

    XRegExp.addToken(
        /\\([pP]){(\^?)([^}]*)}/,
        function (match, scope) {
            var negated = (match[1] === "P" || match[2]),
                item = match[3].replace(/[- _]+/g, "").toLowerCase();

            // \p{}, \P{}, and \p{^} are valid, but the double negative \P{^} isn't
            if (match[1] === "P" && match[2])
                throw SyntaxError("erroneous characters: " + match[0]);
            if (negated && scope === XRegExp.INSIDE_CLASS)
                throw SyntaxError("not supported in character classes: \\" + match[1] + "{" + match[2] + "...}");
            if (!unicode.hasOwnProperty(item))
                throw SyntaxError("invalid or unsupported Unicode item: " + match[0]);

            return scope === XRegExp.OUTSIDE_CLASS ?
                "[" + (negated ? "^" : "") + unicode[item] + "]" :
                unicode[item];
        },
        XRegExp.INSIDE_CLASS | XRegExp.OUTSIDE_CLASS
    );

    XRegExp.addUnicodePackage({
        L: "0041-005A0061-007A00AA00B500BA00C0-00D600D8-00F600F8-02C102C6-02D102E0-02E402EC02EE0370-037403760377037A-037D03860388-038A038C038E-03A103A3-03F503F7-0481048A-05250531-055605590561-058705D0-05EA05F0-05F20621-064A066E066F0671-06D306D506E506E606EE06EF06FA-06FC06FF07100712-072F074D-07A507B107CA-07EA07F407F507FA0800-0815081A082408280904-0939093D09500958-0961097109720979-097F0985-098C098F09900993-09A809AA-09B009B209B6-09B909BD09CE09DC09DD09DF-09E109F009F10A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A59-0A5C0A5E0A72-0A740A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABD0AD00AE00AE10B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3D0B5C0B5D0B5F-0B610B710B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BD00C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D0C580C590C600C610C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBD0CDE0CE00CE10D05-0D0C0D0E-0D100D12-0D280D2A-0D390D3D0D600D610D7A-0D7F0D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60E01-0E300E320E330E40-0E460E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB00EB20EB30EBD0EC0-0EC40EC60EDC0EDD0F000F40-0F470F49-0F6C0F88-0F8B1000-102A103F1050-1055105A-105D106110651066106E-10701075-1081108E10A0-10C510D0-10FA10FC1100-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A1380-138F13A0-13F41401-166C166F-167F1681-169A16A0-16EA1700-170C170E-17111720-17311740-17511760-176C176E-17701780-17B317D717DC1820-18771880-18A818AA18B0-18F51900-191C1950-196D1970-19741980-19AB19C1-19C71A00-1A161A20-1A541AA71B05-1B331B45-1B4B1B83-1BA01BAE1BAF1C00-1C231C4D-1C4F1C5A-1C7D1CE9-1CEC1CEE-1CF11D00-1DBF1E00-1F151F18-1F1D1F20-1F451F48-1F4D1F50-1F571F591F5B1F5D1F5F-1F7D1F80-1FB41FB6-1FBC1FBE1FC2-1FC41FC6-1FCC1FD0-1FD31FD6-1FDB1FE0-1FEC1FF2-1FF41FF6-1FFC2071207F2090-209421022107210A-211321152119-211D212421262128212A-212D212F-2139213C-213F2145-2149214E218321842C00-2C2E2C30-2C5E2C60-2CE42CEB-2CEE2D00-2D252D30-2D652D6F2D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE2E2F300530063031-3035303B303C3041-3096309D-309F30A1-30FA30FC-30FF3105-312D3131-318E31A0-31B731F0-31FF3400-4DB54E00-9FCBA000-A48CA4D0-A4FDA500-A60CA610-A61FA62AA62BA640-A65FA662-A66EA67F-A697A6A0-A6E5A717-A71FA722-A788A78BA78CA7FB-A801A803-A805A807-A80AA80C-A822A840-A873A882-A8B3A8F2-A8F7A8FBA90A-A925A930-A946A960-A97CA984-A9B2A9CFAA00-AA28AA40-AA42AA44-AA4BAA60-AA76AA7AAA80-AAAFAAB1AAB5AAB6AAB9-AABDAAC0AAC2AADB-AADDABC0-ABE2AC00-D7A3D7B0-D7C6D7CB-D7FBF900-FA2DFA30-FA6DFA70-FAD9FB00-FB06FB13-FB17FB1DFB1F-FB28FB2A-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBB1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFBFE70-FE74FE76-FEFCFF21-FF3AFF41-FF5AFF66-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC"
    });

})();

