# Source: internal/AlertRule.js

    ;
    (function($, LiveView, undefined){
    	'use strict';

    	var logger;

    	//Check for required libs/modules
    	if(!LiveView){
    		console.error('LiveView does not exist. Cannot create AlertRule.');
    		return;
    	}
    	else if(!LiveView._internal){
    		console.error('LiveView._internal does not exist. Cannot create sub module AlertRule');
    		return;
    	}
    	else if(!LiveView._internal.Logger){
    		console.error('Logger does not exist. Cannot create sub module AlertRule');
    		return;
    	}

    	//initialize module vars
    	logger = LiveView._internal.Logger;

    	LiveView.AlertRule = (function(){

    		/**
    		 * Object that represents an alert rule.
    		 * @class AlertRule
    		 * @memberOf LiveView
    		 * @param {Object} [settings] Object containing initialization values for the new AlertRule
    		 * @param {Number} [settings.id] The unique identifier for this AlertRule. Note: if an id value is specified for the AlertRule, it will be honored by the server. However, if an AlertRule already exists on the server with the provided id, that alert rule will be overwritten by rule being sent. It is recommended that the id field be left undefined. When adding the rule to the server, the server will assign a new id.
    		 * @param {String} [settings.name] The name of the AlertRule. This can contain spaces and other symbols.
    		 * @param {boolean} [settings.enabled] A flag indicating whether or not the AlertRule is currently enabled (i.e. is it currently being considered when determining whether to fire an alert).
    		 * @param {String} [settings.description] A description of the rule.
    		 * @param {Number} [settings.severity] A number indicating the severity of alerts created by this rule. Higher numbers correspond to a higher degree of severity. By default, the system uses values 1, 3, and 5 to indicate low, medium, and high degrees of severity.
    		 * @param {String} [settings.messageTemplate] A message template that will be filled in with the specified field values of the tuple that caused the alert. Indicate tuple fields in the template by using the $ symbol. For example "Store $storeNumber is running low on $itemName". When the AlertRule is triggered, the field values of the tuple that caused the alert will be substituted in to the corresponding template locations. Field values for this AlertRule may also be referenced in the message template. Fields: Name, Severity, Created, Owner, and ID may all be referenced by using ${AlertRule.fieldName} in the template string (e.g. "Rule ${AlertRule.Name} just fired!").
    		 * @param {Number} [settings.quiescence] If this AlertRule is triggered, quiescence is the number of milliseconds to delay subsequent triggering. This can be useful if this AlertRule triggers frequently once its condition is met and multiple, repeated alerts are undesired. The delay time starts once the actions for the initial trigger have completed.
    		 * @param {Array} [settings.actions] An array of objects that will be parsed into an array of {@link LiveView.AlertRule.Action|Action} objects.
    		 * @param {Object} [settings.alertQueryConfig] An object that will be parsed into into a {@link LiveView.AlertRule.QueryConfig|QueryConfig}. The object should contain fields: predicate, table, predicateDelayInMillis, and queryType.
    		 * @param {String} [settings.status] Indicates whether this AlertRule is in a "valid" or "invalid" state.
    		 * @param {String} [settings.statusMessage] Provides additional details about the current status. If the status is "valid" then statusMessage will just be "OK". If the status is "invalid", the statusMessage will contain more details about why the AlertRule is currently invalid.
    		 * @param {Object} [settings.version] An object that will be parsed into a {@link LiveView.AlertRule.Version|Version}. The object should contain fields: number and string.
    		 * @param {String} [settings.owner] The username of the owner of this AlertRule.
    		 * @param {String} [settings.lastUpdated] A date/time string of the last time this AlertRule was updated.
    		 * @param {String} [settings.type] A string to specify the type of alert (time based or query based).
    		 * @param {String} [settings.cronString] A cron string that defines the behavior of a time based alert.
    		 */
    		function AlertRule(settings){
    			if(!(this instanceof AlertRule)){
    				return new AlertRule(settings);
    			}
    			settings = settings || {};
    			/**
    			 * The unique identifier for this AlertRule. Note: if an id value is specified for the AlertRule, it will be honored by the server. However, if an AlertRule already exists on the server with the provided id, that alert rule will be overwritten by rule being sent. It is recommended that the id field be left undefined. When adding the rule to the server, the server will assign a new id.
    			 * @memberOf LiveView.AlertRule
    			 * @instance
    			 * @member {Number} id
    			 */
    			this.id = settings.id; //id can/should be undefined if creating a new one to add to the server
    			/**
    			 * The name of the AlertRule. This can contain spaces and other symbols.
    			 * @memberOf LiveView.AlertRule
    			 * @instance
    			 * @member {String} name
    			 */
    			this.name = settings.name || '';
    			/**
    			 * A flag indicating whether or not the AlertRule is currently enabled (i.e. is it currently being considered when determining whether to fire an alert).
    			 * @memberOf LiveView.AlertRule
    			 * @instance
    			 * @member {boolean} enabled
    			 */
    			this.enabled = settings.enabled === true;
    			/**
    			 * A description of the rule.
    			 * @memberOf LiveView.AlertRule
    			 * @instance
    			 * @member {String} description
    			 */
    			this.description = settings.description || '';
    			/**
    			 * A number indicating the severity of alerts created by this rule. Higher numbers correspond to a higher degree of severity. By default, the system uses values 1, 3, and 5 to indicate low, medium, and high degrees of severity.
    			 * @memberOf LiveView.AlertRule
    			 * @instance
    			 * @member {Number} severity
    			 */
    			this.severity = isNaN(settings.severity) === false ? settings.severity:1;
    			/**
    			 * A message template that will be filled in with the specified field values of the tuple that caused the alert. Indicate tuple fields in the template by using the $ symbol. For example "Store $storeNumber is running low on $itemName". When the AlertRule is triggered, the field values of the tuple that caused the alert will be substituted in to the corresponding template locations. Field values for this AlertRule may also be referenced in the message template. Fields: Name, Severity, Created, Owner, and ID may all be referenced by using ${AlertRule.fieldName} in the template string (e.g. "Rule ${AlertRule.Name} just fired!").
    			 * @memberOf LiveView.AlertRule
    			 * @instance
    			 * @member {String} messageTemplate
    			 */
    			this.messageTemplate = settings.messageTemplate || settings.message_template || '';
    			/**
    			 * If this AlertRule is triggered, quiescence is the number of milliseconds to delay subsequent triggering. This can be useful if this AlertRule triggers frequently once its condition is met and multiple, repeated alerts are undesired. The delay time starts once the actions for the initial trigger have completed.
    			 * @memberOf LiveView.AlertRule
    			 * @instance
    			 * @member {Number} quiescence
    			 */
    			this.quiescence = isNaN(settings.quiescence) === false ? settings.quiescence:0;
    			/**
    			 * The {@link LiveView.AlertRule.Action|actions} that will execute when this AlertRule is triggered.
    			 * @memberOf LiveView.AlertRule
    			 * @instance
    			 * @member {Array} actions
    			 */
    			this.actions = parseActions(settings.actions);
    			/**
    			 * The query configuration defines the conditions under which this AlertRule will fire an alert.
    			 * @memberOf LiveView.AlertRule
    			 * @instance
    			 * @member {LiveView.AlertRule.QueryConfig} alertQueryConfig
    			 */
    			this.alertQueryConfig = new AlertRule.QueryConfig(settings.alertQueryConfig || settings.alert_query_config);

    			/**
    			 * Indicates whether this AlertRule is in a "valid" or "invalid" state.
    			 * @memberOf LiveView.AlertRule
    			 * @instance
    			 * @member {String} status
    			 */
    			this.status = settings.status || '';
    			/**
    			 * Provides additional details about the current status. If the status is "valid" then statusMessage will just be "OK". If the status is "invalid", the statusMessage will contain more details about why the AlertRule is currently invalid.
    			 * @memberOf LiveView.AlertRule
    			 * @instance
    			 * @member {String} statusMessage
    			 */
    			this.statusMessage = settings.statusMessage || settings.status_message || '';

    			/**
    			 * The version object that has details about the version of this AlertRule.
    			 * @memberOf LiveView.AlertRule
    			 * @instance
    			 * @member {LiveView.AlertRule.Version} version
    			 */
    			this.version = new AlertRule.Version(settings.version);
    			/**
    			 * The username of the owner of this AlertRule.
    			 * @memberOf LiveView.AlertRule
    			 * @instance
    			 * @member {String} owner
    			 */
    			this.owner = settings.owner || '';
    			/**
    			 * A date/time string of the last time this AlertRule was updated.
    			 * @memberOf LiveView.AlertRule
    			 * @instance
    			 * @member {String} lastUpdated
    			 */
    			this.lastUpdated = settings.lastUpdated || settings.last_updated || '';
    			/**
    			 * A date/time string of when this AlertRule was created.
    			 * @memberOf LiveView.AlertRule
    			 * @instance
    			 * @member {String} created
    			 */
    			this.created = settings.created || '';
    			/**
    			 * A enumerated string that specifies whether an alert will be a query based alert or a time based alert.
    			 * In the case of a query based alert, the string should be "query-alert". In the case of a time based alert,
    			 * the string should be "cron-alert".
    			 *
    			 * @memberOf LiveView.AlertRule
    			 * @instance
    			 * @member {String} type
    			 *
                 */
    			this.type = settings.type || '';
    			/**
    			 * In the case of a time based alert, this string specifies the behavior of the time based alert.
    			 * Please see {@link http://www.quartz-scheduler.org/api/2.2.1/org/quartz/CronExpression.html | Quartz Scheduler} for documentation.
    			 *
    			 * @memberOf LiveView.AlertRule
    			 * @instance
    			 * @member {String} cronString
                 */
    			this.cronString = settings.cronString || settings.cron_string || '';

    			//in query config
    //			this.table = settings.table || '';
    //			this.condition = settings.condition || '';

    			//never observed
    //			this.persistedVersion = settings.persistedVersion || '';
    		}

    		AlertRule.prototype = {
    			constructor: AlertRule,
    			toServerObj: function(){
    				return {
    					id: this.id,
    					name: this.name,
    					enabled: this.enabled,
    					description: this.description,
    					severity: this.severity,
    					message_template: this.messageTemplate,
    					quiescence: this.quiescence,
    					actions: serializeActions(this.actions),
    					alert_query_config: this.alertQueryConfig == null ? null : this.alertQueryConfig.toServerObj(),
    					owner: this.owner,
    					status: this.status,
    					status_message: this.status_message,
    					version: this.version.toServerObj(),
    					last_updated: this.lastUpdated,
    					created: this.created,
    					type: this.type,
    					cron_string: this.cronString,
    					xmlSerialize: function(){
    						return {
    							xmlElement: 'alert-rule',
    							attributes: [
    								'id',
    								'name',
    								'enabled',
    								'description',
    								'severity',
    								'quiescence',
    								'owner',
    								'status',
    								'status-message',
    								'last-updated',
    								'created'
    							],
    							children: [
    								'type',
    								'message-template',
    								'alert-query-config',
    								'actions',
    								'version',
    								'cron-string'
    							]
    						};
    					}
    				};
    			}
    		};

    		return AlertRule;
    	})();

    	/**
    	 * Contains fields that determine when an AlertRule should trigger.
    	 * @class QueryConfig
    	 * @memberOf LiveView.AlertRule
    	 * @param {Object} [settings] An object containing initial values for the new QueryConfig instance.
    	 * @param {String} [settings.predicate] The predicate of the query that will execute to determine whether or not to trigger this AlertRule. The predicate can be thought of as the condition under which the AlertRule should fire. The format should follow the LiveQL specification. An example predicate might be: <span style="lvCode">"category='toy' and quantityRemaining < 40"</span>.
    	 * @param {String} [settings.projection] The projection of the query will execute to determine in the case of an aggregate query to determine the aggregate condition.
    	 * @param {Number} [settings.predicateDelayInMillis] The predicate delay time specifies how long the predicate condition must be true before triggering the AlertRule.
    	 * @param {String} [settings.queryType] Indicates what type of query will be executed to evaluate the AlertRule condition. Possible values include: SNAPSHOT, SNAPSHOT_AND_CONTINUOUS, CONTINUOUS, and DELETE.
    	 * @param {String} [settings.table] The name of the LiveView table that the AlertRule will be monitoring.
    	 */
    	LiveView.AlertRule.QueryConfig = function(settings){
    		if(!(this instanceof LiveView.AlertRule.QueryConfig)){
    			return new LiveView.AlertRule.QueryConfig(settings);
    		}
    		settings = settings || {};
    		/**
    		 * The predicate of the query that will execute to determine whether or not to trigger this AlertRule. The predicate can be thought of as the condition under which the AlertRule should fire. The format should follow the LiveQL specification. An example predicate might be: <span style="lvCode">"category='toy' and quantityRemaining < 40"</span>.
    		 * @memberOf LiveView.AlertRule.QueryConfig
    		 * @instance
    		 * @member {String} predicate
    		 */
    		this.predicate = settings.predicate || '';
    		/**
    		 * The projection of the query will execute in the case of an aggregate query to determine the aggregate condition.
    		 * @memberOf LiveView.AlertRule.QueryConfig
    		 * @instance
    		 * @member {String} projection
    		 */
    		this.projection = settings.projection || '';
    		/**
    		 * The predicate delay time specifies how long the predicate condition must be true before triggering the AlertRule.
    		 * @memberOf LiveView.AlertRule.QueryConfig
    		 * @instance
    		 * @member {Number} predicateDelayInMillis
    		 */
    		this.predicateDelayInMillis = settings.predicateDelayInMillis || settings.predicate_delay_in_millis || 0; //action execution delay
    		/**
    		 * Indicates what type of query will be executed to evaluate the AlertRule condition. Possible values include: SNAPSHOT, SNAPSHOT_AND_CONTINUOUS, CONTINUOUS, and DELETE.
    		 * @memberOf LiveView.AlertRule.QueryConfig
    		 * @instance
    		 * @member {String} queryType
    		 */
    		this.queryType = settings.queryType || settings.query_type || '';
    		/**
    		 * The name of the LiveView table that the AlertRule will be monitoring.
    		 * @memberOf LiveView.AlertRule.QueryConfig
    		 * @instance
    		 * @member {String} table
    		 */
    		this.table = settings.table || '';
    	};
    	LiveView.AlertRule.QueryConfig.prototype = {
    		constructor: LiveView.AlertRule.QueryConfig,
    		toServerObj: function(){
    			return {
    				predicate: this.predicate,
    				projection: this.projection,
    				predicate_delay_in_millis: this.predicateDelayInMillis,
    				query_type: this.queryType,
    				table: this.table,
    				xmlSerialize: function(){
    					return {
    						xmlElement: 'alert-query-config',
    						attributes: [
    							'predicate-delay-in-millis',
    							'query-type',
    							'table'
    						],
    						children: [
    							'predicate',
    							'projection'
    						]
    					};
    				}
    			};
    		}
    	};

    	/**
    	 * Contains fields that provide details about an AlertRule's version.
    	 * @class Version
    	 * @memberOf LiveView.AlertRule
    	 * @param {Object} [settings] An object containing initial values for the new Version instance.
    	 * @param {Number} [settings.number] The version number.
    	 * @param {Object} [settings.string] A full-length string identifying the version.
    	 */
    	LiveView.AlertRule.Version = function(settings){
    		if(!(this instanceof LiveView.AlertRule.Version)){
    			return new LiveView.AlertRule.Version(settings);
    		}
    		settings = settings || {};
    		/**
    		 * The version number.
    		 * @memberOf LiveView.AlertRule.Version
    		 * @instance
    		 * @member {Number} number
    		 */
    		this.number = isNaN(settings.number) === true ? (isNaN(settings.version_number) ? settings.version_number:0):settings.number;
    		/**
    		 * A full-length string identifying the version.
    		 * @memberOf LiveView.AlertRule.Version
    		 * @instance
    		 * @member {String} string
    		 */
    		this.string = settings.string || settings.version_string || '';
    	};
    	LiveView.AlertRule.Version.prototype = {
    		constructor: LiveView.AlertRule.Version,
    		toServerObj: function(){
    			return {
    				version_number: this.number,
    				version_string: this.string,
    				xmlSerialize: function(){
    					return {
    						xmlElement: 'version-type',
    						attributes: [
    							'version-number',
    							'version-string'
    						],
    						children: []
    					};
    				}
    			};
    		}
    	};

    	/**
    	 * The base object for AlertRule actions.
    	 * @class Action
    	 * @memberOf LiveView.AlertRule
    	 * @param {Object} [settings] An object containing initial values for the new Action instance.
    	 * @param {boolean} [settings.enabled] Flag indicating whether or not the Action is enabled (i.e. currently being used to determine whether or not to fire alerts).
    	 */
    	LiveView.AlertRule.Action = function(settings){
    		if(!(this instanceof LiveView.AlertRule.Action)){
    			return new LiveView.AlertRule.Action(settings);
    		}
    		settings = settings || {};
    		/**
    		 * Flag indicating whether or not the Action is enabled (i.e. currently being used to determine whether or not to fire alerts).
    		 * @memberOf LiveView.AlertRule.Action
    		 * @instance
    		 * @member {boolean} enabled
    		 */
    		this.enabled = settings.enabled === true;
    	};
    	LiveView.AlertRule.Action.prototype = {
    		constructor: LiveView.AlertRule.Action
    	};

    	/**
    	 * Action that will delete rows described by the query predicate in the specified table.
    	 * @class DeleteRowsAction
    	 * @extends LiveView.AlertRule.Action
    	 * @memberOf LiveView.AlertRule
    	 * @param {Object} [settings] An object containing initial values for the new DeleteRowsAction instance.
    	 * @param {String} [settings.queryPredicate] The query predicate that will be used to select which rows to delete.
    	 * @param {String} [settings.tableName] The name of the table from which rows should be removed.
    	 */
    	LiveView.AlertRule.DeleteRowsAction = function(settings){
    		if(!(this instanceof LiveView.AlertRule.DeleteRowsAction)){
    			return new LiveView.AlertRule.DeleteRowsAction(settings);
    		}
    		settings = settings || {};
    		LiveView.AlertRule.Action.call(this, settings);
    		/**
    		 * The name of the table from which rows should be removed.
    		 * @memberOf LiveView.AlertRule.DeleteRowsAction
    		 * @instance
    		 * @member {String} tableName
    		 */
    		this.tableName = settings.tableName || settings.table || '';
    		/**
    		 * The query predicate that will be used to select which rows to delete.
    		 * @memberOf LiveView.AlertRule.DeleteRowsAction
    		 * @instance
    		 * @member {String} queryPredicate
    		 */
    		this.queryPredicate = settings.queryPredicate || settings.delete_predicate || '';
    	};
    	LiveView.AlertRule.DeleteRowsAction.prototype = $.extend(
    		new LiveView.AlertRule.Action(),
    		{
    			constructor: LiveView.AlertRule.DeleteRowsAction,
    			toServerObj: function(){
    				return {
    					enabled: this.enabled,
    					delete_alert: {
    						table: this.tableName,
    						delete_predicate: this.queryPredicate,
    						xmlSerialize: function(){
    							return {
    								xmlElement: 'delete-alert',
    								children: ['table', 'delete-predicate'],
    								attributes: []
    							}
    						}
    					},
    					xmlSerialize: function(){
    						return {
    							xmlElement: 'action',
    							children: ['delete_alert'],
    							attributes: ['enabled']
    						}
    					}
    				};
    			}
    		}
    	);

    	/**
    	 * Action that will execute Java code on the LiveView server.
    	 * @class ExecJavaAction
    	 * @extends LiveView.AlertRule.Action
    	 * @memberOf LiveView.AlertRule
    	 * @param {Object} [settings] An object containing initial values for the new ExecJavaAction instance.
    	 * @param {String} [settings.class] The Java class name that will perform the action.
    	 * @param {Object} [settings.parameters] A key-value map of parameters to apply when invoking the action.
    	 */
    	LiveView.AlertRule.ExecJavaAction = function(settings){
    		if(!(this instanceof LiveView.AlertRule.ExecJavaAction)){
    			return new LiveView.AlertRule.ExecJavaAction(settings);
    		}
    		settings = settings || {};
    		LiveView.AlertRule.Action.call(this, settings);
    		/**
    		 * The Java class name that will perform the action.
    		 * @memberOf LiveView.AlertRule.ExecJavaAction
    		 * @instance
    		 * @member {String} class
    		 */
    		this.class = settings.class || '';
    		/**
    		 * A key-value map of parameters to apply when invoking the action.
    		 * @memberOf LiveView.AlertRule.ExecJavaAction
    		 * @instance
    		 * @member {Object} parameters
    		 */
    		this.parameters = settings.parameters || {};
    		if(this.parameters.parameter && this.parameters.parameter.length){
    			this.parameters = parseFieldSubstitutions(this.parameters.parameter, 'key', '#CDATA');
    		}
    	};
    	LiveView.AlertRule.ExecJavaAction.prototype = $.extend(
    		new LiveView.AlertRule.Action(),
    		{
    			constructor: LiveView.AlertRule.ExecJavaAction,
    			toServerObj: function(){
    				return {
    					enabled: this.enabled,
    					exec_java: {
    						class: this.class,
    						parameters: serializeParameters(this.parameters),
    						xmlSerialize: function(){
    							return {
    								xmlElement: 'exec-java',
    								children: ['parameters'],
    								attributes: ['class']
    							}
    						}
    					},
    					xmlSerialize: function(){
    						return {
    							xmlElement: 'action',
    							children: ['exec_java'],
    							attributes: ['enabled']
    						}
    					}
    				};
    			}
    		}
    	);
    	/**
    	 * Action that will execute an operating system command on the LiveView server.
    	 * @class ExecOsCommandAction
    	 * @extends LiveView.AlertRule.Action
    	 * @memberOf LiveView.AlertRule
    	 * @param {Object} [settings] An object containing initial values for the new ExecOsCommandAction instance.
    	 * @param {String} [settings.command] The command to issue to the server operating system.
    	 * @param {Object} [settings.parameters] A map of parameter name -> parameter value to be applied to the commmand.
    	 */
    	LiveView.AlertRule.ExecOsCommandAction = function(settings){
    		if(!(this instanceof LiveView.AlertRule.ExecOsCommandAction)){
    			return new LiveView.AlertRule.ExecOsCommandAction(settings);
    		}
    		settings = settings || {};
    		LiveView.AlertRule.Action.call(this, settings);
    		/**
    		 * The command to issue to the server operating system.
    		 * @memberOf LiveView.AlertRule.ExecOsCommandAction
    		 * @instance
    		 * @member {String} command
    		 */
    		this.command = settings.command || '';
    		/**
    		 * A map of parameter name -> parameter value to be applied to the commmand.
    		 * @memberOf LiveView.AlertRule.ExecOsCommandAction
    		 * @instance
    		 * @member {Object} parameters
    		 */
    		this.parameters = settings.parameters || {};
    	};
    	LiveView.AlertRule.ExecOsCommandAction.prototype = $.extend(
    		new LiveView.AlertRule.Action(),
    		{
    			constructor: LiveView.AlertRule.ExecOsCommandAction,
    			toServerObj: function(){
    				var key, command;
    				command = this.command.trim();
    				for(key in this.parameters){
    					if(this.parameters.hasOwnProperty(key)){
    						command += ' ' + key + ' ' + this.parameters[key];
    					}
    				}
    				return {
    					enabled: this.enabled,
    					exec_os_command: {
    						command: command,
    						xmlSerialize: function(){
    							return {
    								xmlElement: 'exec-os-command',
    								attributes: [],
    								children: ['command']
    							}
    						}
    					},
    					xmlSerialize: function(){
    						return {
    							xmlElement: 'action',
    							children: ['exec_os_command'],
    							attributes: ['enabled']
    						}
    					}
    				};
    			}
    		}
    	);

    	/**
    	 * Action that will send a tuple to a LiveView server.
    	 * @class LVPublishAction
    	 * @extends LiveView.AlertRule.Action
    	 * @memberOf LiveView.AlertRule
    	 * @param {Object} [settings] An object containing initial values for the new LVPublishAction instance.
    	 * @param {Object} [settings.fieldSubstitutions] A map of field name to field value. Field values may refer to field values of the tuple that triggered this AlertRule or to properties of this AlertRule. Indicate tuple field values in the template by using the $ symbol. For example "Category"->"$category" would create a field called "Category" whose value is set to the category field value of the AlertRule-triggering tuple. The properties of this AlertRule may also be referenced in the message template. Fields: Name, Severity, Created, Owner, and ID may all be referenced by using ${AlertRule.fieldName} in the template string (e.g. ${AlertRule.Name}).
    	 * @param {String} [settings.lvUri] The LiveView URI destination for the tuple.
    	 * @param {String} [settings.inputStream] The name of the table where the tuple will be sent.
    	 */
    	LiveView.AlertRule.LVPublishAction = function(settings){
    		if(!(this instanceof LiveView.AlertRule.LVPublishAction)){
    			return new LiveView.AlertRule.LVPublishAction(settings);
    		}
    		settings = settings || {};
    		LiveView.AlertRule.Action.call(this, settings);
    		/**
    		 * A map of field name to field value. Field values may refer to field values of the tuple that triggered this AlertRule or to properties of this AlertRule. Indicate tuple field values in the template by using the $ symbol. For example "Category"->"$category" would create a field called "Category" whose value is set to the category field value of the AlertRule-triggering tuple. The properties of this AlertRule may also be referenced in the message template. Fields: Name, Severity, Created, Owner, and ID may all be referenced by using ${AlertRule.fieldName} in the template string (e.g. ${AlertRule.Name}).
    		 * @memberOf LiveView.AlertRule.LVPublishAction
    		 * @instance
    		 * @member {Object} fieldSubstitutions
    		 */
    		this.fieldSubstitutions = settings.fieldSubstitutions || settings.field_substitutions || {};
    		if(this.fieldSubstitutions.field && this.fieldSubstitutions.field.length){
    			this.fieldSubstitutions = parseFieldSubstitutions(this.fieldSubstitutions.field, 'id', '#CDATA');
    		}
    		/**
    		 * The LiveView URI destination for the tuple.
    		 * @memberOf LiveView.AlertRule.LVPublishAction
    		 * @instance
    		 * @member {String} sbUri
    		 */
    		this.lvUri = settings.lvUri || settings.lv_uri || '';
    		/**
    		 * The name of the table where the tuple will be sent.
    		 * @memberOf LiveView.AlertRule.LVPublishAction
    		 * @instance
    		 * @member {String} tableName
    		 */
    		this.tableName = settings.tableName || settings.table_name || '';
    	};
    	LiveView.AlertRule.LVPublishAction.prototype = $.extend(
    		new LiveView.AlertRule.Action(),
    		{
    			constructor: LiveView.AlertRule.LVPublishAction,
    			toServerObj: function(){
    				return {
    					enabled: this.enabled,
    					lv_publish_alert: {
    						field_substitutions: serializeFieldSubstitutions(this.fieldSubstitutions),
    						lv_uri: this.lvUri,
    						table_name: this.tableName,
    						xmlSerialize: function(){
    							return {
    								xmlElement: 'lv-publish-alert',
    								attributes: ['lv-uri', 'table-name'],
    								children: ['field-substitutions'],
    								getChildName: function(elementName){
    									return elementName == 'field-substitutions' ? 'field' : elementName;
    								}
    							}
    						}
    					},
    					xmlSerialize: function(){
    						return {
    							xmlElement: 'action',
    							children: ['lv_publish_alert'],
    							attributes: ['enabled']
    						}
    					}
    				};
    			}
    		}
    	);

    	/**
    	 * Action that will publish a LiveView Alert.
    	 * @class PublishAlertAction
    	 * @extends LiveView.AlertRule.Action
    	 * @memberOf LiveView.AlertRule
    	 * @param {Object} [settings] An object containing initial values for the new PublishAlertAction instance.
    	 * @param {Object} [settings.fieldSubstitutions] A key-value map that maps a tuple field name to place holder string. For example "category":"$category".
    	 * @param {String} [settings.messageTemplate] A message template that will be filled in using the values in the fieldSubstitutions map.
    	 * @param {String} [settings.alertKey] A parametrized string identifier for the Alert.
    	 * @param {String} [settings.alertRecipient] The username of an intended recipient of the alert. The default is "*" to indicate "anyone".
    	 */
    	LiveView.AlertRule.PublishAlertAction = function(settings){
    		if(!(this instanceof LiveView.AlertRule.PublishAlertAction)){
    			return new LiveView.AlertRule.PublishAlertAction(settings);
    		}
    		settings = settings || {};
    		LiveView.AlertRule.Action.call(this, settings);
    		/**
    		 * A key-value map of field name to place holder string. For example "category":"$category".
    		 * @memberOf LiveView.AlertRule.PublishAlertAction
    		 * @instance
    		 * @member {Object} fieldSubstitutions
    		 */
    		this.fieldSubstitutions = settings.fieldSubstitutions || settings.field_substitutions || {};
    		if(this.fieldSubstitutions.field && this.fieldSubstitutions.field.length){
    			this.fieldSubstitutions = parseFieldSubstitutions(this.fieldSubstitutions.field, 'id', '#CDATA');
    		}
    		/**
    		 * A message template that will be filled in using the values in the fieldSubstitutions map.
    		 * @memberOf LiveView.AlertRule.PublishAlertAction
    		 * @instance
    		 * @member {String} messageTemplate
    		 */
    		this.messageTemplate = settings.messageTemplate || settings.message_template || '';
    		/**
    		 * A parametrized string identifier for the Alert
    		 * @memberOf LiveView.AlertRule.PublishAlertAction
    		 * @instance
    		 * @member {String} alertKey
    		 */
    		this.alertKey = settings.alertKey || settings.alert_key || null;
    		/**
    		 * The username of an intended recipient of the alert. The default is "*" to indicate "anyone".
    		 * @memberOf LiveView.AlertRule.PublishAlertAction
    		 * @instance
    		 * @member {String} alertRecipient
    		 */
    		this.alertRecipient = settings.alertRecipient || settings.alert_recipient || '';
    	};
    	LiveView.AlertRule.PublishAlertAction.prototype = $.extend(
    		new LiveView.AlertRule.Action(),
    		{
    			constructor: LiveView.AlertRule.PublishAlertAction,
    			toServerObj: function(){
    				return {
    					enabled: this.enabled,
    					publish_alert: {
    						field_substitutions: serializeFieldSubstitutions(this.fieldSubstitutions),
    						message_template: this.messageTemplate,
    						alert_key: this.alertKey,
    						alert_recipient: this.alertRecipient,
    						xmlSerialize: function(){
    							return {
    								xmlElement: 'publish-alert',
    								attributes: ['alert-recipient', 'alert-table', 'alert-key'],
    								children: ['message-template', 'field-substitutions'],
    								getChildName: function(elementName){
    									return elementName == 'field-substitutions' ? 'field' : elementName;
    								}
    							}
    						}
    					},
    					xmlSerialize: function(){
    						return {
    							xmlElement: 'action',
    							children: ['publish_alert'],
    							attributes: ['enabled']
    						}
    					}
    				};
    			}
    		}
    	);

    	/**
    	 * Action that will send an Email.
    	 * @class SendEmailAction
    	 * @extends LiveView.AlertRule.Action
    	 * @memberOf LiveView.AlertRule
    	 * @param {Object} [settings] An object containing initial values for the new SendEmailAction instance.
    	 * @param {String} [settings.subject] The email subject line.
    	 * @param {String} [settings.body] The email body content.
    	 * @param {Array} [settings.to] An array of recipient email addresses.
    	 * @param {Array} [settings.cc] An array of cc recipient email addresses.
    	 * @param {Array} [settings.bcc] An array of bcc recipient email addresses.
    	 */
    	LiveView.AlertRule.SendEmailAction = function(settings){
    		if(!(this instanceof LiveView.AlertRule.SendEmailAction)){
    			return new LiveView.AlertRule.SendEmailAction(settings);
    		}
    		settings = settings || {};
    		LiveView.AlertRule.Action.call(this, settings);
    		/**
    		 * The email subject line.
    		 * @memberOf LiveView.AlertRule.SendEmailAction
    		 * @instance
    		 * @member {String} subject
    		 */
    		this.subject = settings.subject || '';
    		/**
    		 * The email body content.
    		 * @memberOf LiveView.AlertRule.SendEmailAction
    		 * @instance
    		 * @member {String} body
    		 */
    		this.body = settings.body || '';
    		/**
    		 * An array of recipient email addresses.
    		 * @memberOf LiveView.AlertRule.SendEmailAction
    		 * @instance
    		 * @member {Array} to
    		 */
    		this.to = settings.to || [];
    		/**
    		 * An array of cc recipient email addresses.
    		 * @memberOf LiveView.AlertRule.SendEmailAction
    		 * @instance
    		 * @member {Array} cc
    		 */
    		this.cc = settings.cc || [];
    		/**
    		 * An array of bcc recipient email addresses.
    		 * @memberOf LiveView.AlertRule.SendEmailAction
    		 * @instance
    		 * @member {Array} bcc
    		 */
    		this.bcc = settings.bcc || [];
    	};
    	LiveView.AlertRule.SendEmailAction.prototype = $.extend(
    		new LiveView.AlertRule.Action(),
    		{
    			constructor: LiveView.AlertRule.SendEmailAction,
    			toServerObj: function(){
    				return {
    					enabled: this.enabled,
    					send_email: {
    						to: this.to,
    						cc: this.cc,
    						bcc: this.bcc,
    						subject: this.subject,
    						body: this.body,
    						xmlSerialize: function(){
    							return {
    								xmlElement: 'send-email',
    								children: [
    									"subject",
    									"to",
    									"cc",
    									"bcc",
    									"body"
    								],
    								excludeParentArrayElement: function(o, elementName){
    									return ["to","cc","bcc"].indexOf(elementName) >= 0;
    								},
    								getChildName: function(elementName){
    									return this.excludeParentArrayElement(null, elementName) ? elementName : null;
    								}
    							}
    						}
    					},
    					xmlSerialize: function(){
    						return {
    							xmlElement: 'action',
    							children: ['send_email'],
    							attributes: ['enabled']
    						}
    					}
    				};
    			}
    		}
    	);

    	/**
    	 * Action that will send a tuple to a StreamBase server.
    	 * @class SendTupleAction
    	 * @extends LiveView.AlertRule.Action
    	 * @memberOf LiveView.AlertRule
    	 * @param {Object} [settings] An object containing initial values for the new SendTupleAction instance.
    	 * @param {Object} [settings.fieldSubstitutions] A map of field name to field value. Field values may refer to field values of the tuple that triggered this AlertRule or to properties of this AlertRule. Indicate tuple field values in the template by using the $ symbol. For example "Category"->"$category" would create a field called "Category" whose value is set to the category field value of the AlertRule-triggering tuple. The properties of this AlertRule may also be referenced in the message template. Fields: Name, Severity, Created, Owner, and ID may all be referenced by using ${AlertRule.fieldName} in the template string (e.g. ${AlertRule.Name}).
    	 * @param {String} [settings.sbUri] The StreamBase URI destination for the tuple.
    	 * @param {String} [settings.inputStream] The name of the stream to send the tuple to.
    	 */
    	LiveView.AlertRule.SendTupleAction = function(settings){
    		if(!(this instanceof LiveView.AlertRule.SendTupleAction)){
    			return new LiveView.AlertRule.SendTupleAction(settings);
    		}
    		settings = settings || {};
    		LiveView.AlertRule.Action.call(this, settings);
    		/**
    		 * A map of field name to field value. Field values may refer to field values of the tuple that triggered this AlertRule or to properties of this AlertRule. Indicate tuple field values in the template by using the $ symbol. For example "Category"->"$category" would create a field called "Category" whose value is set to the category field value of the AlertRule-triggering tuple. The properties of this AlertRule may also be referenced in the message template. Fields: Name, Severity, Created, Owner, and ID may all be referenced by using ${AlertRule.fieldName} in the template string (e.g. ${AlertRule.Name}).
    		 * @memberOf LiveView.AlertRule.SendTupleAction
    		 * @instance
    		 * @member {Object} fieldSubstitutions
    		 */
    		this.fieldSubstitutions = settings.fieldSubstitutions || settings.field_substitutions || {};
    		if(this.fieldSubstitutions.field && this.fieldSubstitutions.field.length){
    			this.fieldSubstitutions = parseFieldSubstitutions(this.fieldSubstitutions.field, 'id', '#CDATA');
    		}
    		/**
    		 * The StreamBase URI destination for the tuple.
    		 * @memberOf LiveView.AlertRule.SendTupleAction
    		 * @instance
    		 * @member {String} sbUri
    		 */
    		this.sbUri = settings.sbUri || settings.sb_uri || '';
    		/**
    		 * The name of the stream to send the tuple to.
    		 * @memberOf LiveView.AlertRule.SendTupleAction
    		 * @instance
    		 * @member {String} inputStream
    		 */
    		this.inputStream = settings.inputStream || settings.input_stream || '';
    	};
    	LiveView.AlertRule.SendTupleAction.prototype = $.extend(
    		new LiveView.AlertRule.Action(),
    		{
    			constructor: LiveView.AlertRule.SendTupleAction,
    			toServerObj: function(){
    				return {
    					enabled: this.enabled,
    					send_tuple: {
    						field_substitutions: serializeFieldSubstitutions(this.fieldSubstitutions),
    						sb_uri: this.sbUri,
    						input_stream: this.inputStream,
    						xmlSerialize: function(){
    							return {
    								xmlElement: 'send-tuple',
    								attributes: ['sb-uri', 'input-stream'],
    								children: ['field-substitutions'],
    								getChildName: function(elementName){
    									return elementName == 'field-substitutions' ? 'field' : elementName;
    								}
    							}
    						}
    					},
    					xmlSerialize: function(){
    						return {
    							xmlElement: 'action',
    							children: ['send_tuple'],
    							attributes: ['enabled']
    						}
    					}
    				};
    			}
    		}
    	);

    	/**
    	 * Action that will send a tuple to a LiveView server.
    	 * @class LVPublishAction
    	 * @extends LiveView.AlertRule.Action
    	 * @memberOf LiveView.AlertRule
    	 * @param {Object} [settings] An object containing initial values for the new LVPublishAction instance.
    	 * @param {Object} [settings.fieldSubstitutions] A map of field name to field value. Field values may refer to field values of the tuple that triggered this AlertRule or to properties of this AlertRule. Indicate tuple field values in the template by using the $ symbol. For example "Category"->"$category" would create a field called "Category" whose value is set to the category field value of the AlertRule-triggering tuple. The properties of this AlertRule may also be referenced in the message template. Fields: Name, Severity, Created, Owner, and ID may all be referenced by using ${AlertRule.fieldName} in the template string (e.g. ${AlertRule.Name}).
    	 * @param {String} [settings.lvUri] The LiveView URI destination for the tuple.
    	 * @param {String} [settings.inputStream] The name of the table where the tuple will be sent.
    	 */
    	LiveView.AlertRule.LVPublishAction = function(settings){
    		if(!(this instanceof LiveView.AlertRule.LVPublishAction)){
    			return new LiveView.AlertRule.LVPublishAction(settings);
    		}
    		settings = settings || {};
    		LiveView.AlertRule.Action.call(this, settings);
    		/**
    		 * A map of field name to field value. Field values may refer to field values of the tuple that triggered this AlertRule or to properties of this AlertRule. Indicate tuple field values in the template by using the $ symbol. For example "Category"->"$category" would create a field called "Category" whose value is set to the category field value of the AlertRule-triggering tuple. The properties of this AlertRule may also be referenced in the message template. Fields: Name, Severity, Created, Owner, and ID may all be referenced by using ${AlertRule.fieldName} in the template string (e.g. ${AlertRule.Name}).
    		 * @memberOf LiveView.AlertRule.LVPublishAction
    		 * @instance
    		 * @member {Object} fieldSubstitutions
    		 */
    		this.fieldSubstitutions = settings.fieldSubstitutions || settings.field_substitutions || {};
    		if(this.fieldSubstitutions.field && this.fieldSubstitutions.field.length){
    			this.fieldSubstitutions = parseFieldSubstitutions(this.fieldSubstitutions.field, 'id', '#CDATA');
    		}
    		/**
    		 * The LiveView URI destination for the tuple.
    		 * @memberOf LiveView.AlertRule.LVPublishAction
    		 * @instance
    		 * @member {String} sbUri
    		 */
    		this.lvUri = settings.lvUri || settings.lv_uri || '';
    		/**
    		 * The name of the table where the tuple will be sent.
    		 * @memberOf LiveView.AlertRule.LVPublishAction
    		 * @instance
    		 * @member {String} tableName
    		 */
    		this.tableName = settings.tableName || settings.table_name || '';
    	};
    	LiveView.AlertRule.LVPublishAction.prototype = $.extend(
    		new LiveView.AlertRule.Action(),
    		{
    			constructor: LiveView.AlertRule.LVPublishAction,
    			toServerObj: function(){
    				return {
    					enabled: this.enabled,
    					lv_publish_alert: {
    						field_substitutions: serializeFieldSubstitutions(this.fieldSubstitutions),
    						lv_uri: this.lvUri,
    						table_name: this.tableName,
    						xmlSerialize: function(){
    							return {
    								xmlElement: 'lv-publish-alert',
    								attributes: ['lv-uri', 'table-name'],
    								children: ['field-substitutions'],
    								getChildName: function(elementName){
    									return elementName == 'field-substitutions' ? 'field' : elementName;
    								}
    							}
    						}
    					},
    					xmlSerialize: function(){
    						return {
    							xmlElement: 'action',
    							children: ['lv_publish_alert'],
    							attributes: ['enabled']
    						}
    					}
    				};
    			}
    		}
    	);

    	function parseActions(actionObjs){
    		var actions = [], action, i;
    		actionObjs = actionObjs || [];
    		if(actionObjs.action && actionObjs.action.length){
    			actionObjs = actionObjs.action;
    		}
    		for(i = 0; i < actionObjs.length; i++){
    			if(actionObjs[i].exec_os_command){
    				action = new LiveView.AlertRule.ExecOsCommandAction(actionObjs[i].exec_os_command);
    			}
    			else if(actionObjs[i].exec_java){
    				action = new LiveView.AlertRule.ExecJavaAction(actionObjs[i].exec_java);
    			}
    			else if(actionObjs[i].send_email){
    				action = new LiveView.AlertRule.SendEmailAction(actionObjs[i].send_email);
    			}
    			else if(actionObjs[i].publish_alert){
    				action = new LiveView.AlertRule.PublishAlertAction(actionObjs[i].publish_alert);
    			}
    			else if(actionObjs[i].send_tuple){
    				action = new LiveView.AlertRule.SendTupleAction(actionObjs[i].send_tuple);
    			}
    			else if(actionObjs[i].lv_publish_alert){
    				action = new LiveView.AlertRule.LVPublishAction(actionObjs[i].lv_publish_alert);
    			}
    			else if(actionObjs[i].lv_publish_alert){
    				action = new LiveView.AlertRule.LVPublishAction(actionObjs[i].lv_publish_alert);
    			}
    			else if(actionObjs[i].delete_alert){
    				action = new LiveView.AlertRule.DeleteRowsAction(actionObjs[i].delete_alert);
    			}
    			else if(actionObjs[i] instanceof LiveView.AlertRule.Action){
    				action = actionObjs[i];
    			}
    			else{
    				logger.warn('AlertRule parsing error - Unrecognized action type. Action being ignored...');
    				logger.debug('AlertRule.parseActions - action object:', actionObjs[i]);
    				continue;
    			}
    			action.enabled = actionObjs[i].enabled === true;
    			actions.push(action);
    		}
    		return actions;
    	}

    	function serializeActions(actions){
    		var actionObjs = [], i;
    		for(i = 0; i < actions.length; i++){
    			actionObjs.push(actions[i].toServerObj());
    		}
    		return actionObjs;
    	}

    	function parseFieldSubstitutions(source, keyField, valueField){
    		var fSubs = {}, i;
    		keyField = keyField || 'key';
    		valueField = valueField || 'value';
    		for(i = 0; i < source.length; i++){
    			fSubs[source[i][keyField]] = source[i][valueField];
    		}
    		return fSubs;
    	}

    	function serializeFieldSubstitutions(fieldMap){
    		var key, fields = [];
    		for(key in fieldMap){
    			if(fieldMap.hasOwnProperty(key)){
    				fields.push({
    					id: key,
    					value: fieldMap[key],
    					xmlSerialize: function(){
    						return {
    							xmlElement: 'field',
    							text: 'value',
    							attributes: ['id']
    						}
    					}
    				});
    			}
    		}
    		return fields;
    	}

    	function serializeParameters(parameterMap){
    		var key, params = [];
    		for(key in parameterMap){
    			if(parameterMap.hasOwnProperty(key)){
    				params.push({
    					key: key,
    					value: parameterMap[key],
    					xmlSerialize: function(){
    						return {
    							xmlElement: 'parameter',
    							text: 'value',
    							attributes: ['key']
    						}
    					}
    				});
    			}
    		}
    		return params;
    	}

    })(jQuery, window.LiveView);