1 /**
  2  * Cisco Finesse - JavaScript Library
  3  * Version 10.5(1)
  4  * Cisco Systems, Inc.
  5  * http://www.cisco.com/
  6  *
  7  * Portions created or assigned to Cisco Systems, Inc. are
  8  * Copyright (c) 2014 Cisco Systems, Inc. or its affiliated entities.  All Rights Reserved.
  9  */
 10 /**
 11  * This javascript library is made available to Cisco partners and customers as
 12  * a convenience to help minimize the cost of Cisco Finesse customizations.
 13  * This library can be used in Cisco Finesse deployments.  Cisco does not
 14  * permit the use of this library in customer deployments that do not include
 15  * Cisco Finesse.  Support for the javascript library is provided on a
 16  * "best effort" basis via CDN.  Like any custom deployment, it is the
 17  * responsibility of the partner and/or customer to ensure that the
 18  * customization works correctly and this includes ensuring that the Cisco
 19  * Finesse JavaScript is properly integrated into 3rd party applications.
 20  * Cisco reserves the right to make changes to the javascript code and
 21  * corresponding API as part of the normal Cisco Finesse release cycle.  The
 22  * implication of this is that new versions of the javascript might be
 23  * incompatible with applications built on older Finesse integrations.  That
 24  * said, it is Cisco's intention to ensure javascript compatibility across
 25  * versions as much as possible and Cisco will make every effort to clearly
 26  * document any differences in the javascript across versions in the event
 27  * that a backwards compatibility impacting change is made.
 28  */
 29 
 30 /* Simple JavaScript Inheritance
 31  * By John Resig http://ejohn.org/
 32  * MIT Licensed.
 33  */
 34 // Inspired by base2 and Prototype
 35 (function (factory) {
 36     
 37 
 38     // Define as an AMD module if possible
 39     if ( typeof define === 'function' && define.amd )
 40     {
 41         define('../thirdparty/Class',[], factory );
 42     }
 43     
 44     /* Define using browser globals otherwise
 45      * Prevent multiple instantiations if the script is loaded twice
 46      */
 47     else
 48     {
 49         factory();
 50     }
 51 }(function () {
 52     (function(){
 53         var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
 54         // The base Class implementation (does nothing)
 55         /** @private */
 56         this.Class = function(){};
 57         
 58         // Create a new Class that inherits from this class
 59         /** @private */
 60         Class.extend = function(prop) {
 61           var _super = this.prototype;
 62           
 63           // Instantiate a base class (but only create the instance,
 64           // don't run the init constructor)
 65           initializing = true;
 66           var prototype = new this();
 67           initializing = false;
 68           
 69           // Copy the properties over onto the new prototype
 70           for (var name in prop) {
 71             // Check if we're overwriting an existing function
 72             prototype[name] = typeof prop[name] == "function" && 
 73               typeof _super[name] == "function" && fnTest.test(prop[name]) ?
 74               (function(name, fn){
 75                 return function() {
 76                   var tmp = this._super;
 77                   
 78                   // Add a new ._super() method that is the same method
 79                   // but on the super-class
 80                   this._super = _super[name];
 81                   
 82                   // The method only need to be bound temporarily, so we
 83                   // remove it when we're done executing
 84                   var ret = fn.apply(this, arguments);        
 85                   this._super = tmp;
 86                   
 87                   return ret;
 88                 };
 89               })(name, prop[name]) :
 90               prop[name];
 91           }
 92           
 93           // The dummy class constructor
 94           /** @private */
 95           function Class() {
 96             // All construction is actually done in the init method
 97             if ( !initializing && this.init )
 98               this.init.apply(this, arguments);
 99           }
100           
101           // Populate our constructed prototype object
102           Class.prototype = prototype;
103           
104           // Enforce the constructor to be what we expect
105           Class.prototype.constructor = Class;
106 
107           // And make this class extendable
108           Class.extend = arguments.callee;
109           
110           return Class;
111         };
112       })();
113 }));
114 
115 /**
116  * JavaScript base object that all finesse objects should inherit
117  * from because it encapsulates and provides the common functionality.
118  *
119  * Note: This javascript class requires the "inhert.js" to be included
120  * (which simplifies the class inheritance).
121  *
122  *
123  * @requires finesse.utilities.Logger
124  */
125 
126 /** The following comment is to prevent jslint errors about 
127  * using variables before they are defined.
128  */
129 /*global Class */
130 (function (factory) {
131     
132 
133     // Define as an AMD module if possible
134     if ( typeof define === 'function' && define.amd )
135     {
136         define('FinesseBase', ["../thirdparty/Class"], factory );
137     }
138     /* Define using browser globals otherwise
139      * Prevent multiple instantiations if the script is loaded twice
140      */
141     else
142     {
143         factory(Class);
144     }
145 }(function (Class) {
146     var FinesseBase = Class.extend({
147         init: function () {
148         }
149     }); 
150     
151     window.finesse = window.finesse || {};
152     window.finesse.FinesseBase = FinesseBase;
153     
154     return FinesseBase;
155 }));
156 
157 /**
158  * A collection of conversion utilities.
159  * Last modified 07-06-2011, Cisco Systems
160  *
161  */
162 /** @private */
163 (function (factory) {
164     
165 
166     // Define as an AMD module if possible
167     if ( typeof define === 'function' && define.amd )
168     {
169     	define('utilities/../../thirdparty/util/converter',[], factory);
170     }
171     /* Define using browser globals otherwise
172      * Prevent multiple instantiations if the script is loaded twice
173      */
174     else
175     {
176         factory();
177     } 
178 }(function () {
179     window.finesse = window.finesse || {};
180 
181     /**
182      * @class
183      * Contains a collection of utility functions.
184      * @private
185      */
186     window.finesse.Converter = (function () {
187         return {
188             /*  This work is licensed under Creative Commons GNU LGPL License.
189 
190                 License: http://creativecommons.org/licenses/LGPL/2.1/
191                Version: 0.9
192                 Author:  Stefan Goessner/2006
193                 Web:     http://goessner.net/ 
194 
195                 2013-09-16 Modified to remove use of XmlNode.innerHTML in the innerXml function by Cisco Systems, Inc.
196             */
197             xml2json: function (xml, tab) {
198                 var X = {
199                     toObj: function (xml) {
200                         var o = {};
201                         if (xml.nodeType === 1) {
202                             // element node ..
203                             if (xml.attributes.length)
204                             // element with attributes  ..
205                             for (var i = 0; i < xml.attributes.length; i++)
206                             o["@" + xml.attributes[i].nodeName] = (xml.attributes[i].nodeValue || "").toString();
207                             if (xml.firstChild) {
208                                 // element has child nodes ..
209                                 var textChild = 0,
210                                 cdataChild = 0,
211                                 hasElementChild = false;
212                                 for (var n = xml.firstChild; n; n = n.nextSibling) {
213                                     if (n.nodeType == 1) hasElementChild = true;
214                                     else if (n.nodeType == 3 && n.nodeValue.match(/[^ \f\n\r\t\v]/)) textChild++;
215                                     // non-whitespace text
216                                     else if (n.nodeType == 4) cdataChild++;
217                                     // cdata section node
218                                 }
219                                 if (hasElementChild) {
220                                     if (textChild < 2 && cdataChild < 2) {
221                                         // structured element with evtl. a single text or/and cdata node ..
222                                         X.removeWhite(xml);
223                                         for (var n = xml.firstChild; n; n = n.nextSibling) {
224                                             if (n.nodeType == 3)
225                                             // text node
226                                             o["#text"] = X.escape(n.nodeValue);
227                                             else if (n.nodeType == 4)
228                                             // cdata node
229                                             o["#cdata"] = X.escape(n.nodeValue);
230                                             else if (o[n.nodeName]) {
231                                                 // multiple occurence of element ..
232                                                 if (o[n.nodeName] instanceof Array)
233                                                 o[n.nodeName][o[n.nodeName].length] = X.toObj(n);
234                                                 else
235                                                 o[n.nodeName] = [o[n.nodeName], X.toObj(n)];
236                                             }
237                                             else
238                                             // first occurence of element..
239                                             o[n.nodeName] = X.toObj(n);
240                                         }
241                                     }
242                                     else {
243                                         // mixed content
244                                         if (!xml.attributes.length)
245                                         o = X.escape(X.innerXml(xml));
246                                         else
247                                         o["#text"] = X.escape(X.innerXml(xml));
248                                     }
249                                 }
250                                 else if (textChild) {
251                                     // pure text
252                                     if (!xml.attributes.length)
253                                     o = X.escape(X.innerXml(xml));
254                                     else
255                                     o["#text"] = X.escape(X.innerXml(xml));
256                                 }
257                                 else if (cdataChild) {
258                                     // cdata
259                                     if (cdataChild > 1)
260                                     o = X.escape(X.innerXml(xml));
261                                     else
262                                     for (var n = xml.firstChild; n; n = n.nextSibling)
263                                     o["#cdata"] = X.escape(n.nodeValue);
264                                 }
265                             }
266                             if (!xml.attributes.length && !xml.firstChild) o = null;
267                         }
268                         else if (xml.nodeType == 9) {
269                             // document.node
270                             o = X.toObj(xml.documentElement);
271                         }
272                         else
273                             throw ("unhandled node type: " + xml.nodeType);
274                         return o;
275                     },
276                     toJson: function(o, name, ind) {
277                         var json = name ? ("\"" + name + "\"") : "";
278                         if (o instanceof Array) {
279                             for (var i = 0, n = o.length; i < n; i++)
280                             o[i] = X.toJson(o[i], "", ind + "\t");
281                             json += (name ? ":[": "[") + (o.length > 1 ? ("\n" + ind + "\t" + o.join(",\n" + ind + "\t") + "\n" + ind) : o.join("")) + "]";
282                         }
283                         else if (o == null)
284                         json += (name && ":") + "null";
285                         else if (typeof(o) == "object") {
286                             var arr = [];
287                             for (var m in o)
288                             arr[arr.length] = X.toJson(o[m], m, ind + "\t");
289                             json += (name ? ":{": "{") + (arr.length > 1 ? ("\n" + ind + "\t" + arr.join(",\n" + ind + "\t") + "\n" + ind) : arr.join("")) + "}";
290                         }
291                         else if (typeof(o) == "string")
292                         json += (name && ":") + "\"" + o.toString() + "\"";
293                         else
294                         json += (name && ":") + o.toString();
295                         return json;
296                     },
297                     innerXml: function(node) {
298                         var s = "";
299                         var asXml = function(n) {
300                             var s = "";
301                             if (n.nodeType == 1) {
302                                 s += "<" + n.nodeName;
303                                 for (var i = 0; i < n.attributes.length; i++)
304                                 s += " " + n.attributes[i].nodeName + "=\"" + (n.attributes[i].nodeValue || "").toString() + "\"";
305                                 if (n.firstChild) {
306                                     s += ">";
307                                     for (var c = n.firstChild; c; c = c.nextSibling)
308                                     s += asXml(c);
309                                     s += "</" + n.nodeName + ">";
310                                 }
311                                 else
312                                 s += "/>";
313                             }
314                             else if (n.nodeType == 3)
315                             s += n.nodeValue;
316                             else if (n.nodeType == 4)
317                             s += "<![CDATA[" + n.nodeValue + "]]>";
318                             return s;
319                         };
320                         for (var c = node.firstChild; c; c = c.nextSibling)
321                         s += asXml(c);
322                         return s;
323                     },
324                     escape: function(txt) {
325                         return txt.replace(/[\\]/g, "\\\\")
326                         .replace(/[\"]/g, '\\"')
327                         .replace(/[\n]/g, '\\n')
328                         .replace(/[\r]/g, '\\r');
329                     },
330                     removeWhite: function(e) {
331                         e.normalize();
332                         for (var n = e.firstChild; n;) {
333                             if (n.nodeType == 3) {
334                                 // text node
335                                 if (!n.nodeValue.match(/[^ \f\n\r\t\v]/)) {
336                                     // pure whitespace text node
337                                     var nxt = n.nextSibling;
338                                     e.removeChild(n);
339                                     n = nxt;
340                                 }
341                                 else
342                                 n = n.nextSibling;
343                             }
344                             else if (n.nodeType == 1) {
345                                 // element node
346                                 X.removeWhite(n);
347                                 n = n.nextSibling;
348                             }
349                             else
350                             // any other node
351                             n = n.nextSibling;
352                         }
353                         return e;
354                     }
355                 };
356                 if (xml.nodeType == 9)
357                 // document node
358                 xml = xml.documentElement;
359                 var json = X.toJson(X.toObj(X.removeWhite(xml)), xml.nodeName, "\t");
360                 return "{\n" + tab + (tab ? json.replace(/\t/g, tab) : json.replace(/\t|\n/g, "")) + "\n}";
361             },
362             
363             /*  This work is licensed under Creative Commons GNU LGPL License.
364 
365                 License: http://creativecommons.org/licenses/LGPL/2.1/
366                Version: 0.9
367                 Author:  Stefan Goessner/2006
368                 Web:     http://goessner.net/ 
369             */
370             json2xml: function(o, tab) {
371                 var toXml = function(v, name, ind) {
372                     var xml = "";
373                     if (v instanceof Array) {
374                         for (var i = 0, n = v.length; i < n; i++)
375                         xml += ind + toXml(v[i], name, ind + "\t") + "\n";
376                     }
377                     else if (typeof(v) == "object") {
378                         var hasChild = false;
379                         xml += ind + "<" + name;
380                         for (var m in v) {
381                             if (m.charAt(0) == "@")
382                             xml += " " + m.substr(1) + "=\"" + v[m].toString() + "\"";
383                             else
384                             hasChild = true;
385                         }
386                         xml += hasChild ? ">": "/>";
387                         if (hasChild) {
388                             for (var m in v) {
389                                 if (m == "#text")
390                                 xml += v[m];
391                                 else if (m == "#cdata")
392                                 xml += "<![CDATA[" + v[m] + "]]>";
393                                 else if (m.charAt(0) != "@")
394                                 xml += toXml(v[m], m, ind + "\t");
395                             }
396                             xml += (xml.charAt(xml.length - 1) == "\n" ? ind: "") + "</" + name + ">";
397                         }
398                     }
399                     else {
400                         xml += ind + "<" + name + ">" + v.toString() + "</" + name + ">";
401                     }
402                     return xml;
403                 },
404                 xml = "";
405                 for (var m in o)
406                 xml += toXml(o[m], m, "");
407                 return tab ? xml.replace(/\t/g, tab) : xml.replace(/\t|\n/g, "");
408             }
409         };
410     })();
411 }));
412 
413 /**
414  * SaxParser.js: provides a simple SAX parser
415  *
416  * NONVALIDATING - this will not validate whether you have valid XML or not. It will simply report what it finds.
417  * Only supports elements, attributes, and text. No comments, cdata, processing instructions, etc.
418  */
419 
420 /**
421  * @requires
422  * @ignore
423  */
424 // Add SaxParser to the finesse.utilities namespace
425 var finesse = finesse || {};
426 finesse.utilities = finesse.utilities || {};
427 
428 (function (factory) {
429     
430 
431     // Define as an AMD module if possible
432     if ( typeof define === 'function' && define.amd )
433     {
434         define('utilities/SaxParser', [], factory );
435     }
436     /* Define using browser globals otherwise
437      * Prevent multiple instantiations if the script is loaded twice
438      */
439     else
440     {
441         finesse.utilities.SaxParser = factory();
442     }
443 }(function () {
444 	return {
445 		parse: function(xml, callback) {
446 			// Event callbacks
447             /** @private */
448 			var triggerEvent = function (type, data) {
449 					callback.call(null, type, data);
450 				},
451                 /** @private */
452 				triggerStartElement = function (name) {
453 					triggerEvent("StartElement", name);
454 				},
455                 /** @private */
456 				triggerEndElement = function (name) {
457 					triggerEvent("EndElement", name);
458 				},
459                 /** @private */
460 				triggerAttribute = function (name, value) {
461 					triggerEvent("Attribute", { "name": name, "value": value });
462 				},
463                 /** @private */
464 				triggerText = function (text) {
465 					triggerEvent("Text", text);
466 				},
467 
468 				// Parsing
469 				cursor = 0,
470 				xmlLength = xml.length,
471 				whitespaceRegex = /^[ \t\r\n]*$/,
472 				/** @private */
473 				isWhitespace = function (text) {
474 					return whitespaceRegex.test(text);
475 				},
476                 /** @private */
477 				moveToNonWhitespace = function () {
478 					while (isWhitespace(xml.charAt(cursor))) {
479 						cursor += 1;
480 					}
481 				},
482                 /** @private */
483 				parseAttribute = function () {
484 					var nameBuffer = [],
485 						valueBuffer = [],
486 						valueIsQuoted = false,
487 						cursorChar = "";
488 
489 					nameBuffer.push(xml.charAt(cursor));
490 
491 					// Get the name
492 					cursor += 1;
493 					while (cursor < xmlLength) {
494 						cursorChar = xml.charAt(cursor);
495 						if (isWhitespace(cursorChar) || cursorChar === "=") {
496 							// Move on to gathering value
497 							break;
498 						}
499 						else {
500 							nameBuffer.push(cursorChar);
501 						}
502 						cursor += 1;
503 					}
504 
505 					// Skip the equals sign and any whitespace
506 					moveToNonWhitespace();
507 					if (cursorChar === "=") {
508 						cursor += 1;
509 					} else {
510 						throw new Error("Did not find = following attribute name at " + cursor);
511 					}
512 					moveToNonWhitespace();
513 
514 					// Get the value
515 					valueIsQuoted = cursor !== xmlLength - 1 ? xml.charAt(cursor) === "\"": false;
516 					if (valueIsQuoted) {
517 						cursor += 1;
518 						while (cursor < xmlLength) {
519 							cursorChar = xml.charAt(cursor);
520 							if (cursorChar === "\"") {
521 								// Found the closing quote, so end value
522 								triggerAttribute(nameBuffer.join(""), valueBuffer.join(""));
523 								break;
524 							}
525 							else {
526 								valueBuffer.push(cursorChar);
527 							}
528 							cursor += 1;
529 						}
530 					}
531 					else {
532 						throw new Error("Found unquoted attribute value at " + cursor);
533 					}
534 				},
535                 /** @private */
536 				parseEndElement = function () {
537 					var elementNameBuffer = [],
538 						cursorChar = "";
539 					cursor += 2;
540 					while (cursor < xmlLength) {
541 						cursorChar = xml.charAt(cursor);
542 						if (cursorChar === ">") {
543 							triggerEndElement(elementNameBuffer.join(""));
544 							break;
545 						}
546 						else {
547 							elementNameBuffer.push(cursorChar);
548 						}
549 						cursor += 1;
550 					}
551 				},
552                 /** @private */
553 				parseReference = function() {
554 					var type,
555 						TYPE_DEC_CHAR_REF = 1,
556 						TYPE_HEX_CHAR_REF = 2,
557 						TYPE_ENTITY_REF = 3,
558 						buffer = "";
559 					cursor += 1;
560 					// Determine the type of reference.
561 					if (xml.charAt(cursor) === "#") {
562 						cursor += 1;
563 						if (xml.charAt(cursor) === "x") {
564 							type = TYPE_HEX_CHAR_REF;
565 							cursor += 1;
566 						} else {
567 							type = TYPE_DEC_CHAR_REF;
568 						}
569 					} else {
570 						type = TYPE_ENTITY_REF;
571 					}
572 					// Read the reference into a buffer.
573 					while (xml.charAt(cursor) !== ";") {
574 						buffer += xml.charAt(cursor);
575 						cursor += 1;
576 						if (cursor >= xmlLength) {
577 							throw new Error("Unterminated XML reference: " + buffer);
578 						}
579 					}
580 					// Convert the reference to the appropriate character.
581 					switch (type) {
582 						case TYPE_DEC_CHAR_REF:
583 							return String.fromCharCode(parseInt(buffer, 10));
584 						case TYPE_HEX_CHAR_REF:
585 							return String.fromCharCode(parseInt(buffer, 16));
586 						case TYPE_ENTITY_REF:
587 							switch (buffer) {
588 								case "amp":
589 									return "&";
590 								case "lt":
591 									return "<";
592 								case "gt":
593 									return ">";
594 								case "apos":
595 									return "'";
596 								case "quot":
597 									return "\"";
598 								default:
599 									throw new Error("Invalid XML entity reference: " + buffer);
600 							}
601 							// break; (currently unreachable)
602 					}
603 				},
604                 /** @private */
605 				parseElement = function () {
606 					var elementNameBuffer = [],
607 						textBuffer = [],
608 						cursorChar = "",
609 						whitespace = false;
610 
611 					// Get element name
612 					cursor += 1;
613 					while (cursor < xmlLength) {
614 						cursorChar = xml.charAt(cursor);
615 						whitespace = isWhitespace(cursorChar);
616 						if (!whitespace && cursorChar !== "/" && cursorChar !== ">") {
617 							elementNameBuffer.push(cursorChar);
618 						}
619 						else {
620 							elementNameBuffer = elementNameBuffer.join("");
621 							triggerStartElement(elementNameBuffer);
622 							break;
623 						}
624 						cursor += 1;
625 					}
626 
627 					// Get attributes
628 					if (whitespace) {
629 						while (cursor < xmlLength) {
630 							moveToNonWhitespace();
631 							cursorChar = xml.charAt(cursor);
632 							if (cursorChar !== "/" && cursorChar !== ">") {
633 								// Start of attribute
634 								parseAttribute();
635 							}
636 							cursorChar = xml.charAt(cursor);
637 							if (cursorChar === "/" || cursorChar === ">") {
638 								break;
639 							}
640 							else {
641 								cursor += 1;
642 							}
643 						}
644 					}
645 
646 					// End tag if "/>" was found,
647 					// otherwise we're at the end of the start tag and have to parse into it
648 					if (cursorChar === "/") {
649 						if (cursor !== xmlLength - 1 && xml.charAt(cursor + 1) === ">") {
650 							cursor += 1;
651 							triggerEndElement(elementNameBuffer);
652 						}
653 					}
654 					else {
655 						// cursor is on ">", so parse into element content. Assume text until we find a "<",
656 						// which could be a child element or the current element's end tag. We do not support
657 						// mixed content of text and elements as siblings unless the text is only whitespace.
658 						// Text cannot contain <, >, ", or &. They should be <, >, ", & respectively.
659 						cursor += 1;
660 						while (cursor < xmlLength) {
661 							cursorChar = xml.charAt(cursor);
662 							if (cursorChar === "<") {
663 								// Determine if end tag or element
664 								if (cursor !== xmlLength - 1 && xml.charAt(cursor + 1) === "/") {
665 									// At end tag
666 									textBuffer = textBuffer.join("");
667 									if (!isWhitespace(textBuffer)) {
668 										triggerText(textBuffer);
669 									}
670 									parseEndElement();
671 									break;
672 								}
673 								else {
674 									// At start tag
675 									textBuffer = textBuffer.join("");
676 									if (!isWhitespace(textBuffer)) {
677 										triggerText(textBuffer);
678 									}
679 									parseElement();
680 									textBuffer = [];
681 								}
682 							} else if (cursorChar === "&") {
683 								textBuffer.push(parseReference());
684 							}
685 							else {
686 								textBuffer.push(cursorChar);
687 							}
688 							cursor += 1;
689 						}
690 					}
691 				},
692                 /** @private */
693 				skipXmlDeclaration = function() {
694 					if (xml.substr(0, 5) === "<?xml" && isWhitespace(xml.charAt(5))) {
695 						cursor = xml.indexOf(">") + 1;
696 					}
697 					moveToNonWhitespace();
698 				};
699 
700 			// Launch.
701 			skipXmlDeclaration();
702 			parseElement();
703 		}
704 	};
705 }));
706 
707 /**
708 * Date.parse with progressive enhancement for ISO 8601 <https://github.com/csnover/js-iso8601>
709 * ?? 2011 Colin Snover <http://zetafleet.com>
710 * Released under MIT license.
711 */
712 (function (factory) {
713     
714 
715     // Define as an AMD module if possible
716     if ( typeof define === 'function' && define.amd )
717     {
718         define('iso8601', [], factory );
719     }
720     /* Define using browser globals otherwise
721      * Prevent multiple instantiations if the script is loaded twice
722      */
723     else
724     {
725         factory();
726     } 
727 }(function () {
728     (function (Date, undefined) {
729         var origParse = Date.parse, numericKeys = [ 1, 4, 5, 6, 7, 10, 11 ];
730     	/** @private **/
731         Date.parse = function (date) {
732             var timestamp, struct, minutesOffset = 0;
733 
734             // ES5 ??15.9.4.2 states that the string should attempt to be parsed as a Date Time String Format string
735             // before falling back to any implementation-specific date parsing, so that???s what we do, even if native
736             // implementations could be faster
737             // 1 YYYY 2 MM 3 DD 4 HH 5 mm 6 ss 7 msec 8 Z 9 ?? 10 tzHH 11 tzmm
738             if ((struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(date))) {
739                 // avoid NaN timestamps caused by ???undefined??? values being passed to Date.UTC
740                 for (var i = 0, k; (k = numericKeys[i]); ++i) {
741                     struct[k] = +struct[k] || 0;
742                 }
743 
744                 // allow undefined days and months
745                 struct[2] = (+struct[2] || 1) - 1;
746                 struct[3] = +struct[3] || 1;
747 
748                 if (struct[8] !== 'Z' && struct[9] !== undefined) {
749                     minutesOffset = struct[10] * 60 + struct[11];
750 
751                     if (struct[9] === '+') {
752                         minutesOffset = 0 - minutesOffset;
753                     }
754                 }
755 
756                 timestamp = Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7]);
757             }
758             else {
759                 timestamp = origParse ? origParse(date) : NaN;
760             }
761 
762             return timestamp;
763         };
764     }(Date));
765 }));
766 
767 /*!
768 Math.uuid.js (v1.4)
769 http://www.broofa.com
770 mailto:robert@broofa.com
771 
772 Copyright (c) 2010 Robert Kieffer
773 Dual licensed under the MIT and GPL licenses.
774 */
775 
776 /*
777  * Generate a random uuid.
778  *
779  * USAGE: Math.uuid(length, radix)
780  *   length - the desired number of characters
781  *   radix  - the number of allowable values for each character.
782  *
783  * EXAMPLES:
784  *   // No arguments  - returns RFC4122, version 4 ID
785  *   >>> Math.uuid()
786  *   "92329D39-6F5C-4520-ABFC-AAB64544E172"
787  *
788  *   // One argument - returns ID of the specified length
789  *   >>> Math.uuid(15)     // 15 character ID (default base=62)
790  *   "VcydxgltxrVZSTV"
791  *
792  *   // Two arguments - returns ID of the specified length, and radix. (Radix must be <= 62)
793  *   >>> Math.uuid(8, 2)  // 8 character ID (base=2)
794  *   "01001010"
795  *   >>> Math.uuid(8, 10) // 8 character ID (base=10)
796  *   "47473046"
797  *   >>> Math.uuid(8, 16) // 8 character ID (base=16)
798  *   "098F4D35"
799  */
800 (function (factory) {
801     
802 
803     // Define as an AMD module if possible
804     if ( typeof define === 'function' && define.amd )
805     {
806         define('Math.uuid', [], factory );
807     }
808     /* Define using browser globals otherwise
809      * Prevent multiple instantiations if the script is loaded twice
810      */
811     else
812     {
813         factory();
814     } 
815 }(function () {
816     (function() {
817         // Private array of chars to use
818         var CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
819 
820         /** @private **/
821         Math.uuid = function (len, radix) {
822           var chars = CHARS, uuid = [], i;
823           radix = radix || chars.length;
824 
825           if (len) {
826             // Compact form
827             for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random()*radix];
828           } else {
829             // rfc4122, version 4 form
830             var r;
831 
832             // rfc4122 requires these characters
833             uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
834             uuid[14] = '4';
835 
836             // Fill in random data.  At i==19 set the high bits of clock sequence as
837             // per rfc4122, sec. 4.1.5
838             for (i = 0; i < 36; i++) {
839               if (!uuid[i]) {
840                 r = 0 | Math.random()*16;
841                 uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
842               }
843             }
844           }
845 
846           return uuid.join('');
847         };
848 
849         // A more performant, but slightly bulkier, RFC4122v4 solution.  We boost performance
850         // by minimizing calls to random()
851         /** @private **/
852         Math.uuidFast = function() {
853           var chars = CHARS, uuid = new Array(36), rnd=0, r;
854           for (var i = 0; i < 36; i++) {
855             if (i==8 || i==13 ||  i==18 || i==23) {
856               uuid[i] = '-';
857             } else if (i==14) {
858               uuid[i] = '4';
859             } else {
860               if (rnd <= 0x02) rnd = 0x2000000 + (Math.random()*0x1000000)|0;
861               r = rnd & 0xf;
862               rnd = rnd >> 4;
863               uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
864             }
865           }
866           return uuid.join('');
867         };
868 
869         // A more compact, but less performant, RFC4122v4 solution:
870         /** @private **/
871         Math.uuidCompact = function() {
872           return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
873             var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
874             return v.toString(16);
875           });
876         };
877       })();
878 }));
879 
880 /**
881  * The following comment prevents JSLint errors concerning undefined global variables.
882  * It tells JSLint that these identifiers are defined elsewhere.
883  */
884 /*jslint bitwise:true, browser:true, nomen:true, regexp:true, sloppy:true, white:true, plusplus: true, unparam: true, forin: true */
885 
886 /** The following comment is to prevent jslint errors about 
887  * using variables before they are defined.
888  */
889 /*global $, _prefs,_uiMsg,ciscowidgets,dojo,finesse,gadgets,hostUrl, Handlebars */
890 
891 /**
892  *  A collection of utility functions.
893  *
894  * @requires finesse.Converter
895  */
896 var finesse = finesse || {};
897 /** @namespace Useful javascript utility methods. */  
898 finesse.utilities = finesse.utilities || {};
899 
900 (function (factory) {
901     
902 
903     // Define as an AMD module if possible
904     if ( typeof define === 'function' && define.amd )
905     {
906         define('utilities/Utilities', ["../../thirdparty/util/converter",
907                 "utilities/SaxParser",
908                 "iso8601",
909                 "Math.uuid"], factory );
910     }
911     /* Define using browser globals otherwise
912      * Prevent multiple instantiations if the script is loaded twice
913      */
914     else
915     {
916         finesse.utilities.Utilities = factory(finesse.Converter, finesse.utilities.SaxParser);
917     }
918 }(function (Converter, SaxParser) {
919     var Utilities = /** @lends finesse.utilities.Utilities */ {
920 
921         /**
922          * @class
923          * A PhoneBook is a list of Contacts available to a User for quick dial.
924          * 
925          * @augments finesse.restservices.RestBase
926          * @see finesse.restservices.Contacts
927          * @constructs
928          */
929         _fakeConstuctor: function () {
930             /* This is here for jsdocs. */
931         },
932             
933         /**
934          * @private
935          * Retrieves the specified item from window.localStorage
936          * @param {String} key
937          *     The key of the item to retrieve
938          * @returns {String}
939          *     The string with the value of the retrieved item; returns
940          *     what the browser would return if not found (typically null or undefined)
941          *     Returns false if window.localStorage feature is not even found.
942          */
943         getDOMStoreItem: function (key) {
944             var store = window.localStorage;
945             if (store) {
946                 return store.getItem(key);
947             }
948         },
949 
950         /**
951          * @private
952          * Sets an item into window.localStorage
953          * @param {String} key
954          *     The key for the item to set
955          * @param {String} value
956          *     The value to set
957          * @returns {Boolean}
958          *     True if successful, false if window.localStorage is
959          *     not even found.
960          */
961         setDOMStoreItem: function (key, value) {
962             var store = window.localStorage;
963             if (store) {
964                 store.setItem(key, value);
965                 return true;
966             }
967             return false;
968         },
969 
970         /**
971          * @private
972          * Removes a particular item from window.localStorage
973          * @param {String} key
974          *     The key of the item to remove
975          * @returns {Boolean}
976          *     True if successful, false if not
977          *     Returns false if window.localStorage feature is not even found.
978          */
979         removeDOMStoreItem: function (key) {
980             var store = window.localStorage;
981             if (store) {
982                 store.removeItem(key);
983                 return true;
984             }
985             return false;
986         },
987 
988         /**
989          * @private
990          * Dumps all the contents of window.localStorage
991          * @returns {Boolean}
992          *     True if successful, false if not.
993          *     Returns false if window.localStorage feature is not even found.
994          */
995         clearDOMStore: function () {
996             var store = window.localStorage;
997             if (store) {
998                 store.clear();
999                 return true;
1000             }
1001             return false;
1002         },
1003 
1004         /**
1005          * @private
1006          * Creates a message listener for window.postMessage messages.
1007          * @param {Function} callback
1008          *     The callback that will be invoked with the message. The callback
1009          *     is responsible for any security checks.
1010          * @param {String} [origin]
1011          *     The origin to check against for security. Allows all messages
1012          *     if no origin is provided.
1013          * @returns {Function}
1014          *     The callback function used to register with the message listener.
1015          *     This is different than the one provided as a parameter because
1016          *     the function is overloaded with origin checks.
1017          * @throws {Error} If the callback provided is not a function.
1018          */
1019         receiveMessage: function (callback, origin) {
1020             if (typeof callback !== "function") {
1021                 throw new Error("Callback is not a function.");
1022             }
1023 
1024             //Create a function closure to perform origin check.
1025             /** @private */
1026             var cb = function (e) {
1027                 // If an origin check is requested (provided), we'll only invoke the callback if it passes
1028                 if (typeof origin !== "string" || (typeof origin === "string" && typeof e.origin === "string" && e.origin.toLowerCase() === origin.toLowerCase())) {
1029                     callback(e);
1030                 }
1031             };
1032 
1033             if (window.addEventListener) { //Firefox, Opera, Chrome, Safari
1034                 window.addEventListener("message", cb, false);
1035             } else { //Internet Explorer
1036                 window.attachEvent("onmessage", cb);
1037             }
1038 
1039             //Return callback used to register with listener so that invoker
1040             //could use it to remove.
1041             return cb;
1042         },
1043 
1044         /**
1045          * @private
1046          * Sends a message to a target frame using window.postMessage.
1047          * @param {Function} message
1048          *     Message to be sent to target frame.
1049          * @param {Object} [target="parent"]
1050          *     An object reference to the target frame. Default us the parent.
1051          * @param {String} [targetOrigin="*"]
1052          *     The URL of the frame this frame is sending the message to.
1053          */
1054         sendMessage: function (message, target, targetOrigin) {
1055             //Default to any target URL if none is specified.
1056             targetOrigin = targetOrigin || "*";
1057 
1058             //Default to parent target if none is specified.
1059             target = target || parent;
1060 
1061             //Ensure postMessage is supported by browser before invoking.
1062             if (window.postMessage) {
1063                 target.postMessage(message, targetOrigin);
1064             }
1065         },
1066 
1067         /**
1068          * Returns the passed in handler, if it is a function.
1069          * @param {Function} handler
1070          *     The handler to validate
1071          * @returns {Function}
1072          *     The provided handler if it is valid
1073          * @throws Error
1074          *     If the handler provided is invalid
1075          */
1076         validateHandler: function (handler) {
1077             if (handler === undefined || typeof handler === "function") {
1078                 return handler;
1079             } else {
1080                 throw new Error("handler must be a function");
1081             }
1082         },
1083 
1084         /**
1085          * @private
1086          * Tries to get extract the AWS error code from a
1087          * finesse.clientservices.ClientServices parsed error response object.
1088          * @param {Object} rsp
1089          *     The handler to validate
1090          * @returns {String}
1091          *     The error code, HTTP status code, or undefined
1092          */
1093         getErrCode: function (rsp) {
1094             try { // Best effort to get the error code
1095                 return rsp.object.ApiErrors.ApiError.ErrorType;
1096             } catch (e) { // Second best effort to get the HTTP Status code
1097                 if (rsp && rsp.status) {
1098                     return "HTTP " + rsp.status;
1099                 }
1100             } // Otherwise, don't return anything (undefined)
1101         },
1102 
1103         /**
1104          * @private
1105          * Tries to get extract the AWS error data from a
1106          * finesse.clientservices.ClientServices parsed error response object.
1107          * @param {Object} rsp
1108          *     The handler to validate
1109          * @returns {String}
1110          *     The error data, HTTP status code, or undefined
1111          */
1112         getErrData: function (rsp) {
1113             try { // Best effort to get the error data
1114                 return rsp.object.ApiErrors.ApiError.ErrorData;
1115             } catch (e) { // Second best effort to get the HTTP Status code
1116                 if (rsp && rsp.status) {
1117                     return "HTTP " + rsp.status;
1118                 }
1119             } // Otherwise, don't return anything (undefined)
1120         },
1121         
1122         /**
1123          * @private
1124          * Tries to get extract the AWS overrideable boolean from a
1125          * finesse.clientservices.ClientServices parsed error response object.
1126          * @param {Object} rsp
1127          *     The handler to validate
1128          * @returns {String}
1129          *     The overrideable boolean, HTTP status code, or undefined
1130          */
1131         getErrOverrideable: function (rsp) {
1132             try { // Best effort to get the override boolean
1133                 return rsp.object.ApiErrors.ApiError.Overrideable;
1134             } catch (e) { // Second best effort to get the HTTP Status code
1135                 if (rsp && rsp.status) {
1136                     return "HTTP " + rsp.status;
1137                 }
1138             } // Otherwise, don't return anything (undefined)
1139         },
1140 
1141         /**
1142          * Trims leading and trailing whitespace from a string.
1143          * @param {String} str
1144          *     The string to trim
1145          * @returns {String}
1146          *     The trimmed string
1147          */
1148         trim: function (str) {
1149             return str.replace(/^\s*/, "").replace(/\s*$/, "");
1150         },
1151 
1152         /**
1153          * Utility method for getting the current time in milliseconds.
1154          * @returns {String}
1155          *     The current time in milliseconds
1156          */
1157         currentTimeMillis : function () {
1158             return (new Date()).getTime();
1159         },
1160 
1161        /**
1162         * Gets the current drift (between client and server)
1163         *
1164         * @returns {integer} which is the current drift (last calculated; 0 if we have not calculated yet)
1165         */
1166        getCurrentDrift : function () {
1167             var drift;
1168             
1169             //Get the current client drift from localStorage
1170             drift = window.sessionStorage.getItem("clientTimestampDrift");
1171             if (drift) {
1172                  drift = parseInt(drift, 10);
1173                  if (isNaN(drift)) {
1174                       drift = 0; 
1175                  }
1176             }
1177           return drift;
1178         },
1179 
1180        /**
1181         * Converts the specified clientTime to server time by adjusting by the current drift.
1182         *
1183         * @param clientTime is the time in milliseconds
1184         * @returns {int} serverTime in milliseconds
1185         */
1186         convertToServerTimeMillis : function(clientTime) {
1187             var drift = this.getCurrentDrift();
1188             return (clientTime + drift);
1189         },
1190 
1191         /**
1192          * Utility method for getting the current time,
1193          * adjusted by the calculated "drift" to closely
1194          * approximate the server time.  This is used
1195          * when calculating durations based on a server
1196          * timestamp, which otherwise can produce unexpected
1197          * results if the times on client and server are
1198          * off.
1199          * 
1200          * @returns {String}
1201          *     The current server time in milliseconds
1202          */
1203         currentServerTimeMillis : function () {
1204             var drift = this.getCurrentDrift();
1205             return (new Date()).getTime() + drift;
1206         },
1207 
1208         /**
1209          * Given a specified timeInMs, this method will builds a string which displays minutes and seconds. 
1210          *
1211          * @param timeInMs is the time in milliseconds
1212          * @returns {String} which corresponds to minutes and seconds (e.g. 11:23)
1213          */
1214         buildTimeString : function (timeInMs) {
1215            var min, sec, timeStr = "00:00";
1216           
1217            if (timeInMs && timeInMs !== "-1") {
1218               // calculate minutes, and seconds
1219               min = this.pad(Math.floor(timeInMs / 60000));
1220               sec = this.pad(Math.floor((timeInMs % 60000) / 1000));
1221               
1222               // construct MM:SS time string
1223               timeStr =  min + ":" + sec;
1224            }
1225            return timeStr;  
1226         },
1227         
1228         /**
1229          * Given a specified timeInMs, this method will builds a string which displays minutes and seconds (and optionally hours)
1230          *
1231          * @param timeInMs is the time in milliseconds
1232          * @returns {String} which corresponds to hours, minutes and seconds (e.g. 01:11:23 or 11:23)
1233          */
1234         buildTimeStringWithOptionalHours: function (timeInMs) {
1235            var hour, min, sec, timeStr = "00:00", optionalHour = "", timeInSecs;
1236           
1237            if (timeInMs && timeInMs !== "-1") {
1238               timeInSecs = timeInMs / 1000;
1239               
1240               // calculate {hours}, minutes, and seconds
1241               hour = this.pad(Math.floor(timeInSecs / 3600));
1242               min = this.pad(Math.floor((timeInSecs % 3600) / 60));
1243               sec = this.pad(Math.floor((timeInSecs % 3600) % 60));   
1244               
1245               //Optionally add the hour if we have hours
1246               if (hour > 0) {
1247                 optionalHour = hour + ":";
1248               }
1249               
1250               // construct MM:SS time string (or optionally HH:MM:SS)
1251               timeStr = optionalHour + min + ":" + sec; 
1252            }
1253            return timeStr;
1254         },
1255         
1256         
1257         /**
1258          * Builds a string which specifies the amount of time user has been in this state (e.g. 11:23).
1259          *
1260          * @param adjustedServerTimeInMs is integer argument which specifies the expected server time (accounting for clientdrift)
1261          * @param stateStartTimeInMs is integer argument which specifies time call entered current state
1262          * @returns {String} which is the elapsed time (MINUTES:SECONDS) 
1263          *
1264          */
1265         buildElapsedTimeString : function (adjustedServerTimeInMs, stateStartTimeInMs) {
1266            var result, delta;
1267            
1268            result = "--:--";
1269            if (stateStartTimeInMs !== 0) {
1270              delta = adjustedServerTimeInMs - stateStartTimeInMs;
1271              
1272              if (delta > 0) {
1273                result = this.buildTimeString(delta);
1274              }
1275           }
1276           return result;
1277        },
1278        
1279         /**
1280          * Builds a string which specifies the amount of time user has been in this state with optional hours (e.g. 01:11:23 or 11:23).
1281          *
1282          * @param adjustedServerTimeInMs is integer argument which specifies the expected server time (accounting for clientdrift)
1283          * @param startTimeInMs is integer argument which specifies the start time
1284          * @returns {String} which is the elapsed time (MINUTES:SECONDS) or (HOURS:MINUTES:SECONDS)
1285          *
1286          */
1287         buildElapsedTimeStringWithOptionalHours : function (adjustedServerTimeInMs, stateStartTimeInMs) {
1288            var result, delta;
1289            
1290            result = "--:--";
1291            if (stateStartTimeInMs !== 0) {
1292              delta = adjustedServerTimeInMs - stateStartTimeInMs;
1293              
1294              if (delta > 0) {
1295                result = this.buildTimeStringWithOptionalHours(delta);
1296              }
1297           }
1298           return result;
1299        },
1300        
1301        
1302        /**
1303         * Builds a string which displays the total call time in minutes and seconds.
1304         *
1305         * @param adjustedServerTimeInMs is integer argument which specifies the expected server time (accounting for clientdrift)
1306         * @param callStartTimeInMs is integer argument which specifies time the call started
1307         * @returns {String} which is the elapsed time [MINUTES:SECONDS]
1308         */
1309        buildTotalTimeString : function (adjustedServerTimeInMs, callStartTimeInMs) {
1310           return this.buildElapsedTimeString(adjustedServerTimeInMs, callStartTimeInMs);
1311        },
1312        
1313        /**
1314         * Builds a string which displays the hold time in minutes and seconds.
1315         *
1316         * @param adjustedServerTimeInMs is integer argument which specifies the expected server time (accounting for clientdrift)
1317         * @param holdStartTimeInMs is integer argument which specifies time the hold started
1318         * @returns {String} which is the elapsed time [MINUTES:SECONDS] 
1319         */
1320        buildHoldTimeString : function (adjustedServerTimeInMs, holdStartTimeInMs) {
1321           return this.buildElapsedTimeString(adjustedServerTimeInMs, holdStartTimeInMs);
1322       },
1323       
1324       /**
1325        * Builds a string which displays the elapsed time the call has been in wrap up.
1326        *
1327        * @param adjustedServerTimeInMs is integer argument which specifies the expected server time (accounting for clientdrift)
1328        * @param wrapupStartTimeInMs is integer argument which specifies time call entered wrapup state
1329        * @returns {String} which is the elapsed wrapup time
1330        *
1331        */
1332       buildWrapupTimeString : function (adjustedServerTimeInMs, wrapupStartTimeInMs) {
1333          return this.buildElapsedTimeString(adjustedServerTimeInMs, wrapupStartTimeInMs);
1334       },
1335       
1336       /**
1337        * Extracts a time from the timeStr.  Note: The timeStr could be empty.  In this case, the time returned will be 0.
1338        * @param timeStr is a time string in ISO8601 format (note: could be empty)
1339        * @returns {long} is the time 
1340        */
1341       extractTime : function (timeStr) {
1342          var result = 0, theDate;
1343          if (timeStr === "") {
1344            result = 0;
1345          } else if (timeStr === null) {
1346            result = 0;
1347          } else {
1348            theDate = this.parseDateStringISO8601(timeStr);
1349            result = theDate.getTime();
1350          }
1351          return result;
1352       },
1353       
1354       /**
1355        * @private
1356        * Generates an RFC1422v4-compliant UUID using pesudorandom numbers.
1357        * @returns {String}
1358        *     An RFC1422v4-compliant UUID using pesudorandom numbers.
1359        **/        
1360         generateUUID: function () {
1361             return Math.uuidCompact();
1362         },
1363 
1364         /** @private */
1365         xml2json: Converter.xml2json,
1366         
1367         
1368         /**
1369          * @private
1370          * Utility method to get the JSON parser either from gadgets.json
1371          * or from window.JSON (which will be initialized by CUIC if 
1372          * browser doesn't support
1373          */
1374         getJSONParser: function() {
1375             var _container = window.gadgets || {},
1376                 parser = _container.json || window.JSON;
1377             return parser;
1378         },
1379 
1380        /**
1381         * @private
1382         * Utility method to convert a javascript object to XML.
1383         * @param {Object} object
1384         *   The object to convert to XML.
1385         * @param {Boolean} escapeFlag
1386         *   If escapeFlag evaluates to true:
1387         *       - XML escaping is done on the element values.
1388         *       - Attributes, #cdata, and #text is not supported.
1389         *       - The XML is unformatted (no whitespace between elements).
1390         *   If escapeFlag evaluates to false:
1391         *       - Element values are written 'as is' (no escaping).
1392         *       - Attributes, #cdata, and #text is supported.
1393         *       - The XML is formatted.
1394         * @returns The XML string.
1395         */
1396         json2xml: function (object, escapeFlag) {
1397             var xml;
1398             if (escapeFlag) {
1399                 xml = this._json2xmlWithEscape(object);
1400             }
1401             else {
1402                 xml = Converter.json2xml(object, '\t');
1403             }
1404             return xml;
1405         },
1406 
1407         /**
1408          * @private
1409          * Utility method to convert XML string into javascript object.
1410          */
1411         xml2JsObj : function (event) {
1412             var parser = this.getJSONParser();
1413             return parser.parse(Converter.xml2json(jQuery.parseXML(event), ""));
1414         },
1415 
1416        /**
1417         * @private
1418         * Utility method to convert an XML string to a javascript object.
1419         * @desc This function calls to the SAX parser and responds to callbacks
1420         *     received from the parser. Entity translation is not handled here.
1421         * @param {String} xml
1422         *   The XML to parse.
1423         * @returns The javascript object.
1424         */
1425         xml2js: function (xml) {
1426             var STATES = {
1427                     INVALID: 0,
1428                     NEW_NODE: 1,
1429                     ATTRIBUTE_NODE: 2,
1430                     TEXT_NODE: 3,
1431                     END_NODE: 4
1432                 },
1433                 state = STATES.INVALID,
1434                 rootObj = {},
1435                 newObj,
1436                 objStack = [rootObj],
1437                 nodeName = "",
1438 
1439                 /**
1440                 * @private
1441                 * Adds a property to the current top JSO.
1442                 * @desc This is also where we make considerations for arrays.
1443                 * @param {String} name
1444                 *   The name of the property to add.
1445                 * @param (String) value
1446                 *     The value of the property to add.
1447                 */
1448                 addProperty = function (name, value) {
1449                     var current = objStack[objStack.length - 1];
1450                     if(current.hasOwnProperty(name) && current[name] instanceof Array){
1451                         current[name].push(value);
1452                     }else if(current.hasOwnProperty(name)){
1453                         current[name] = [current[name], value];
1454                     }else{
1455                         current[name] = value;
1456                     }
1457                 },
1458 
1459                 /**
1460                 * @private
1461                 * The callback passed to the SAX parser which processes events from
1462                 * the SAX parser in order to construct the resulting JSO.
1463                 * @param (String) type
1464                 *     The type of event received.
1465                 * @param (String) data
1466                 *     The data received from the SAX parser. The contents of this
1467                 *     parameter vary based on the type of event.
1468                 */
1469                 xmlFound = function (type, data) {
1470                     switch (type) {
1471                     case "StartElement":
1472                         // Because different node types have different expectations
1473                         // of parenting, we don't push another JSO until we know
1474                         // what content we're getting
1475 
1476                         // If we're already in the new node state, we're running
1477                         // into a child node. There won't be any text here, so
1478                         // create another JSO
1479                         if(state === STATES.NEW_NODE){
1480                             newObj = {};
1481                             addProperty(nodeName, newObj);
1482                             objStack.push(newObj);
1483                         }
1484                         state = STATES.NEW_NODE;
1485                         nodeName = data;
1486                         break;
1487                     case "EndElement":
1488                         // If we're in the new node state, we've found no content
1489                         // set the tag property to null
1490                         if(state === STATES.NEW_NODE){
1491                             addProperty(nodeName, null);
1492                         }else if(state === STATES.END_NODE){
1493                             objStack.pop();
1494                         }
1495                         state = STATES.END_NODE;
1496                         break;
1497                     case "Attribute":
1498                         // If were in the new node state, no JSO has yet been created
1499                         // for this node, create one
1500                         if(state === STATES.NEW_NODE){
1501                             newObj = {};
1502                             addProperty(nodeName, newObj);
1503                             objStack.push(newObj);
1504                         }
1505                         // Attributes are differentiated from child elements by a
1506                         // preceding "@" in the property name
1507                         addProperty("@" + data.name, data.value);
1508                         state = STATES.ATTRIBUTE_NODE;
1509                         break;
1510                     case "Text":
1511                         // In order to maintain backwards compatibility, when no
1512                         // attributes are assigned to a tag, its text contents are
1513                         // assigned directly to the tag property instead of a JSO.
1514 
1515                         // If we're in the attribute node state, then the JSO for
1516                         // this tag was already created when the attribute was
1517                         // assigned, differentiate this property from a child
1518                         // element by naming it "#text"
1519                         if(state === STATES.ATTRIBUTE_NODE){
1520                             addProperty("#text", data);
1521                         }else{
1522                             addProperty(nodeName, data);
1523                         }
1524                         state = STATES.TEXT_NODE;
1525                         break;
1526                     }
1527                 };
1528             SaxParser.parse(xml, xmlFound);
1529             return rootObj;
1530         },
1531 
1532        /**
1533         * @private
1534         * Traverses a plain-old-javascript-object recursively and outputs its XML representation.
1535         * @param {Object} obj
1536         *     The javascript object to be converted into XML.
1537         * @returns {String} The XML representation of the object.
1538         */
1539         js2xml: function (obj) {
1540             var xml = "", i, elem;
1541 
1542             if (obj !== null) {
1543                 if (obj.constructor === Object) {
1544                     for (elem in obj) {
1545                         if (obj[elem] === null || typeof(obj[elem]) === 'undefined') {
1546                             xml += '<' + elem + '/>';
1547                         } else if (obj[elem].constructor === Array) {
1548                             for (i = 0; i < obj[elem].length; i++) {
1549                                 xml += '<' + elem + '>' + this.js2xml(obj[elem][i]) + '</' + elem + '>';
1550                             }
1551                         } else if (elem[0] !== '@') {
1552                             if (this.js2xmlObjIsEmpty(obj[elem])) {
1553                                 xml += '<' + elem + this.js2xmlAtt(obj[elem]) + '/>';
1554                             } else if (elem === "#text") {
1555                                 xml += obj[elem];
1556                             } else {
1557                                 xml += '<' + elem + this.js2xmlAtt(obj[elem]) + '>' + this.js2xml(obj[elem]) + '</' + elem + '>';
1558                             }
1559                         }
1560                     }
1561                 } else {
1562                     xml = obj;
1563                 }
1564             }
1565 
1566             return xml;
1567         },
1568 
1569        /**
1570         * @private
1571         * Utility method called exclusively by js2xml() to find xml attributes.
1572         * @desc Traverses children one layer deep of a javascript object to "look ahead"
1573         * for properties flagged as such (with '@').
1574         * @param {Object} obj
1575         *   The obj to traverse.
1576         * @returns {String} Any attributes formatted for xml, if any.
1577         */
1578         js2xmlAtt: function (obj) {
1579             var elem;
1580 
1581             if (obj !== null) {
1582                 if (obj.constructor === Object) {
1583                     for (elem in obj) {
1584                         if (obj[elem] !== null && typeof(obj[elem]) !== "undefined" && obj[elem].constructor !== Array) {
1585                             if (elem[0] === '@'){
1586                                 return ' ' + elem.substring(1) + '="' + obj[elem] + '"';
1587                             }
1588                         }
1589                     }
1590                 }
1591             }
1592 
1593             return '';
1594         },
1595 
1596        /**
1597         * @private
1598         * Utility method called exclusively by js2xml() to determine if
1599         * a node has any children, with special logic for ignoring attributes.
1600         * @desc Attempts to traverse the elements in the object while ignoring attributes.
1601         * @param {Object} obj
1602         *   The obj to traverse.
1603         * @returns {Boolean} whether or not the JS object is "empty"
1604         */
1605         js2xmlObjIsEmpty: function (obj) {
1606             var elem;
1607 
1608             if (obj !== null) {
1609                 if (obj.constructor === Object) {
1610                     for (elem in obj) {
1611                         if (obj[elem] !== null) {
1612                             if (obj[elem].constructor === Array){
1613                                 return false;
1614                             }
1615 
1616                             if (elem[0] !== '@'){
1617                                 return false;
1618                             }
1619                         } else {
1620                             return false;
1621                         }
1622                     }
1623                 } else {
1624                     return false;
1625                 }
1626             }
1627 
1628             return true;
1629         },
1630 
1631         /**
1632          * Encodes the given string into base64.
1633          *<br>
1634          * <b>NOTE:</b> {input} is assumed to be UTF-8; only the first
1635          * 8 bits of each input element are significant.
1636          *
1637          * @param {String} input
1638          *     The string to convert to base64.
1639          * @returns {String}
1640          *     The converted string.
1641          */
1642         b64Encode: function (input) {
1643             var output = "", idx, data,
1644                 table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
1645 
1646             for (idx = 0; idx < input.length; idx += 3) {
1647                 data =  input.charCodeAt(idx) << 16 |
1648                             input.charCodeAt(idx + 1) << 8 |
1649                             input.charCodeAt(idx + 2);
1650 
1651                 //assume the first 12 bits are valid
1652                 output +=   table.charAt((data >>> 18) & 0x003f) +
1653                             table.charAt((data >>> 12) & 0x003f);
1654                 output +=   ((idx + 1) < input.length) ?
1655                             table.charAt((data >>> 6) & 0x003f) :
1656                             "=";
1657                 output +=   ((idx + 2) < input.length) ?
1658                             table.charAt(data & 0x003f) :
1659                             "=";
1660             }
1661 
1662             return output;
1663         },
1664 
1665         /**
1666          * Decodes the given base64 string.
1667          * <br>
1668          * <b>NOTE:</b> output is assumed to be UTF-8; only the first
1669          * 8 bits of each output element are significant.
1670          *
1671          * @param {String} input
1672          *     The base64 encoded string
1673          * @returns {String}
1674          *     Decoded string
1675          */
1676         b64Decode: function (input) {
1677             var output = "", idx, h, data,
1678                 table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
1679 
1680             for (idx = 0; idx < input.length; idx += 4) {
1681                 h = [
1682                     table.indexOf(input.charAt(idx)),
1683                     table.indexOf(input.charAt(idx + 1)),
1684                     table.indexOf(input.charAt(idx + 2)),
1685                     table.indexOf(input.charAt(idx + 3))
1686                 ];
1687 
1688                 data = (h[0] << 18) | (h[1] << 12) | (h[2] << 6) | h[3];
1689                 if (input.charAt(idx + 2) === '=') {
1690                     data = String.fromCharCode(
1691                         (data >>> 16) & 0x00ff
1692                     );
1693                 } else if (input.charAt(idx + 3) === '=') {
1694                     data = String.fromCharCode(
1695                         (data >>> 16) & 0x00ff,
1696                         (data >>> 8) & 0x00ff
1697                     );
1698                 } else {
1699                     data = String.fromCharCode(
1700                         (data >>> 16) & 0x00ff,
1701                         (data >>> 8) & 0x00ff,
1702                         data & 0x00ff
1703                     );
1704                 }
1705                 output += data;
1706             }
1707 
1708             return output;
1709         },
1710 
1711         /**
1712          * @private
1713          * Extracts the username and the password from the Base64 encoded string.
1714          * @params {String}
1715          *     A base64 encoded string containing credentials that (when decoded)
1716          *     are colon delimited.
1717          * @returns {Object}
1718          *     An object with the following structure:
1719          *     {id:string, password:string}
1720          */
1721         getCredentials: function (authorization) {
1722             var credObj = {},
1723                 credStr = this.b64Decode(authorization),
1724                 colonIndx = credStr.indexOf(":");
1725 
1726             //Check to ensure that string is colon delimited.
1727             if (colonIndx === -1) {
1728                 throw new Error("String is not colon delimited.");
1729             }
1730 
1731             //Extract ID and password.
1732             credObj.id = credStr.substring(0, colonIndx);
1733             credObj.password = credStr.substring(colonIndx + 1);
1734             return credObj;
1735         },
1736 
1737         /**
1738          * Takes a string and removes any spaces within the string.
1739          * @param {String} string
1740          *     The string to remove spaces from
1741          * @returns {String}
1742          *     The string without spaces
1743          */
1744         removeSpaces: function (string) {
1745             return string.split(' ').join('');
1746         },
1747 
1748         /**
1749          * Escapes spaces as encoded " " characters so they can
1750          * be safely rendered by jQuery.text(string) in all browsers.
1751          *
1752          * (Although IE behaves as expected, Firefox collapses spaces if this function is not used.)
1753          *
1754          * @param text
1755          *    The string whose spaces should be escaped
1756          *
1757          * @returns
1758          *    The string with spaces escaped
1759          */
1760         escapeSpaces: function (string) {
1761             return string.replace(/\s/g, '\u00a0');
1762         },
1763 
1764         /**
1765          * Adds a span styled to line break at word edges around the string passed in.
1766          * @param str String to be wrapped in word-breaking style.
1767          * @private
1768          */
1769         addWordWrapping : function (str) {
1770             return '<span style="word-wrap: break-word;">' + str + '</span>';
1771         },
1772 
1773         /**
1774          * Takes an Object and determines whether it is an Array or not.
1775          * @param {Object} obj
1776          *     The Object in question
1777          * @returns {Boolean}
1778          *     true if the object is an Array, else false.
1779          */
1780         isArray: function (obj) {
1781             return obj.constructor.toString().indexOf("Array") !== -1;
1782         },
1783 
1784         /**
1785          * @private
1786          * Takes a data object and returns an array extracted
1787          * @param {Object} data
1788          *     JSON payload
1789          *
1790          * @returns {array}
1791          *     extracted array
1792          */
1793         getArray: function (data) {
1794             if (this.isArray(data)) {
1795                 //Return if already an array.
1796                 return data;
1797             } else {
1798                 //Create an array, iterate through object, and push to array. This
1799                 //should only occur with one object, and therefore one obj in array.
1800                 var arr = [];
1801                 arr.push(data);
1802                 return arr;
1803             }
1804         },
1805 
1806         /**
1807          * @private
1808          * Extracts the ID for an entity given the Finesse REST URI. The ID is
1809          * assumed to be the last element in the URI (after the last "/").
1810          * @param {String} uri
1811          *     The Finesse REST URI to extract the ID from.
1812          * @returns {String}
1813          *     The ID extracted from the REST URI.
1814          */
1815         getId: function (uri) {
1816             if (!uri) {
1817                 return "";
1818             }
1819             var strLoc = uri.lastIndexOf("/");
1820             return uri.slice(strLoc + 1);
1821         },
1822 
1823         /**
1824          * Compares two objects for equality.
1825          * @param {Object} obj1 
1826          *      First of two objects to compare.
1827          * @param {Object} obj2
1828          *      Second of two objects to compare.
1829          */
1830         getEquals: function (objA, objB) {
1831             var key;
1832 
1833             for (key in objA) {
1834                 if (objA.hasOwnProperty(key)) {
1835                     if (!objA[key]) {
1836                         objA[key] = "";
1837                     }
1838 
1839                     if (typeof objB[key] === 'undefined') {
1840                         return false;
1841                     }
1842                     if (typeof objB[key] === 'object') {
1843                         if (!objB[key].equals(objA[key])) {
1844                             return false;
1845                         }
1846                     }
1847                     if (objB[key] !== objA[key]) {
1848                         return false;
1849                     }
1850                 }
1851             }
1852             return true;
1853         },
1854 
1855         /**
1856          * Regular expressions used in translating HTML and XML entities
1857          */
1858         ampRegEx : new RegExp('&', 'gi'),
1859         ampEntityRefRegEx : new RegExp('&', 'gi'),
1860         ltRegEx : new RegExp('<', 'gi'),
1861         ltEntityRefRegEx : new RegExp('<', 'gi'),
1862         gtRegEx : new RegExp('>', 'gi'),
1863         gtEntityRefRegEx : new RegExp('>', 'gi'),
1864         xmlSpecialCharRegEx: new RegExp('[&<>"\']', 'g'),
1865         entityRefRegEx: new RegExp('&[^;]+(?:;|$)', 'g'),
1866 
1867         /**
1868          * Translates between special characters and HTML entities
1869          *
1870          * @param text
1871          *     The text to translate
1872          *
1873          * @param makeEntityRefs
1874          *    If true, encode special characters as HTML entities; if
1875          *    false, decode HTML entities back to special characters
1876          *
1877          * @private
1878          */
1879         translateHTMLEntities: function (text, makeEntityRefs) {
1880             if (typeof(text) !== "undefined" && text !== null && text !== "") {
1881                 if (makeEntityRefs) {
1882                     text = text.replace(this.ampRegEx, '&');
1883                     text = text.replace(this.ltRegEx, '<');
1884                     text = text.replace(this.gtRegEx, '>');
1885                 } else {
1886                     text = text.replace(this.gtEntityRefRegEx, '>');
1887                     text = text.replace(this.ltEntityRefRegEx, '<');
1888                     text = text.replace(this.ampEntityRefRegEx, '&');
1889                 }
1890             }
1891 
1892             return text;
1893         },
1894 
1895         /**
1896          * Translates between special characters and XML entities
1897          *
1898          * @param text
1899          *     The text to translate
1900          *
1901          * @param makeEntityRefs
1902          *    If true, encode special characters as XML entities; if
1903          *    false, decode XML entities back to special characters
1904          *
1905          * @private
1906          */
1907         translateXMLEntities: function (text, makeEntityRefs) {
1908             /** @private */
1909             var escape = function (character) {
1910                 switch (character) {
1911                     case "&":
1912                         return "&";
1913                     case "<":
1914                         return "<";
1915                     case ">":
1916                         return ">";
1917                     case "'":
1918                         return "'";
1919                     case "\"":
1920                         return """;
1921                     default:
1922                         return character;
1923                 }
1924             },
1925             /** @private */
1926             unescape = function (entity) {
1927                 switch (entity) {
1928                     case "&":
1929                         return "&";
1930                     case "<":
1931                         return "<";
1932                     case ">":
1933                         return ">";
1934                     case "'":
1935                         return "'";
1936                     case """:
1937                         return "\"";
1938                     default:
1939                         if (entity.charAt(1) === "#" && entity.charAt(entity.length - 1) === ";") {
1940                             if (entity.charAt(2) === "x") {
1941                                 return String.fromCharCode(parseInt(entity.slice(3, -1), 16));
1942                             } else {
1943                                 return String.fromCharCode(parseInt(entity.slice(2, -1), 10));
1944                             }
1945                         } else {
1946                             throw new Error("Invalid XML entity: " + entity);
1947                         }
1948                 }
1949             };
1950 
1951             if (typeof(text) !== "undefined" && text !== null && text !== "") {
1952                 if (makeEntityRefs) {
1953                     text = text.replace(this.xmlSpecialCharRegEx, escape);
1954                 } else {
1955                     text = text.replace(this.entityRefRegEx, unescape);
1956                 }
1957             }
1958 
1959             return text;
1960         },
1961 
1962         /**
1963          * @private
1964          * Utility method to pad the number with a leading 0 for single digits
1965          * @param (Number) num
1966          *     the number to pad
1967          */
1968         pad : function (num) {
1969             if (num < 10) {
1970                 return "0" + num;
1971             }
1972 
1973             return String(num);
1974         },
1975         
1976         /**
1977          * Pad with zeros based on a padWidth.
1978          *
1979          * @param num
1980          * @param padWidth
1981          * @returns {String} with padded zeros (based on padWidth)
1982          */
1983         padWithWidth : function (num, padWidth) {
1984             var value, index, result;
1985             
1986             result = "";
1987             for(index=padWidth;index>1;index--)
1988             {
1989                 value = Math.pow(10, index-1);
1990                 
1991                 if (num < value) {
1992                    result = result + "0";
1993                 }
1994             }
1995             result = result + num;
1996             
1997             return String(result);
1998         },
1999         
2000         /**
2001          * Converts a date to an ISO date string.
2002          *
2003          * @param aDate
2004          * @returns {String} in ISO date format
2005          *
2006          * Note: Some browsers don't support this method (e.g. IE8).
2007          */
2008         convertDateToISODateString : function (aDate) {
2009              var result;
2010              
2011              result =  aDate.getUTCFullYear() + "-" + this.padWithWidth(aDate.getUTCMonth()+1, 2) + "-" + this.padWithWidth(aDate.getUTCDate(), 2) + "T" + this.padWithWidth(aDate.getUTCHours(), 2) + ":" + this.padWithWidth(aDate.getUTCMinutes(), 2) + ":" + this.padWithWidth(aDate.getUTCSeconds(), 2)+ "." + this.padWithWidth(aDate.getUTCMilliseconds(), 3) + "Z";
2012              return result;
2013         },
2014         
2015        /**
2016         * Get the date in ISO date format. 
2017         * 
2018         * @param aDate is the date
2019         * @returns {String} date in ISO format
2020         *
2021         * Note: see convertDateToISODateString() above.
2022         */
2023         dateToISOString : function (aDate) {
2024              var result;
2025              
2026              try {
2027                 result = aDate.toISOString();
2028              } catch (e) {
2029                 result = this.convertDateToISODateString(aDate);
2030              }
2031              return result;
2032         },
2033         
2034         /**
2035          * Parse string (which is formated as ISO8601 date) into Javascript Date object.
2036          *
2037          * @param s ISO8601 string
2038          * @return {Date}
2039          * Note: Some browsers don't support Date constructor which take ISO8601 date (e.g. IE 8).
2040          */
2041         parseDateStringISO8601 : function (s) {
2042              var i, re = /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:.(\d+))?(Z|[+\-]\d{2})(?::(\d{2}))?/,
2043              d = s.match(re);
2044              if( !d ) {
2045                 return null;
2046              }
2047              for( i in d ) {
2048                 d[i] = ~~d[i];
2049              }
2050              return new Date(Date.UTC(d[1], d[2] - 1, d[3], d[4], d[5], d[6], d[7]) + (d[8] * 60 + d[9]) * 60000);
2051         },
2052         
2053         /**
2054          * Utility method to render a timestamp value (in seconds) into HH:MM:SS format.
2055          * @param {Number} time
2056          *     The timestamp in ms to render
2057          * @returns {String}
2058          * Time string in HH:MM:SS format.
2059          */
2060         getDisplayTime : function (time) {
2061             var hour, min, sec, timeStr = "00:00:00";
2062 
2063             if (time && time !== "-1") {
2064                 // calculate hours, minutes, and seconds
2065                 hour = this.pad(Math.floor(time / 3600));
2066                 min = this.pad(Math.floor((time % 3600) / 60));
2067                 sec = this.pad(Math.floor((time % 3600) % 60));
2068                 // construct HH:MM:SS time string
2069                 timeStr = hour + ":" + min + ":" + sec;
2070             }
2071 
2072             return timeStr;
2073         },
2074 
2075         /**
2076          * Checks if the string is null. If it is, return empty string; else return
2077          * the string itself.
2078          * 
2079          * @param  {String} str 
2080          * The string to check
2081          * @return {String}     
2082          * Empty string or string itself
2083          */
2084         convertNullToEmptyString : function (str) {
2085             return str || "";
2086         },
2087 
2088         /**
2089          * Utility method to render a timestamp string (of format
2090          * YYYY-MM-DDTHH:MM:SSZ) into a duration of HH:MM:SS format.
2091          * 
2092          * @param {String} timestamp
2093          *           The timestamp to render
2094          * @param {Date} [now]
2095          *            Optional argument to provide the time from which to
2096          *            calculate the duration instead of using the current time
2097          * @returns {String}
2098          * Duration string in HH:MM:SS format.
2099          */
2100         convertTsToDuration : function (timestamp, now) {
2101             return this.convertTsToDurationWithFormat(timestamp, false, now); 
2102         },
2103         
2104         /**
2105          * Utility method to render a timestamp string (of format
2106          * YYYY-MM-DDTHH:MM:SSZ) into a duration of HH:MM:SS format,
2107          * with optional -1 for null or negative times.
2108          * 
2109          * @param {String} timestamp
2110          *             The timestamp to render
2111          * @param {Boolean} forFormat
2112          *            If True, if duration is null or negative, return -1 so that the duration can be formated
2113          *            as needed in the Gadget. 
2114          * @param {Date} [now]
2115          *             Optional argument to provide the time from which to
2116          *            calculate the duration instead of using the current time
2117          * @returns {String}
2118          * Duration string in HH:MM:SS format.
2119          */
2120         convertTsToDurationWithFormat : function (timestamp, forFormat, now) {
2121             var startTimeInMs, nowInMs, durationInSec = "-1";
2122             
2123             // Calculate duration
2124             if (timestamp && typeof timestamp === "string") {
2125                 // first check it '--' for a msg in grid
2126                 if (timestamp === '--' || timestamp ==="" || timestamp === "-1") {
2127                     return "-1";
2128                 }
2129                 // else try convert string into a time
2130                 startTimeInMs = Date.parse(timestamp);
2131                 if (!isNaN(startTimeInMs)) {
2132                     if (!now || !(now instanceof Date)) {
2133                         nowInMs = this.currentServerTimeMillis();
2134                     } else {
2135                         nowInMs = this.convertToServerTimeMillis(now.getTime());
2136                     }
2137                     durationInSec = Math.floor((nowInMs - startTimeInMs) / 1000);
2138                     // Since currentServerTime is not exact (lag between sending and receiving
2139                     // messages will differ slightly), treat a slightly negative (less than 1 sec) 
2140                     // value as 0, to avoid "--" showing up when a state first changes.
2141                     if (durationInSec === -1) {
2142                         durationInSec = 0;
2143                     }
2144                     
2145                     if (durationInSec < 0) {
2146                         if (forFormat) {
2147                             return "-1";
2148                         } else {
2149                             return this.getDisplayTime("-1");
2150                         }
2151                     }
2152                 }
2153             }else {
2154                 if(forFormat){
2155                     return "-1";
2156                 }
2157             }
2158             return this.getDisplayTime(durationInSec);
2159          },
2160          
2161         /**
2162          * Takes a string (typically from window.location) and finds the value which corresponds to a name. For
2163          * example: http://www.company.com/?param1=value1¶m2=value2
2164          *
2165          * @param str is the string to search
2166          * @param name is the name to search for
2167          */
2168         getParameterByName : function(str, name) {
2169             var regex, results;
2170             name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
2171             regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
2172             results = regex.exec(str);
2173             return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
2174         }, 
2175         
2176         /**
2177          * @private
2178          * Gets the user Authorization String from the window session.
2179          * @returns the Authorization String
2180          * 
2181          */
2182         getUserAuthString: function () {
2183             var authString = window.sessionStorage.getItem('userFinesseAuth');
2184             return authString;
2185         },
2186         
2187         /**
2188          * @private
2189          * Adds a new cookie to the page with a default domain.
2190          * @param {String} key
2191          *      the key to assign a value to
2192          * @param {String} value
2193          *      the value to assign to the key
2194          * @param {Number} days
2195          *      number of days (from current) until the cookie should expire
2196          */
2197         addCookie : function (key, value, days) {
2198             var date, expires = "",
2199                 cookie = key + "=" + escape(value);
2200             if (typeof days === "number") {
2201                 date = new Date();
2202                 date.setTime(date.getTime() + (days * 24 * 3600 * 1000));
2203                 cookie += "; expires=" + date.toGMTString();
2204             }
2205             document.cookie = cookie + "; path=/";
2206         },
2207 
2208         /**
2209          * @private
2210          * Get the value of a cookie given a key.
2211          * @param {String} key
2212          *      a key to lookup
2213          * @returns {String}
2214          *      the value mapped to a key, null if key doesn't exist
2215          */
2216         getCookie : function (key) {
2217             var i, pairs, pair;
2218             if (document.cookie) {
2219                 pairs = document.cookie.split(";");
2220                 for (i = 0; i < pairs.length; i += 1) {
2221                     pair = this.trim(pairs[i]).split("=");
2222                     if (pair[0] === key) {
2223                         return unescape(pair[1]);
2224                     }
2225                 }
2226             }
2227             return null;
2228         },
2229 
2230         /**
2231          * @private
2232          * Deletes the cookie mapped to specified key.
2233          * @param {String} key
2234          *      the key to delete
2235          */
2236         deleteCookie : function (key) {
2237             this.addCookie(key, "", -1);
2238         },
2239 
2240         /**
2241          * @private
2242          * Case insensitive sort for use with arrays or Dojox stores
2243          * @param {String} a
2244          *      first value
2245          * @param {String} b
2246          *      second value
2247          */
2248         caseInsensitiveSort: function (a, b) {
2249             var ret = 0, emptyString = "";
2250             a = a + emptyString;
2251             b = b + emptyString;
2252             a = a.toLowerCase();
2253             b = b.toLowerCase();
2254             if (a > b) {
2255                 ret = 1;
2256             }
2257             if (a < b) { 
2258                 ret = -1;
2259             }
2260             return ret;
2261         },
2262 
2263         /**
2264          * @private
2265         * Calls the specified function to render the dojo wijit for a gadget  when the gadget first becomes visible.
2266         *
2267         * The displayWjitFunc function will be called once and only once when the div for our wijit 
2268         * becomes visible for the first time.  This is necessary because some dojo wijits such as the grid
2269         * throw exceptions and do not render properly if they are created in a display:none div.
2270         * If our gadget is visisble the function will be called immediately.
2271         * If our gadget is not yet visisble, then it sets a timer and waits for it to become visible.
2272         * NOTE:  The timer may seem inefficent, originally I tried connecting to the tab onclick handler, but
2273         * there is a problem with dojo.connnect to an iframe's parent node in Internet Explorer. 
2274         * In Firefox the click handler works OK, but it happens before the node is actually visisble, so you
2275         * end up waiting for the node to become visisble anyway.
2276         * @displayWjitFunc:  A function to be called once our gadget has become visisble for th first time.
2277         */  
2278         onGadgetFirstVisible: function (displayWjitFunc) {
2279             var i, q, frameId, gadgetNbr, gadgetTitleId, panelId, panelNode, link, iterval, once = false, active = false, tabId = "#finesse-tab-selector";
2280             try {
2281                 frameId = dojo.attr(window.frameElement, "id"); // Figure out what gadget number we are by looking at our frameset
2282                 gadgetNbr = frameId.match(/\d+$/)[0];  // Strip the number off the end of the frame Id, that's our gadget number
2283                 gadgetTitleId = "#finesse_gadget_" + gadgetNbr + "_title";  // Create a a gadget title id from the number
2284                 
2285                 // Loop through all of the tab panels to find one that has our gadget id
2286                 dojo.query('.tab-panel', window.parent.document).some(function (node, index, arr) {
2287                     q = dojo.query(gadgetTitleId, node);  // Look in this panel for our gadget id
2288                     if (q.length > 0) {  // You found it
2289                         panelNode = node;
2290                         panelId = dojo.attr(panelNode, "id");  // Get panel id  e.g. panel_Workgroups
2291                         active = dojo.hasClass(panelNode, "active");
2292                         tabId = "#tab_" + panelId.slice(6);  // Turn it into a tab id e.g.tab_Workgroups
2293                         return;
2294                     }
2295                 });
2296                 // If panel is already active - execute the function - we're done
2297                 if (active) {
2298                     //?console.log(frameId + " is visible display it");
2299                     setTimeout(displayWjitFunc);
2300                 } 
2301                 // If its not visible - wait for the active class to show up.
2302                 else {
2303                     //?console.log(frameId  + " (" + tabId + ") is NOT active wait for it");
2304                     iterval = setInterval(dojo.hitch(this, function () {
2305                         if (dojo.hasClass(panelNode, "active")) {
2306                             //?console.log(frameId  + " (" + tabId + ") is visible display it");
2307                             clearInterval(iterval);
2308                             setTimeout(displayWjitFunc);
2309                         } 
2310                     }), 250);
2311                 }
2312             } catch (err) {
2313                 //?console.log("Could not figure out what tab " + frameId + " is in: " + err);
2314             }
2315         },
2316 
2317         /**
2318          * @private
2319          * Downloads the specified url using a hidden iframe. In order to cause the browser to download rather than render
2320          * in the hidden iframe, the server code must append the header "Content-Disposition" with a value of 
2321          * "attachment; filename=\"<WhateverFileNameYouWant>\"".
2322          */
2323         downloadFile : function (url) {
2324             var iframe = document.getElementById("download_iframe");
2325 
2326             if (!iframe)
2327             {
2328                 iframe = document.createElement("iframe");
2329                 $(document.body).append(iframe);
2330                 $(iframe).css("display", "none");
2331             }
2332 
2333             iframe.src = url;
2334         },
2335 
2336         /**
2337          * @private
2338          * bitMask has functions for testing whether bit flags specified by integers are set in the supplied value
2339          */
2340         bitMask: {
2341             /** @private */
2342             isSet: function (value, mask) {
2343                 return (value & mask) === mask;
2344             },
2345             /**
2346              * Returns true if all flags in the intArray are set on the specified value
2347              * @private 
2348              */
2349             all: function (value, intArray) {
2350                 var i = intArray.length;
2351                 if (typeof(i) === "undefined")
2352                 {
2353                     intArray = [intArray];
2354                     i = 1;
2355                 }
2356                 while ((i = i - 1) !== -1)
2357                 {
2358                     if (!this.isSet(value, intArray[i]))
2359                     {
2360                         return false;
2361                     }
2362                 }
2363                 return true;
2364             },
2365             /**
2366              * @private
2367              * Returns true if any flags in the intArray are set on the specified value
2368              */
2369             any: function (value, intArray) {
2370                 var i = intArray.length;
2371                 if (typeof(i) === "undefined")
2372                 {
2373                     intArray = [intArray];
2374                     i = 1;
2375                 }
2376                 while ((i = i - 1) !== -1)
2377                 {
2378                     if (this.isSet(value, intArray[i]))
2379                     {
2380                         return true;
2381                     }
2382                 }
2383                 return false;
2384             }
2385         },
2386 
2387         /** @private */
2388         renderDojoGridOffScreen: function (grid) {
2389             var offscreenDiv = $("<div style='position: absolute; left: -5001px; width: 5000px;'></div>")[0];
2390             $(document.body).append(offscreenDiv);
2391             grid.placeAt(offscreenDiv);
2392             grid.startup();
2393             document.body.removeChild(offscreenDiv);
2394             return grid;
2395         },
2396 
2397         /** @private */
2398         initializeSearchInput: function(searchInput, changeCallback, callbackDelay, callbackScope, placeholderText) {
2399             var timerId = null,
2400                 theControl = typeof(searchInput) === "string" ? $("#" + searchInput) : $(searchInput),
2401                 theInputControl = theControl.find("input"),
2402                 theClearButton = theControl.find("a"),
2403                 inputControlWidthWithClear = 204,
2404                 inputControlWidthNoClear = 230,
2405                 sPreviousInput = theInputControl.val(),
2406                 /** @private **/
2407                 toggleClearButton = function(){
2408                     if (theInputControl.val() === "") {
2409                         theClearButton.hide();
2410                         theControl.removeClass("input-append");
2411                         theInputControl.width(inputControlWidthNoClear);
2412                     } else {
2413                         theInputControl.width(inputControlWidthWithClear);
2414                         theClearButton.show();
2415                         theControl.addClass("input-append");
2416                     }
2417                 };
2418 
2419             // set placeholder text
2420             theInputControl.attr('placeholder', placeholderText);
2421 
2422             theInputControl.unbind('keyup').bind('keyup', function() {
2423                 if (sPreviousInput !== theInputControl.val()) {
2424                     window.clearTimeout(timerId);
2425                     sPreviousInput = theInputControl.val();
2426                     timerId = window.setTimeout(function() {
2427                         changeCallback.call((callbackScope || window), theInputControl.val());
2428                         theInputControl[0].focus();
2429                     }, callbackDelay);
2430                 }
2431 
2432                 toggleClearButton();
2433             });
2434 
2435             theClearButton.bind('click', function() {
2436                 theInputControl.val('');
2437                 changeCallback.call((callbackScope || window), '');
2438 
2439                 toggleClearButton();
2440                 theInputControl[0].focus(); // jquery and dojo on the same page break jquery's focus() method
2441             });
2442 
2443             theInputControl.val("");
2444             toggleClearButton();
2445         },
2446 
2447         DataTables: {
2448             /** @private */
2449             createDataTable: function (options, dataTableOptions) {
2450                 var grid,
2451                     table = $('<table cellpadding="0" cellspacing="0" border="0" class="finesse"><thead><tr></tr></thead></table>'),
2452                     headerRow = table.find("tr"),
2453                     defaultOptions = {
2454                         "aaData": [],
2455                         "bPaginate": false,
2456                         "bLengthChange": false,
2457                         "bFilter": false,
2458                         "bInfo": false,
2459                         "sScrollY": "176",
2460                         "oLanguage": {
2461                             "sEmptyTable": "",
2462                             "sZeroRecords": ""
2463                         }
2464                     },
2465                     gridOptions = $.extend({}, defaultOptions, dataTableOptions),
2466                     columnDefs = [],
2467                     columnFormatter;
2468 
2469                 // Create a header cell for each column, and set up the datatable definition for the column
2470                 $(options.columns).each(function (index, column) {
2471                     headerRow.append($("<th></th>"));
2472                     columnDefs[index] = {
2473                         "mData": column.propertyName,
2474                         "sTitle": column.columnHeader,
2475                         "sWidth": column.width,
2476                         "aTargets": [index],
2477                         "bSortable": column.sortable,
2478                         "bVisible": column.visible,
2479                         "mRender": column.render
2480                     };
2481                     if (typeof(column.renderFunction) === "function")
2482                     {
2483                         /** @ignore **/
2484                         columnDefs[index].mRender = /** @ignore **/ function (value, type, dataObject) { 
2485                             var returnValue;
2486 
2487                             //Apply column render logic to value before applying extra render function
2488                             if (typeof(column.render) === "function")
2489                             {
2490                                 value = column.render.call(value, value, value);
2491                             }
2492 
2493                             if (typeof(type) === "string")
2494                             {
2495                                 switch (type)
2496                                 {
2497                                 case "undefined":
2498                                 case "sort":
2499                                     returnValue = value;
2500                                     break;
2501                                 case "set":
2502                                     throw new Error("Unsupported set data in Finesse Grid");
2503                                 case "filter":
2504                                 case "display":
2505                                 case "type":
2506                                     returnValue = column.renderFunction.call(dataObject, value, dataObject);
2507                                     break;
2508                                 default:
2509                                     break;
2510                                 }
2511                             }
2512                             else
2513                             {
2514                                 throw new Error("type param not specified in Finesse DataTable mData");
2515                             }
2516 
2517                             return  returnValue;
2518                         };
2519                     }
2520                 });
2521                 gridOptions.aoColumnDefs = columnDefs;
2522 
2523                 // Set the height
2524                 if (typeof(options.bodyHeightPixels) !== "undefined" && options.bodyHeightPixels !== null)
2525                 {
2526                     gridOptions.sScrollY = options.bodyHeightPixels + "px";
2527                 }
2528 
2529                 // Place it into the DOM
2530                 if (typeof(options.container) !== "undefined" && options.container !== null)
2531                 {
2532                     $(options.container).append(table);
2533                 }
2534 
2535                 // Create the DataTable
2536                 table.dataTable(gridOptions);
2537 
2538                 return table;
2539             }
2540         },
2541         
2542         /**
2543          * @private
2544          * Sets a dojo button to the specified disable state, removing it from
2545          * the tab order if disabling, and restoring it to the tab order if enabling.
2546          * @param {Object} dojoButton Reference to the dijit.form.Button object. This is not the DOM element.
2547          * @param {bool} disabled
2548          */
2549         setDojoButtonDisabledAttribute: function (dojoButton, disabled) {
2550             var labelNode,
2551                 tabIndex;
2552 
2553             dojoButton.set("disabled", disabled);
2554 
2555             // Remove the tabindex attribute on disabled buttons, store it, 
2556             // and replace it when it becomes enabled again
2557             labelNode = $("#" + dojoButton.id + "_label");
2558             if (disabled)
2559             {
2560                 labelNode.data("finesse:dojoButton:tabIndex", labelNode.attr("tabindex"));
2561                 labelNode.removeAttr("tabindex");
2562             }
2563             else
2564             {
2565                 tabIndex = labelNode.data("finesse:dojoButton:tabIndex");
2566                 if (typeof(tabIndex) === "string")
2567                 {
2568                     labelNode.attr("tabindex", Number(tabIndex));
2569                 }
2570             }
2571         },
2572 
2573         /**
2574          * @private
2575          * Measures the given text using the supplied fontFamily and fontSize
2576          * @param  {string} text       text to measure
2577          * @param  {string} fontFamily
2578          * @param  {string} fontSize
2579          * @return {number} pixel width
2580          */
2581         measureText: function (text, fontFamily, fontSize) {
2582             var width,
2583                 element = $("<div></div>").text(text).css({
2584                     "fontSize": fontSize,
2585                     "fontFamily": fontFamily
2586                 }).addClass("offscreen").appendTo(document.body);
2587 
2588             width = element.width();
2589             element.remove();
2590 
2591             return width;
2592         },
2593 
2594         /**
2595          * Adjusts the gadget height. Shindig's gadgets.window.adjustHeight fails when
2596          * needing to resize down in IE. This gets around that by calculating the height
2597          * manually and passing it in.
2598          * @return {undefined}
2599          */
2600         "adjustGadgetHeight": function () {
2601             var bScrollHeight = $("body").height() + 20;
2602             gadgets.window.adjustHeight(bScrollHeight);
2603         },
2604 
2605         /**
2606         * Private helper method for converting a javascript object to xml, where the values of the elements are
2607         * appropriately escaped for XML.
2608         * This is a simple implementation that does not implement cdata or attributes. It is also 'unformatted' in that
2609         * there is no whitespace between elements.
2610         * @param object The javascript object to convert to XML.
2611         * @returns The XML string.
2612         * @private
2613         */
2614         _json2xmlWithEscape: function(object) {
2615             var that = this,
2616                 xml = "",
2617                 m,
2618                 /** @private **/
2619                 toXmlHelper = function(value, name) {
2620                 var xml = "",
2621                     i,
2622                     m;
2623                 if (value instanceof Array) {
2624                     for (i = 0; i < value.length; ++i) {
2625                         xml += toXmlHelper(value[i], name);
2626                     }
2627                 }
2628                 else if (typeof value === "object") {
2629                     xml += "<" + name + ">";
2630                     for (m in value) {
2631                         if (value.hasOwnProperty(m)) {
2632                            xml += toXmlHelper(value[m], m);
2633                         }
2634                     }
2635                     xml += "</" + name + ">";
2636                 }
2637                 else {
2638                     // is a leaf node
2639                     xml += "<" + name + ">" + that.translateHTMLEntities(value.toString(), true) +
2640                         "</" + name + ">";
2641                 }
2642                 return xml;
2643             };
2644             for (m in object) {
2645                 if (object.hasOwnProperty(m)) {
2646                     xml += toXmlHelper(object[m], m);
2647                 }
2648             }
2649             return xml;
2650         },
2651 
2652         /**
2653          * Utility to detect the browser version of IE, whether it is IE9 or IE8 or in compatibility mode.
2654          * If IE is earlier than IE8, version returns undefined.
2655          * 
2656          * @return {Object} browser object has the following form:
2657          * {
2658          *     isIE: {Boolean},
2659          *     version: {String}, // 8 for IE8, 9 or IE9, 11 or IE11
2660          *     isCompatibilityMode: {Boolean}
2661          * }
2662          */
2663         detectIEBrowserVersion: function () {
2664             var browser = {
2665                 isIE: false,
2666                 isCompatibilityMode: false
2667             },
2668 
2669             useragent = navigator.userAgent,
2670 
2671             appName = navigator.appName;
2672 
2673             // Check to see if app is IE
2674             if (appName.indexOf("Microsoft Internet Explorer") !== -1) {
2675                 browser.isIE = true;
2676                 // Check for Trident version
2677                 if (useragent.indexOf("Trident/5.0") !== -1) { // IE9
2678                     browser.version = "9";
2679                     if (useragent.indexOf("MSIE 9.0") === -1) {
2680                         browser.isCompatibilityMode = true;
2681                     }
2682                 } else if (useragent.indexOf("Trident/4.0") !== -1) { // IE8
2683                     browser.version = "8";
2684                     if (useragent.indexOf("MSIE 8.0") === -1) {
2685                         browser.isCompatibilityMode = true;
2686                     }
2687                 }
2688             }
2689             //IE 11 follows different rules. Non standard.
2690             else if (appName.indexOf("Netscape") !== -1) {
2691                 if(useragent.match(/Trident.*rv\:11\./) !== -1) {
2692                     browser.isIE = true;
2693                     browser.version = "11";
2694                 }
2695             }
2696             return browser;            
2697         },
2698 
2699         /**
2700          * Use JQuery's implementation of Promises (Deferred) to execute code when 
2701          * multiple async processes have finished. An example use:
2702          *
2703          * var asyncProcess1 = $.Deferred(),
2704          *     asyncProcess2 = $.Deferred();
2705          *     
2706          * finesse.utilities.Utilities.whenAllDone(asyncProcess1, asyncProcess2) // WHEN both asyncProcess1 and asyncProcess2 are resolved or rejected ...
2707          *     .then(
2708          *         // First function passed to then() is called when all async processes are complete, regardless of errors
2709          *         function () {
2710          *             console.log("all processes completed");
2711          *         },
2712          *         // Second function passed to then() is called if any async processed threw an exception
2713          *         function (failures) { // Array of failure messages
2714          *             console.log("Number of failed async processes: " + failures.length);
2715          *         });
2716          *
2717          * Found at:
2718          * http://stackoverflow.com/a/15094263/1244030
2719          *
2720          * Pass in any number of $.Deferred instances.
2721          * @returns {Object}
2722          */
2723         whenAllDone: function () {
2724             var deferreds = [],
2725                 result = $.Deferred();
2726 
2727             $.each(arguments, function(i, current) {
2728                 var currentDeferred = $.Deferred();
2729                 current.then(function() {
2730                     currentDeferred.resolve(false, arguments);
2731                 }, function() {
2732                     currentDeferred.resolve(true, arguments);
2733                 });
2734                 deferreds.push(currentDeferred);
2735             });
2736 
2737             $.when.apply($, deferreds).then(function() {
2738                 var failures = [],
2739                     successes = [];
2740 
2741                 $.each(arguments, function(i, args) {
2742                     // If we resolved with `true` as the first parameter
2743                     // we have a failure, a success otherwise
2744                     var target = args[0] ? failures : successes,
2745                         data = args[1];
2746                     // Push either all arguments or the only one
2747                     target.push(data.length === 1 ? data[0] : args);
2748                 });
2749 
2750                 if(failures.length) {
2751                     return result.reject.apply(result, failures);
2752                 }
2753 
2754                 return result.resolve.apply(result, successes);
2755             });
2756 
2757             return result;
2758         }
2759     };    
2760     
2761     return Utilities;
2762 }));
2763 
2764 /** The following comment is to prevent jslint errors about 
2765  * using variables before they are defined.
2766  */
2767 /*global finesse*/
2768 
2769 /**
2770  * Initiated by the Master to create a shared BOSH connection.
2771  *
2772  * @requires Utilities
2773  */
2774 
2775 /**
2776  * @class
2777  * Establishes a shared event connection by creating a communication tunnel
2778  * with the notification server and consume events which could be published.
2779  * Public functions are exposed to register to the connection status information
2780  * and events.
2781  * @constructor
2782  * @param {String} host
2783  *     The host name/ip of the Finesse server.
2784  * @throws {Error} If required constructor parameter is missing.
2785  */
2786 /** @private */
2787 (function (factory) {
2788     
2789 
2790     // Define as an AMD module if possible
2791     if ( typeof define === 'function' && define.amd )
2792     {
2793         define('clientservices/MasterTunnel',["utilities/Utilities"], factory );
2794     }
2795     
2796     /* Define using browser globals otherwise
2797      * Prevent multiple instantiations if the script is loaded twice
2798      */
2799     else
2800     {
2801         factory(finesse.utilities.Utilities);
2802     }
2803     
2804 }(function (Utilities) {
2805      var MasterTunnel = function (host, scheme) { 
2806         if (typeof host !== "string" || host.length === 0) {
2807             throw new Error("Required host parameter missing.");
2808         }
2809 
2810         var
2811 
2812         /**
2813          * Flag to indicate whether the tunnel frame is loaded.
2814          * @private
2815          */
2816         _isTunnelLoaded = false,
2817 
2818         /**
2819          * Short reference to the Finesse utility.
2820          * @private
2821          */
2822         _util = Utilities,
2823 
2824         /**
2825          * The URL with host and port to the Finesse server.
2826          * @private
2827          */
2828         _tunnelOrigin,
2829 
2830         /**
2831          * Location of the tunnel HTML URL.
2832          * @private
2833          */
2834         _tunnelURL,
2835         
2836         /**
2837          * The port on which to connect to the Finesse server to load the eventing resources.
2838          * @private
2839          */
2840         _tunnelOriginPort,
2841         
2842         /**
2843          * Flag to indicate whether we have processed the tunnel config yet.
2844          * @private
2845          */
2846         _isTunnelConfigInit = false,
2847 
2848         /**
2849          * The tunnel frame window object.
2850          * @private
2851          */
2852         _tunnelFrame,
2853 
2854         /**
2855          * The handler registered with the object to be invoked when an event is
2856          * delivered by the notification server.
2857          * @private
2858          */
2859         _eventHandler,
2860         
2861         /**
2862          * The handler registered with the object to be invoked when presence is
2863          * delivered by the notification server.
2864          * @private
2865          */
2866         _presenceHandler,
2867 
2868         /**
2869          * The handler registered with the object to be invoked when the BOSH
2870          * connection has changed states. The object will contain the "status"
2871          * property and a "resourceID" property only if "status" is "connected".
2872          * @private
2873          */
2874         _connInfoHandler,
2875 
2876         /**
2877          * The last connection status published by the JabberWerx library.
2878          * @private
2879          */
2880         _statusCache,
2881 
2882         /**
2883          * The last event sent by notification server.
2884          * @private
2885          */
2886         _eventCache,
2887 
2888         /**
2889          * The ID of the user logged into notification server.
2890          * @private
2891          */
2892         _id,
2893 
2894         /**
2895          * The domain of the XMPP server, representing the portion of the JID
2896          * following '@': userid@domain.com
2897          * @private
2898          */
2899         _xmppDomain,
2900 
2901         /**
2902          * The password of the user logged into notification server.
2903          * @private
2904          */
2905         _password,
2906 
2907         /**
2908          * The jid of the pubsub service on the XMPP server
2909          * @private
2910          */
2911         _pubsubDomain,
2912 
2913         /**
2914          * The resource to use for the BOSH connection.
2915          * @private
2916          */
2917         _resource,
2918 
2919         /**
2920          * The resource ID identifying the client device (that we receive from the server).
2921          * @private
2922          */
2923         _resourceID,
2924 
2925         /**
2926          * The different types of messages that could be sent to the parent frame.
2927          * The types here should be understood by the parent frame and used to
2928          * identify how the message is formatted.
2929          * @private
2930          */
2931         _TYPES = {
2932             EVENT: 0,
2933             ID: 1,
2934             PASSWORD: 2,
2935             RESOURCEID: 3,
2936             STATUS: 4,
2937             XMPPDOMAIN: 5,
2938             PUBSUBDOMAIN: 6,
2939             SUBSCRIBE: 7,
2940             UNSUBSCRIBE: 8,
2941             PRESENCE: 9,
2942             CONNECT_REQ: 10
2943         },
2944 
2945         _handlers = {
2946             subscribe: {},
2947             unsubscribe: {}
2948         },
2949         
2950 
2951         /**
2952          * Create a connection info object.
2953          * @returns {Object}
2954          *     A connection info object containing a "status" and "resourceID".
2955          * @private
2956          */
2957         _createConnInfoObj = function () {
2958             return {
2959                 status: _statusCache,
2960                 resourceID: _resourceID
2961             };
2962         },
2963 
2964         /**
2965          * Utility function which sends a message to the dynamic tunnel frame
2966          * event frame formatted as follows: "type|message".
2967          * @param {Number} type
2968          *     The category type of the message.
2969          * @param {String} message
2970          *     The message to be sent to the tunnel frame.
2971          * @private
2972          */
2973         _sendMessage = function (type, message) {
2974             message = type + "|" + message;
2975             _util.sendMessage(message, _tunnelFrame, _tunnelOrigin);
2976         },
2977 
2978         /**
2979          * Utility to process the response of a subscribe request from
2980          * the tunnel frame, then invoking the stored callback handler
2981          * with the respective data (error, when applicable)
2982          * @param {String} data
2983          *     The response in the format of "node[|error]"
2984          * @private
2985          */
2986         _processSubscribeResponse = function (data) {
2987             var dataArray = data.split("|"),
2988             node = dataArray[0],
2989             err;
2990             
2991             //Error is optionally the second item in the array
2992             if (dataArray.length) {
2993                 err = dataArray[1];
2994             }
2995             
2996             // These response handlers are short lived and should be removed and cleaned up immediately after invocation.
2997             if (_handlers.subscribe[node]) {
2998                 _handlers.subscribe[node](err);
2999                 delete _handlers.subscribe[node];
3000             }
3001         },
3002 
3003         /**
3004          * Utility to process the response of an unsubscribe request from
3005          * the tunnel frame, then invoking the stored callback handler
3006          * with the respective data (error, when applicable)
3007          * @param {String} data
3008          *     The response in the format of "node[|error]"
3009          * @private
3010          */
3011         _processUnsubscribeResponse = function (data) {
3012             var dataArray = data.split("|"),
3013             node = dataArray[0],
3014             err;
3015             
3016             //Error is optionally the second item in the array
3017             if (dataArray.length) {
3018                 err = dataArray[1];
3019             }
3020             
3021             // These response handlers are short lived and should be removed and cleaned up immediately after invocation.
3022             if (_handlers.unsubscribe[node]) {
3023                 _handlers.unsubscribe[node](err);
3024                 delete _handlers.unsubscribe[node];
3025             }
3026         },
3027 
3028         /**
3029          * Handler for messages delivered by window.postMessage. Listens for events
3030          * published by the notification server, connection status published by
3031          * the JabberWerx library, and the resource ID created when the BOSH
3032          * connection has been established.
3033          * @param {Object} e
3034          *     The message object as provided by the window.postMessage feature.
3035          * @private
3036          */
3037         _messageHandler = function (e) {
3038             var
3039 
3040             //Extract the message type and message data. The expected format is
3041             //"type|data" where type is a number represented by the TYPES object.
3042             delimPos = e.data.indexOf("|"),
3043             type = Number(e.data.substr(0, delimPos)),
3044             data =  e.data.substr(delimPos + 1);
3045             
3046             //Accepts messages and invoke the correct registered handlers.
3047             switch (type) {
3048             case _TYPES.EVENT:
3049                 _eventCache = data;
3050                 if (typeof _eventHandler === "function") {
3051                     _eventHandler(data);
3052                 }
3053                 break;
3054             case _TYPES.STATUS:
3055                 _statusCache = data;
3056 
3057                 //A "loaded" status means that the frame is ready to accept
3058                 //credentials for establishing a BOSH connection.
3059                 if (data === "loaded") {
3060                     _isTunnelLoaded = true;
3061                     if(_resource) {
3062                         _sendMessage(_TYPES.RESOURCEID, _resource);
3063                     }
3064                     _sendMessage(_TYPES.ID, _id);
3065                     _sendMessage(_TYPES.XMPPDOMAIN, _xmppDomain);
3066                     _sendMessage(_TYPES.PASSWORD, _password);
3067                     _sendMessage(_TYPES.PUBSUBDOMAIN, _pubsubDomain);
3068                 } else if (typeof _connInfoHandler === "function") {
3069                     _connInfoHandler(_createConnInfoObj());
3070                 }
3071                 break;
3072             case _TYPES.RESOURCEID:
3073                 _resourceID = data;
3074                 break;
3075             case _TYPES.SUBSCRIBE:
3076                 _processSubscribeResponse(data);
3077                 break;
3078             case _TYPES.UNSUBSCRIBE:
3079                 _processUnsubscribeResponse(data);
3080                 break;
3081             case _TYPES.PRESENCE:
3082                 if (typeof _presenceHandler === "function") {
3083                     _presenceHandler(data);
3084                 }
3085                 break;
3086             default:
3087                 break;
3088             }
3089         },
3090 
3091         /**
3092          * Initialize the tunnel config so that the url can be http or https with the appropriate port
3093          * @private
3094          */
3095         _initTunnelConfig = function () {
3096             if (_isTunnelConfigInit === true) {
3097                 return;
3098             }
3099             
3100             //Initialize tunnel origin
3101             //Determine tunnel origin based on host and scheme
3102             _tunnelOriginPort = (scheme && scheme.indexOf("https") !== -1) ? "7443" : "7071";
3103             if (scheme) {
3104                 _tunnelOrigin = scheme + "://" + host + ":" + _tunnelOriginPort;
3105             } else {
3106                 _tunnelOrigin = "http://" + host + ":" + _tunnelOriginPort;
3107             }
3108             _tunnelURL = _tunnelOrigin + "/tunnel/";
3109             
3110             _isTunnelConfigInit = true;
3111         },
3112 
3113         /**
3114          * Create the tunnel iframe which establishes the shared BOSH connection.
3115          * Messages are sent across frames using window.postMessage.
3116          * @private
3117          */
3118         _createTunnel = function () {
3119             var tunnelID = ((self === parent) ? "tunnel-frame" : "autopilot-tunnel-frame"),
3120             iframe = document.createElement("iframe");         
3121             iframe.style.display = "none";
3122             iframe.setAttribute("id", tunnelID);
3123             iframe.setAttribute("name", tunnelID);
3124             iframe.setAttribute("src", _tunnelURL);
3125             document.body.appendChild(iframe);
3126             _tunnelFrame = window.frames[tunnelID];
3127         };
3128 
3129         /**
3130          * Sends a message via postmessage to the EventTunnel to attempt to connect to the XMPP server
3131          * @private
3132          */
3133         this.makeConnectReq = function () {
3134             _sendMessage(_TYPES.PASSWORD, _password);
3135         };
3136         
3137         /**
3138          * @private
3139          * Returns the host of the Finesse server.
3140          * @returns {String}
3141          *     The host specified during the creation of the object.
3142          */
3143         this.getHost = function () {
3144             return host;
3145         };
3146 
3147         /**
3148          * @private
3149          * The resource ID of the user who is logged into the notification server.
3150          * @returns {String}
3151          *     The resource ID generated by the notification server.
3152          */
3153         this.getResourceID = function () {
3154             return _resourceID;
3155         };
3156 
3157         /**
3158          * @private
3159          * Indicates whether the tunnel frame is loaded.
3160          * @returns {Boolean}
3161          *     True if the tunnel frame is loaded, false otherwise.
3162          */
3163         this.isTunnelLoaded = function () {
3164             return _isTunnelLoaded;
3165         };
3166 
3167         /**
3168          * @private
3169          * The location of the tunnel HTML URL.
3170          * @returns {String}
3171          *     The location of the tunnel HTML URL.
3172          */
3173         this.getTunnelURL = function () {
3174             return _tunnelURL;
3175         };
3176 
3177         /**
3178          * @private
3179          * Tunnels a subscribe request to the eventing iframe.
3180          * @param {String} node
3181          *     The node to subscribe to
3182          * @param {Function} handler
3183          *     Handler to invoke upon success or failure
3184          */
3185         this.subscribe = function (node, handler) {
3186             if (handler && typeof handler !== "function") {
3187                 throw new Error("Parameter is not a function.");
3188             }
3189             _handlers.subscribe[node] = handler;
3190             _sendMessage(_TYPES.SUBSCRIBE, node);
3191         };
3192 
3193         /**
3194          * @private
3195          * Tunnels an unsubscribe request to the eventing iframe.
3196          * @param {String} node
3197          *     The node to unsubscribe from
3198          * @param {Function} handler
3199          *     Handler to invoke upon success or failure
3200          */
3201         this.unsubscribe = function (node, handler) {
3202             if (handler && typeof handler !== "function") {
3203                 throw new Error("Parameter is not a function.");
3204             }
3205             _handlers.unsubscribe[node] = handler;
3206             _sendMessage(_TYPES.UNSUBSCRIBE, node);
3207         };
3208 
3209         /**
3210          * @private
3211          * Registers a handler to be invoked when an event is delivered. Only one
3212          * is registered at a time. If there has already been an event that was
3213          * delivered, the handler will be invoked immediately.
3214          * @param {Function} handler
3215          *     Invoked when an event is delivered through the event connection.
3216          */
3217         this.registerEventHandler = function (handler) {
3218             if (typeof handler !== "function") {
3219                 throw new Error("Parameter is not a function.");
3220             }
3221             _eventHandler = handler;
3222             if (_eventCache) {
3223                 handler(_eventCache);
3224             }
3225         };
3226 
3227         /**
3228          * @private
3229          * Unregisters the event handler completely.
3230          */
3231         this.unregisterEventHandler = function () {
3232             _eventHandler = undefined;
3233         };
3234         
3235         /**
3236          * @private
3237          * Registers a handler to be invoked when a presence event is delivered. Only one
3238          * is registered at a time. 
3239          * @param {Function} handler
3240          *     Invoked when a presence event is delivered through the event connection.
3241          */
3242         this.registerPresenceHandler = function (handler) {
3243             if (typeof handler !== "function") {
3244                 throw new Error("Parameter is not a function.");
3245             }
3246             _presenceHandler = handler;
3247         };
3248         
3249         /**
3250          * @private
3251          * Unregisters the presence event handler completely.
3252          */
3253         this.unregisterPresenceHandler = function () {
3254             _presenceHandler = undefined;
3255         };
3256 
3257         /**
3258          * @private
3259          * Registers a handler to be invoked when a connection status changes. The
3260          * object passed will contain a "status" property, and a "resourceID"
3261          * property, which will contain the most current resource ID assigned to
3262          * the client. If there has already been an event that was delivered, the
3263          * handler will be invoked immediately.
3264          * @param {Function} handler
3265          *     Invoked when a connection status changes.
3266          */
3267         this.registerConnectionInfoHandler = function (handler) {
3268             if (typeof handler !== "function") {
3269                 throw new Error("Parameter is not a function.");
3270             }
3271             _connInfoHandler = handler;
3272             if (_statusCache) {
3273                 handler(_createConnInfoObj());
3274             }
3275         };
3276 
3277         /**
3278          * @private
3279          * Unregisters the connection information handler.
3280          */
3281         this.unregisterConnectionInfoHandler = function () {
3282             _connInfoHandler = undefined;
3283         };
3284 
3285         /**
3286          * @private
3287          * Start listening for events and create a event tunnel for the shared BOSH
3288          * connection.
3289          * @param {String} id
3290          *     The ID of the user for the notification server.
3291          * @param {String} password
3292          *     The password of the user for the notification server.
3293          * @param {String} xmppDomain
3294          *     The XMPP domain of the notification server
3295          * @param {String} pubsubDomain
3296          *     The location (JID) of the XEP-0060 PubSub service
3297          * @param {String} resource
3298          *     The resource to connect to the notification servier with.
3299          */
3300         this.init = function (id, password, xmppDomain, pubsubDomain, resource) {
3301             
3302             if (typeof id !== "string" || typeof password !== "string" || typeof xmppDomain !== "string" || typeof pubsubDomain !== "string") {
3303                 throw new Error("Invalid or missing required parameters.");
3304             }
3305 
3306             _initTunnelConfig();
3307             
3308             _id = id;
3309             _password = password;
3310             _xmppDomain = xmppDomain;
3311             _pubsubDomain = pubsubDomain;
3312             _resource = resource;
3313 
3314             //Attach a listener for messages sent from tunnel frame.
3315             _util.receiveMessage(_messageHandler, _tunnelOrigin);
3316 
3317             //Create the tunnel iframe which will establish the shared connection.
3318             _createTunnel();
3319         };
3320 
3321         //BEGIN TEST CODE//
3322 //        /**
3323 //         * Test code added to expose private functions that are used by unit test
3324 //         * framework. This section of code is removed during the build process
3325 //         * before packaging production code. The [begin|end]TestSection are used
3326 //         * by the build to identify the section to strip.
3327 //         * @ignore
3328 //         */
3329 //        this.beginTestSection = 0;
3330 //
3331 //        /**
3332 //         * @ignore
3333 //         */
3334 //        this.getTestObject = function () {
3335 //            //Load mock dependencies.
3336 //            var _mock = new MockControl();
3337 //            _util = _mock.createMock(finesse.utilities.Utilities);
3338 //
3339 //            return {
3340 //                //Expose mock dependencies
3341 //                mock: _mock,
3342 //                util: _util,
3343 //
3344 //                //Expose internal private functions
3345 //                types: _TYPES,
3346 //                createConnInfoObj: _createConnInfoObj,
3347 //                sendMessage: _sendMessage,
3348 //                messageHandler: _messageHandler,
3349 //                createTunnel: _createTunnel,
3350 //                handlers: _handlers,
3351 //                initTunnelConfig : _initTunnelConfig
3352 //            };
3353 //        };
3354 //
3355 //        /**
3356 //         * @ignore
3357 //         */
3358 //        this.endTestSection = 0;
3359 //        //END TEST CODE//
3360     };
3361     
3362     /** @namespace JavaScript class objects and methods to handle the subscription to Finesse events.*/
3363     finesse.clientservices = finesse.clientservices || {};
3364 
3365     window.finesse = window.finesse || {};
3366     window.finesse.clientservices = window.finesse.clientservices || {};
3367     window.finesse.clientservices.MasterTunnel = MasterTunnel;
3368 
3369 }));
3370 
3371 /**
3372  * Contains a list of topics used for client side pubsub.
3373  *
3374  */
3375 
3376 /** @private */
3377 (function (factory) {
3378     
3379 
3380     // Define as an AMD module if possible
3381     if ( typeof define === 'function' && define.amd )
3382     {
3383         define('clientservices/Topics',[], factory );
3384     }
3385     
3386     /* Define using browser globals otherwise
3387      * Prevent multiple instantiations if the script is loaded twice
3388      */
3389     else
3390     {
3391         factory();
3392     }
3393     
3394 }(function () {
3395     
3396    var Topics = (function () {
3397 
3398         /**
3399          * @private
3400          * The namespace prepended to all Finesse topics.
3401          */
3402         this.namespace = "finesse.info";
3403     
3404         /**
3405          * @private
3406          * Gets the full topic name with the Finesse namespace prepended.
3407          * @param {String} topic
3408          *     The topic category.
3409          * @returns {String}
3410          *     The full topic name with prepended namespace.
3411          */
3412         var _getNSTopic = function (topic) {
3413             return this.namespace + "." + topic;
3414         };
3415         
3416         /** @scope finesse.clientservices.Topics */
3417         return {
3418             /** 
3419              * @private
3420              * Client side request channel. 
3421              */
3422             REQUESTS: _getNSTopic("requests"),
3423     
3424             /** 
3425              * @private
3426              * Client side response channel. 
3427              */
3428             RESPONSES: _getNSTopic("responses"),
3429 
3430             /** 
3431              * @private
3432              * Connection status. 
3433              */
3434             EVENTS_CONNECTION_INFO: _getNSTopic("connection"),
3435             
3436             /** 
3437              * @private
3438              * Presence channel 
3439              */
3440             PRESENCE: _getNSTopic("presence"),
3441     
3442             /**
3443              * @private
3444              * Convert a Finesse REST URI to a OpenAjax compatible topic name.
3445              */
3446             getTopic: function (restUri) {
3447                 //The topic should not start with '/' else it will get replaced with
3448                 //'.' which is invalid.
3449                 //Thus, remove '/' if it is at the beginning of the string
3450                 if (restUri.indexOf('/') === 0) {
3451                     restUri = restUri.substr(1);
3452                 }
3453     
3454                 //Replace every instance of "/" with ".". This is done to follow the
3455                 //OpenAjaxHub topic name convention.
3456                 return restUri.replace(/\//g, ".");
3457             }
3458         };
3459     }());
3460     window.finesse = window.finesse || {};
3461     window.finesse.clientservices = window.finesse.clientservices || {};
3462     /** @private */
3463     window.finesse.clientservices.Topics = Topics;
3464     
3465     return Topics;
3466 }));
3467 
3468 /** The following comment is to prevent jslint errors about 
3469  * using variables before they are defined.
3470  */
3471 /*global finesse*/
3472 
3473 /**
3474  * Registers with the MasterTunnel to receive events, which it
3475  *     could publish to the OpenAjax gadget pubsub infrastructure.
3476  *
3477  * @requires OpenAjax, finesse.clientservices.MasterTunnel, finesse.clientservices.Topics
3478  */
3479 
3480 /** @private */
3481 (function (factory) {
3482     
3483 
3484     // Define as an AMD module if possible
3485     if ( typeof define === 'function' && define.amd )
3486     {
3487         define('clientservices/MasterPublisher',["clientservices/MasterTunnel",
3488                 "clientservices/Topics",
3489                 "utilities/Utilities"], factory );
3490     }
3491     
3492     /* Define using browser globals otherwise
3493      * Prevent multiple instantiations if the script is loaded twice
3494      */
3495     else
3496     {
3497         factory(finesse.clientservices.MasterTunnel, finesse.clientservices.Topics, finesse.utilities.Utilities);
3498     }
3499     
3500 }(function (MasterTunnel, Topics, Utilities) {
3501     
3502      var MasterPublisher = function (tunnel, hub) {
3503         if (!(tunnel instanceof MasterTunnel)) {
3504             throw new Error("Required tunnel object missing or invalid.");
3505         }
3506 
3507         var
3508         
3509         ClientServices = finesse.clientservices.ClientServices,
3510 
3511         /**
3512          * Reference to the gadget pubsub Hub instance.
3513          * @private
3514          */
3515         _hub = hub,
3516 
3517         /**
3518          * Reference to the Topics class.
3519          * @private
3520          */
3521         _topics = Topics,
3522         
3523         /**
3524          * Reference to conversion utilities class.
3525          * @private
3526          */
3527         _utils = Utilities,
3528         
3529         /**
3530          * References to ClientServices logger methods
3531          * @private
3532          */
3533         _logger = {
3534             log: ClientServices.log
3535         },
3536         
3537         /**
3538          * Store the passed in tunnel.
3539          * @private
3540          */
3541         _tunnel = tunnel,
3542 
3543         /**
3544          * Caches the connection info event so that it could be published if there
3545          * is a request for it.
3546          * @private
3547          */
3548         _connInfoCache = {},
3549 
3550         /**
3551          * The types of possible request types supported when listening to the
3552          * requests channel. Each request type could result in different operations.
3553          * @private
3554          */
3555         _REQTYPES = {
3556             CONNECTIONINFO: "ConnectionInfoReq",
3557             SUBSCRIBE: "SubscribeNodeReq",
3558             UNSUBSCRIBE: "UnsubscribeNodeReq",
3559             CONNECT: "ConnectionReq"
3560         },
3561 
3562         /**
3563          * Will store list of nodes that have OF subscriptions created
3564          *     _nodesList[node][subscribing].reqIds[subid]
3565          *     _nodesList[node][active].reqIds[subid]
3566          *     _nodesList[node][unsubscribing].reqIds[subid]
3567          *     _nodesList[node][holding].reqIds[subid]
3568          * @private
3569          */
3570         _nodesList = {},
3571         
3572         /**
3573          * The states that a subscription can be in
3574          * @private
3575          */
3576         _CHANNELSTATES = {
3577             UNINITIALIZED: "Uninitialized",
3578             PENDING: "Pending",
3579             OPERATIONAL: "Operational"
3580         },
3581 
3582         /**
3583           * Checks if the payload is JSON 
3584           * @returns {Boolean}
3585           * @private
3586           */
3587         _isJsonPayload = function(event) {
3588             var delimStart, delimEnd, retval = false;
3589             
3590             try { 
3591               delimStart = event.indexOf('{');
3592               delimEnd = event.lastIndexOf('}');
3593 
3594               if ((delimStart !== -1 ) && (delimEnd === (event.length - 1))) {
3595                 retval = true;  //event contains JSON payload
3596               }
3597             } catch (err) {
3598               _logger.log("MasterPublisher._isJsonPayload() - Caught error: " + err);
3599             }
3600             return retval;
3601         },
3602         
3603                 /**
3604           * Parses a JSON event and then publishes.
3605           *
3606           * @param {String} event
3607           *     The full event payload.
3608           * @throws {Error} If the payload object is malformed.
3609           * @private
3610           */
3611         _parseAndPublishJSONEvent = function(event) {
3612             var topic, eventObj, publishEvent,
3613             delimPos = event.indexOf("{"),
3614             node, parser,
3615             eventJson = event,
3616             returnObj = {node: null, data: null};
3617 
3618             try {
3619                //Extract and strip the node path from the message
3620                if (delimPos > 0) 
3621                {
3622                   //We need to decode the URI encoded node path
3623                   //TODO: make sure this is kosher with OpenAjax topic naming
3624                   node = decodeURI(event.substr(0, delimPos));
3625                   eventJson = event.substr(delimPos);
3626                   
3627                   //Converting the node path to openAjaxhub topic
3628                   topic = _topics.getTopic(node);
3629                   
3630                   returnObj.node = node;
3631                   returnObj.payload = eventJson;
3632                } 
3633                else 
3634                {
3635                   _logger.log("MasterPublisher._parseAndPublishJSONEvent() - [ERROR] node is not given in postMessage: " + eventJson);
3636                   throw new Error("node is not given in postMessage: " + eventJson);
3637                }
3638 
3639                parser = _utils.getJSONParser();
3640 
3641                eventObj = parser.parse(eventJson);
3642                returnObj.data = eventObj;
3643 
3644             } catch (err) {
3645                _logger.log("MasterPublisher._parseAndPublishJSONEvent() - [ERROR] Malformed event payload: " + err);
3646                throw new Error("Malformed event payload : " + err);
3647             }
3648             
3649             _logger.log("MasterPublisher._parseAndPublishJSONEvent() - Received JSON event on node '" + node + "': " + eventJson); 
3650             
3651             publishEvent = {content : event, object : eventObj };
3652 
3653             //Publish event to proper event topic.
3654             if (topic && eventObj) {
3655                _hub.publish(topic, publishEvent);
3656             }
3657         },
3658         
3659         /**
3660           * Parses an XML event and then publishes.
3661           *
3662           * @param {String} event
3663           *     The full event payload.
3664           * @throws {Error} If the payload object is malformed.
3665           * @private
3666           */
3667         _parseAndPublishXMLEvent = function(event) {
3668             var topic, eventObj, publishEvent, restTopic,
3669             delimPos = event.indexOf("<"),
3670             node,
3671             eventXml = event;
3672             
3673             try {
3674                //Extract and strip the node path from the message
3675                if (delimPos > 0) {
3676                   //We need to decode the URI encoded node path
3677                   //TODO: make sure this is kosher with OpenAjax topic naming
3678                   node = decodeURI(event.substr(0, delimPos));
3679                   eventXml = event.substr(delimPos);
3680                   //Converting the node path to openAjaxhub topic
3681                   topic = _topics.getTopic(node);
3682                } else {
3683                   _logger.log("MasterPublisher._parseAndPublishXMLEvent() - [ERROR] node is not given in postMessage: " + eventXml);
3684                   throw new Error("node is not given in postMessage: " + eventXml);
3685                }
3686 
3687                eventObj = _utils.xml2JsObj(eventXml);
3688                   
3689            } catch (err) {
3690                _logger.log("MasterPublisher._parseAndPublishXMLEvent() - [ERROR] Malformed event payload: " + err);
3691                throw new Error("Malformed event payload : " + err);
3692            }
3693            
3694            _logger.log("MasterPublisher._parseAndPublishXMLEvent() - Received XML event on node '" + node + "': " + eventXml);
3695            
3696            publishEvent = {content : event, object : eventObj };
3697 
3698            //Publish event to proper event topic.
3699            if (topic && eventObj) {
3700                _hub.publish(topic, publishEvent);
3701            }
3702         },
3703         
3704         /**
3705          * Publishes events to the appropriate topic. The topic name is determined
3706          * by fetching the source value from the event.
3707          * @param {String} event
3708          *     The full event payload.
3709          * @throws {Error} If the payload object is malformed.
3710          * @private
3711          */
3712         _eventHandler = function (event) {
3713             
3714             //Handle JSON or XML events
3715             if (!_isJsonPayload(event))
3716             {
3717                //XML
3718                _parseAndPublishXMLEvent(event);
3719             }
3720             else
3721             {
3722                //JSON
3723                _parseAndPublishJSONEvent(event);
3724             }
3725         },
3726         
3727         
3728         /**
3729          * Handler for when presence events are sent through the MasterTunnel.
3730          * @returns {Object}
3731          *     A presence xml event.
3732          * @private
3733          */
3734         _presenceHandler = function (event) {
3735             var eventObj = _utils.xml2JsObj(event), publishEvent;
3736             
3737             publishEvent = {content : event, object : eventObj};
3738             
3739             if (eventObj) {
3740                 _hub.publish(_topics.PRESENCE, publishEvent);
3741             }
3742         },
3743 
3744         /**
3745          * Clone the connection info object from cache.
3746          * @returns {Object}
3747          *     A connection info object containing a "status" and "resourceID".
3748          * @private
3749          */
3750         _cloneConnInfoObj = function () {
3751             if (_connInfoCache) {
3752                 return {
3753                     status: _connInfoCache.status,
3754                     resourceID: _connInfoCache.resourceID
3755                 };
3756             } else {
3757                 return null;
3758             }
3759         },
3760 
3761         /**
3762          * Cleans up any outstanding subscribe/unsubscribe requests and notifies them of errors.
3763          * This is done if we get disconnected because we cleanup explicit subscriptions on disconnect.
3764          * @private
3765          */
3766         _cleanupPendingRequests = function () {
3767             var node, curSubid, errObj = {
3768                 error: {
3769                     errorType: "Disconnected",
3770                     errorMessage: "Outstanding request will never complete."
3771                 }
3772             };
3773 
3774             // Iterate through all outstanding subscribe requests to notify them that it will never return
3775             for (node in _nodesList) {
3776                 if (_nodesList.hasOwnProperty(node)) {
3777                     for (curSubid in _nodesList[node].subscribing.reqIds) {
3778                         if (_nodesList[node].subscribing.reqIds.hasOwnProperty(curSubid)) {
3779                             // Notify this outstanding subscribe request to give up and error out
3780                             _hub.publish(_topics.RESPONSES + "." + curSubid, errObj); 
3781                         }
3782                     }
3783                     for (curSubid in _nodesList[node].unsubscribing.reqIds) {
3784                         if (_nodesList[node].unsubscribing.reqIds.hasOwnProperty(curSubid)) {
3785                             // Notify this outstanding unsubscribe request to give up and error out
3786                             _hub.publish(_topics.RESPONSES + "." + curSubid, errObj); 
3787                         }
3788                     }
3789                 }
3790             }
3791         },
3792 
3793         /**
3794          * Publishes the connection info to the connection info topic.
3795          * @param {Object} connInfo
3796          *     The connection info object containing the status and resource ID.
3797          * @private
3798          */
3799         _connInfoHandler = function (connInfo) {
3800             var before = _connInfoCache.status;
3801             _connInfoCache = connInfo;
3802             _logger.log("MasterPublisher._connInfoHandler() - Connection status: " + connInfo.status);
3803             _hub.publish(_topics.EVENTS_CONNECTION_INFO, _cloneConnInfoObj());
3804             if (before === "connected" && connInfo.status !== "connected") {
3805                 // Fail all pending requests when we transition to disconnected
3806                 _cleanupPendingRequests();
3807             }
3808         },
3809 
3810         
3811         /**
3812          * Utility method to bookkeep node subscription requests and determine
3813          * whehter it is necessary to tunnel the request to JabberWerx.
3814          * @param {String} node
3815          *     The node of interest
3816          * @param {String} reqId
3817          *     A unique string identifying the request/subscription
3818          * @private
3819          */
3820         _subscribeNode = function (node, subid) {
3821             if (_connInfoCache.status !== "connected") {
3822                 _hub.publish(_topics.RESPONSES + "." + subid, {
3823                     error: {
3824                         errorType: "Not connected",
3825                         errorMessage: "Cannot subscribe without connection."
3826                     }
3827                 });
3828                 return;
3829             }
3830             // NODE DOES NOT YET EXIST
3831             if (!_nodesList[node]) {
3832                 _nodesList[node] = {
3833                     "subscribing": {
3834                         "reqIds": {},
3835                         "length": 0
3836                     },
3837                     "active": {
3838                         "reqIds": {},
3839                         "length": 0
3840                     },
3841                     "unsubscribing": {
3842                         "reqIds": {},
3843                         "length": 0
3844                     },
3845                     "holding": {
3846                         "reqIds": {},
3847                         "length": 0
3848                     }
3849                 };
3850             }
3851             if (_nodesList[node].active.length === 0) {
3852                 if (_nodesList[node].unsubscribing.length === 0) {
3853                     if (_nodesList[node].subscribing.length === 0) {
3854                         _nodesList[node].subscribing.reqIds[subid] = true;
3855                         _nodesList[node].subscribing.length += 1;
3856 
3857                         _logger.log("MasterPublisher._subscribeNode() - Attempting to subscribe to node '" + node + "'");
3858                         _tunnel.subscribe(node, function (err) {
3859                             var errObj, curSubid;
3860                             if (err) {
3861                                 errObj = {
3862                                     subscribe: {
3863                                         content: err
3864                                     }
3865                                 };
3866 
3867                                 try {
3868                                     errObj.subscribe.object = gadgets.json.parse((_utils.xml2json(jQuery.parseXML(err), "")));
3869                                 } catch (e) {
3870                                     errObj.error = {
3871                                         errorType: "parseError",
3872                                         errorMessage: "Could not serialize XML: " + e
3873                                     };
3874                                 }
3875                                 _logger.log("MasterPublisher._subscribeNode() - Error subscribing to node '" + node + "': " + err);
3876                             } else {
3877                                 _logger.log("MasterPublisher._subscribeNode() - Subscribed to node '" + node + "'");
3878                             }
3879 
3880                             for (curSubid in _nodesList[node].subscribing.reqIds) {
3881                                 if (_nodesList[node].subscribing.reqIds.hasOwnProperty(curSubid)) {
3882                                     _hub.publish(_topics.RESPONSES + "." + curSubid, errObj);
3883                                     if (!err) {
3884                                         _nodesList[node].active.reqIds[curSubid] = true;
3885                                         _nodesList[node].active.length += 1;
3886                                     }
3887                                     delete _nodesList[node].subscribing.reqIds[curSubid];
3888                                     _nodesList[node].subscribing.length -= 1;
3889                                 }
3890                             }
3891                         });
3892                         
3893                     } else { //other ids are subscribing
3894                         _nodesList[node].subscribing.reqIds[subid] = true;
3895                         _nodesList[node].subscribing.length += 1;
3896                     }                       
3897                 } else { //An unsubscribe request is pending, hold onto these subscribes until it is done
3898                     _nodesList[node].holding.reqIds[subid] = true;
3899                     _nodesList[node].holding.length += 1;
3900                 }
3901             } else { // The node has active subscriptions; add this subid and return successful response
3902                 _nodesList[node].active.reqIds[subid] = true;
3903                 _nodesList[node].active.length += 1;
3904                 _hub.publish(_topics.RESPONSES + "." + subid, undefined); 
3905             }
3906         },
3907 
3908         /**
3909          * Utility method to bookkeep node unsubscribe requests and determine
3910          * whehter it is necessary to tunnel the request to JabberWerx.
3911          * @param {String} node
3912          *     The node to unsubscribe from
3913          * @param {String} reqId
3914          *     A unique string identifying the subscription to remove
3915          * @private
3916          */
3917         _unsubscribeNode = function (node, subid) {
3918             if (!_nodesList[node]) { //node DNE, publish success response
3919                 _hub.publish(_topics.RESPONSES + "." + subid, undefined); 
3920             } else {
3921                 if (_connInfoCache.status !== "connected") {
3922                     _hub.publish(_topics.RESPONSES + "." + subid, {
3923                         error: {
3924                             errorType: "Not connected",
3925                             errorMessage: "Cannot unsubscribe without connection."
3926                         }
3927                     });
3928                     return;
3929                 }
3930                 if (_nodesList[node].active.length > 1) {
3931                     delete _nodesList[node].active.reqIds[subid];
3932                     _hub.publish(_topics.RESPONSES + "." + subid, undefined); 
3933                     _nodesList[node].active.length -= 1;
3934                 } else if (_nodesList[node].active.length === 1) { // transition subid from active category to unsubscribing category
3935                     _nodesList[node].unsubscribing.reqIds[subid] = true;
3936                     _nodesList[node].unsubscribing.length += 1;
3937                     delete _nodesList[node].active.reqIds[subid];
3938                     _nodesList[node].active.length -= 1;
3939 
3940                     _logger.log("MasterPublisher._unsubscribeNode() - Attempting to unsubscribe from node '" + node + "'");
3941                     _tunnel.unsubscribe(node, function (err) {
3942                         var errObj, curSubid;
3943                         if (err) {
3944                             errObj = {
3945                                 subscribe: {
3946                                     content: err
3947                                 }
3948                             };
3949 
3950                             try {
3951                                 errObj.subscribe.object = gadgets.json.parse((_utils.xml2json(jQuery.parseXML(err), "")));
3952                             } catch (e) {
3953                                 errObj.error = {
3954                                     errorType: "parseError",
3955                                     errorMessage: "Could not serialize XML: " + e
3956                                 };
3957                             }
3958                             _logger.log("MasterPublisher._unsubscribeNode() - Error unsubscribing from node '" + node + "': " + err);
3959                         } else {
3960                             _logger.log("MasterPublisher._unsubscribeNode() - Unsubscribed from node '" + node + "'");
3961                         }
3962 
3963                         for (curSubid in _nodesList[node].unsubscribing.reqIds) {
3964                             if (_nodesList[node].unsubscribing.reqIds.hasOwnProperty(curSubid)) {
3965                                 // publish to all subids whether unsubscribe failed or succeeded
3966                                 _hub.publish(_topics.RESPONSES + "." + curSubid, errObj); 
3967                                 if (!err) {
3968                                     delete _nodesList[node].unsubscribing.reqIds[curSubid];
3969                                     _nodesList[node].unsubscribing.length -= 1;
3970                                 } else { // Just remove the subid from unsubscribing; the next subscribe request will operate with node already created
3971                                     delete _nodesList[node].unsubscribing.reqIds[curSubid];
3972                                     _nodesList[node].unsubscribing.length -= 1;
3973                                 }   
3974                             }
3975                         }
3976                         
3977                         if (!err && _nodesList[node].holding.length > 0) { // if any subscribe requests came in while unsubscribing from OF, now transition from holding to subscribing
3978                             for (curSubid in _nodesList[node].holding.reqIds) {
3979                                 if (_nodesList[node].holding.reqIds.hasOwnProperty(curSubid)) {
3980                                     delete _nodesList[node].holding.reqIds[curSubid];
3981                                     _nodesList[node].holding.length -= 1;
3982                                     _subscribeNode(node, curSubid);                             
3983                                 }
3984                             }
3985                         }
3986                     });
3987                 } else { // length <= 0?
3988                     _hub.publish(_topics.RESPONSES + "." + subid, undefined);
3989                 }
3990             }
3991         },
3992         
3993         /**
3994          * Handles client requests to establish a BOSH connection.
3995          * @param {String} id
3996          *     id of the xmpp user
3997          * @param {String} password
3998          *     password of the xmpp user
3999          * @param {String} xmppDomain
4000          *     xmppDomain of the xmpp user account
4001          * @private
4002          */
4003         _connect = function (id, password, xmppDomain) {
4004             _tunnel.makeConnectReq(id, password, xmppDomain);
4005         },
4006 
4007         /**
4008          * Handles client requests made to the request topic. The type of the
4009          * request is described in the "type" property within the data payload. Each
4010          * type can result in a different operation.
4011          * @param {String} topic
4012          *     The topic which data was published to.
4013          * @param {Object} data
4014          *     The data containing requests information published by clients.
4015          * @param {String} data.type
4016          *     The type of the request. Supported: "ConnectionInfoReq"
4017          * @param {Object} data.data
4018          *     May contain data relevant for the particular requests.
4019          * @param {String} [data.invokeID]
4020          *     The ID used to identify the request with the response. The invoke ID
4021          *     will be included in the data in the publish to the topic. It is the
4022          *     responsibility of the client to correlate the published data to the
4023          *     request made by using the invoke ID.
4024          * @private
4025          */
4026         _clientRequestHandler = function (topic, data) {
4027             var dataCopy;
4028 
4029             //Ensure a valid data object with "type" and "data" properties.
4030             if (typeof data === "object" &&
4031                     typeof data.type === "string" &&
4032                     typeof data.data === "object") {
4033                 switch (data.type) {
4034                 case _REQTYPES.CONNECTIONINFO:
4035                     //It is possible that Slave clients come up before the Master
4036                     //client. If that is the case, the Slaves will need to make a
4037                     //request for the Master to send the latest connection info to the
4038                     //connectionInfo topic.
4039                     dataCopy = _cloneConnInfoObj();
4040                     if (dataCopy) {
4041                         if (data.invokeID !== undefined) {
4042                             dataCopy.invokeID = data.invokeID;
4043                         }
4044                         _hub.publish(_topics.EVENTS_CONNECTION_INFO, dataCopy);
4045                     }
4046                     break;
4047                 case _REQTYPES.SUBSCRIBE:
4048                     if (typeof data.data.node === "string") {
4049                         _subscribeNode(data.data.node, data.invokeID);
4050                     }
4051                     break;
4052                 case _REQTYPES.UNSUBSCRIBE:
4053                     if (typeof data.data.node === "string") {
4054                         _unsubscribeNode(data.data.node, data.invokeID);
4055                     }
4056                     break;
4057                 case _REQTYPES.CONNECT:
4058                     // Deprecated: Disallow others (non-masters) from administering BOSH connections that are not theirs
4059                     _logger.log("MasterPublisher._clientRequestHandler(): F403: Access denied. Non-master ClientService instances do not have the clearance level to make this request: makeConnectionReq");
4060                     break;
4061                 default:
4062                     break;
4063                 }
4064             }
4065         };
4066 
4067         (function () {
4068             //Register to receive events and connection status from tunnel.
4069             _tunnel.registerEventHandler(_eventHandler);
4070             _tunnel.registerPresenceHandler(_presenceHandler);
4071             _tunnel.registerConnectionInfoHandler(_connInfoHandler);
4072 
4073             //Listen to a request channel to respond to any requests made by other
4074             //clients because the Master may have access to useful information.
4075             _hub.subscribe(_topics.REQUESTS, _clientRequestHandler);
4076         }());
4077 
4078         /**
4079          * @private
4080          * Handles client requests to establish a BOSH connection.
4081          * @param {String} id
4082          *     id of the xmpp user
4083          * @param {String} password
4084          *     password of the xmpp user
4085          * @param {String} xmppDomain
4086          *     xmppDomain of the xmpp user account
4087          */
4088         this.connect = function (id, password, xmppDomain) {
4089           _connect(id, password, xmppDomain);
4090         };
4091 
4092         /**
4093          * @private
4094          * Resets the list of explicit subscriptions
4095          */
4096         this.wipeout = function () {
4097             _cleanupPendingRequests();
4098             _nodesList = {};
4099        };
4100 
4101         //BEGIN TEST CODE//
4102        /**
4103         * Test code added to expose private functions that are used by unit test
4104         * framework. This section of code is removed during the build process
4105         * before packaging production code. The [begin|end]TestSection are used
4106         * by the build to identify the section to strip.
4107         * @ignore
4108         */
4109        this.beginTestSection = 0;
4110 
4111        /**
4112         * @ignore
4113         */
4114        this.getTestObject = function () {
4115            //Load mock dependencies.
4116            var _mock = new MockControl();
4117            _hub = _mock.createMock(gadgets.Hub);
4118            _tunnel = _mock.createMock();
4119 
4120            return {
4121                //Expose mock dependencies
4122                mock: _mock,
4123                hub: _hub,
4124                tunnel: _tunnel,
4125                setTunnel: function (tunnel) {
4126                    _tunnel = tunnel;
4127                },
4128                getTunnel: function () {
4129                    return _tunnel;
4130                },
4131 
4132                //Expose internal private functions
4133                reqtypes: _REQTYPES,
4134                eventHandler: _eventHandler,
4135                presenceHandler: _presenceHandler,
4136                
4137                subscribeNode: _subscribeNode,
4138                unsubscribeNode: _unsubscribeNode,
4139                
4140                getNodeList: function () {
4141                    return _nodesList;
4142                },
4143                setNodeList: function (nodelist) {
4144                    _nodesList = nodelist;
4145                },
4146                
4147                cloneConnInfoObj: _cloneConnInfoObj,
4148                connInfoHandler: _connInfoHandler,
4149                clientRequestHandler: _clientRequestHandler
4150 
4151            };
4152        };
4153 
4154 
4155        /**
4156         * @ignore
4157         */
4158        this.endTestSection = 0;
4159        //END TEST CODE//
4160 
4161     };
4162     
4163     window.finesse = window.finesse || {};
4164     window.finesse.clientservices = window.finesse.clientservices || {};
4165     window.finesse.clientservices.MasterPublisher = MasterPublisher;
4166 
4167 }));
4168 
4169 /** The following comment is to prevent jslint errors about 
4170  * using variables before they are defined.
4171  */
4172 /*global publisher:true */
4173 
4174 /**
4175  * Exposes a set of API wrappers that will hide the dirty work of
4176  *     constructing Finesse API requests and consuming Finesse events.
4177  *
4178  * @requires OpenAjax, jQuery 1.5, finesse.utilities.Utilities
4179  */
4180 
4181 
4182 /**
4183  * Allow clients to make Finesse API requests and consume Finesse events by
4184  * calling a set of exposed functions. The Services layer will do the dirty
4185  * work of establishing a shared BOSH connection (for designated Master
4186  * modules), consuming events for client subscriptions, and constructing API
4187  * requests.
4188  */
4189 /** @private */
4190 (function (factory) {
4191     
4192 
4193     // Define as an AMD module if possible
4194     if ( typeof define === 'function' && define.amd )
4195     {
4196         define('clientservices/ClientServices',["clientservices/MasterTunnel",
4197                 "clientservices/MasterPublisher",
4198                 "clientservices/Topics",
4199                 "utilities/Utilities"], factory );
4200     }
4201     
4202     /* Define using browser globals otherwise
4203      * Prevent multiple instantiations if the script is loaded twice
4204      */
4205     else
4206     {
4207         factory(finesse.clientservices.MasterTunnel, finesse.clientservices.MasterPublisher, finesse.clientservices.Topics, finesse.utilities.Utilities);
4208     }
4209     
4210 }(function (MasterTunnel, MasterPublisher, Topics, Utilities) {
4211     
4212      var ClientServices = (function () {/** @lends finesse.clientservices.ClientServices.prototype */
4213         var
4214 
4215         /**
4216          * Shortcut reference to the master tunnel
4217          * @private
4218          */
4219         _tunnel,
4220 
4221         _publisher,
4222 
4223         /**
4224          * Shortcut reference to the finesse.utilities.Utilities singleton
4225          * This will be set by init()
4226          * @private
4227          */
4228         _util,
4229 
4230         /**
4231          * Shortcut reference to the gadgets.io object.
4232          * This will be set by init()
4233          * @private
4234          */
4235         _io,
4236 
4237         /**
4238          * Shortcut reference to the gadget pubsub Hub instance.
4239          * This will be set by init()
4240          * @private
4241          */
4242         _hub,
4243 
4244         /**
4245          * Logger object set externally by setLogger, defaults to nothing.
4246          * @private
4247          */
4248         _logger = {},
4249 
4250         /**
4251          * Shortcut reference to the Topics class.
4252          * This will be set by init()
4253          * @private
4254          */
4255         _topics,
4256 
4257         /**
4258          * Config object needed to initialize this library
4259          * This must be set by init()
4260          * @private
4261          */
4262         _config,
4263 
4264         /**
4265          * @private
4266          * Whether or not this ClientService instance is a Master.
4267          */
4268         _isMaster = false,
4269 
4270         /**
4271          * @private
4272          * Whether the Client Services have been initiated yet.
4273          */
4274         _inited = false,
4275 
4276         /**
4277          * Stores the list of subscription IDs for all subscriptions so that it
4278          * could be retrieve for unsubscriptions.
4279          * @private
4280          */
4281         _subscriptionID = {},
4282 
4283         /**
4284          * The possible states of the JabberWerx BOSH connection.
4285          * @private
4286          */
4287         _STATUS = {
4288             CONNECTING: "connecting",
4289             CONNECTED: "connected",
4290             DISCONNECTED: "disconnected",
4291             DISCONNECTED_CONFLICT: "conflict",
4292             DISCONNECTED_UNAUTHORIZED: "unauthorized",
4293             DISCONNECTING: "disconnecting",
4294             RECONNECTING: "reconnecting",
4295             UNLOADING: "unloading",
4296             FAILING: "failing",
4297             RECOVERED: "recovered"
4298         },
4299 
4300         _failoverMode = false,
4301 
4302         /**
4303          * Handler function to be invoked when BOSH connection is connecting.
4304          * @private
4305          */
4306         _onConnectingHandler,
4307 
4308         /**
4309          * Handler function to be invoked when BOSH connection is connected
4310          * @private
4311          */
4312         _onConnectHandler,
4313 
4314         /**
4315          * Handler function to be invoked when BOSH connection is disconnecting.
4316          * @private
4317          */
4318         _onDisconnectingHandler,
4319 
4320         /**
4321          * Handler function to be invoked when the BOSH is disconnected.
4322          * @private
4323          */
4324         _onDisconnectHandler,
4325 
4326         /**
4327          * Handler function to be invoked when the BOSH is reconnecting.
4328          * @private
4329          */
4330         _onReconnectingHandler,
4331         
4332         /**
4333          * Handler function to be invoked when the BOSH is unloading.
4334          * @private
4335          */
4336         _onUnloadingHandler,
4337 
4338         /**
4339          * Contains a cache of the latest connection info containing the current
4340          * state of the BOSH connection and the resource ID.
4341          * @private
4342          */
4343         _connInfo,
4344 
4345         /**
4346          * Keeps track of all the objects that need to be refreshed when we recover
4347          * due to our resilient connection. Only objects that we subscribe to will
4348          * be added to this list.
4349          * @private
4350          */
4351         _refreshList = [],
4352 
4353         /**
4354          * @private
4355          * Centralized logger.log method for external logger
4356          * @param {String} msg
4357          *     Message to log
4358          */
4359         _log = function (msg) {
4360             // If the external logger throws up, it stops here.
4361             try {
4362                 if (_logger.log) {
4363                     _logger.log("[ClientServices] " + msg);
4364                 }
4365             } catch (e) { }
4366         },
4367 
4368         /**
4369          * Go through each object in the _refreshList and call its refresh() function
4370          * @private
4371          */
4372         _refreshObjects = function () {
4373             var i;
4374 
4375             // wipe out the explicit subscription list before we refresh objects
4376             if (_publisher) {
4377                 _publisher.wipeout();
4378             }
4379 
4380             // refresh each item in the refresh list
4381             for (i = _refreshList.length - 1; i >= 0; i -= 1) {
4382                 _log("Refreshing " + _refreshList[i].getRestUrl());
4383                 _refreshList[i].refresh(10);
4384             }
4385         },
4386 
4387         /**
4388          * Handler to process connection info publishes.
4389          * @param {Object} data
4390          *     The connection info data object.
4391          * @param {String} data.status
4392          *     The BOSH connection status.
4393          * @param {String} data.resourceID
4394          *     The resource ID for the connection.
4395          * @private
4396          */
4397         _connInfoHandler =  function (data) {
4398 
4399             //Invoke registered handler depending on status received. Due to the
4400             //request topic where clients can make request for the Master to publish
4401             //the connection info, there is a chance that duplicate connection info
4402             //events may be sent, so ensure that there has been a state change
4403             //before invoking the handlers.
4404             if (_connInfo === undefined || _connInfo.status !== data.status) {
4405                 _connInfo = data;
4406                 switch (data.status) {
4407                 case _STATUS.CONNECTING:
4408                     if (_isMaster && _onConnectingHandler) {
4409                         _onConnectingHandler();
4410                     }
4411                     break;
4412                 case _STATUS.CONNECTED:
4413                     if ((_isMaster || !_failoverMode) && _onConnectHandler) {
4414                         _onConnectHandler();
4415                     }
4416                     break;
4417                 case _STATUS.DISCONNECTED:
4418                     if (_isMaster && _onDisconnectHandler) {
4419                         _onDisconnectHandler();
4420                     }
4421                     break;
4422                 case _STATUS.DISCONNECTED_CONFLICT:
4423                     if (_isMaster && _onDisconnectHandler) {
4424                         _onDisconnectHandler("conflict");
4425                     }
4426                     break;
4427                 case _STATUS.DISCONNECTED_UNAUTHORIZED:
4428                     if (_isMaster && _onDisconnectHandler) {
4429                         _onDisconnectHandler("unauthorized");
4430                     }
4431                     break;
4432                 case _STATUS.DISCONNECTING:
4433                     if (_isMaster && _onDisconnectingHandler) {
4434                         _onDisconnectingHandler();
4435                     }
4436                     break;
4437                 case _STATUS.RECONNECTING:
4438                     if (_isMaster && _onReconnectingHandler) {
4439                         _onReconnectingHandler();
4440                     }
4441                     break;
4442                 case _STATUS.UNLOADING:
4443                     if (_isMaster && _onUnloadingHandler) {
4444                         _onUnloadingHandler();
4445                     }
4446                     break;
4447                 case _STATUS.FAILING:
4448                     if (!_isMaster) {
4449                         // Stop
4450                         _failoverMode = true;
4451                         if (_onDisconnectHandler) {
4452                             _onDisconnectHandler();
4453                         }
4454                     }
4455                     break;
4456                 case _STATUS.RECOVERED:
4457                     if (!_isMaster) {
4458                         _failoverMode = false;
4459                         if (_onConnectHandler) {
4460                             _onConnectHandler();
4461                         }
4462                     }
4463                     // Whenever we are recovered, we need to refresh any objects
4464                     // that are stored.
4465                     _refreshObjects();
4466                     break;
4467                 }
4468             }
4469         },
4470 
4471         /**
4472          * Ensure that ClientServices have been inited.
4473          * @private
4474          */
4475         _isInited = function () {
4476             if (!_inited) {
4477                 throw new Error("ClientServices needs to be inited.");
4478             }
4479         },
4480 
4481         /**
4482          * Have the client become the Master by initiating a tunnel to a shared
4483          * event BOSH connection. The Master is responsible for publishing all
4484          * events to the pubsub infrastructure.
4485          * @private
4486          */
4487         _becomeMaster = function () {
4488             _tunnel = new MasterTunnel(_config.host, _config.scheme);
4489             _publisher = new MasterPublisher(_tunnel, _hub);
4490             _tunnel.init(_config.id, _config.password, _config.xmppDomain, _config.pubsubDomain, _config.resource);
4491             _isMaster = true;
4492         },
4493 
4494         /**
4495          * Make a request to the request channel to have the Master publish the
4496          * connection info object.
4497          * @private
4498          */
4499         _makeConnectionInfoReq = function () {
4500             var data = {
4501                 type: "ConnectionInfoReq",
4502                 data: {},
4503                 invokeID: (new Date()).getTime()
4504             };
4505             _hub.publish(_topics.REQUESTS, data);
4506         },
4507 
4508         /**
4509          * Utility method to register a handler which is associated with a
4510          * particular connection status.
4511          * @param {String} status
4512          *     The connection status string.
4513          * @param {Function} handler
4514          *     The handler to associate with a particular connection status.
4515          * @throws {Error}
4516          *     If the handler provided is not a function.
4517          * @private
4518          */
4519         _registerHandler = function (status, handler) {
4520             if (typeof handler === "function") {
4521                 if (_connInfo && _connInfo.status === status) {
4522                     handler();
4523                 }
4524                 switch (status) {
4525                 case _STATUS.CONNECTING:
4526                     _onConnectingHandler = handler;
4527                     break;
4528                 case _STATUS.CONNECTED:
4529                     _onConnectHandler = handler;
4530                     break;
4531                 case _STATUS.DISCONNECTED:
4532                     _onDisconnectHandler = handler;
4533                     break;
4534                 case _STATUS.DISCONNECTING:
4535                     _onDisconnectingHandler = handler;
4536                     break;
4537                 case _STATUS.RECONNECTING:
4538                     _onReconnectingHandler = handler;
4539                     break;
4540                 case _STATUS.UNLOADING:
4541                     _onUnloadingHandler = handler;
4542                     break;
4543                 }
4544 
4545             } else {
4546                 throw new Error("Callback is not a function");
4547             }
4548         };
4549 
4550         return {
4551 
4552             /**
4553              * @private
4554              * Adds an item to the list to be refreshed upon reconnect
4555              * @param {RestBase} object - rest object to be refreshed
4556              */
4557             addToRefreshList: function (object) {
4558                 _refreshList.push(object);
4559             },
4560 
4561             /**
4562              * @private
4563              * Removes the given item from the refresh list
4564              * @param  {RestBase} object - rest object to be removed
4565              */
4566             removeFromRefreshList: function (object) {
4567                 var i;
4568                 for (i = _refreshList.length - 1; i >= 0; i -= 1) {
4569                     if (_refreshList[i] === object) {
4570                         _refreshList.splice(i, 1);
4571                         break;
4572                     }
4573                 }
4574             },
4575 
4576             /**
4577              * @private
4578              * The location of the tunnel HTML URL.
4579              * @returns {String}
4580              *     The location of the tunnel HTML URL.
4581              */
4582             getTunnelURL: function () {
4583                 return _tunnel.getTunnelURL();            
4584             },
4585             
4586             /**
4587              * @private
4588              * Indicates whether the tunnel frame is loaded.
4589              * @returns {Boolean}
4590              *     True if the tunnel frame is loaded, false otherwise.
4591              */
4592             isTunnelLoaded: function () {
4593                 return _tunnel.isTunnelLoaded();            
4594             },
4595             
4596             /**
4597              * @private
4598              * Indicates whether the ClientServices instance is a Master.
4599              * @returns {Boolean}
4600              *     True if this instance of ClientServices is a Master, false otherwise.
4601              */
4602             isMaster: function () {
4603                 return _isMaster;
4604             },
4605 
4606             /**
4607              * @private
4608              * Get the resource ID. An ID is only available if the BOSH connection has
4609              * been able to connect successfully.
4610              * @returns {String}
4611              *     The resource ID string. Null if the BOSH connection was never
4612              *     successfully created and/or the resource ID has not been associated.
4613              */
4614             getResourceID: function () {
4615                 if (_connInfo !== undefined) {
4616                     return _connInfo.resourceID;
4617                 }
4618                 return null;
4619             },
4620             
4621             /*
4622             getHub: function () {
4623                 return _hub;
4624             },
4625         */
4626             /**
4627              * @private
4628              * Add a callback to be invoked when the BOSH connection is attempting
4629              * to connect. If the connection is already trying to connect, the
4630              * callback will be invoked immediately.
4631              * @param {Function} handler
4632              *      An empty param function to be invoked on connecting. Only one
4633              *      handler can be registered at a time. Handlers already registered
4634              *      will be overwritten.
4635              */
4636             registerOnConnectingHandler: function (handler) {
4637                 _registerHandler(_STATUS.CONNECTING, handler);
4638             },
4639 
4640             /**
4641              * @private
4642              * Removes the on connecting callback that was registered.
4643              */
4644             unregisterOnConnectingHandler: function () {
4645                 _onConnectingHandler = undefined;
4646             },
4647 
4648             /**
4649              * @private
4650              * Add a callback to be invoked when the BOSH connection has been
4651              * established. If the connection has already been established, the
4652              * callback will be invoked immediately.
4653              * @param {Function} handler
4654              *      An empty param function to be invoked on connect. Only one handler
4655              *      can be registered at a time. Handlers already registered will be
4656              *      overwritten.
4657              */
4658             registerOnConnectHandler: function (handler) {
4659                 _registerHandler(_STATUS.CONNECTED, handler);
4660             },
4661 
4662             /**
4663              * @private
4664              * Removes the on connect callback that was registered.
4665              */
4666             unregisterOnConnectHandler: function () {
4667                 _onConnectHandler = undefined;
4668             },
4669 
4670             /**
4671              * @private
4672              * Add a callback to be invoked when the BOSH connection goes down. If
4673              * the connection is already down, invoke the callback immediately.
4674              * @param {Function} handler
4675              *      An empty param function to be invoked on disconnected. Only one
4676              *      handler can be registered at a time. Handlers already registered
4677              *      will be overwritten.
4678              */
4679             registerOnDisconnectHandler: function (handler) {
4680                 _registerHandler(_STATUS.DISCONNECTED, handler);
4681             },
4682 
4683             /**
4684              * @private
4685              * Removes the on disconnect callback that was registered.
4686              */
4687             unregisterOnDisconnectHandler: function () {
4688                 _onDisconnectHandler = undefined;
4689             },
4690 
4691             /**
4692              * @private
4693              * Add a callback to be invoked when the BOSH is currently disconnecting. If
4694              * the connection is already disconnecting, invoke the callback immediately.
4695              * @param {Function} handler
4696              *      An empty param function to be invoked on disconnected. Only one
4697              *      handler can be registered at a time. Handlers already registered
4698              *      will be overwritten.
4699              */
4700             registerOnDisconnectingHandler: function (handler) {
4701                 _registerHandler(_STATUS.DISCONNECTING, handler);
4702             },
4703 
4704             /**
4705              * @private
4706              * Removes the on disconnecting callback that was registered.
4707              */
4708             unregisterOnDisconnectingHandler: function () {
4709                 _onDisconnectingHandler = undefined;
4710             },
4711 
4712             /**
4713              * @private
4714              * Add a callback to be invoked when the BOSH connection is attempting
4715              * to connect. If the connection is already trying to connect, the
4716              * callback will be invoked immediately.
4717              * @param {Function} handler
4718              *      An empty param function to be invoked on connecting. Only one
4719              *      handler can be registered at a time. Handlers already registered
4720              *      will be overwritten.
4721              */
4722             registerOnReconnectingHandler: function (handler) {
4723                 _registerHandler(_STATUS.RECONNECTING, handler);
4724             },
4725 
4726             /**
4727              * @private
4728              * Removes the on reconnecting callback that was registered.
4729              */
4730             unregisterOnReconnectingHandler: function () {
4731                 _onReconnectingHandler = undefined;
4732             },
4733             
4734             /**
4735              * @private
4736              * Add a callback to be invoked when the BOSH connection is unloading
4737              * 
4738              * @param {Function} handler
4739              *      An empty param function to be invoked on connecting. Only one
4740              *      handler can be registered at a time. Handlers already registered
4741              *      will be overwritten.
4742              */
4743             registerOnUnloadingHandler: function (handler) {
4744                 _registerHandler(_STATUS.UNLOADING, handler);
4745             },
4746             
4747             /**
4748              * @private
4749              * Removes the on unloading callback that was registered.
4750              */
4751             unregisterOnUnloadingHandler: function () {
4752                 _onUnloadingHandler = undefined;
4753             },
4754 
4755             /**
4756              * @private
4757              * Proxy method for gadgets.io.makeRequest. The will be identical to gadgets.io.makeRequest
4758              * ClientServices will mixin the BASIC Auth string, locale, and host, since the
4759              * configuration is encapsulated in here anyways.
4760              * This removes the dependency
4761              * @param {String} url
4762              *     The relative url to make the request to (the host from the passed in config will be
4763              *     appended). It is expected that any encoding to the URL is already done.
4764              * @param {Function} handler
4765              *     Callback handler for makeRequest to invoke when the response returns.
4766              *     Completely passed through to gadgets.io.makeRequest
4767              * @param {Object} params
4768              *     The params object that gadgets.io.makeRequest expects. Authorization and locale
4769              *     headers are mixed in.
4770              */
4771             makeRequest: function (url, handler, params) {
4772                 var requestedScheme, scheme = "http";
4773                 
4774                 // ClientServices needs to be initialized with a config for restHost, auth, and locale
4775                 _isInited();
4776                 
4777                 // Allow mixin of auth and locale headers
4778                 params = params || {};
4779 
4780                 // Override refresh interval to 0 instead of default 3600 as a way to workaround makeRequest 
4781                 // using GET http method because then the params are added to the url as query params, which 
4782                 // exposes the authorization string in the url. This is a placeholder until oauth comes in
4783                 params[gadgets.io.RequestParameters.REFRESH_INTERVAL] = params[gadgets.io.RequestParameters.REFRESH_INTERVAL] || 0;
4784                 
4785                 params[gadgets.io.RequestParameters.HEADERS] = params[gadgets.io.RequestParameters.HEADERS] || {};
4786                 
4787                 // Add Basic auth to request header
4788                 params[gadgets.io.RequestParameters.HEADERS].Authorization = "Basic " + _config.authorization;
4789                 //Locale
4790                 params[gadgets.io.RequestParameters.HEADERS].locale = _config.locale;
4791 
4792                 //Allow clients to override the scheme:
4793                 //  - If not specified  => we use HTTP
4794                 //  - If null specified => we use _config.scheme
4795                 //  - Otherwise         => we use whatever they provide
4796                 requestedScheme = params.SCHEME; 
4797                 if (!(requestedScheme === undefined || requestedScheme === "undefined")) {
4798                     if (requestedScheme === null) {
4799                        scheme = _config.scheme;
4800                     } else {
4801                        scheme = requestedScheme;
4802                     }
4803                 }
4804                 
4805                 _log("RequestedScheme: " + requestedScheme + "; Scheme: " + scheme);
4806                 gadgets.io.makeRequest(encodeURI(scheme + "://" + _config.restHost + ":" + _config.localhostPort) + url, handler, params);
4807             },
4808 
4809             /**
4810              * @private
4811              * Utility function to make a subscription to a particular topic. Only one
4812              * callback function is registered to a particular topic at any time.
4813              * @param {String} topic
4814              *     The full topic name. The topic name should follow the OpenAjax
4815              *     convention using dot notation (ex: finesse.api.User.1000).
4816              * @param {Function} callback
4817              *     The function that should be invoked with the data when an event
4818              *     is delivered to the specific topic.
4819              * @returns {Boolean}
4820              *     True if the subscription was made successfully and the callback was
4821              *     been registered. False if the subscription already exist, the
4822              *     callback was not overwritten.
4823              */
4824             subscribe: function (topic, callback, disableDuringFailover) {
4825                 _isInited();
4826 
4827                 //Ensure that the same subscription isn't made twice.
4828                 if (!_subscriptionID[topic]) {
4829                     //Store the subscription ID using the topic name as the key.
4830                     _subscriptionID[topic] = _hub.subscribe(topic,
4831                         //Invoke the callback just with the data object.
4832                         function (topic, data) {
4833                             if (!disableDuringFailover || _isMaster || !_failoverMode) {
4834                                 // Halt all intermediate event processing while the master instance attempts to rebuild the connection. This only occurs:
4835                                 // - For RestBase objects (which pass the disableDuringFailover flag), so that intermediary events while recovering are hidden away until everything is all good
4836                                 //    - We shouldn't be halting anything else because we have infrastructure requests that use the hub pub sub
4837                                 // - Master instance will get all events regardless, because it is responsible for managing failover
4838                                 // - If we are not in a failover mode, everything goes
4839                                 // _refreshObjects will reconcile anything that was missed once we are back in action
4840                                 callback(data);
4841                             } 
4842                         });
4843                     return true;
4844                 }
4845                 return false;
4846             },
4847 
4848             /**
4849              * @private
4850              * Unsubscribe from a particular topic.
4851              * @param {String} topic
4852              *     The full topic name.
4853              */
4854             unsubscribe: function (topic) {
4855                 _isInited();
4856 
4857                 //Unsubscribe from the topic using the subscription ID recorded when
4858                 //the subscription was made, then delete the ID from data structure.
4859                 if (_subscriptionID[topic]) {
4860                     _hub.unsubscribe(_subscriptionID[topic]);
4861                     delete _subscriptionID[topic];
4862                 }
4863             },
4864 
4865             /**
4866              * @private
4867              * Make a request to the request channel to have the Master subscribe
4868              * to a node.
4869              * @param {String} node
4870              *     The node to subscribe to.
4871              */
4872             subscribeNode: function (node, handler) {
4873                 if (handler && typeof handler !== "function") {
4874                     throw new Error("ClientServices.subscribeNode: handler is not a function");
4875                 }
4876                 
4877                 // Construct the request to send to MasterPublisher through the OpenAjax Hub
4878                 var data = {
4879                     type: "SubscribeNodeReq",
4880                     data: {node: node},
4881                     invokeID: _util.generateUUID()
4882                 },
4883                 responseTopic = _topics.RESPONSES + "." + data.invokeID,
4884                 _this = this;
4885 
4886                 // We need to first subscribe to the response channel
4887                 this.subscribe(responseTopic, function (rsp) {
4888                     // Since this channel is only used for this singular request,
4889                     // we are not interested anymore.
4890                     // This is also critical to not leaking memory by having OpenAjax
4891                     // store a bunch of orphaned callback handlers that enclose on
4892                     // our entire ClientServices singleton
4893                     _this.unsubscribe(responseTopic);
4894                     if (handler) {
4895                         handler(data.invokeID, rsp);
4896                     }
4897                 });
4898                 // Then publish the request on the request channel
4899                 _hub.publish(_topics.REQUESTS, data);
4900             },
4901 
4902             /**
4903              * @private
4904              * Make a request to the request channel to have the Master unsubscribe
4905              * from a node.
4906              * @param {String} node
4907              *     The node to unsubscribe from.
4908              */
4909             unsubscribeNode: function (node, subid, handler) {
4910                 if (handler && typeof handler !== "function") {
4911                     throw new Error("ClientServices.unsubscribeNode: handler is not a function");
4912                 }
4913                 
4914                 // Construct the request to send to MasterPublisher through the OpenAjax Hub
4915                 var data = {
4916                     type: "UnsubscribeNodeReq",
4917                     data: {
4918                         node: node,
4919                         subid: subid
4920                     },
4921                     invokeID: _util.generateUUID()
4922                 },
4923                 responseTopic = _topics.RESPONSES + "." + data.invokeID,
4924                 _this = this;
4925 
4926                 // We need to first subscribe to the response channel
4927                 this.subscribe(responseTopic, function (rsp) {
4928                     // Since this channel is only used for this singular request,
4929                     // we are not interested anymore.
4930                     // This is also critical to not leaking memory by having OpenAjax
4931                     // store a bunch of orphaned callback handlers that enclose on
4932                     // our entire ClientServices singleton
4933                     _this.unsubscribe(responseTopic);
4934                     if (handler) {
4935                         handler(rsp);
4936                     }
4937                 });
4938                 // Then publish the request on the request channel
4939                 _hub.publish(_topics.REQUESTS, data);
4940             },
4941             
4942             /**
4943              * @private
4944              * Make a request to the request channel to have the Master connect to the XMPP server via BOSH
4945              */
4946             makeConnectionReq : function () {
4947                 // Disallow others (non-masters) from administering BOSH connections that are not theirs
4948                 if (_isMaster && _publisher) {
4949                     _publisher.connect(_config.id, _config.password, _config.xmppDomain);
4950                 } else {
4951                     _log("F403: Access denied. Non-master ClientService instances do not have the clearance level to make this request: makeConnectionReq");
4952                 }
4953             },
4954         
4955             /**
4956              * @private
4957              * Set's the global logger for this Client Services instance.
4958              * @param {Object} logger
4959              *     Logger object with the following attributes defined:<ul>
4960              *         <li><b>log:</b> function (msg) to simply log a message
4961              *     </ul>
4962              */
4963             setLogger: function (logger) {
4964                 // We want to check the logger coming in so we don't have to check every time it is called.
4965                 if (logger && typeof logger === "object" && typeof logger.log === "function") {
4966                     _logger = logger;
4967                 } else {
4968                     // We are resetting it to an empty object so that _logger.log in .log is falsy.
4969                     _logger = {};
4970                 }
4971             },
4972             
4973             /**
4974              * @private
4975              * Centralized logger.log method for external logger
4976              * @param {String} msg
4977              *     Message to log
4978              */
4979             log: _log,
4980 
4981             /**
4982              * @class
4983              * Allow clients to make Finesse API requests and consume Finesse events by
4984              * calling a set of exposed functions. The Services layer will do the dirty
4985              * work of establishing a shared BOSH connection (for designated Master
4986              * modules), consuming events for client subscriptions, and constructing API
4987              * requests.
4988              * 
4989              * @constructs
4990              */
4991             _fakeConstuctor: function () {
4992                 /* This is here so we can document init() as a method rather than as a constructor. */
4993             },
4994             
4995             /**
4996              * Initiates the Client Services with the specified config parameters.
4997              * Enabling the Client Services as Master will trigger the establishment
4998              * of a BOSH event connection.
4999              * @param {Object} config
5000              *     Configuration object containing properties used for making REST requests:<ul>
5001              *         <li><b>host:</b> The Finesse server IP/host as reachable from the browser
5002              *         <li><b>restHost:</b> The Finesse API IP/host as reachable from the gadget container
5003              *         <li><b>id:</b> The ID of the user. This is an optional param as long as the
5004              *         appropriate authorization string is provided, otherwise it is
5005              *         required.</li>
5006              *         <li><b>password:</b> The password belonging to the user. This is an optional param as
5007              *         long as the appropriate authorization string is provided,
5008              *         otherwise it is required.</li>
5009              *         <li><b>authorization:</b> The base64 encoded "id:password" authentication string. This
5010              *         param is provided to allow the ability to hide the password
5011              *         param. If provided, the id and the password extracted from this
5012              *         string will be used over the config.id and config.password.</li>
5013              *     </ul>
5014              * @throws {Error} If required constructor parameter is missing.
5015              * @example
5016              *      finesse.clientservices.ClientServices.init(finesse.gadget.Config);
5017              */
5018             init: function (config) {
5019                 if (!_inited) {
5020                     //Validate the properties within the config object if one is provided.
5021                     if (!(typeof config === "object" &&
5022                          typeof config.host === "string" && config.host.length > 0 && config.restHost && 
5023                          (typeof config.authorization === "string" ||
5024                                  (typeof config.id === "string" &&
5025                                          typeof config.password === "string")))) {
5026                         throw new Error("Config object contains invalid properties.");
5027                     }
5028 
5029                     // Initialize configuration
5030                     _config = config;
5031 
5032                     // Set shortcuts
5033                     _util = Utilities;
5034                     _topics = Topics;
5035                     
5036                     //TODO: document when this is properly supported
5037                     // Allows hub and io dependencies to be passed in. Currently only used for unit tests.
5038                     _hub = config.hub || gadgets.Hub;
5039                     _io = config.io || gadgets.io;
5040 
5041                     //If the authorization string is provided, then use that to
5042                     //extract the ID and the password. Otherwise use the ID and
5043                     //password from the respective ID and password params.
5044                     if (_config.authorization) {
5045                         var creds = _util.getCredentials(_config.authorization);
5046                         _config.id = creds.id;
5047                         _config.password = creds.password;
5048                     }
5049                     else {
5050                         _config.authorization = _util.b64Encode(
5051                                 _config.id + ":" + _config.password);
5052                     }
5053 
5054                     _inited = true;
5055 
5056                     if (_hub) {
5057                         //Subscribe to receive connection information. Since it is possible that
5058                         //the client comes up after the Master comes up, the client will need
5059                         //to make a request to have the Master send the latest connection info.
5060                         //It would be possible that all clients get connection info again.
5061                         this.subscribe(_topics.EVENTS_CONNECTION_INFO, _connInfoHandler);
5062                         _makeConnectionInfoReq();
5063                     }
5064                 }
5065 
5066                 //Return the CS object for object chaining.
5067                 return this;
5068             },
5069 
5070             /**
5071              * @private
5072              * Initializes the BOSH component of this ClientServices instance. This establishes
5073              * the BOSH connection and will trigger the registered handlers as the connection
5074              * status changes respectively:<ul>
5075              *     <li>registerOnConnectingHandler</li>
5076              *     <li>registerOnConnectHandler</li>
5077              *     <li>registerOnDisconnectHandler</li>
5078              *     <li>registerOnDisconnectingHandler</li>
5079              *     <li>registerOnReconnectingHandler</li>
5080              *     <li>registerOnUnloadingHandler</li>
5081              * <ul>
5082              *
5083              * @param {Object} config
5084              *     An object containing the following (optional) handlers for the request:<ul>
5085              *         <li><b>xmppDomain:</b> {String} The domain of the XMPP server. Available from the SystemInfo object.
5086              *         This is used to construct the JID: user@domain.com</li>
5087              *         <li><b>pubsubDomain:</b> {String} The pub sub domain where the pub sub service is running.
5088              *         Available from the SystemInfo object.
5089              *         This is used for creating or removing subscriptions.</li>
5090              *         <li><b>resource:</b> {String} The resource to connect to the notification server with.</li>
5091              *     </ul>
5092              */
5093             initBosh: function (config) {
5094                 //Validate the properties within the config object if one is provided.
5095                 if (!(typeof config === "object" && typeof config.xmppDomain === "string" && typeof config.pubsubDomain === "string")) {
5096                     throw new Error("Config object contains invalid properties.");
5097                 }
5098                 
5099                 // Mixin the required information for establishing the BOSH connection
5100                 _config.xmppDomain = config.xmppDomain;
5101                 _config.pubsubDomain = config.pubsubDomain;
5102                 _config.resource = config.resource;
5103                 
5104                 //Initiate Master launch sequence
5105                 _becomeMaster(); 
5106             },
5107 
5108             /**
5109              * @private
5110              * Sets the failover mode to either FAILING or RECOVERED. This will only occur in the master instance and is meant to be
5111              * used by a stereotypical failover monitor type module to notify non-master instances (i.e. in gadgets)
5112              * @param {Object} failoverMode
5113              *     true if failing, false or something falsy when recovered
5114              */
5115             setFailoverMode: function (failoverMode) {
5116                 if (_isMaster) {
5117                     _hub.publish(_topics.EVENTS_CONNECTION_INFO, {
5118                         status: (failoverMode ? _STATUS.FAILING : _STATUS.RECOVERED)
5119                     });
5120                 }
5121             },
5122 
5123             /**
5124              * @private
5125              * Private accessor used to inject mocked private dependencies for unit testing
5126              */
5127             _getTestObj: function () {
5128                 return {
5129                     setPublisher: function (publisher) {
5130                         _publisher = publisher;
5131                     }
5132                 };
5133             }
5134         };
5135     }());
5136      
5137     window.finesse = window.finesse || {};
5138     window.finesse.clientservices = window.finesse.clientservices || {};
5139     window.finesse.clientservices.ClientServices = ClientServices;
5140     
5141     return ClientServices;
5142 
5143 }));
5144 
5145 /**
5146  * The following comment prevents JSLint errors concerning undefined global variables.
5147  * It tells JSLint that these identifiers are defined elsewhere.
5148  */
5149 /*jslint bitwise:true, browser:true, nomen:true, regexp:true, sloppy:true, white:true */
5150 
5151 /** The following comment is to prevent jslint errors about 
5152  * using variables before they are defined.
5153  */
5154 /*global Handlebars */
5155 
5156 /**
5157  * JavaScript class to implement common notification
5158  *               functionality.
5159  * 
5160  * @requires Class
5161  * @requires finesse.FinesseBase
5162  */
5163 /** @private */
5164  (function (factory) {
5165     
5166 
5167     // Define as an AMD module if possible
5168     if ( typeof define === 'function' && define.amd )
5169     {
5170         define('restservices/Notifier',['FinesseBase',
5171                 'clientservices/ClientServices'], factory );
5172     }
5173     
5174     /* Define using browser globals otherwise
5175      * Prevent multiple instantiations if the script is loaded twice
5176      */
5177     else
5178     {
5179         factory(finesse.FinesseBase, finesse.clientservices.ClientServices);
5180     }   
5181 }(function (FinesseBase, ClientServices) {
5182 	var Notifier = FinesseBase.extend({
5183 		/**
5184          * Initializes the notifier object.
5185          */
5186         init : function () {
5187             this._super();
5188             this._listenerCallback = [];
5189         },
5190 
5191         /**
5192          * Add a listener.
5193          * 
5194          * @param callback_function
5195          * @param scope
5196          *            is the callback function to add
5197          */
5198         addListener : function (callback_function, scope) {
5199             var len = this._listenerCallback.length, i, cb, add = true;
5200             for (i = 0; i < len; i += 1) {
5201                 cb = this._listenerCallback[i].callback;
5202                 if (cb === callback_function) {
5203                     // this callback already exists
5204                     add = false;
5205                     break;
5206                 }
5207             }
5208             if (add) {
5209                 this._listenerCallback.push({ "callback": this._isAFunction(callback_function), "scope": (scope || window) });
5210             }            
5211         },
5212 
5213         /**
5214          * Remove a listener.
5215          * 
5216          * @param callback_function
5217          *            is the callback function to remove
5218          * @return {Boolean} true if removed
5219          */
5220         removeListener : function (callback_function) {
5221 
5222             var result = false, len = this._listenerCallback.length, i, cb;
5223             for (i = len - 1; i >= 0; i -=1) {
5224                 cb = this._listenerCallback[i].callback;
5225                 if (cb === callback_function) {
5226                     this._listenerCallback[i] = undefined;
5227                     this._listenerCallback.splice(i, 1);
5228                     result = true;
5229                     break;
5230                 }
5231             }
5232             
5233             return result;
5234         },
5235 
5236         /**
5237 	 * Removes all listeners
5238 	 * @return {undefined}
5239 	 */
5240 	reset: function () {
5241 		this._listenerCallback = [];
5242 	},
5243 
5244 	/**
5245          * Notify all listeners.
5246          * 
5247          * @param obj
5248          *            is the object that has changed
5249          */
5250         notifyListeners : function (obj) {
5251             var len = this._listenerCallback.length, i, callbackFunction, scope;
5252 
5253             for (i = 0; i < len; i += 1) {
5254                 // Be sure that one bad callback does not prevent other listeners
5255                 // from receiving.
5256                 try {
5257                     callbackFunction = this._listenerCallback[i].callback;
5258                     scope = this._listenerCallback[i].scope;
5259                     if (typeof callbackFunction === 'function') {
5260                         callbackFunction.call(scope, obj);
5261                     }
5262                 } catch (err) {
5263                     ClientServices.log("Exception caught: " + err);
5264                 }
5265             }
5266         },
5267 
5268         /**
5269          * Gets a copy of the listeners.
5270          * @return changeListenerCopy (array of callbacks)
5271          */
5272         getListeners : function () {
5273             var changeListenerCopy = [], len = this._listenerCallback.length, i;
5274 
5275             for (i = 0; i < len; i += 1) {
5276                 changeListenerCopy.push(this._listenerCallback[i].callback);
5277             }
5278 
5279             return changeListenerCopy;
5280         },
5281         
5282         /**
5283          * Verifies that the handler is function.
5284          * @param handler to verify
5285          * @return the handler 
5286          * @throws Error if not a function
5287          */
5288         _isAFunction : function (handler) {
5289             if (handler === undefined || typeof handler === "function") {
5290                 return handler;
5291             } else {
5292                 throw new Error("handler must be a function");
5293             }
5294         }
5295 	});
5296 	
5297 	window.finesse = window.finesse || {};
5298 	window.finesse.restservices = window.finesse.restservices || {};
5299 	window.finesse.restservices.Notifier = Notifier;
5300 
5301 	/** @namespace JavaScript classes and methods that represent REST objects and collections. */
5302     finesse.restservices = finesse.restservices || {};
5303 	
5304 	return Notifier;
5305 }));
5306 
5307 /**
5308  * JavaScript base object that all REST objects should inherit
5309  * from because it encapsulates and provides the common functionality that
5310  * all REST objects need.
5311  *
5312  * @requires finesse.clientservices.ClientServices
5313  * @requires Class
5314  */
5315 
5316 /** @private */
5317 (function (factory) {
5318     
5319 
5320     // Define as an AMD module if possible
5321     if ( typeof define === 'function' && define.amd )
5322     {
5323         define('restservices/RestBase', ["FinesseBase",
5324                  "utilities/Utilities",
5325                  "restservices/Notifier",
5326                  "clientservices/ClientServices",
5327                  "clientservices/Topics"], factory );
5328     }
5329     /* Define using browser globals otherwise
5330      * Prevent multiple instantiations if the script is loaded twice
5331      */
5332     else
5333     {
5334         factory(finesse.FinesseBase, finesse.utilities.Utilities,
5335                 finesse.restservices.Notifier,
5336                 finesse.clientservices.ClientServices,
5337                 finesse.clientservices.Topics);
5338     } 
5339 }(function (FinesseBase, Utilities, Notifier, ClientServices, Topics) {
5340     
5341     var RestBase = FinesseBase.extend(/** @lends finesse.restservices.RestBase.prototype */{
5342 
5343         doNotLog: false,        
5344 
5345         /**
5346          * Used by _processUpdate() and restRequest().
5347          * Maps requestIds to object-wrapped callbacks passed to restRequest(),
5348          * so that one of the callbacks can be fired when a corresponding event is
5349          * received inside _processUpdate().
5350          * @private
5351          */
5352         _pendingCallbacks: {},
5353         
5354         /**
5355          * Gets the REST class for the current object.  This object throws an
5356          * exception because subtype must implement.
5357          * @throws {Error} because subtype must implement
5358          * @private
5359          */
5360         getRestClass: function () {
5361             throw new Error("getRestClass(): Not implemented in subtype.");
5362         },
5363 
5364         /**
5365          * Gets the REST type for the current object.  This object throws an
5366          * exception because subtype must implement.
5367          * @throws {Error} because subtype must implement.
5368          * @private
5369          */
5370         getRestType: function () {
5371             throw new Error("getRestType(): Not implemented in subtype.");
5372         },
5373 
5374         /**
5375          * Gets the node path for the current object.  This object throws an
5376          * exception because subtype must implement.
5377          * @throws {Error} because subtype must implement.
5378          * @private
5379          */
5380         getXMPPNodePath: function () {
5381             throw new Error("getXMPPNodePath(): Not implemented in subtype.");
5382         },
5383         
5384         /**
5385          * Boolean function that specifies whether the REST object supports
5386          * requests. True by default. Subclasses should override if false.
5387          * @private
5388          */
5389         supportsRequests: true,
5390 
5391         /**
5392          * Boolean function that specifies whether the REST object supports
5393          * subscriptions. True by default. Subclasses should override if false.
5394          * @private
5395          */
5396         supportsSubscriptions: true,
5397         
5398         /**
5399          * Boolean function that specifies whether the REST object should retain
5400          * a copy of the REST response. False by default. Subclasses should override if true.
5401          * @private
5402          */
5403         keepRestResponse: false,
5404 
5405         /**
5406          * Boolean function that specifies whether the REST object explicitly
5407          * subscribes. False by default. Subclasses should override if true.
5408          * @private
5409          */
5410         explicitSubscription: false,
5411 
5412         /**
5413          * Boolean function that specifies whether subscribing should be
5414          * automatically done at construction. Defaults to true.
5415          * This be overridden at object construction, not by implementing subclasses
5416          * @private
5417          */
5418         autoSubscribe: true,
5419         
5420         /**
5421          * Private reference to default logger
5422          * @private
5423          */
5424         _logger: {
5425             log: ClientServices.log,
5426             error: ClientServices.log
5427         },
5428 
5429         /**
5430          * @class
5431          * JavaScript representation of a REST object. Also exposes methods to operate
5432          * on the object against the server.  This object is typically extended into individual
5433          * REST Objects (like Dialog, User, etc...), and shouldn't be used directly.
5434          *
5435          * @constructor
5436          * @param {String} id
5437          *     The ID that uniquely identifies the REST object.
5438          * @param {Object} callbacks
5439          *     An object containing callbacks for instantiation and runtime
5440          *     Callback to invoke upon successful instantiation, passes in REST object.
5441          * @param {Function} callbacks.onLoad(this)
5442          *     Callback to invoke upon loading the data for the first time.
5443          * @param {Function} callbacks.onChange(this)
5444          *     Callback to invoke upon successful update object (PUT)
5445          * @param {Function} callbacks.onAdd(this)
5446          *     Callback to invoke upon successful update to add object (POST)
5447          * @param {Function} callbacks.onDelete(this)
5448          *     Callback to invoke upon successful update to delete object (DELETE)
5449          * @param {Function} callbacks.onError(rsp)
5450          *     Callback to invoke on update error (refresh or event)
5451          *     as passed by finesse.restservices.RestBase.restRequest()
5452          *     {
5453          *         status: {Number} The HTTP status code returned
5454          *         content: {String} Raw string of response
5455          *         object: {Object} Parsed object of response
5456          *         error: {Object} Wrapped exception that was caught
5457          *         error.errorType: {String} Type of error that was caught
5458          *         error.errorMessage: {String} Message associated with error
5459          *     }
5460          * @param {RestBase} [restObj]
5461          *     A RestBase parent object which this object has an association with.
5462          * @constructs
5463          */
5464         init: function (options, callbacks, restObj) {
5465             /**
5466               * Initialize the base class
5467               */
5468             var _this = this;
5469 
5470             this._super();
5471 
5472             if (typeof options === "object") {
5473                 this._id = options.id;
5474                 this._restObj = options.parentObj;
5475                 this.autoSubscribe = (options.autoSubscribe === false) ? false : true;
5476                 this.doNotSubscribe = options.doNotSubscribe;
5477                 this.doNotRefresh = this.doNotRefresh || options.doNotRefresh;
5478                 callbacks = {
5479                     onLoad: options.onLoad,
5480                     onChange: options.onChange,
5481                     onAdd: options.onAdd,
5482                     onDelete: options.onDelete,
5483                     onError: options.onError
5484                 };
5485             } else {
5486                 this._id = options;
5487                 this._restObj = restObj;
5488             }
5489             
5490             // Common stuff
5491             
5492             this._data = {};
5493             
5494             //Contains the full rest response to be processed by upper layers if needed
5495             this._restResponse = undefined;
5496 
5497             this._lastUpdate = {};
5498 
5499             this._util = Utilities;
5500 
5501             //Should be correctly initialized in either a window OR gadget context
5502             this._config = finesse.container.Config;
5503 
5504             // Setup all the notifiers - change, load and error.
5505             this._changeNotifier = new Notifier();
5506             this._loadNotifier = new Notifier();
5507             this._addNotifier = new Notifier();
5508             this._deleteNotifier = new Notifier();
5509             this._errorNotifier = new Notifier();
5510 
5511             this._loaded = false;
5512 
5513             // Protect against null dereferencing of options allowing its
5514             // (nonexistent) keys to be read as undefined
5515             callbacks = callbacks || {};
5516 
5517             this.addHandler('load', callbacks.onLoad);
5518             this.addHandler('change', callbacks.onChange);
5519             this.addHandler('add', callbacks.onAdd);
5520             this.addHandler('delete', callbacks.onDelete);
5521             this.addHandler('error', callbacks.onError);
5522 
5523             // Attempt to get the RestType then synchronize
5524             try {
5525                 this.getRestType();
5526 
5527                 // Only subscribe if this REST object supports subscriptions
5528                 // and autoSubscribe was not requested to be disabled as a construction option
5529                 if (this.supportsSubscriptions && this.autoSubscribe && !this.doNotSubscribe) {
5530                     this.subscribe({
5531                         success: function () {
5532                             //TODO: figure out how to use Function.call() or Function.apply() here...
5533                             //this is exactly the same as the below else case other than the scope of "this"
5534                             if (typeof options === "object" && options.data) {
5535                                 if (!_this._processObject(_this._normalize(options.data))) {
5536                                     // notify of error if we fail to construct
5537                                     _this._errorNotifier.notifyListeners(_this);
5538                                 }
5539                             } else {
5540                                 // Only subscribe if this REST object supports requests
5541                                 if (_this.supportsRequests) {
5542                                     _this._synchronize();
5543                                 }
5544                             }
5545                         },
5546                         error: function (err) {
5547                             _this._errorNotifier.notifyListeners(err);
5548                         }
5549                     });
5550                 } else {
5551                     if (typeof options === "object" && options.data) {
5552                         if (!this._processObject(this._normalize(options.data))) {
5553                             // notify of error if we fail to construct
5554                             this._errorNotifier.notifyListeners(this);
5555                         }
5556                     } else {
5557                         // Only subscribe if this REST object supports requests
5558                         if (this.supportsRequests) {
5559                             this._synchronize();
5560                         }
5561                     }
5562                 }
5563 
5564             } catch (err) {
5565                 this._logger.error('id=' + this._id + ': ' + err);
5566             }
5567         },
5568 
5569         /**
5570          * Determines if the object has a particular property.
5571          * @param obj is the object to examine
5572          * @param property is the property to check for
5573          * @returns {Boolean}
5574          */
5575         hasProperty: function (obj, prop) {
5576             return (obj !== null) && (obj.hasOwnProperty(prop));
5577         },
5578 
5579         /**
5580          * Gets a property from the object.
5581          * @param obj is the object to examine
5582          * @param property is the property to get
5583          * @returns {Property Value} or {Null} if not found
5584          */
5585         getProperty: function (obj, property) {
5586             var result = null;
5587 
5588             if (this.hasProperty(obj, property) === false) {
5589                 result = null;
5590             } else {
5591                 result = obj[property];
5592             }
5593             return result;
5594         },
5595 
5596         /**
5597          * Utility to extracts the ID from the specified REST URI. This is with the
5598          * assumption that the ID is always the last element in the URI after the
5599          * "/" delimiter.
5600          * @param {String} restUri
5601          *     The REST uri (i.e. /finesse/api/User/1000).
5602          * @private
5603          */
5604         _extractId: function (restObj) {
5605             var obj, restUri = "", strLoc;
5606             for (obj in restObj) {
5607                 if (restObj.hasOwnProperty(obj)) {
5608                     restUri = restObj[obj].uri;
5609                     break;
5610                 }
5611             }
5612             return Utilities.getId(restUri);
5613         },
5614 
5615         /**
5616          * Gets the data for this object.
5617          * @returns {Object} which is contained in data
5618          */
5619         getData: function () {
5620             return this._data;
5621         },
5622         
5623         /**
5624          * Gets the complete REST response to the request made
5625          * @returns {Object} which is contained in data
5626          * @private
5627          */
5628         getRestResponse: function () {
5629             return this._restResponse;
5630         },
5631 
5632         /**
5633          * The REST URL in which this object can be referenced.
5634          * @return {String}
5635          *     The REST URI for this object.
5636          * @private
5637          */
5638         getRestUrl: function () {
5639             var
5640             restObj = this._restObj,
5641             restUrl = "";
5642 
5643             //Prepend the base REST object if one was provided.
5644             if (restObj instanceof RestBase) {
5645                 restUrl += restObj.getRestUrl();
5646             }
5647             //Otherwise prepend with the default webapp name.
5648             else {
5649                 restUrl += "/finesse/api";
5650             }
5651 
5652             //Append the REST type.
5653             restUrl += "/" + this.getRestType();
5654 
5655             //Append ID if it is not undefined, null, or empty.
5656             if (this._id) {
5657                 restUrl += "/" + this._id;
5658             }
5659             return restUrl;
5660         },
5661 
5662         /**
5663          * Getter for the id of this RestBase
5664          * @returns {String}
5665          *     The id of this RestBase
5666          */
5667         getId: function () {
5668             return this._id;
5669         },
5670 
5671         /**
5672          * Synchronize this object with the server using REST GET request.
5673          * @private
5674          */
5675         _synchronize: function (retries) {
5676             // Fetch this REST object
5677             if (typeof this._id === "string") {
5678                 var _this = this, isLoaded = this._loaded, _RETRY_INTERVAL = 10 * 1000;
5679 
5680                 this._doGET(
5681                     {
5682                         success: function (rsp) {
5683                             if (!_this._processResponse(rsp)) {
5684                                 if (retries > 0) {
5685                                     setTimeout(function () {
5686                                         _this._synchronize(retries - 1);
5687                                     }, _RETRY_INTERVAL);
5688                                 } else {
5689                                     _this._errorNotifier.notifyListeners(_this);
5690                                 }
5691                             } else {
5692                                 // If this object was already "loaded" prior to
5693                                 // the _doGET request, then call the
5694                                 // changeNotifier
5695                                 if (isLoaded) {
5696                                     _this._changeNotifier.notifyListeners(_this);
5697                                 }
5698                             }
5699                         },
5700                         error: function (rsp) {
5701                             if (retries > 0) {
5702                                 setTimeout(function () {
5703                                     _this._synchronize(retries - 1);
5704                                 }, _RETRY_INTERVAL);
5705                                 
5706                             } else {
5707                                 _this._errorNotifier.notifyListeners(rsp);
5708                             }
5709                         }
5710                     }
5711                 );
5712 
5713             } else {
5714                 throw new Error("Can't construct a <" + this.getRestType() + "> due to invalid id type.");
5715             }
5716         },
5717 
5718         /**
5719          * Adds an handler to this object.
5720          * If notifierType is 'load' and the object has already loaded, the callback is invoked immediately
5721          * @param {String} notifierType
5722          *     The type of notifier to add to ('load', 'change', 'add', 'delete', 'error')
5723          * @param {Function} callback
5724          *     The function callback to invoke.
5725          * @example
5726          *   // Handler for additions to the Dialogs collection object.  
5727          *   // When Dialog (a RestBase object) is created, add a change handler.
5728          *   _handleDialogAdd = function(dialog) {
5729          *      dialog.addHandler('change', _handleDialogChange);
5730          *   }
5731          */
5732         addHandler: function (notifierType, callback, scope) {
5733             var notifier = null;
5734             try {
5735                 Utilities.validateHandler(callback);
5736 
5737                 notifier = this._getNotifierReference(notifierType);
5738 
5739                 notifier.addListener(callback, scope);
5740                 
5741                 // If load handler is added and object has
5742                 // already been loaded, invoke callback
5743                 // immediately
5744                 if (notifierType === 'load' && this._loaded) {
5745                     callback.call((scope || window), this);
5746                 }
5747             } catch (err) {
5748                 this._logger.error('id=' + this._id + ': ' + err);
5749             }
5750         },
5751 
5752         /**
5753          * Removes a handler from this object.
5754          * @param {String} notifierType
5755          *     The type of notifier to remove ('load', 'change', 'add', 'delete', 'error')
5756          * @param {Function} callback
5757          *     The function to remove.
5758          */
5759         removeHandler: function (notifierType, callback) {
5760             var notifier = null;
5761             try {
5762                 Utilities.validateHandler(callback);
5763 
5764                 notifier = this._getNotifierReference(notifierType);
5765 
5766                 if (typeof(callback) === "undefined")
5767                 {
5768                     // Remove all listeners for the type
5769                     notifier.reset();
5770                 }
5771                 else
5772                 {
5773                     // Remove the specified listener
5774                     finesse.utilities.Utilities.validateHandler(callback);
5775                     notifier.removeListener(callback);
5776                 }
5777             } catch (err) {
5778                 this._logger.error('id=' + this._id + ': ' + err);
5779             }
5780         },
5781 
5782         /**
5783          * Utility method gating any operations that require complete instantiation
5784          * @throws Error
5785          *     If this object was not fully instantiated yet
5786          * @returns {finesse.restservices.RestBase}
5787          *     This RestBase object to allow cascading
5788          */
5789         isLoaded: function () {
5790             if (!this._loaded) {
5791                 throw new Error("Cannot operate on object that is not fully instantiated, use onLoad/onLoadError handlers");
5792             }
5793             return this; // Allow cascading
5794         },
5795 
5796 
5797 
5798         /**
5799          * Force an update on this object. Since an asynchronous GET is performed,
5800          * it is necessary to have an onChange handler registered in order to be
5801          * notified when the response of this returns.
5802          * @param {Integer} retries
5803          *    The number or retry attempts to make.
5804          * @returns {finesse.restservices.RestBase}
5805          *     This RestBase object to allow cascading
5806          */
5807         refresh: function (retries) {
5808             var _this = this;
5809 
5810             if (this.explicitSubscription) {
5811                 this._subscribeNode({
5812                     success: function () {
5813                         //Disallow GETs if object doesn't support it.
5814                         if (!_this.supportsRequests) {
5815                             throw new Error("Object doesn't support request operations.");
5816                         }
5817 
5818                         _this._synchronize(retries);
5819 
5820                         return this; // Allow cascading
5821                     },
5822                     error: function (err) {
5823                         _this._errorNotifier.notifyListeners(err);
5824                     }
5825                 });
5826             } else {
5827                 //Disallow GETs if object doesn't support it.
5828                 if (!this.supportsRequests) {
5829                     throw new Error("Object doesn't support request operations.");
5830                 }
5831 
5832                 this._synchronize(retries);
5833 
5834                 return this; // Allow cascading
5835             }
5836         },
5837 
5838         /**
5839          * Utility method to validate against the known schema of this RestBase
5840          * @param {Object} obj
5841          *     The object to validate
5842          * @returns {Boolean}
5843          *     True if the object fits the schema of this object. This usually
5844          *     means all required keys or nested objects are present.
5845          *     False otherwise.
5846          * @private
5847          */
5848         _validate: function (obj) {
5849             var valid = (typeof obj === "object" && this.hasProperty(obj, this.getRestType()));
5850             if (!valid)
5851             {
5852                 this._logger.error(this.getRestType() + " failed validation! Does your JS REST class return the correct string from getRestType()?");
5853             }
5854             return valid;
5855         },
5856 
5857         /**
5858          * Utility method to fetch this RestBase from the server
5859          * @param {finesse.interfaces.RequestHandlers} handlers
5860          *     An object containing the handlers for the request
5861          * @returns {finesse.restservices.RestBase}
5862          *     This RestBase object to allow cascading
5863          * @private
5864          */
5865         _doGET: function (handlers) {
5866             this.restRequest(this.getRestUrl(), handlers);
5867             return this; // Allow cascading
5868         },
5869 
5870         /**
5871          * Common update event handler used by the pubsub callback closure.
5872          * Processes the update event then notifies listeners.
5873          * @param {Object} scope
5874          *     An object containing callbacks to handle the asynchronous get
5875          * @param {Object} update
5876          *     An object containing callbacks to handle the asynchronous get
5877          * @private
5878          */
5879         _updateEventHandler: function (scope, update) {
5880             if (scope._processUpdate(update)) {
5881                 switch (update.object.Update.event) {
5882                 case "POST":
5883                     scope._addNotifier.notifyListeners(scope);
5884                     break;
5885                 case "PUT":
5886                     scope._changeNotifier.notifyListeners(scope);
5887                     break;
5888                 case "DELETE":
5889                     scope._deleteNotifier.notifyListeners(scope);
5890                     break;
5891                 }
5892             }   
5893         },
5894 
5895         /**
5896          * Utility method to create a callback to be given to OpenAjax to invoke when a message
5897          * is published on the topic of our REST URL (also XEP-0060 node).
5898          * This needs to be its own defined method so that subclasses can have their own implementation.
5899          * @returns {Function} callback(update)
5900          *     The callback to be invoked when an update event is received. This callback will
5901          *     process the update and notify listeners.
5902          * @private
5903          */
5904         _createPubsubCallback: function () {
5905             var _this = this;
5906             return function (update) {
5907                 _this._updateEventHandler(_this, update);
5908             };
5909         },
5910 
5911         /**
5912          * Subscribe to pubsub infra using the REST URL as the topic name.
5913          * @param {finesse.interfaces.RequestHandlers} handlers
5914          *     An object containing the handlers for the request
5915          * @private
5916          */
5917         subscribe: function (callbacks) {
5918             // Only need to do a subscription to client pubsub. No need to trigger
5919             // a subscription on the Finesse server due to implicit subscribe (at
5920             // least for now).
5921             var _this = this,
5922             topic = Topics.getTopic(this.getRestUrl()),
5923             handlers,
5924             successful = ClientServices.subscribe(topic, this._createPubsubCallback(), true);
5925 
5926             callbacks = callbacks || {};
5927 
5928             handlers = {
5929                 /** @private */
5930                 success: function () {
5931                     // Add item to the refresh list in ClientServices to refresh if
5932                     // we recover due to our resilient connection. However, do
5933                     // not add if doNotRefresh flag is set.
5934                     if (!_this.doNotRefresh) {
5935                         ClientServices.addToRefreshList(_this);
5936                     }
5937 
5938                     if (typeof callbacks.success === "function") {
5939                         callbacks.success();
5940                     }
5941                 },
5942                 /** @private */
5943                 error: function (err) {
5944                     if (successful) {
5945                         ClientServices.unsubscribe(topic);
5946                     }
5947 
5948                     if (typeof callbacks.error === "function") {
5949                         callbacks.error(err);
5950                     }
5951                 }
5952             };
5953 
5954             // Request a node subscription only if this object requires explicit subscriptions
5955             if (this.explicitSubscription === true) {
5956                 this._subscribeNode(handlers);
5957             } else {
5958                 if (successful) {
5959                     this._subid = "OpenAjaxOnly";
5960                     handlers.success();
5961                 } else {
5962                     handlers.error();
5963                 }
5964             }
5965 
5966             return this;
5967         },
5968 
5969         /**
5970          * Unsubscribe to pubsub infra using the REST URL as the topic name.
5971          * @param {finesse.interfaces.RequestHandlers} handlers
5972          *     An object containing the handlers for the request
5973          * @private
5974          */
5975         unsubscribe: function (callbacks) {
5976             // Only need to do a subscription to client pubsub. No need to trigger
5977             // a subscription on the Finesse server due to implicit subscribe (at
5978             // least for now).
5979             var _this = this,
5980             topic = Topics.getTopic(this.getRestUrl()),
5981             handlers;
5982 
5983             // no longer keep track of object to refresh on reconnect
5984             ClientServices.removeFromRefreshList(_this);
5985 
5986             callbacks = callbacks || {};
5987 
5988             handlers = {
5989                 /** @private */
5990                 success: function () {
5991                     if (typeof callbacks.success === "function") {
5992                         callbacks.success();
5993                     }
5994                 },
5995                 /** @private */
5996                 error: function (err) {
5997                     if (typeof callbacks.error === "function") {
5998                         callbacks.error(err);
5999                     }
6000                 }
6001             };
6002 
6003             if (this._subid) {
6004                 ClientServices.unsubscribe(topic);
6005                 // Request a node unsubscribe only if this object requires explicit subscriptions
6006                 if (this.explicitSubscription === true) {
6007                     this._unsubscribeNode(handlers);
6008                 } else {
6009                     this._subid = undefined;
6010                     handlers.success();
6011                 }
6012             } else {
6013                 handlers.success();
6014             }
6015 
6016             return this;
6017         },
6018 
6019         /**
6020          * Private utility to perform node subscribe requests for explicit subscriptions
6021          * @param {finesse.interfaces.RequestHandlers} handlers
6022          *     An object containing the handlers for the request
6023          * @private
6024          */
6025         _subscribeNode: function (callbacks) {
6026             var _this = this;
6027 
6028             // Protect against null dereferencing of callbacks allowing its (nonexistent) keys to be read as undefined
6029             callbacks = callbacks || {};
6030 
6031             ClientServices.subscribeNode(this.getXMPPNodePath(), function (subid, err) {
6032                 if (err) {
6033                     if (typeof callbacks.error === "function") {
6034                         callbacks.error(err);
6035                     }
6036                 } else {
6037                     // Store the subid on a successful subscribe
6038                     _this._subid = subid;
6039                     if (typeof callbacks.success === "function") {
6040                         callbacks.success();
6041                     }
6042                 }
6043             });
6044         },
6045 
6046         /**
6047          * Private utility to perform node unsubscribe requests for explicit subscriptions
6048          * @param {finesse.interfaces.RequestHandlers} handlers
6049          *     An object containing the handlers for the request
6050          * @private
6051          */
6052         _unsubscribeNode: function (callbacks) {
6053             var _this = this;
6054 
6055             // Protect against null dereferencing of callbacks allowing its (nonexistent) keys to be read as undefined
6056             callbacks = callbacks || {};
6057 
6058             ClientServices.unsubscribeNode(this.getXMPPNodePath(), this._subid, function (err) {
6059                 _this._subid = undefined;
6060                 if (err) {
6061                     if (typeof callbacks.error === "function") {
6062                         callbacks.error(err);
6063                     }
6064                 } else {
6065                     if (typeof callbacks.success === "function") {
6066                         callbacks.success();
6067                     }
6068                 }
6069             });
6070         },
6071 
6072         /**
6073          * Validate and store the object into the internal data store.
6074          * @param {Object} object
6075          *     The JavaScript object that should match of schema of this REST object.
6076          * @returns {Boolean}
6077          *     True if the object was validated and stored successfully.
6078          * @private
6079          */
6080         _processObject: function (object) {
6081             if (this._validate(object)) {
6082                 this._data = this.getProperty(object, this.getRestType()); // Should clone the object here?
6083 
6084                 // If loaded for the first time, call the load notifiers.
6085                 if (!this._loaded) {
6086                     this._loaded = true;
6087                     this._loadNotifier.notifyListeners(this);
6088                 }
6089 
6090                 return true;
6091             }
6092             return false;
6093         },
6094 
6095         /**
6096          * Normalize the object to mitigate the differences between the backend
6097          * and what this REST object should hold. For example, the backend sends
6098          * send an event with the root property name being lower case. In order to
6099          * match the GET, the property should be normalized to an upper case.
6100          * @param {Object} object
6101          *     The object which should be normalized.
6102          * @returns {Object}
6103          *     Return the normalized object.
6104          * @private
6105          */
6106         _normalize: function (object) {
6107             var
6108             restType = this.getRestType(),
6109             // Get the REST object name with first character being lower case.
6110             objRestType = restType.charAt(0).toLowerCase() + restType.slice(1);
6111 
6112             // Normalize payload to match REST object. The payload for an update
6113             // use a lower case object name as oppose to upper case. Only normalize
6114             // if necessary.
6115             if (!this.hasProperty(object, restType) && this.hasProperty(object, objRestType)) {
6116                 //Since the object is going to be modified, clone the object so that
6117                 //it doesn't affect others (due to OpenAjax publishing to other
6118                 //subscriber.
6119                 object = jQuery.extend(true, {}, object);
6120 
6121                 object[restType] = object[objRestType];
6122                 delete(object[objRestType]);
6123             }
6124             return object;
6125         },
6126 
6127         /**
6128          * Utility method to process the response of a successful get
6129          * @param {Object} rsp
6130          *     The response of a successful get
6131          * @returns {Boolean}
6132          *     True if the update was successfully processed (the response object
6133          *     passed the schema validation) and updated the internal data cache,
6134          *     false otherwise.
6135          * @private
6136          */
6137         _processResponse: function (rsp) {
6138             try {
6139                 if (this.keepRestResponse) {
6140                     this._restResponse = rsp.content;
6141                 }
6142                 return this._processObject(rsp.object);
6143             }
6144             catch (err) {
6145                 this._logger.error(this.getRestType() + ': ' + err);
6146             }
6147             return false;
6148         },
6149 
6150         /**
6151          * Utility method to process the update notification.
6152          * @param {Object} update
6153          *     The payload of an update notification.
6154          * @returns {Boolean}
6155          *     True if the update was successfully processed (the update object
6156          *     passed the schema validation) and updated the internal data cache,
6157          *     false otherwise.
6158          * @private
6159          */
6160         _processUpdate: function (update) {
6161             try {
6162                 var updateObj, requestId, fakeResponse, receivedError;
6163 
6164                 // The backend will send the data object with a lower case. To be
6165                 // consistent with what should be represented in this object, the
6166                 // object name should be upper case. This will normalize the object.
6167                 updateObj = this._normalize(update.object.Update.data);
6168 
6169                 // Store the last event.
6170                 this._lastUpdate = update.object;
6171 
6172                 requestId = this._lastUpdate.Update ? this._lastUpdate.Update.requestId : undefined;
6173 
6174                 if (requestId && this._pendingCallbacks[requestId]) {
6175 
6176                     /*
6177                      * The passed success/error callbacks are expecting to be passed an AJAX response, so construct
6178                      * a simulated/"fake" AJAX response object from the information in the received event.
6179                      * The constructed object should conform to the contract for response objects specified
6180                      * in _createAjaxHandler().
6181                      */
6182                     fakeResponse = {};
6183 
6184                     //The contract says that rsp.content should contain the raw text of the response so we simulate that here.
6185                     //For some reason json2xml has trouble with the native update object, so we serialize a clone of it by
6186                     //doing a parse(stringify(update)).
6187                     fakeResponse.content = this._util.json2xml(gadgets.json.parse(gadgets.json.stringify(update)));
6188 
6189                     fakeResponse.object = {};
6190 
6191                     if (updateObj.apiErrors && updateObj.apiErrors.apiError) { //Error case
6192 
6193                         //TODO: The lowercase -> uppercase ApiErrors translation method below is undesirable, can it be improved?
6194                         receivedError = updateObj.apiErrors.apiError;
6195                         fakeResponse.object.ApiErrors = {};
6196                         fakeResponse.object.ApiErrors.ApiError = {};
6197                         fakeResponse.object.ApiErrors.ApiError.ErrorData = receivedError.errorData || undefined;
6198                         fakeResponse.object.ApiErrors.ApiError.ErrorMessage = receivedError.errorMessage || undefined;
6199                         fakeResponse.object.ApiErrors.ApiError.ErrorType = receivedError.errorType || undefined;
6200 
6201                         /*
6202                          * Since this is the error case, supply the error callback with a '400 BAD REQUEST' status code. We don't know what the real
6203                          * status code should be since the event we're constructing fakeResponse from doesn't include a status code.
6204                          * This is just to conform to the contract for the error callback in _createAjaxHandler().
6205                          **/
6206                         fakeResponse.status = 400;
6207 
6208                     } else { //Success case
6209 
6210                         fakeResponse.object = this._lastUpdate;
6211 
6212                         /*
6213                          * Since this is the success case, supply the success callback with a '200 OK' status code. We don't know what the real
6214                          * status code should be since the event we're constructing fakeResponse from doesn't include a status code.
6215                          * This is just to conform to the contract for the success callback in _createAjaxHandler().
6216                          **/
6217                         fakeResponse.status = 200;
6218                     }
6219 
6220                     try {
6221 
6222                         if (fakeResponse.object.ApiErrors && this._pendingCallbacks[requestId].error) {
6223                             this._pendingCallbacks[requestId].error(fakeResponse);
6224                         } 
6225                         // HTTP 202 is handled as a success, besides, we cannot infer that a non-error is a success.
6226                         /*else if (this._pendingCallbacks[requestId].success) {
6227                             this._pendingCallbacks[requestId].success(fakeResponse);
6228                         }*/
6229 
6230                     } catch (callbackErr) {
6231 
6232                         this._logger.error(this.getRestType() + ": Caught error while firing callback: " + callbackErr);
6233 
6234                     }
6235 
6236                     //Clean up _pendingCallbacks now that we fired a callback corresponding to the received requestId.
6237                     delete this._pendingCallbacks[requestId];
6238 
6239                 } else {
6240                     this._logger.log(this.getRestType() + ": Received the following event with an invalid or unknown requestId:");
6241                     this._logger.log(gadgets.json.stringify(update));
6242                 }
6243 
6244                 return this._processObject(updateObj);
6245             }
6246             catch (err) {
6247                 this._logger.error(this.getRestType() + ': ' + err);
6248             }
6249             return false;
6250         },
6251 
6252         /**
6253          * Utility method to create ajax response handler closures around the
6254          * provided callbacks. Callbacks should be passed through from .ajax().
6255          * makeRequest is responsible for garbage collecting these closures.
6256          * @param {finesse.interfaces.RequestHandlers} handlers
6257          *     An object containing the handlers for the request
6258          * @private
6259          */
6260         _createAjaxHandler: function (options) {
6261             //We should not need to check this again since it has already been done in .restRequest()
6262             //options = options || {};
6263 
6264             //Get a reference to the parent User object
6265             var _this = this;
6266 
6267             return function (rsp) {
6268 
6269                 var requestId, error = false, rspObj;
6270 
6271                 if (options.success || options.error) {
6272                     rspObj = {
6273                         status: rsp.rc,
6274                         content: rsp.text
6275                     };
6276 
6277                     if (!_this.doNotLog) {
6278                         _this._logger.log(_this.getRestType() + ": requestId='" + options.uuid + "', Returned with status=" + rspObj.status + ", content='" + rspObj.content + "'");
6279                     }
6280 
6281                     //Some responses may not have a body.
6282                     if (rsp.text && rsp.text.length > 0) {
6283                         try {
6284                             rspObj.object = _this._util.xml2js(rsp.text);
6285                         } catch (e) {
6286                             error = true;
6287                             rspObj.error = {
6288                                 errorType: "parseError",
6289                                 errorMessage: "Could not serialize XML: " + e
6290                             };
6291                         }
6292                     } else {
6293                         rspObj.object = {};
6294                     }
6295 
6296                     if (!error && rspObj.status >= 200 && rspObj.status < 300) {
6297                         if (options.success) {
6298                             options.success(rspObj);
6299                         }
6300                     } else {
6301                         if (options.error) {
6302                             options.error(rspObj);
6303                         }
6304                     }
6305 
6306                     /*
6307                      * If a synchronous error happened after a non-GET request (usually a validation error), we
6308                      * need to clean up the request's entry in _pendingCallbacks since no corresponding event
6309                      * will arrive later. The corresponding requestId should be present in the response headers.
6310                      *
6311                      * It appears Shindig changes the header keys to lower case, hence 'requestid' instead of
6312                      * 'requestId' below.
6313                      **/
6314                     if (rspObj.status !== 202 && rsp.headers && rsp.headers.requestid) {
6315                         requestId = rsp.headers.requestid[0];
6316                         if (_this._pendingCallbacks[requestId]) {
6317                             delete _this._pendingCallbacks[requestId];
6318                         }
6319                     }
6320                 }
6321             };
6322         },
6323 
6324         /**
6325          * Utility method to make an asynchronous request
6326          * @param {String} url
6327          *     The unencoded URL to which the request is sent (will be encoded)
6328          * @param {Object} options
6329          *     An object containing additional options for the request.
6330          * @param {Object} options.content
6331          *     An object to send in the content body of the request. Will be
6332          *     serialized into XML before sending.
6333          * @param {String} options.method
6334          *     The type of request. Defaults to "GET" when none is specified.
6335          * @param {Function} options.success(rsp)
6336          *     A callback function to be invoked for a successful request.
6337          *     {
6338          *         status: {Number} The HTTP status code returned
6339          *         content: {String} Raw string of response
6340          *         object: {Object} Parsed object of response
6341          *     }
6342          * @param {Function} options.error(rsp)
6343          *     A callback function to be invoked for an unsuccessful request.
6344          *     {
6345          *         status: {Number} The HTTP status code returned
6346          *         content: {String} Raw string of response
6347          *         object: {Object} Parsed object of response
6348          *         error: {Object} Wrapped exception that was caught
6349          *         error.errorType: {String} Type of error that was caught
6350          *         error.errorMessage: {String} Message associated with error
6351          *     }
6352          * @private
6353         */
6354         restRequest: function (url, options) {
6355 
6356             var params, encodedUrl;
6357 
6358             params = {};
6359 
6360             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
6361             options = options || {};
6362             options.success = this._util.validateHandler(options.success);
6363             options.error = this._util.validateHandler(options.error);
6364 
6365             // Request Headers
6366             params[gadgets.io.RequestParameters.HEADERS] = {};
6367 
6368             // HTTP method is a passthrough to gadgets.io.makeRequest, makeRequest defaults to GET
6369             params[gadgets.io.RequestParameters.METHOD] = options.method;
6370 
6371             //true if this should be a GET request, false otherwise
6372             if (!options.method || options.method === "GET") {
6373                 //Disable caching for GETs
6374                 if (url.indexOf("?") > -1) {
6375                     url += "&";
6376                 } else {
6377                     url += "?";
6378                 }
6379                 url += "nocache=" + this._util.currentTimeMillis();
6380             } else {
6381                 /**
6382                  * If not GET, generate a requestID and add it to the headers, then wrap
6383                  * callbacks into an object and store it in _pendingCallbacks.
6384                  * If we receive a synchronous error response instead of a 202 as expected,
6385              * the AJAX handler will clean up _pendingCallbacks.
6386                  **/
6387                 /*
6388                  * TODO: Clean up _pendingCallbacks if an entry persists after a certain amount of time has passed.
6389                  * In the block below, can store the current time (new Date().getTime()) alongside the
6390                  * callbacks in the new _pendingCallbacks entry. Then iterate through a copty of _pendingCallbacks,
6391                  * deleting all entries inside _pendingCallbacks that are older than a certain threshold (2 minutes for example.)
6392                  * This solves a potential memory leak issue if we never receive an event for a given stored requestId;
6393                  * we don't want to store unfired callbacks forever.
6394                  */
6395                 /** @private */
6396                 options.uuid = this._util.generateUUID();
6397                 params[gadgets.io.RequestParameters.HEADERS].requestId = options.uuid;
6398                 //By default, Shindig strips nearly all of the response headers, but this parameter tells Shindig
6399                 //to send the headers through unmodified; we need to be able to read the 'requestId' header if we
6400                 //get a synchronous error as a result of a non-GET request. (See the bottom of _createAjaxHandler().)
6401                 params[gadgets.io.RequestParameters.GET_FULL_HEADERS] = "true";
6402                 this._pendingCallbacks[options.uuid] = {};
6403                 this._pendingCallbacks[options.uuid].success = options.success;
6404                 this._pendingCallbacks[options.uuid].error = options.error;
6405             }
6406 
6407             //debugger;
6408             // NAT: IGNORE this until you hit save after changing assignments, then
6409             // pause here and set window.errorOnRequest to true, step past the next line,
6410             // and then set it to false. True value will throw an error when saving assignments.
6411             encodedUrl = encodeURI(url) + (window.errorOnRestRequest ? "ERROR" : "");
6412 
6413             if (!this.doNotLog) {
6414                 this._logger.log(this.getRestType() + ": requestId='" + options.uuid + "', Making REST request: method=" + (options.method || "GET") + ", url='" + encodedUrl + "'");
6415             }
6416 
6417             // Content Body
6418             if (typeof options.content === "object") {
6419                 // Content Type
6420                 params[gadgets.io.RequestParameters.HEADERS]["Content-Type"] = "application/xml";
6421                 // Content
6422                 params[gadgets.io.RequestParameters.POST_DATA] = this._util.js2xml(options.content);
6423                 
6424                 if (!this.doNotLog) {
6425                     this._logger.log(this.getRestType() + ": requestId='" + options.uuid + "', POST_DATA='" + params[gadgets.io.RequestParameters.POST_DATA] + "'");
6426                 }
6427             }
6428 
6429             ClientServices.makeRequest(encodedUrl, this._createAjaxHandler(options), params);
6430         },
6431 
6432         /**
6433          * Retrieves a reference to a particular notifierType.
6434          * @param notifierType is a string which indicates the notifier to retrieve
6435          * ('load', 'change', 'add', 'delete', 'error')
6436          * @return {Notifier}
6437          * @private
6438          */
6439         _getNotifierReference: function (notifierType) {
6440             var notifierReference = null;
6441             if (notifierType === 'load') {
6442                 notifierReference = this._loadNotifier;
6443             } else if (notifierType === 'change') {
6444                 notifierReference = this._changeNotifier;
6445             } else if (notifierType === 'add') {
6446                 notifierReference = this._addNotifier;
6447             } else if (notifierType === 'delete') {
6448                 notifierReference = this._deleteNotifier;
6449             } else if (notifierType === 'error') {
6450                 notifierReference = this._errorNotifier;
6451             } else {
6452                 throw new Error("_getNotifierReference(): Trying to get unknown notifier(notifierType=" + notifierType + ")");
6453             }
6454 
6455             return notifierReference;
6456         }
6457     });
6458 
6459     window.finesse = window.finesse || {};
6460     window.finesse.restservices = window.finesse.restservices || {};
6461     window.finesse.restservices.RestBase = RestBase;
6462     
6463     return RestBase;
6464 }));
6465 
6466 /** The following comment is to prevent jslint errors about 
6467  * using variables before they are defined.
6468  */
6469 /*global finesse*/
6470 
6471 /**
6472  * JavaScript base object that all REST collection objects should
6473  * inherit from because it encapsulates and provides the common functionality
6474  * that all REST objects need.
6475  *
6476  * @requires finesse.clientservices.ClientServices
6477  * @requires Class
6478  * @requires finesse.FinesseBase
6479  * @requires finesse.restservices.RestBase
6480  */
6481 
6482 /**
6483  * @class
6484  * JavaScript representation of a REST collection object.
6485  *
6486  * @constructor
6487  * @param {Function} callbacks.onCollectionAdd(this)
6488  *     Callback to invoke upon successful item addition to the collection.
6489  * @param {Function} callbacks.onCollectionDelete(this)
6490  *     Callback to invoke upon successful item deletion from the collection.
6491  * @borrows finesse.restservices.RestBase as finesse.restservices.RestCollectionBase
6492  */
6493 /** @private */
6494 (function (factory) {
6495     
6496 
6497     // Define as an AMD module if possible
6498     if ( typeof define === 'function' && define.amd )
6499     {
6500         define('restservices/RestCollectionBase', ['restservices/RestBase',
6501                  'utilities/Utilities',
6502                  'restservices/Notifier'], factory );
6503     }
6504     /* Define using browser globals otherwise
6505      * Prevent multiple instantiations if the script is loaded twice
6506      */
6507     else
6508     {
6509         factory(finesse.restservices.RestBase, finesse.utilities.Utilities, finesse.restservices.Notifier);
6510     } 
6511 }(function (RestBase, Utilities, Notifier) {
6512     var RestCollectionBase = RestBase.extend(/** @lends finesse.restservices.RestCollectionBase.prototype */{
6513 
6514         /**
6515          * Boolean function that specifies whether the collection handles subscribing
6516          * and propagation of events for the individual REST object items the
6517          * collection holds. False by default. Subclasses should override if true.
6518          * @private
6519          */
6520         supportsRestItemSubscriptions: false,
6521 
6522         /**
6523          * Gets the constructor the individual items that make of the collection.
6524          * For example, a Dialogs collection object will hold a list of Dialog items.
6525          * @throws Error because subtype must implement.
6526          * @private
6527          */
6528         getRestItemClass: function () {
6529             throw new Error("getRestItemClass(): Not implemented in subtype.");
6530         },
6531 
6532         /**
6533          * Gets the REST type of the individual items that make of the collection.
6534          * For example, a Dialogs collection object will hold a list of Dialog items.
6535          * @throws Error because subtype must implement.
6536          * @private
6537          */
6538         getRestItemType: function () {
6539             throw new Error("getRestItemType(): Not implemented in subtype.");
6540         },
6541 
6542         /**
6543          * The base REST URL in which items this object contains can be referenced.
6544          * @return {String}
6545          *     The REST URI for items this object contains.
6546          * @private
6547          */
6548         getRestItemBaseUrl: function () {
6549             var
6550             restUrl = "/finesse/api";
6551 
6552             //Append the REST type.
6553             restUrl += "/" + this.getRestItemType();
6554 
6555             return restUrl;
6556         },
6557 
6558          /*
6559          * Creates a new object from the given data
6560          * @param data - data object
6561          * @private
6562          */
6563         _objectCreator: function (data) {
6564             var objectId = this._extractId(data),
6565             newRestObj = this._collection[objectId],
6566             _this = this;
6567 
6568             //Prevent duplicate entries into collection.
6569             if (!newRestObj) {
6570                 //Create a new REST object using the subtype defined by the
6571                 //overridden method.
6572                 newRestObj = new (this.getRestItemClass())({
6573                     doNotSubscribe: this.handlesItemSubscription,
6574                     doNotRefresh: this.handlesItemRefresh,
6575                     id: objectId,
6576                     data: data,
6577                     onLoad: function (newObj) {
6578                         //Normalize and add  REST object to collection datastore.
6579                         _this._collection[objectId] = newObj;
6580                         _this._collectionAddNotifier.notifyListeners(newObj);
6581                         _this.length += 1;
6582                     }
6583                 });
6584             }
6585             else {
6586                 //If entry already exist in collection, process the new event,
6587                 //and notify all change listeners since an existing object has
6588                 //change. This could happen in the case when the Finesse server
6589                 //cycles, and sends a snapshot of the user's calls.
6590                 newRestObj._processObject(data);
6591                 newRestObj._changeNotifier.notifyListeners(newRestObj);
6592             }
6593         },
6594 
6595         /*
6596          * Deletes and object and notifies its handlers
6597          * @param data - data object
6598          * @private
6599          */
6600         _objectDeleter: function (data) {
6601             var objectId = this._extractId(data),
6602             object = this._collection[objectId];
6603             if (object) {
6604                 //Even though this is a delete, let's make sure the object we are passing has got good data
6605                 object._processObject(data);
6606                 //Notify listeners and delete from internal datastore.
6607                 this._collectionDeleteNotifier.notifyListeners(object);
6608                 delete this._collection[objectId];
6609                 this.length -= 1;
6610             }
6611         },
6612 
6613          /**
6614           * Creates an anonymous function for notifiying error listeners of a particular object
6615           * data.
6616           * @param obj - the objects whose error listeners to notify
6617           * @returns {Function}
6618           *     Callback for notifying of errors
6619           * @private
6620           */
6621         _createErrorNotifier: function (obj) {
6622             return function (err) {
6623                 obj._errorNotifier.notifyListeners(err);
6624             };
6625         },
6626 
6627          /**
6628           * Replaces the collection with a refreshed list using the passed in
6629           * data.
6630           * @param data - data object (usually this._data)
6631           * @private
6632           */
6633          _buildRefreshedCollection: function (data) {
6634             var i, dataObject, object, objectId, dataArray, newIds = [], foundFlag;
6635             if (data && this.getProperty(data, this.getRestItemType()) !== null) {
6636                 dataArray = Utilities.getArray(this.getProperty(data, this.getRestItemType()));
6637             } else {
6638                 dataArray = [];
6639             }
6640 
6641             // iterate through each item in the new data and add to or update collection
6642             for (i = 0; i < dataArray.length; i += 1) {
6643                 dataObject = {};
6644                 dataObject[this.getRestItemType()] = dataArray[i];
6645                 objectId = this._extractId(dataObject);
6646 
6647                 this._objectCreator(dataObject);
6648                 newIds.push(objectId);
6649 
6650                 // resubscribe if the object requires an explicit subscription
6651                 object = this._collection[objectId];
6652                 if (this.handlesItemRefresh && object.explicitSubscription) {
6653                     object._subscribeNode({
6654                         error: this._createErrorNotifier(object)
6655                     });
6656                 }
6657             }
6658 
6659             // now clean up items (if any) that were removed
6660             for (objectId in this._collection) {
6661                 if (this._collection.hasOwnProperty(objectId)) {
6662                     foundFlag = false;
6663                     for (i = newIds.length - 1; i >= 0; i -= 1) {
6664                         if (newIds[i] === objectId) {
6665                             foundFlag = true;
6666                             break;
6667                         }
6668                     }
6669                     // did not find in updated list, so delete it
6670                     if (!foundFlag) {
6671                         this._objectDeleter({'data': this._collection[objectId]._data});
6672                     }
6673                 }
6674             }
6675         },
6676 
6677          /**
6678           * The actual refresh operation, refactored out so we don't have to repeat code
6679           * @private
6680           */
6681         _RESTRefresh: function () {
6682             var _this = this;
6683             this._doGET({
6684                 success: function(rsp) {
6685                     if (_this._processResponse(rsp)) {
6686                         _this._buildRefreshedCollection(_this._data);
6687                     } else {
6688                         _this._errorNotifier.notifyListeners(_this);
6689                     }
6690                 },
6691                 error: function(rsp) {
6692                     _this._errorNotifier.notifyListeners(rsp);
6693                 }
6694             });            
6695         },
6696 
6697         /**
6698          * Force an update on this object. Since an asynchronous GET is performed,
6699          * it is necessary to have an onChange handler registered in order to be
6700          * notified when the response of this returns.
6701          * @returns {finesse.restservices.RestBaseCollection}
6702          *     This RestBaseCollection object to allow cascading
6703          */
6704          refresh: function() {
6705             var _this = this, isLoaded = this._loaded;
6706 
6707             // resubscribe if the collection requires an explicit subscription
6708             if (this.explicitSubscription) {
6709                 this._subscribeNode({
6710                     success: function () {
6711                         _this._RESTRefresh();
6712                     },
6713                     error: function (err) {
6714                         _this._errorNotifier.notifyListeners(err);
6715                     }
6716                 });
6717             } else {
6718                 this._RESTRefresh();
6719             }
6720 
6721             return this; // Allow cascading
6722          },
6723 
6724         /**
6725          * @private
6726          * The _addHandlerCb and _deleteHandlerCb require that data be passed in the
6727          * format of an array of {(Object Type): object} objects. For example, a
6728          * queues object would return [{Queue: queue1}, {Queue: queue2}, ...].
6729          * @param skipOuterObject If {true} is passed in for this param, then the "data"
6730          *                           property is returned instead of an object with the
6731          *                           data appended.
6732          * @return {Array}
6733          */
6734         extractCollectionData: function (skipOuterObject) {
6735             var restObjs,
6736             obj,
6737             result = [],
6738             _this = this;
6739             
6740             if (this._data)
6741             {
6742                 restObjs = this._data[this.getRestItemType()];
6743     
6744                 if (restObjs)
6745                 {
6746                     // check if there are multiple objects to pass
6747                     if (!$.isArray(restObjs))
6748                     {
6749                         restObjs = [restObjs];
6750                     }
6751     
6752                     // if so, create an object for each and add to result array
6753                     $.each(restObjs, function (id, object) {
6754                         if (skipOuterObject === true)
6755                         {
6756                             obj = object;
6757                         }
6758                         else
6759                         {
6760                             obj = {};
6761                             obj[_this.getRestItemType()] = object;
6762                         }
6763                         result.push(obj);
6764                     });
6765                 }
6766                 
6767             }
6768             
6769             return result;
6770         },
6771 
6772         /**
6773          * For Finesse, collections are handled uniquely on a POST and
6774          * doesn't necessary follow REST conventions. A POST on a collection
6775          * doesn't mean that the collection has been created, it means that an
6776          * item has been added to the collection. This function will generate
6777          * a closure which will handle this logic appropriately.
6778          * @param {Object} scope
6779          *     The scope of where the callback should be invoked.
6780          * @private
6781          */
6782         _addHandlerCb: function (scope) {
6783             return function (restItem) {
6784                 var data = restItem.extractCollectionData();               
6785 
6786                 $.each(data, function (id, object) {
6787                     scope._objectCreator(object);
6788                 });
6789             };
6790         },
6791 
6792         /**
6793          * For Finesse, collections are handled uniquely on a DELETE and
6794          * doesn't necessary follow REST conventions. A DELETE on a collection
6795          * doesn't mean that the collection has been deleted, it means that an
6796          * item has been deleted from the collection. This function will generate
6797          * a closure which will handle this logic appropriately.
6798          * @param {Object} scope
6799          *     The scope of where the callback should be invoked.
6800          * @private
6801          */
6802         _deleteHandlerCb: function (scope) {
6803             return function (restItem) {
6804                 var data = restItem.extractCollectionData();
6805 
6806                 $.each(data, function (id, obj) {
6807                     scope._objectDeleter(obj);
6808                 });
6809             };
6810         },
6811 
6812         /**
6813          * Utility method to process the update notification for Rest Items
6814          * that are children of the collection whose events are published to
6815          * the collection's node.
6816          * @param {Object} update
6817          *     The payload of an update notification.
6818          * @returns {Boolean}
6819          *     True if the update was successfully processed (the update object
6820          *     passed the schema validation) and updated the internal data cache,
6821          *     false otherwise.
6822          * @private
6823          */
6824         _processRestItemUpdate: function (update) {
6825             var object, objectId, updateObj = update.object.Update;
6826 
6827             //Extract the ID from the source if the Update was an error.
6828             if (updateObj.data.apiErrors) {
6829                 objectId = Utilities.getId(updateObj.source);
6830             }
6831             //Otherwise extract from the data object itself.
6832             else {
6833                 objectId = this._extractId(updateObj.data);
6834             }
6835 
6836             object = this._collection[objectId];
6837             if (object) {
6838                 if (object._processUpdate(update)) {
6839                     switch (updateObj.event) {
6840                     case "POST":
6841                         object._addNotifier.notifyListeners(object);
6842                         break;
6843                     case "PUT":
6844                         object._changeNotifier.notifyListeners(object);
6845                         break;
6846                     case "DELETE":
6847                         object._deleteNotifier.notifyListeners(object);
6848                         break;
6849                     }
6850                 }
6851             }
6852         },
6853 
6854         /**
6855          * SUBCLASS IMPLEMENTATION (override):
6856          * For collections, this callback has the additional responsibility of passing events
6857          * of collection item updates to the item objects themselves. The collection needs to
6858          * do this because item updates are published to the collection's node.
6859          * @returns {Function}
6860          *     The callback to be invoked when an update event is received
6861          * @private
6862          */
6863         _createPubsubCallback: function () {
6864             var _this = this;
6865             return function (update) {
6866                 //If the source of the update is our REST URL, this means the collection itself is modified
6867                 if (update.object.Update.source === _this.getRestUrl()) {
6868                     _this._updateEventHandler(_this, update);
6869                 } else {
6870                     //Otherwise, it is safe to assume that if we got an event on our topic, it must be a
6871                     //rest item update of one of our children that was published on our node (OpenAjax topic)
6872                     _this._processRestItemUpdate(update);
6873                 }
6874             };
6875         },
6876 
6877         /**
6878          * @class
6879          * This is the base collection object. 
6880          *
6881          * @constructs
6882          * @augments finesse.restservices.RestBase
6883          * @see finesse.restservices.Contacts
6884          * @see finesse.restservices.Dialogs
6885          * @see finesse.restservices.PhoneBooks
6886          * @see finesse.restservices.Queues
6887          * @see finesse.restservices.WorkflowActions
6888          * @see finesse.restservices.Workflows
6889          * @see finesse.restservices.WrapUpReasons
6890          */
6891         _fakeConstuctor: function () {
6892             /* This is here to hide the real init constructor from the public docs */
6893         },
6894         
6895        /**
6896          * @private
6897          * @param {Object} options
6898          *     An object with the following properties:<ul>
6899          *         <li><b>id:</b> The id of the object being constructed</li>
6900          *         <li><b>onCollectionAdd(this): (optional)</b> when an object is added to this collection</li>
6901          *         <li><b>onCollectionDelete(this): (optional)</b> when an object is removed from this collection</li>
6902          *         <li><b>onLoad(this): (optional)</b> when the collection is successfully loaded from the server</li>
6903          *         <li><b>onChange(this): (optional)</b> when an update notification of the collection is received. 
6904          *         This does not include adding and deleting members of the collection</li>
6905          *         <li><b>onAdd(this): (optional)</b> when a notification that the collection is created is received</li>
6906          *         <li><b>onDelete(this): (optional)</b> when a notification that the collection is deleted is received</li>
6907          *         <li><b>onError(rsp): (optional)</b> if loading of the collection fails, invoked with the error response object:<ul>
6908          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
6909          *             <li><b>content:</b> {String} Raw string of response</li>
6910          *             <li><b>object:</b> {Object} Parsed object of response</li>
6911          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
6912          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
6913          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
6914          *             </ul></li>
6915          *         </ul></li>
6916          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
6917          **/
6918         init: function (options) {
6919 
6920             options = options || {};
6921             options.id = "";
6922 
6923             //Make internal datastore collection to hold a list of objects.
6924             this._collection = {};
6925             this.length = 0;
6926 
6927             //Collections will have additional callbacks that will be invoked when
6928             //an item has been added/deleted.
6929             this._collectionAddNotifier = new Notifier();
6930             this._collectionDeleteNotifier = new Notifier();
6931 
6932             //Initialize the base class.
6933             this._super(options);
6934 
6935             this.addHandler('collectionAdd', options.onCollectionAdd);
6936             this.addHandler('collectionDelete', options.onCollectionDelete);
6937 
6938             //For Finesse, collections are handled uniquely on a POST/DELETE and
6939             //doesn't necessary follow REST conventions. A POST on a collection
6940             //doesn't mean that the collection has been created, it means that an
6941             //item has been added to the collection. A DELETE means that an item has
6942             //been removed from the collection. Due to this, we are attaching
6943             //special callbacks to the add/delete that will handle this logic.
6944             this.addHandler("add", this._addHandlerCb(this));
6945             this.addHandler("delete", this._deleteHandlerCb(this));
6946         },
6947 
6948         /**
6949          * Returns the collection.
6950          * @returns {Object}
6951          *     The collection as an object
6952          */
6953         getCollection: function () {
6954             //TODO: is this safe? or should we instead return protected functions such as .each(function)?
6955             return this._collection;
6956         },
6957 
6958         /**
6959          * Utility method to build the internal collection data structure (object) based on provided data
6960          * @param {Object} data
6961          *     The data to build the internal collection from
6962          * @private
6963          */
6964         _buildCollection: function (data) {
6965             var i, object, objectId, dataArray;
6966             if (data && this.getProperty(data, this.getRestItemType()) !== null) {
6967                 dataArray = Utilities.getArray(this.getProperty(data, this.getRestItemType()));
6968                 for (i = 0; i < dataArray.length; i += 1) {
6969 
6970                     object = {};
6971                     object[this.getRestItemType()] = dataArray[i];
6972                     objectId = this._extractId(object);
6973                     this._collection[objectId] = new (this.getRestItemClass())({
6974                         doNotSubscribe: this.handlesItemSubscription,
6975                         doNotRefresh: this.handlesItemRefresh,
6976                         id: objectId,
6977                         data: object
6978                     });
6979                     this.length += 1;
6980                 }
6981             }
6982         },
6983 
6984         /**
6985          * Called to know whether to include an item in the _collection and _data. Return false to keep it, true to filter out (discard) it.
6986          * Override this in subclasses if you need only object with certain attribute values.
6987          * @param  {Object} item Item to test.
6988          * @return {Boolean} False to keep, true to filter out (discard);
6989          */
6990         _filterOutItem: function (item) {
6991             return false;
6992         },
6993     
6994         /**
6995          * Validate and store the object into the internal data store.
6996          * SUBCLASS IMPLEMENTATION (override):
6997          * Performs collection specific logic to _buildCollection internally based on provided data
6998          * @param {Object} object
6999          *     The JavaScript object that should match of schema of this REST object.
7000          * @returns {Boolean}
7001          *     True if the object was validated and stored successfully.
7002          * @private
7003          */
7004         _processObject: function (object) {
7005             var i,
7006                 restItemType = this.getRestItemType(),
7007                 items;
7008             if (this._validate(object)) {
7009                 this._data = this.getProperty(object, this.getRestType()); // Should clone the object here?
7010     
7011                 // If a subclass has overriden _filterOutItem then we'll need to run through the items and remove them
7012                 if (this._data)
7013                 {
7014                     items = this._data[restItemType];
7015     
7016                     if (typeof(items) !== "undefined")
7017                     {
7018                         if (typeof(items.length) === "undefined")
7019                         {
7020                             // Single object
7021                             if (this._filterOutItem(items))
7022                             {
7023                                 this._data[restItemType] = items = [];
7024                             }
7025                             
7026                         }
7027                         else
7028                         {
7029                             // filter out objects
7030                             for (i = items.length - 1; i !== -1; i = i - 1)
7031                             {
7032                                 if (this._filterOutItem(items[i]))
7033                                 {
7034                                     items.splice(i, 1);
7035                                 }
7036                             }
7037                         }
7038                     }
7039                 }
7040     
7041                 // If loaded for the first time, call the load notifiers.
7042                 if (!this._loaded) {
7043                     this._buildCollection(this._data);
7044                     this._loaded = true;
7045                     this._loadNotifier.notifyListeners(this);
7046                 }
7047                 
7048                 return true;
7049                 
7050             }
7051             return false;
7052         },
7053 
7054         /**
7055          * Retrieves a reference to a particular notifierType.
7056          * @param {String} notifierType
7057          *      Specifies the notifier to retrieve (load, change, error, add, delete)
7058          * @return {Notifier} The notifier object.
7059          */
7060         _getNotifierReference: function (notifierType) {
7061             var notifierReference;
7062 
7063             try {
7064                 //Use the base method to get references for load/change/error.
7065                 notifierReference = this._super(notifierType);
7066             } catch (err) {
7067                 //Check for add/delete
7068                 if (notifierType === "collectionAdd") {
7069                     notifierReference = this._collectionAddNotifier;
7070                 } else if (notifierType === "collectionDelete") {
7071                     notifierReference = this._collectionDeleteNotifier;
7072                 } else {
7073                     //Rethrow exception from base class.
7074                     throw err;
7075                 }
7076             }
7077             return notifierReference;
7078         }
7079     });
7080     
7081     window.finesse = window.finesse || {};
7082     window.finesse.restservices = window.finesse.restservices || {};
7083     window.finesse.restservices.RestCollectionBase = RestCollectionBase;
7084     
7085     return RestCollectionBase;
7086 }));
7087 
7088 /**
7089  * JavaScript representation of the Finesse Dialog object.
7090  *
7091  * @requires finesse.clientservices.ClientServices
7092  * @requires Class
7093  * @requires finesse.FinesseBase
7094  * @requires finesse.restservices.RestBase
7095  */
7096 
7097 /** @private */
7098 (function (factory) {
7099     
7100 
7101     // Define as an AMD module if possible
7102     if ( typeof define === 'function' && define.amd )
7103     {
7104         define('restservices/Dialog', ['restservices/RestBase',
7105                  'utilities/Utilities'], factory );
7106     }
7107     /* Define using browser globals otherwise
7108      * Prevent multiple instantiations if the script is loaded twice
7109      */
7110     else
7111     {
7112         factory(finesse.restservices.RestBase, finesse.utilities.Utilities);
7113     } 
7114 }(function (RestBase, Utilities) {
7115 	var Dialog = RestBase.extend(/** @lends finesse.restservices.Dialog.prototype */{
7116 
7117         /**
7118          * @class
7119          * A Dialog is an attempted connection between or among multiple participants,
7120          * for example, a regular phone call, a conference, or a silent monitor session.
7121          * 
7122          * @augments finesse.restservices.RestBase
7123          * @constructs
7124          */
7125         _fakeConstuctor: function () {
7126             /* This is here to hide the real init constructor from the public docs */
7127         },
7128         
7129         /**
7130          * @private
7131          *
7132          * @param {Object} options
7133          *     An object with the following properties:<ul>
7134          *         <li><b>id:</b> The id of the object being constructed</li>
7135          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
7136          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
7137          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
7138          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
7139          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
7140          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
7141          *             <li><b>content:</b> {String} Raw string of response</li>
7142          *             <li><b>object:</b> {Object} Parsed object of response</li>
7143          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
7144          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
7145          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
7146          *             </ul></li>
7147          *         </ul></li>
7148          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
7149          **/
7150         init: function (options) {
7151             this._super(options);
7152         },
7153 
7154         /**
7155          * @private
7156          * Gets the REST class for the current object - this is the Dialog class.
7157          * @returns {Object} The Dialog class.
7158          */
7159         getRestClass: function () {
7160             return Dialog;
7161         },
7162         
7163         /**
7164          * @private
7165          * The constant for agent device.
7166          */
7167         _agentDeviceType: "AGENT_DEVICE",
7168         
7169         /**
7170          * @private
7171          * Gets the REST type for the current object - this is a "Dialog".
7172          * @returns {String} The Dialog string.
7173          */
7174         getRestType: function () {
7175             return "Dialog";
7176         },
7177 
7178         /**
7179          * @private
7180          * Override default to indicate that this object doesn't support making
7181          * requests.
7182          */
7183         supportsRequests: false,
7184 
7185         /**
7186          * @private
7187          * Override default to indicate that this object doesn't support subscriptions.
7188          */
7189         supportsSubscriptions: false,
7190 
7191         /**
7192          * Getter for the from address.
7193          * @returns {String} The from address.
7194          */
7195         getFromAddress: function () {
7196             this.isLoaded();
7197             return this.getData().fromAddress;
7198         },
7199 
7200         /**
7201          * Getter for the to address.
7202          * @returns {String} The to address.
7203          */
7204         getToAddress: function () {
7205             this.isLoaded();
7206             return this.getData().toAddress;
7207         },
7208         
7209         /**
7210          * Getter for the media type.
7211          * @returns {String} The media type.
7212          */
7213         getMediaType: function () {
7214             this.isLoaded();
7215             return this.getData().mediaType;
7216         },
7217         
7218         /**
7219          * @private
7220          * Getter for the uri.
7221          * @returns {String} The uri.
7222          */
7223         getDialogUri: function () {
7224             this.isLoaded();
7225             return this.getData().uri;
7226         },
7227 
7228         /**
7229          * Getter for the callType.
7230          * @deprecated Use getMediaProperties().callType instead.
7231          * @returns {String} The callType.
7232          */
7233         getCallType: function () {
7234             this.isLoaded();
7235             return this.getData().mediaProperties.callType;
7236         },
7237 
7238         /**
7239          * Getter for the DNIS. This is usually the actual number dialed.
7240          * @deprecated Use getMediaProperties().DNIS instead.
7241          * @returns {String} The callType.
7242          */
7243         getDNIS: function () {
7244             this.isLoaded();
7245             return this.getData().mediaProperties.DNIS;
7246         },
7247         
7248         /**
7249          * Getter for the Dialog state.
7250          * @returns {String} The Dialog state.
7251          */
7252         getState: function () {
7253             this.isLoaded();
7254             return this.getData().state;
7255         },
7256 
7257         /**
7258          * Retrieves a list of participants within the Dialog object.
7259          * @returns {Object} Array list of participants.
7260          */
7261         getParticipants: function () {
7262             this.isLoaded();
7263             var participants = this.getData().participants.Participant;
7264             //Due to the nature of the XML->JSO converter library, a single
7265             //element in the XML array will be considered to an object instead of
7266             //a real array. This will handle those cases to ensure that an array is
7267             //always returned.
7268 
7269             return Utilities.getArray(participants);
7270         },
7271 
7272        /**
7273          * gets the participant timer counters 
7274          *
7275          * @param {String} participantExt Extension of participant.
7276          * @returns {Object} which contains state, startTime, and stateChangeTime fields
7277          */
7278         getParticipantTimerCounters : function (participantExt) {
7279           var part, participantTimerCounters = {}, idx, participants;
7280           
7281           participants = this.getParticipants();
7282 
7283 
7284           //Loop through all the participants and find the right participant (based on participantExt)
7285           for(idx=0;idx<participants.length;idx=idx+1)
7286           {
7287             part = participants[idx];
7288             
7289             if (part.mediaAddress === participantExt)
7290             {
7291                 participantTimerCounters.startTime= part.startTime;
7292                 participantTimerCounters.stateChangeTime= part.stateChangeTime;
7293                 participantTimerCounters.state= part.state;
7294                 break;
7295             }
7296           }
7297           
7298           return participantTimerCounters;
7299         },
7300         
7301         /**
7302          * Determines the droppable participants.  A droppable participant is a participant that is an agent extension.   
7303          * (It is not a CTI Route Point, IVR Port, or the caller)
7304          * 
7305          * @param {String} filterExtension used to remove a single extension from the list
7306          * @returns {Array} Participants which is an array of all participants which can be dropped.
7307          */
7308         getDroppableParticipants: function (filterExtension) {
7309           this.isLoaded();
7310           var droppableParticipants = [], participants, index, idx, filterExtensionToRemove = "", callStateOk, part;
7311 
7312           participants = this.getParticipants();
7313 
7314           if (filterExtension)
7315           {
7316             filterExtensionToRemove = filterExtension;
7317           }
7318 
7319           //Loop through all the participants to remove non-agents & remove filterExtension
7320           //We could have removed filterExtension using splice, but we have to iterate through
7321           //the list anyway.
7322           for(idx=0;idx<participants.length;idx=idx+1)
7323           {
7324             part = participants[idx];
7325 
7326             //Skip the filterExtension
7327             if (part.mediaAddress !== filterExtensionToRemove)
7328             {
7329                 callStateOk = this._isParticipantStateDroppable(part);
7330 
7331                 //Remove non-agents & make sure callstate 
7332                 if (callStateOk === true && part.mediaAddressType === this._agentDeviceType)
7333                 {
7334                   droppableParticipants.push(part);
7335                 }
7336             }
7337         }
7338 
7339         return Utilities.getArray(droppableParticipants);
7340         },
7341 
7342         _isParticipantStateDroppable : function (part)
7343         {
7344           var isParticipantStateDroppable = false;
7345           if (part.state === Dialog.ParticipantStates.ACTIVE || part.state === Dialog.ParticipantStates.ACCEPTED || part.state === Dialog.ParticipantStates.HELD)
7346           {
7347             isParticipantStateDroppable = true;
7348           }
7349           
7350           return isParticipantStateDroppable;
7351         },
7352         
7353         /**
7354          * Is the participant droppable
7355          *
7356          * @param {String} participantExt Extension of participant.
7357          * @returns {Boolean} True is droppable.
7358          */
7359         isParticipantDroppable : function (participantExt) {
7360           var droppableParticipants = null, isDroppable = false, idx, part, callStateOk;
7361           
7362           droppableParticipants = this.getDroppableParticipants();
7363           
7364           if (droppableParticipants) 
7365           {
7366             for(idx=0;idx<droppableParticipants.length;idx=idx+1)
7367             {
7368               part = droppableParticipants[idx];
7369              
7370               if (part.mediaAddress === participantExt)
7371               {
7372                 callStateOk = this._isParticipantStateDroppable(part);
7373 
7374                 //Remove non-agents & make sure callstate 
7375                 if (callStateOk === true && part.mediaAddressType === this._agentDeviceType)
7376                 {
7377                   isDroppable = true;
7378                   break;
7379                 }
7380               }
7381             }
7382           }
7383           
7384           return isDroppable;
7385         },
7386         
7387         /**
7388          * Retrieves a list of media properties from the dialog object.
7389          * @returns {Object} Map of call variables; names mapped to values.
7390          * Variables may include the following:<ul>
7391          * <li>dialedNumber: The number dialed.
7392          * <li>callType: The type of call. Call types include:<ul>
7393          *     <li>ACD_IN
7394          *     <li>PREROUTE_ACD_IN
7395          *     <li>PREROUTE_DIRECT_AGENT
7396          *     <li>TRANSFER
7397          *     <li>OTHER_IN
7398          *     <li>OUT
7399          *     <li>AGENT_INSIDE
7400          *     <li>CONSULT
7401          *     <li>CONFERENCE
7402          *     <li>SUPERVISOR_MONITOR
7403          *     <li>OUTBOUND
7404          *     <li>OUTBOUND_PREVIEW</ul>
7405          * <li>DNIS: The DNIS provided. For routed calls, this is the route point.
7406          * <li>wrapUpReason: A description of the call.
7407          * <li>Call Variables, by name.  The name indicates whether it is a call variable or ECC variable.
7408          * Call variable names start with callVariable#, where # is 1-10. ECC variable names (both scalar and array) are prepended with "user".
7409          * ECC variable arrays include an index enclosed within square brackets located at the end of the ECC array name.
7410          * <li>The following call variables provide additional details about an Outbound Option call:<ul>
7411          *     <li>BACampaign
7412          *     <li>BAAccountNumber
7413          *     <li>BAResponse
7414          *     <li>BAStatus<ul>
7415          *         <li>PREDICTIVE_OUTBOUND: A predictive outbound call.
7416          *         <li>PROGRESSIVE_OUTBOUND: A progressive outbound call.
7417          *         <li>PREVIEW_OUTBOUND_RESERVATION: Agent is reserved for a preview outbound call.
7418          *         <li>PREVIEW_OUTBOUND: Agent is on a preview outbound call.</ul>
7419          *     <li>BADialedListID
7420          *     <li>BATimeZone
7421          *     <li>BABuddyName</ul></ul>
7422          *     
7423          */
7424         getMediaProperties: function () {
7425             var mpData, currentMediaPropertiesMap, thisMediaPropertiesJQuery;
7426 
7427             this.isLoaded();
7428             
7429             // We have to convert to jQuery object to do a proper compare
7430             thisMediaPropertiesJQuery = jQuery(this.getData().mediaProperties);
7431             
7432             if ((this._lastMediaPropertiesJQuery !== undefined) 
7433                     && (this._lastMediaPropertiesMap !== undefined) 
7434                     && (this._lastMediaPropertiesJQuery.is(thisMediaPropertiesJQuery))) {
7435 
7436                     return this._lastMediaPropertiesMap;
7437             }
7438             
7439             currentMediaPropertiesMap = {};
7440 
7441             mpData = this.getData().mediaProperties;
7442 
7443             if (mpData) {
7444                 if (mpData.callvariables && mpData.callvariables.CallVariable) {
7445                     jQuery.each(mpData.callvariables.CallVariable, function (i, callVariable) {
7446 			currentMediaPropertiesMap[callVariable.name] = callVariable.value;
7447                     });
7448                 }
7449 
7450                 jQuery.each(mpData, function (key, value) {
7451                     if (key !== 'callvariables') {
7452 			currentMediaPropertiesMap[key] = value;
7453                     }
7454                 });
7455             }
7456             
7457             this._lastMediaPropertiesMap = currentMediaPropertiesMap;
7458             this._lastMediaPropertiesJQuery = thisMediaPropertiesJQuery;
7459 
7460             return this._lastMediaPropertiesMap;
7461         },
7462 
7463         /**
7464          * Retrieves information about the currently scheduled callback, if any.
7465          * @returns {Object} If no callback has been set, will return undefined. If 
7466          * a callback has been set, it will return a map with one or more of the 
7467          * following entries, depending on what values have been set. 
7468          *    callbackTime   - the callback time, if it has been set.
7469          *    callbackNumber - the callback number, if it has been set.
7470          */
7471         getCallbackInfo: function() {
7472             this.isLoaded();
7473             return this.getData().scheduledCallbackInfo;
7474         },
7475 
7476         /**
7477          * @private
7478          * Invoke a request to the server given a content body and handlers.
7479          *
7480          * @param {Object} contentBody
7481          *     A JS object containing the body of the action request.
7482          * @param {finesse.interfaces.RequestHandlers} handlers
7483          *     An object containing the handlers for the request
7484          */
7485         _makeRequest: function (contentBody, handlers) {
7486             // Protect against null dereferencing of options allowing its
7487             // (nonexistent) keys to be read as undefined
7488             handlers = handlers || {};
7489 
7490             this.restRequest(this.getRestUrl(), {
7491                 method: 'PUT',
7492                 success: handlers.success,
7493                 error: handlers.error,
7494                 content: contentBody
7495             });
7496         },
7497 
7498         /**
7499          * Invoke a consult call out to a destination.
7500          *
7501          * @param {String} mediaAddress
7502          *     The media address of the user performing the consult call.
7503          * @param {String} toAddress
7504          *     The destination address of the consult call.
7505          * @param {finesse.interfaces.RequestHandlers} handlers
7506          *     An object containing the handlers for the request
7507          */
7508         makeConsultCall: function (mediaAddress, toAddress, handlers) {
7509             this.isLoaded();
7510             var contentBody = {};
7511             contentBody[this.getRestType()] = {
7512                 "targetMediaAddress": mediaAddress,
7513                 "toAddress": toAddress,
7514                 "requestedAction": Dialog.Actions.CONSULT_CALL
7515             };
7516             this._makeRequest(contentBody, handlers);
7517             return this; // Allow cascading
7518         },
7519         
7520         /**
7521          * Invoke a single step transfer request.
7522          *
7523          * @param {String} mediaAddress
7524          *     The media address of the user performing the single step transfer.
7525          * @param {String} toAddress
7526          *     The destination address of the single step transfer.
7527          * @param {finesse.interfaces.RequestHandlers} handlers
7528          *     An object containing the handlers for the request
7529          */
7530         initiateDirectTransfer: function (mediaAddress, toAddress, handlers) {
7531             this.isLoaded();
7532             var contentBody = {};
7533             contentBody[this.getRestType()] = {
7534                 "targetMediaAddress": mediaAddress,
7535                 "toAddress": toAddress,
7536                 "requestedAction": Dialog.Actions.TRANSFER_SST
7537             };
7538             this._makeRequest(contentBody, handlers);
7539             return this; // Allow cascading
7540         },
7541 
7542         /**
7543          * Update this dialog's wrap-up reason.
7544          *
7545          * @param {String} wrapUpReason
7546          *     The new wrap-up reason for this dialog
7547          * @param {finesse.interfaces.RequestHandlers} handlers
7548          *     An object containing the handlers for the request
7549          */
7550         updateWrapUpReason: function (wrapUpReason, options)
7551         {
7552             this.isLoaded();
7553             var mediaProperties =
7554             {
7555                 "wrapUpReason": wrapUpReason
7556             };
7557 
7558             options = options || {};
7559             options.content = {};
7560             options.content[this.getRestType()] =
7561             {
7562                 "mediaProperties": mediaProperties,
7563                 "requestedAction": Dialog.Actions.UPDATE_CALL_DATA
7564             };
7565             options.method = "PUT";
7566             this.restRequest(this.getRestUrl(), options);
7567 
7568             return this;
7569         },
7570 
7571         /**
7572          * Invoke a request to server based on the action given.
7573          * @param {String} mediaAddress
7574          *     The media address of the user performing the action.
7575          * @param {finesse.restservices.Dialog.Actions} action
7576          *     The action string indicating the action to invoke on dialog.
7577          * @param {finesse.interfaces.RequestHandlers} handlers
7578          *     An object containing the handlers for the request
7579          */
7580         requestAction: function (mediaAddress, action, handlers) {
7581             this.isLoaded();
7582             var contentBody = {};
7583             contentBody[this.getRestType()] = {
7584                 "targetMediaAddress": mediaAddress,
7585                 "requestedAction": action
7586             };
7587             this._makeRequest(contentBody, handlers);
7588             return this; // Allow cascading
7589         },
7590         
7591         /**
7592          * Wrapper around "requestAction" to request PARTICIPANT_DROP action.
7593          *
7594          * @param targetMediaAddress is the address to drop
7595          * @param {finesse.interfaces.RequestHandlers} handlers
7596          *     An object containing the handlers for the request
7597          */
7598         dropParticipant: function (targetMediaAddress, handlers) {
7599             this.requestAction(targetMediaAddress, Dialog.Actions.PARTICIPANT_DROP, handlers);
7600         },
7601         
7602         /**
7603          * Invoke a request to server to send DTMF digit tones.
7604          * @param {String} mediaAddress
7605          * @param {String} action
7606          *     The action string indicating the action to invoke on dialog.
7607          * @param {finesse.interfaces.RequestHandlers} handlers
7608          *     An object containing the handlers for the request
7609          */
7610         sendDTMFRequest: function (mediaAddress, handlers, digit) {
7611             this.isLoaded();
7612             var contentBody = {};
7613             contentBody[this.getRestType()] = {
7614                 "targetMediaAddress": mediaAddress,
7615                 "requestedAction": "SEND_DTMF",
7616                 "actionParams": {
7617                     "ActionParam": {
7618                         "name": "dtmfString",
7619                         "value": digit
7620                     }
7621                 }
7622             };
7623             this._makeRequest(contentBody, handlers);
7624             return this; // Allow cascading
7625         },
7626 
7627         /**
7628          * Invoke a request to server to set the time for a callback.
7629          * @param {String} mediaAddress
7630          * @param {String} callbackTime 
7631          *     The requested time for the callback, in YYYY-MM-DDTHH:MM format
7632          *     (ex: 2013-12-24T23:59)
7633          * @param {finesse.interfaces.RequestHandlers} handlers
7634          *     An object containing the handlers for the request
7635          */
7636         updateCallbackTime: function (mediaAddress, callbackTime, handlers) {
7637             this.isLoaded();
7638             var contentBody = {};
7639             contentBody[this.getRestType()] = {
7640                 "targetMediaAddress": mediaAddress,
7641                 "requestedAction": Dialog.Actions.UPDATE_SCHEDULED_CALLBACK,
7642                 "actionParams": {
7643                     "ActionParam": {
7644                         "name": "callbackTime",
7645                         "value": callbackTime
7646                     }
7647                 }
7648             };
7649             this._makeRequest(contentBody, handlers);
7650             return this; // Allow cascading
7651         },
7652 
7653         /**
7654          * Invoke a request to server to set the number for a callback.
7655          * @param {String} mediaAddress
7656          * @param {String} callbackNumber
7657          *     The requested number to call for the callback
7658          * @param {finesse.interfaces.RequestHandlers} handlers
7659          *     An object containing the handlers for the request
7660          */
7661         updateCallbackNumber: function (mediaAddress, callbackNumber, handlers) {
7662             this.isLoaded();
7663             var contentBody = {};
7664             contentBody[this.getRestType()] = {
7665                 "targetMediaAddress": mediaAddress,
7666                 "requestedAction": Dialog.Actions.UPDATE_SCHEDULED_CALLBACK,
7667                 "actionParams": {
7668                     "ActionParam": {
7669                         "name": "callbackNumber",
7670                         "value": callbackNumber
7671                     }
7672                 }
7673             };
7674             this._makeRequest(contentBody, handlers);
7675             return this; // Allow cascading
7676         },
7677 
7678         /**
7679          * Invoke a request to server to cancel a callback.
7680          * @param {String} mediaAddress
7681          * @param {finesse.interfaces.RequestHandlers} handlers
7682          *     An object containing the handlers for the request
7683          */
7684         cancelCallback: function (mediaAddress, handlers) {
7685             this.isLoaded();
7686             var contentBody = {};
7687             contentBody[this.getRestType()] = {
7688                 "targetMediaAddress": mediaAddress,
7689                 "requestedAction": Dialog.Actions.CANCEL_SCHEDULED_CALLBACK
7690             };
7691             this._makeRequest(contentBody, handlers);
7692             return this; // Allow cascading
7693         },
7694 
7695         /**
7696          * Invoke a request to server to reclassify the call type.
7697          * @param {String} mediaAddress
7698          * @param {String} callbackNumber
7699          *     The requested number to call for the callback
7700          * @param {finesse.interfaces.RequestHandlers} handlers
7701          *     An object containing the handlers for the request
7702          */
7703         reclassifyCall: function (mediaAddress, classification, handlers) {
7704             this.isLoaded();
7705             var contentBody = {};
7706             contentBody[this.getRestType()] = {
7707                 "targetMediaAddress": mediaAddress,
7708                 "requestedAction": Dialog.Actions.RECLASSIFY,
7709                 "actionParams": {
7710                     "ActionParam": {
7711                         "name": "outboundClassification",
7712                         "value": classification
7713                     }
7714                 }
7715             };
7716             this._makeRequest(contentBody, handlers);
7717             return this; // Allow cascading
7718         }       
7719 
7720 
7721     });
7722 
7723     Dialog.Actions = /** @lends finesse.restservices.Dialog.Actions.prototype */ {
7724             /**
7725              * Drops the Participant from the Dialog.
7726              */
7727             DROP: "DROP",
7728             /**
7729              * Answers a Dialog.
7730              */
7731             ANSWER: "ANSWER",
7732             /**
7733              * Holds the Dialog.
7734              */
7735             HOLD: "HOLD",
7736             /**
7737              * Barges into a Call Dialog.
7738              */
7739             BARGE_CALL: "BARGE_CALL",
7740             /**
7741              * Allow as Supervisor to Drop a Participant from the Dialog.
7742              */
7743             PARTICIPANT_DROP: "PARTICIPANT_DROP",
7744             /**
7745              * Makes a new Call Dialog.
7746              */
7747             MAKE_CALL: "MAKE_CALL",
7748             /**
7749              * Retrieves a Dialog that is on Hold.
7750              */
7751             RETRIEVE: "RETRIEVE",
7752             /**
7753              * Sets the time or number for a callback. Can be
7754              * either a new callback, or updating an existing one.
7755              */
7756             UPDATE_SCHEDULED_CALLBACK: "UPDATE_SCHEDULED_CALLBACK",
7757             /**
7758              * Cancels a callback.
7759              */
7760             CANCEL_SCHEDULED_CALLBACK: "CANCEL_SCHEDULED_CALLBACK",
7761             /**
7762              * Initiates a Consult Call.
7763              */
7764             CONSULT_CALL: "CONSULT_CALL",
7765             /**
7766              * Initiates a Transfer of a Dialog.
7767              */
7768             TRANSFER: "TRANSFER",
7769             /**
7770              * Initiates a Single-Step Transfer of a Dialog.
7771              */
7772             TRANSFER_SST: "TRANSFER_SST",
7773             /**
7774              * Initiates a Conference of a Dialog.
7775              */
7776             CONFERENCE: "CONFERENCE",
7777             /**
7778              * Changes classification for a call
7779              */
7780             RECLASSIFY: "RECLASSIFY", 
7781             /**
7782              * Updates data on a Call Dialog.
7783              */
7784             UPDATE_CALL_DATA: "UPDATE_CALL_DATA",
7785             /**
7786              * Initiates a Recording on a Call Dialog.
7787              */
7788             START_RECORDING : "START_RECORDING",
7789             /**
7790              * Sends DTMF (dialed digits) to a Call Dialog.
7791              */
7792             DTMF : "SEND_DTMF",            
7793             /**
7794              * Accepts a Dialog that is being Previewed.
7795              */
7796             ACCEPT: "ACCEPT",
7797             /**
7798              * Rejects a Dialog.
7799              */
7800             REJECT: "REJECT",
7801             /**
7802              * Closes a Dialog.
7803              */
7804             CLOSE : "CLOSE",
7805             /**
7806              * @class Set of action constants for a Dialog.  These should be used for
7807              * {@link finesse.restservices.Dialog#requestAction}.
7808              * @constructs
7809              */
7810             _fakeConstructor : function () {} // For JS Doc to work need a constructor so that the lends/constructs build the doc properly
7811         };  
7812 
7813     Dialog.States = /** @lends finesse.restservices.Dialog.States.prototype */ {
7814        /**
7815          * Indicates that the call is ringing at a device.
7816          */
7817         ALERTING: "ALERTING",
7818         /**
7819          * Indicates that the phone is off the hook at a device.
7820          */
7821         INITIATING: "INITIATING",
7822         /**
7823          * Indicates that the dialog has a least one active participant.
7824          */
7825         ACTIVE: "ACTIVE",
7826         /**
7827          * Indicates that the dialog has no active participants.
7828          */
7829         DROPPED: "DROPPED",
7830         /**
7831          * Indicates that the phone is dialing at the device.
7832          */
7833         INITIATED: "INITIATED",
7834         /**
7835          * Indicates that the dialog has failed.
7836          * @see Dialog.ReasonStates
7837          */
7838         FAILED: "FAILED",
7839         /**
7840          * Indicates that the user has accepted an OUTBOUND_PREVIEW dialog.
7841          */
7842         ACCEPTED: "ACCEPTED",
7843         /**
7844          * @class Possible Dialog State constants.
7845          * The State flow of a typical in-bound Dialog is as follows: INITIATING, INITIATED, ALERTING, ACTIVE, DROPPED.
7846          * @constructs
7847          */
7848         _fakeConstructor : function () {} // For JS Doc to work need a constructor so that the lends/constructs build the doc properly
7849     };
7850 
7851     Dialog.ParticipantStates = /** @lends finesse.restservices.Dialog.ParticipantStates.prototype */ {
7852         /**
7853           * Indicates that an incoming call is ringing on the device.
7854           */
7855          ALERTING: "ALERTING",
7856          /**
7857           * Indicates that an outgoing call, not yet active, exists on the device.
7858           */
7859          INITIATING: "INITIATING",
7860          /**
7861           * Indicates that the participant is active on the call.
7862           */
7863          ACTIVE: "ACTIVE",
7864          /**
7865           * Indicates that the participant has dropped from the call.
7866           */
7867          DROPPED: "DROPPED",
7868          /**
7869           * Indicates that the participant has held their connection to the call.
7870           */
7871          HELD: "HELD",
7872          /**
7873           * Indicates that the phone is dialing at a device.
7874           */
7875          INITIATED: "INITIATED",
7876          /**
7877           * Indicates that the call failed.
7878           * @see Dialog.ReasonStates
7879           */
7880          FAILED: "FAILED",
7881          /**
7882           * Indicates that the participant is not in active state on the call, but is wrapping up after the participant has dropped from the call.
7883           */
7884          WRAP_UP: "WRAP_UP",
7885          /**
7886           * Indicates that the participant has accepted the dialog.  This state is applicable to OUTBOUND_PREVIEW dialogs.
7887           */
7888          ACCEPTED: "ACCEPTED",
7889          /**
7890           * @class Possible Dialog Participant State constants.
7891           * @constructs
7892           */
7893          _fakeConstructor : function () {} // For JS Doc to work need a constructor so that the lends/constructs build the doc properly
7894      };
7895 
7896     Dialog.ReasonStates = /** @lends finesse.restservices.Dialog.ReasonStates.prototype */ {
7897        /**
7898         * Dialog was Busy.  This will typically be for a Failed Dialog.
7899         */
7900         BUSY: "BUSY",
7901         /**
7902          * Dialog reached a Bad Destination.  This will typically be for a Failed Dialog.
7903          */
7904         BAD_DESTINATION: "BAD_DESTINATION",
7905         /**
7906          * All Other Reasons.  This will typically be for a Failed Dialog.
7907          */
7908         OTHER: "OTHER",
7909         /**
7910          * The Device Resource for the Dialog was not available.
7911          */
7912         DEVICE_RESOURCE_NOT_AVAILABLE : "DEVICE_RESOURCE_NOT_AVAILABLE",
7913         /**
7914          * @class Possible dialog state reasons code constants.
7915          * @constructs
7916          */
7917         _fakeConstructor : function () {} // For JS Doc to work need a constructor so that the lends/constructs build the doc properly
7918     };
7919    
7920     window.finesse = window.finesse || {};
7921     window.finesse.restservices = window.finesse.restservices || {};
7922     window.finesse.restservices.Dialog = Dialog;
7923     
7924     
7925     return Dialog;
7926 }));
7927 
7928 /**
7929  * JavaScript representation of the Finesse Dialogs collection
7930  * object which contains a list of Dialog objects.
7931  *
7932  * @requires finesse.clientservices.ClientServices
7933  * @requires Class
7934  * @requires finesse.FinesseBase
7935  * @requires finesse.restservices.RestBase
7936  * @requires finesse.restservices.Dialog
7937  */
7938 /** @private */
7939 (function (factory) {
7940     
7941 
7942     // Define as an AMD module if possible
7943     if ( typeof define === 'function' && define.amd )
7944     {
7945         define('restservices/Dialogs', ['restservices/RestCollectionBase',
7946                  'restservices/Dialog'], factory );
7947     }
7948     /* Define using browser globals otherwise
7949      * Prevent multiple instantiations if the script is loaded twice
7950      */
7951     else
7952     {
7953         factory(finesse.restservices.RestCollectionBase, finesse.restservices.Dialog);
7954     } 
7955 }(function (RestCollectionBase, Dialog) {
7956     var Dialogs = RestCollectionBase.extend(/** @lends finesse.restservices.Dialogs.prototype */{
7957 
7958         /**
7959          * @class
7960          * JavaScript representation of a Dialogs collection object. Also exposes
7961          * methods to operate on the object against the server.
7962          * @augments finesse.restservices.RestCollectionBase
7963          * @constructs
7964          * @see finesse.restservices.Dialog
7965          * @example
7966          *  _dialogs = _user.getDialogs( {
7967          *      onCollectionAdd : _handleDialogAdd,
7968          *      onCollectionDelete : _handleDialogDelete,
7969          *      onLoad : _handleDialogsLoaded
7970          *  });
7971          *  
7972          * _dialogCollection = _dialogs.getCollection();
7973          * for (var dialogId in _dialogCollection) {
7974          *     if (_dialogCollection.hasOwnProperty(dialogId)) {
7975          *         _dialog = _dialogCollection[dialogId];
7976          *         etc...
7977          *     }
7978          * }
7979          */
7980         _fakeConstuctor: function () {
7981             /* This is here to hide the real init constructor from the public docs */
7982         },
7983         
7984         /**
7985          * @private
7986          * @param {Object} options
7987          *     An object with the following properties:<ul>
7988          *         <li><b>id:</b> The id of the object being constructed</li>
7989          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
7990          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
7991          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
7992          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
7993          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
7994          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
7995          *             <li><b>content:</b> {String} Raw string of response</li>
7996          *             <li><b>object:</b> {Object} Parsed object of response</li>
7997          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
7998          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
7999          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
8000          *             </ul></li>
8001          *         </ul></li>
8002          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
8003          **/
8004         init: function (options) {
8005             this._super(options);
8006         },
8007 
8008         /**
8009          * @private
8010          * Gets the REST class for the current object - this is the Dialogs class.
8011          */
8012         getRestClass: function () {
8013             return Dialogs;
8014         },
8015 
8016         /**
8017          * @private
8018          * Gets the REST class for the objects that make up the collection. - this
8019          * is the Dialog class.
8020          */
8021         getRestItemClass: function () {
8022             return Dialog;
8023         },
8024 
8025         /**
8026          * @private
8027          * Gets the REST type for the current object - this is a "Dialogs".
8028          */
8029         getRestType: function () {
8030             return "Dialogs";
8031         },
8032 
8033         /**
8034          * @private
8035          * Gets the REST type for the objects that make up the collection - this is "Dialogs".
8036          */
8037         getRestItemType: function () {
8038             return "Dialog";
8039         },
8040 
8041         /**
8042          * @private
8043          * Override default to indicates that the collection doesn't support making
8044          * requests.
8045          */
8046         supportsRequests: true,
8047 
8048         /**
8049          * @private
8050          * Override default to indicates that the collection subscribes to its objects.
8051          */
8052         supportsRestItemSubscriptions: true,
8053 
8054         /**
8055          * @private
8056          * Create a new Dialog in this collection
8057          *
8058          * @param {String} toAddress
8059          *     The to address of the new Dialog
8060          * @param {String} fromAddress
8061          *     The from address of the new Dialog
8062          * @param {finesse.interfaces.RequestHandlers} handlers
8063          *     An object containing the (optional) handlers for the request.
8064          * @return {finesse.restservices.Dialogs}
8065          *     This Dialogs object, to allow cascading.
8066          */
8067         createNewCallDialog: function (toAddress, fromAddress, handlers)
8068         {
8069             var contentBody = {};
8070             contentBody[this.getRestItemType()] = {
8071                 "requestedAction": "MAKE_CALL",
8072                 "toAddress": toAddress,
8073                 "fromAddress": fromAddress
8074             };
8075 
8076             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
8077             handlers = handlers || {};
8078 
8079             this.restRequest(this.getRestUrl(), {
8080                 method: 'POST',
8081                 success: handlers.success,
8082                 error: handlers.error,
8083                 content: contentBody
8084             });
8085             return this; // Allow cascading
8086         },
8087 
8088         /**
8089          * @private
8090          * Create a new Dialog in this collection as a result of a requested action
8091          *
8092          * @param {String} toAddress
8093          *     The to address of the new Dialog
8094          * @param {String} fromAddress
8095          *     The from address of the new Dialog
8096          * @param {finesse.restservices.Dialog.Actions} actionType
8097          *     The associated action to request for creating this new dialog
8098          * @param {finesse.interfaces.RequestHandlers} handlers
8099          *     An object containing the (optional) handlers for the request.
8100          * @return {finesse.restservices.Dialogs}
8101          *     This Dialogs object, to allow cascading.
8102          */
8103         createNewSuperviseCallDialog: function (toAddress, fromAddress, actionType, handlers)
8104         {
8105             var contentBody = {};
8106             this._isLoaded = true;
8107 
8108             contentBody[this.getRestItemType()] = {
8109                 "requestedAction": actionType,
8110                 "toAddress": toAddress,
8111                 "fromAddress": fromAddress
8112             };
8113 
8114             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
8115             handlers = handlers || {};
8116 
8117             this.restRequest(this.getRestUrl(), {
8118                 method: 'POST',
8119                 success: handlers.success,
8120                 error: handlers.error,
8121                 content: contentBody
8122             });
8123             return this; // Allow cascading
8124         },
8125         
8126         /**
8127          * @private
8128          * Create a new Dialog in this collection as a result of a requested action
8129          * @param {String} fromAddress
8130          *     The from address of the new Dialog
8131          * @param {String} toAddress
8132          *     The to address of the new Dialog
8133          * @param {finesse.restservices.Dialog.Actions} actionType
8134          *     The associated action to request for creating this new dialog
8135          * @param {String} dialogUri
8136          *     The associated uri of SUPERVISOR_MONITOR call
8137          * @param {finesse.interfaces.RequestHandlers} handlers
8138          *     An object containing the (optional) handlers for the request.
8139          * @return {finesse.restservices.Dialogs}
8140          *     This Dialogs object, to allow cascading.
8141          */
8142         createNewBargeCall: function (fromAddress, toAddress, actionType, dialogURI, handlers) {
8143             this.isLoaded();
8144          
8145             var contentBody = {};
8146             contentBody[this.getRestItemType()] = {
8147                 "fromAddress": fromAddress,
8148                 "toAddress": toAddress,
8149                 "requestedAction": actionType,
8150                 "associatedDialogUri": dialogURI
8151                 
8152             };
8153             // (nonexistent) keys to be read as undefined
8154             handlers = handlers || {};  
8155             this.restRequest(this.getRestUrl(), {
8156                 method: 'POST',
8157                 success: handlers.success,
8158                 error: handlers.error,
8159                 content: contentBody
8160             });
8161             return this; // Allow cascading
8162         },
8163 
8164         /**
8165          * Utility method to get the number of dialogs in this collection.
8166          * 'excludeSilentMonitor' flag is provided as an option to exclude calls with type
8167          * 'SUPERVISOR_MONITOR' from the count.
8168          * @param  {Boolean} excludeSilentMonitor If true, calls with type of 'SUPERVISOR_MONITOR' will be excluded from the count.
8169          * @return {Number} The number of dialogs in this collection.
8170          */
8171         getDialogCount: function (excludeSilentMonitor) {
8172             this.isLoaded();
8173 
8174             var dialogId, count = 0;
8175             if (excludeSilentMonitor) {
8176                 for (dialogId in this._collection) {
8177                     if (this._collection.hasOwnProperty(dialogId)) {
8178                         if (this._collection[dialogId].getCallType() !== 'SUPERVISOR_MONITOR') {
8179                             count += 1;
8180                         }
8181                     }
8182                 }
8183 
8184                 return count;
8185             } else {
8186                 return this.length;
8187             }        
8188         }
8189 
8190     });
8191     
8192     window.finesse = window.finesse || {};
8193     window.finesse.restservices = window.finesse.restservices || {};
8194     window.finesse.restservices.Dialogs = Dialogs;
8195     
8196     return Dialogs;
8197 }));
8198 
8199 /**
8200  * JavaScript representation of the Finesse ClientLog object
8201  *
8202  * @requires finesse.clientservices.ClientServices
8203  * @requires Class
8204  * @requires finesse.FinesseBase
8205  * @requires finesse.restservices.RestBase
8206  */
8207 
8208 /** The following comment is to prevent jslint errors about 
8209  * using variables before they are defined.
8210  */
8211 /** @private */
8212 /*global finesse*/
8213 
8214 (function (factory) {
8215     
8216 
8217     // Define as an AMD module if possible
8218     if ( typeof define === 'function' && define.amd )
8219     {
8220         define('restservices/ClientLog',["restservices/RestBase"], factory );
8221     }
8222     
8223     /* Define using browser globals otherwise
8224      * Prevent multiple instantiations if the script is loaded twice
8225      */
8226     else
8227     {
8228         factory(finesse.restservices.RestBase);
8229     }
8230     
8231 }(function (RestBase) {
8232     
8233     var ClientLog = RestBase.extend(/** @lends finesse.restservices.ClientLog.prototype */{    
8234         /**
8235          * @private
8236          * Returns whether this object supports transport logs
8237          */
8238         doNotLog : true,
8239 
8240         doNotRefresh: true,
8241         
8242         explicitSubscription : true,
8243         
8244         /**
8245          * @class
8246          * @private
8247          * JavaScript representation of a ClientLog object. Also exposes methods to operate
8248          * on the object against the server.
8249          *
8250          * @param {Object} options
8251          *     An object with the following properties:<ul>
8252          *         <li><b>id:</b> The id of the object being constructed</li>
8253          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
8254          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
8255          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
8256          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
8257          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
8258          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
8259          *             <li><b>content:</b> {String} Raw string of response</li>
8260          *             <li><b>object:</b> {Object} Parsed object of response</li>
8261          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
8262          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
8263          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
8264          *             </ul></li>
8265          *         </ul></li>
8266          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
8267          * @constructs
8268          * @augments finesse.restservices.RestBase
8269          **/
8270         init: function (options) {
8271             this._super({
8272                 id: "", 
8273                 data: {clientLog : null},
8274                 onAdd: options.onAdd,
8275                 onChange: options.onChange,
8276                 onLoad: options.onLoad,
8277                 onError: options.onError,
8278                 parentObj: options.parentObj
8279                 });
8280         },
8281 
8282         /**
8283          * @private
8284          * Gets the REST class for the current object - this is the ClientLog object.
8285          */
8286         getRestClass: function () {
8287             return ClientLog;
8288         },
8289 
8290         /**
8291          * @private
8292          * Gets the REST type for the current object - this is a "ClientLog".
8293          */
8294         getRestType: function ()
8295         {
8296             return "ClientLog";
8297         },
8298         
8299         /**
8300          * @private
8301          * Gets the node path for the current object
8302          * @returns {String} The node path
8303          */
8304         getXMPPNodePath: function () {
8305             return this.getRestUrl();
8306         },
8307            
8308         /**
8309          * @private
8310          * Invoke a request to the server given a content body and handlers.
8311          *
8312          * @param {Object} contentBody
8313          *     A JS object containing the body of the action request.
8314          * @param {Object} handlers
8315          *     An object containing the following (optional) handlers for the request:<ul>
8316          *         <li><b>success(rsp):</b> A callback function for a successful request to be invoked with the following
8317          *         response object as its only parameter:<ul>
8318          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
8319          *             <li><b>content:</b> {String} Raw string of response</li>
8320          *             <li><b>object:</b> {Object} Parsed object of response</li></ul>
8321          *         <li>A error callback function for an unsuccessful request to be invoked with the
8322          *         error response object as its only parameter:<ul>
8323          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
8324          *             <li><b>content:</b> {String} Raw string of response</li>
8325          *             <li><b>object:</b> {Object} Parsed object of response (HTTP errors)</li>
8326          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
8327          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
8328          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
8329          *             </ul></li>
8330          *         </ul>
8331          */
8332         sendLogs: function (contentBody, handlers) {
8333             // Protect against null dereferencing of options allowing its
8334             // (nonexistent) keys to be read as undefined
8335             handlers = handlers || {};
8336 
8337             this.restRequest(this.getRestUrl(), {
8338                 method: 'POST',
8339                 //success: handlers.success,
8340                 error: handlers.error,
8341                 content: contentBody
8342             });
8343         }
8344     });
8345     
8346     window.finesse = window.finesse || {};
8347     window.finesse.restservices = window.finesse.restservices || {};
8348     window.finesse.restservices.ClientLog = ClientLog;
8349     
8350     return ClientLog;
8351 }));
8352 
8353 /**
8354  * JavaScript representation of the Finesse Queue object
8355  * @requires finesse.clientservices.ClientServices
8356  * @requires Class
8357  * @requires finesse.FinesseBase
8358  * @requires finesse.restservices.RestBase
8359  */
8360 
8361 /** @private */
8362  (function (factory) {
8363     
8364 
8365     // Define as an AMD module if possible
8366     if ( typeof define === 'function' && define.amd )
8367     {
8368         define('restservices/Queue', ['restservices/RestBase',
8369                  'utilities/Utilities'], factory );
8370     }
8371     /* Define using browser globals otherwise
8372      * Prevent multiple instantiations if the script is loaded twice
8373      */
8374     else
8375     {
8376         factory(finesse.restservices.RestBase, finesse.utilities.Utilities);
8377     } 
8378 }(function (RestBase, Utilities) {
8379 	var Queue = RestBase.extend(/** @lends finesse.restservices.Queue.prototype */{
8380 
8381         /**
8382          * @class
8383          * A Queue is a list of Contacts available to a User for quick dial.
8384          * 
8385          * @augments finesse.restservices.RestBase
8386          * @constructs
8387          */
8388         _fakeConstuctor: function () {
8389             /* This is here to hide the real init constructor from the public docs */
8390         },
8391         
8392 		/**
8393 		 * @private
8394 		 * JavaScript representation of a Queue object. Also exposes methods to operate
8395 		 * on the object against the server.
8396 		 *
8397 		 * @constructor
8398 		 * @param {String} id
8399 		 *     Not required...
8400 		 * @param {Object} callbacks
8401 		 *     An object containing callbacks for instantiation and runtime
8402 		 * @param {Function} callbacks.onLoad(this)
8403 		 *     Callback to invoke upon successful instantiation
8404 		 * @param {Function} callbacks.onLoadError(rsp)
8405 		 *     Callback to invoke on instantiation REST request error
8406 		 *     as passed by finesse.clientservices.ClientServices.ajax()
8407 		 *     {
8408 		 *         status: {Number} The HTTP status code returned
8409 		 *         content: {String} Raw string of response
8410 		 *         object: {Object} Parsed object of response
8411 		 *         error: {Object} Wrapped exception that was caught
8412 		 *         error.errorType: {String} Type of error that was caught
8413 		 *         error.errorMessage: {String} Message associated with error
8414 		 *     }
8415 		 * @param {Function} callbacks.onChange(this)
8416 		 *     Callback to invoke upon successful update
8417 		 * @param {Function} callbacks.onError(rsp)
8418 		 *     Callback to invoke on update error (refresh or event)
8419 		 *     as passed by finesse.clientservices.ClientServices.ajax()
8420 		 *     {
8421 		 *         status: {Number} The HTTP status code returned
8422 		 *         content: {String} Raw string of response
8423 		 *         object: {Object} Parsed object of response
8424 		 *         error: {Object} Wrapped exception that was caught
8425 		 *         error.errorType: {String} Type of error that was caught
8426 		 *         error.errorMessage: {String} Message associated with error
8427 		 *     }
8428 		 *  
8429 		 */
8430         init: function (id, callbacks, restObj) {
8431             this._super(id, callbacks, restObj);
8432         },
8433 
8434         /**
8435          * @private
8436          * Gets the REST class for the current object - this is the Queue object.
8437          */
8438         getRestClass: function () {
8439             return Queue;
8440         },
8441 
8442         /**
8443          * @private
8444          * Gets the REST type for the current object - this is a "Queue".
8445          */
8446         getRestType: function () {
8447             return "Queue";
8448         },
8449 
8450         /**
8451          * @private
8452          * Returns whether this object supports subscriptions
8453          */
8454         supportsSubscriptions: function () {
8455             return true;
8456         },
8457         
8458         /**
8459          * @private
8460          * Specifies whether this object's subscriptions need to be explicitly requested
8461          */
8462         explicitSubscription: true,
8463         
8464         /**
8465          * @private
8466          * Gets the node path for the current object - this is the team Users node
8467          * @returns {String} The node path
8468          */
8469         getXMPPNodePath: function () {
8470             return this.getRestUrl();
8471         },
8472         
8473         /**
8474          * Getter for the queue id
8475          * @returns {String}
8476          *     The id of the Queue
8477          */
8478         getId: function () {
8479             this.isLoaded();
8480             return this._id;
8481         },
8482         
8483         /**
8484          * Getter for the queue name
8485          * @returns {String}
8486          *      The name of the Queue
8487          */
8488         getName: function () {
8489             this.isLoaded();
8490             return this.getData().name;
8491         },
8492         
8493         /**
8494          * Getter for the queue statistics.
8495          * Supported statistics include:<br>
8496          *  - callsInQueue<br>
8497          *  - startTimeOfLongestCallInQueue<br>
8498          *  <br>
8499          *  These statistics can be accessed via dot notation:<br>
8500          *  i.e.: getStatistics().callsInQueue
8501          * @returns {Object}
8502          *      The Object with different statistics as properties.
8503          */
8504         getStatistics: function () {
8505             this.isLoaded();
8506             return this.getData().statistics;       
8507         },
8508 
8509         /**
8510          * Parses a uriString to retrieve the id portion
8511          * @param {String} uriString
8512          * @return {String} id
8513          */
8514         _parseIdFromUriString : function (uriString) {
8515             return Utilities.getId(uriString);
8516         }
8517 
8518     });
8519 	
8520 	window.finesse = window.finesse || {};
8521     window.finesse.restservices = window.finesse.restservices || {};
8522     window.finesse.restservices.Queue = Queue;
8523     
8524     return Queue;
8525 }));
8526 
8527 /**
8528  * JavaScript representation of the Finesse Queues collection
8529  * object which contains a list of Queue objects.
8530  * @requires finesse.clientservices.ClientServices
8531  * @requires Class
8532  * @requires finesse.FinesseBase
8533  * @requires finesse.restservices.RestBase
8534  * @requires finesse.restservices.RestCollectionBase
8535  */
8536 
8537 /**
8538  * @class
8539  * JavaScript representation of a Queues collection object.
8540  *
8541  * @constructor
8542  * @borrows finesse.restservices.RestCollectionBase as finesse.restservices.Queues
8543  */
8544 
8545 /** @private */
8546  (function (factory) {
8547     
8548 
8549     // Define as an AMD module if possible
8550     if ( typeof define === 'function' && define.amd )
8551     {
8552         define('restservices/Queues', ['restservices/RestCollectionBase',
8553                  'restservices/Queue'], factory );
8554     }
8555     /* Define using browser globals otherwise
8556      * Prevent multiple instantiations if the script is loaded twice
8557      */
8558     else
8559     {
8560         factory(finesse.restservices.RestCollectionBase, finesse.restservices.Queue);
8561     } 
8562 }(function (RestCollectionBase, Queue) {
8563 	var Queues = RestCollectionBase.extend(/** @lends finesse.restservices.Queues.prototype */{
8564 
8565         /**
8566          * @class
8567          * JavaScript representation of a Queues collection object. 
8568          * @augments finesse.restservices.RestCollectionBase
8569          * @constructs
8570          * @see finesse.restservices.Queue
8571          * @example
8572          *  _queues = _user.getQueues( {
8573          *      onCollectionAdd : _handleQueueAdd,
8574          *      onCollectionDelete : _handleQueueDelete,
8575          *      onLoad : _handleQueuesLoaded
8576          *  });
8577          *  
8578          * _queueCollection = _queues.getCollection();
8579          * for (var queueId in _queueCollection) {
8580          *     if (_queueCollection.hasOwnProperty(queueId)) {
8581          *         _queue = _queueCollection[queueId];
8582          *         etc...
8583          *     }
8584          * }
8585          */
8586         _fakeConstuctor: function () {
8587             /* This is here to hide the real init constructor from the public docs */
8588         },
8589 	    
8590          /**
8591          * @private
8592          * JavaScript representation of a Queues object. Also exposes
8593          * methods to operate on the object against the server.
8594          *
8595          * @param {Object} options
8596          *     An object with the following properties:<ul>
8597          *         <li><b>id:</b> The id of the object being constructed</li>
8598          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
8599          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
8600          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
8601          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
8602          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
8603          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
8604          *             <li><b>content:</b> {String} Raw string of response</li>
8605          *             <li><b>object:</b> {Object} Parsed object of response</li>
8606          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
8607          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
8608          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
8609          *             </ul></li>
8610          *         </ul></li>
8611          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
8612          **/
8613         init: function (options) {
8614             this._super(options);           
8615         },
8616 
8617         /**
8618          * @private
8619          * Gets xmpp node path.
8620          */
8621         getXMPPNodePath: function () {
8622             return this.getRestUrl();
8623         },
8624 
8625         /**
8626          * @private
8627          * Gets the REST class for the current object - this is the Queues class.
8628          */
8629         getRestClass: function () {
8630             return Queues;
8631         },
8632 
8633         /**
8634          * @private
8635          * Gets the REST class for the objects that make up the collection. - this
8636          * is the Queue class.
8637          */
8638         getRestItemClass: function () {
8639             return Queue;
8640         },
8641 
8642         /**
8643          * @private
8644          * Gets the REST type for the current object - this is a "Queues".
8645          */
8646         getRestType: function () {
8647             return "Queues";
8648         },
8649         
8650         /**
8651          * @private
8652          * Gets the REST type for the objects that make up the collection - this is "Queue".
8653          */
8654         getRestItemType: function () {
8655             return "Queue";
8656         },
8657 
8658         explicitSubscription: true,
8659         
8660         handlesItemRefresh: true
8661     });
8662     
8663     window.finesse = window.finesse || {};
8664     window.finesse.restservices = window.finesse.restservices || {};
8665     window.finesse.restservices.Queues = Queues;
8666     
8667     return Queues;
8668 }));
8669 
8670 /**
8671  * JavaScript representation of the Finesse WrapUpReason object.
8672  *
8673  * @requires finesse.clientservices.ClientServices
8674  * @requires Class
8675  * @requires finesse.FinesseBase
8676  * @requires finesse.restservices.RestBase
8677  */
8678 
8679 /** @private */
8680 (function (factory) {
8681     
8682 
8683     // Define as an AMD module if possible
8684     if ( typeof define === 'function' && define.amd )
8685     {
8686         define('restservices/WrapUpReason',['restservices/RestBase'], factory);
8687     }
8688     /* Define using browser globals otherwise
8689      * Prevent multiple instantiations if the script is loaded twice
8690      */
8691     else
8692     {
8693         factory(finesse.restservices.RestBase);
8694     } 
8695 }(function (RestBase) {
8696 
8697     var WrapUpReason = RestBase.extend(/** @lends finesse.restservices.WrapUpReason.prototype */{
8698 
8699         /**
8700          * @class
8701          * A WrapUpReason is a code and description identifying a particular reason that a
8702          * User is in WORK (WrapUp) mode.
8703          * 
8704          * @augments finesse.restservices.RestBase
8705          * @see finesse.restservices.User
8706          * @see finesse.restservices.User.States#WORK
8707          * @constructs
8708          */
8709         _fakeConstuctor: function () {
8710             /* This is here to hide the real init constructor from the public docs */
8711         },
8712         
8713         /** 
8714          * @private
8715          * JavaScript representation of a WrapUpReason object. Also exposes
8716          * methods to operate on the object against the server.
8717          *
8718          * @param {Object} options
8719          *     An object with the following properties:<ul>
8720          *         <li><b>id:</b> The id of the object being constructed</li>
8721          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
8722          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
8723          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
8724          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
8725          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
8726          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
8727          *             <li><b>content:</b> {String} Raw string of response</li>
8728          *             <li><b>object:</b> {Object} Parsed object of response</li>
8729          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
8730          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
8731          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
8732          *             </ul></li>
8733          *         </ul></li>
8734          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
8735          **/
8736         init: function (options) {
8737             this._super(options);
8738         },
8739 
8740         /**
8741          * @private
8742          * Gets the REST class for the current object - this is the WrapUpReason class.
8743          * @returns {Object} The WrapUpReason class.
8744          */
8745         getRestClass: function () {
8746             return WrapUpReason;
8747         },
8748 
8749         /**
8750          * @private
8751          * Gets the REST type for the current object - this is a "WrapUpReason".
8752          * @returns {String} The WrapUpReason string.
8753          */
8754         getRestType: function () {
8755             return "WrapUpReason";
8756         },
8757 
8758         /**
8759          * @private
8760          * Gets the REST type for the current object - this is a "WrapUpReasons".
8761          * @returns {String} The WrapUpReasons string.
8762          */
8763         getParentRestType: function () {
8764             return "WrapUpReasons";
8765         },
8766 
8767         /**
8768          * @private
8769          * Override default to indicate that this object doesn't support making
8770          * requests.
8771          */
8772         supportsRequests: false,
8773 
8774         /**
8775          * @private
8776          * Override default to indicate that this object doesn't support subscriptions.
8777          */
8778         supportsSubscriptions: false,
8779 
8780         /**
8781          * Getter for the label.
8782          * @returns {String} The label.
8783          */
8784         getLabel: function () {
8785             this.isLoaded();
8786             return this.getData().label;
8787         },
8788 
8789         /**
8790          * @private
8791          * Getter for the forAll flag.
8792          * @returns {Boolean} True if global.
8793          */
8794         getForAll: function () {
8795             this.isLoaded();
8796             return this.getData().forAll;
8797         },
8798 
8799         /**
8800          * @private
8801          * Getter for the Uri value.
8802          * @returns {String} The Uri.
8803          */
8804         getUri: function () {
8805             this.isLoaded();
8806             return this.getData().uri;
8807         }
8808     });
8809 
8810     window.finesse = window.finesse || {};
8811     window.finesse.restservices = window.finesse.restservices || {};
8812     window.finesse.restservices.WrapUpReason = WrapUpReason;
8813         
8814     return WrapUpReason;
8815 }));
8816 
8817 /**
8818 * JavaScript representation of the Finesse WrapUpReasons collection
8819 * object which contains a list of WrapUpReason objects.
8820  *
8821  * @requires finesse.clientservices.ClientServices
8822  * @requires Class
8823  * @requires finesse.FinesseBase
8824  * @requires finesse.restservices.RestBase
8825  * @requires finesse.restservices.Dialog
8826  * @requires finesse.restservices.RestCollectionBase
8827  */
8828 
8829 /** @private */
8830 (function (factory) {
8831     
8832 
8833     // Define as an AMD module if possible
8834     if ( typeof define === 'function' && define.amd )
8835     {
8836         define('restservices/WrapUpReasons', ['restservices/RestCollectionBase',
8837                  'restservices/WrapUpReason'], factory );
8838     }
8839     /* Define using browser globals otherwise
8840      * Prevent multiple instantiations if the script is loaded twice
8841      */
8842     else
8843     {
8844         factory(finesse.restservices.RestCollectionBase, finesse.restservices.WrapUpReason);
8845     } 
8846 }(function (RestCollectionBase, WrapUpReason) {
8847 
8848     var WrapUpReasons = RestCollectionBase.extend(/** @lends finesse.restservices.WrapUpReasons.prototype */{
8849         
8850         /**
8851          * @class
8852          * JavaScript representation of a WrapUpReasons collection object. 
8853          * @augments finesse.restservices.RestCollectionBase
8854          * @constructs
8855          * @see finesse.restservices.WrapUpReason
8856          * @example
8857          *  _wrapUpReasons = _user.getWrapUpReasons ( {
8858          *      onCollectionAdd : _handleWrapUpReasonAdd,
8859          *      onCollectionDelete : _handleWrapUpReasonDelete,
8860          *      onLoad : _handleWrapUpReasonsLoaded
8861          *  });
8862          *  
8863          * _wrapUpReasonCollection = _wrapUpReasons.getCollection();
8864          * for (var wrapUpReasonId in _wrapUpReasonCollection) {
8865          *     if (_wrapUpReasonCollection.hasOwnProperty(wrapUpReasonId)) {
8866          *         _wrapUpReason = _wrapUpReasonCollection[wrapUpReasonId];
8867          *         etc...
8868          *     }
8869          * }
8870         */
8871         _fakeConstuctor: function () {
8872             /* This is here to hide the real init constructor from the public docs */
8873         },
8874         
8875         /** 
8876          * @private
8877          * JavaScript representation of a WrapUpReasons collection object. Also exposes
8878          * methods to operate on the object against the server.
8879          *
8880          * @param {Object} options
8881          *     An object with the following properties:<ul>
8882          *         <li><b>id:</b> The id of the object being constructed</li>
8883          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
8884          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
8885          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
8886          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
8887          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
8888          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
8889          *             <li><b>content:</b> {String} Raw string of response</li>
8890          *             <li><b>object:</b> {Object} Parsed object of response</li>
8891          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
8892          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
8893          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
8894          *             </ul></li>
8895          *         </ul></li>
8896          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
8897          **/
8898         init: function (options) {
8899             this._super(options);           
8900         },
8901 
8902         /**
8903          * @private
8904          * Gets the REST class for the current object - this is the WrapUpReasons class.
8905          */
8906         getRestClass: function () {
8907             return WrapUpReasons;
8908         },
8909 
8910         /**
8911          * @private
8912          * Gets the REST class for the objects that make up the collection. - this
8913          * is the WrapUpReason class.
8914          */
8915         getRestItemClass: function () {
8916             return WrapUpReason;
8917         },
8918 
8919         /**
8920          * @private
8921          * Gets the REST type for the current object - this is a "WrapUpReasons".
8922          */
8923         getRestType: function () {
8924             return "WrapUpReasons";
8925         },
8926         
8927         /**
8928          * @private
8929          * Gets the REST type for the objects that make up the collection - this is "WrapUpReason".
8930          */
8931         getRestItemType: function () {
8932             return "WrapUpReason";
8933         },
8934 
8935         /**
8936          * @private
8937          * Override default to indicates that the collection supports making
8938          * requests.
8939          */
8940         supportsRequests: true,
8941 
8942         /**
8943          * @private
8944          * Override default to indicate that this object doesn't support subscriptions.
8945          */
8946         supportsRestItemSubscriptions: false,
8947 
8948         /**
8949          * @private
8950          * Retrieve the Wrap-Up Reason Codes. This call will re-query the server and refresh the collection.
8951          *
8952          * @returns {finesse.restservices.WrapUpReasons}
8953          *     This ReadyReasonCodes object to allow cascading.
8954          */
8955         get: function () {
8956             // set loaded to false so it will rebuild the collection after the get
8957             this._loaded = false;
8958             // reset collection
8959             this._collection = {};
8960             // perform get
8961             this._synchronize();
8962             return this;
8963         }
8964         
8965     });
8966  
8967     window.finesse = window.finesse || {};
8968     window.finesse.restservices = window.finesse.restservices || {};
8969     window.finesse.restservices.WrapUpReasons = WrapUpReasons;
8970        
8971     return WrapUpReasons;
8972 }));
8973 
8974 /**
8975  * JavaScript representation of the Finesse Contact object.
8976  * @requires finesse.clientservices.ClientServices
8977  * @requires Class
8978  * @requires finesse.FinesseBase
8979  * @requires finesse.restservices.RestBase
8980  */
8981 /** @private */
8982 (function (factory) {
8983     
8984 
8985     // Define as an AMD module if possible
8986     if ( typeof define === 'function' && define.amd )
8987     {
8988         define('restservices/Contact',['restservices/RestBase'], factory);
8989     }
8990     /* Define using browser globals otherwise
8991      * Prevent multiple instantiations if the script is loaded twice
8992      */
8993     else
8994     {
8995         factory(finesse.restservices.RestBase);
8996     } 
8997 }(function (RestBase) {
8998     var Contact = RestBase.extend(/** @lends finesse.restservices.Contact.prototype */{
8999 
9000         /**
9001          * @class
9002          * A Contact is a single entry in a PhoneBook, consisting of a First and Last Name,
9003          * a Phone Number, and a Description.
9004          * 
9005          * @augments finesse.restservices.RestBase
9006          * @see finesse.restservices.PhoneBook
9007          * @constructs
9008          */
9009         _fakeConstuctor: function () {
9010             /* This is here to hide the real init constructor from the public docs */
9011         },
9012         
9013         /**
9014          * @private
9015          * @param {Object} options
9016          *     An object with the following properties:<ul>
9017          *         <li><b>id:</b> The id of the object being constructed</li>
9018          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
9019          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
9020          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
9021          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
9022          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
9023          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
9024          *             <li><b>content:</b> {String} Raw string of response</li>
9025          *             <li><b>object:</b> {Object} Parsed object of response</li>
9026          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
9027          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
9028          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
9029          *             </ul></li>
9030          *         </ul></li>
9031          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
9032          **/
9033         init: function (options) {
9034             this._super(options);
9035         },
9036 
9037         /**
9038          * @private
9039          * Gets the REST class for the current object - this is the Contact class.
9040          * @returns {Object} The Contact class.
9041          */
9042         getRestClass: function () {
9043             return Contact;
9044         },
9045 
9046         /**
9047          * @private
9048          * Gets the REST type for the current object - this is a "Contact".
9049          * @returns {String} The Contact string.
9050          */
9051         getRestType: function () {
9052             return "Contact";
9053         },
9054 
9055         /**
9056          * @private
9057          * Override default to indicate that this object doesn't support making
9058          * requests.
9059          */
9060         supportsRequests: false,
9061 
9062         /**
9063          * @private
9064          * Override default to indicate that this object doesn't support subscriptions.
9065          */
9066         supportsSubscriptions: false,
9067 
9068         /**
9069          * Getter for the firstName.
9070          * @returns {String} The firstName.
9071          */
9072         getFirstName: function () {
9073             this.isLoaded();
9074             return this.getData().firstName;
9075         },
9076 
9077         /**
9078          * Getter for the lastName.
9079          * @returns {String} The lastName.
9080          */
9081         getLastName: function () {
9082             this.isLoaded();
9083             return this.getData().lastName;
9084         },
9085 
9086         /**
9087          * Getter for the phoneNumber.
9088          * @returns {String} The phoneNumber.
9089          */
9090         getPhoneNumber: function () {
9091             this.isLoaded();
9092             return this.getData().phoneNumber;
9093         },
9094 
9095         /**
9096          * Getter for the description.
9097          * @returns {String} The description.
9098          */
9099         getDescription: function () {
9100             this.isLoaded();
9101             return this.getData().description;
9102         },
9103 
9104         /** @private */
9105         createPutSuccessHandler: function(contact, contentBody, successHandler){
9106             return function (rsp) {
9107                 // Update internal structure based on response. Here we
9108                 // inject the contentBody from the PUT request into the
9109                 // rsp.object element to mimic a GET as a way to take
9110                 // advantage of the existing _processResponse method.
9111                 rsp.object = contentBody;
9112                 contact._processResponse(rsp);
9113 
9114                 //Remove the injected Contact object before cascading response
9115                 rsp.object = {};
9116                 
9117                 //cascade response back to consumer's response handler
9118                 successHandler(rsp);
9119             };
9120         },
9121 
9122         /** @private */
9123         createPostSuccessHandler: function (contact, contentBody, successHandler) {
9124             return function (rsp) {
9125                 rsp.object = contentBody;
9126                 contact._processResponse(rsp);
9127 
9128                 //Remove the injected Contact object before cascading response
9129                 rsp.object = {};
9130 
9131                 //cascade response back to consumer's response handler
9132                 successHandler(rsp);
9133             };
9134         },
9135 
9136         /**
9137          * Add
9138          * @private
9139          */
9140         add: function (newValues, handlers) {
9141             // this.isLoaded();
9142             var contentBody = {};
9143 
9144             contentBody[this.getRestType()] = {
9145                 "firstName": newValues.firstName,
9146                 "lastName": newValues.lastName,
9147                 "phoneNumber": newValues.phoneNumber,
9148                 "description": newValues.description
9149             };
9150 
9151             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
9152             handlers = handlers || {};
9153 
9154             this.restRequest(this.getRestUrl(), {
9155                 method: 'POST',
9156                 success: this.createPostSuccessHandler(this, contentBody, handlers.success),
9157                 error: handlers.error,
9158                 content: contentBody
9159             });
9160 
9161             return this; // Allow cascading
9162         },
9163 
9164         /**
9165          * Update
9166          * @private
9167          */
9168         update: function (newValues, handlers) {
9169             this.isLoaded();
9170             var contentBody = {};
9171 
9172             contentBody[this.getRestType()] = {
9173                 "uri": this.getId(),
9174                 "firstName": newValues.firstName,
9175                 "lastName": newValues.lastName,
9176                 "phoneNumber": newValues.phoneNumber,
9177                 "description": newValues.description
9178             };
9179 
9180             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
9181             handlers = handlers || {};
9182 
9183             this.restRequest(this.getRestUrl(), {
9184                 method: 'PUT',
9185                 success: this.createPutSuccessHandler(this, contentBody, handlers.success),
9186                 error: handlers.error,
9187                 content: contentBody
9188             });
9189 
9190             return this; // Allow cascading
9191         },
9192 
9193 
9194         /**
9195          * Delete
9196          * @private
9197          */
9198         "delete": function ( handlers) {
9199             this.isLoaded();
9200 
9201             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
9202             handlers = handlers || {};
9203 
9204             this.restRequest(this.getRestUrl(), {
9205                 method: 'DELETE',
9206                 success: this.createPutSuccessHandler(this, {}, handlers.success),
9207                 error: handlers.error,
9208                 content: undefined
9209             });
9210 
9211             return this; // Allow cascading
9212         }
9213     });
9214 
9215     window.finesse = window.finesse || {};
9216     window.finesse.restservices = window.finesse.restservices || {};
9217     window.finesse.restservices.Contact = Contact;
9218     
9219     return Contact;
9220 }));
9221 
9222 /**
9223 * JavaScript representation of the Finesse Contacts collection
9224 * object which contains a list of Contact objects.
9225  *
9226  * @requires finesse.clientservices.ClientServices
9227  * @requires Class
9228  * @requires finesse.FinesseBase
9229  * @requires finesse.restservices.RestBase
9230  * @requires finesse.restservices.Dialog
9231  * @requires finesse.restservices.RestCollectionBase
9232  */
9233 /** @private */
9234 (function (factory) {
9235     
9236 
9237     // Define as an AMD module if possible
9238     if ( typeof define === 'function' && define.amd )
9239     {
9240         define('restservices/Contacts', ['restservices/RestCollectionBase',
9241                 'restservices/Contact'], factory );
9242     }
9243     /* Define using browser globals otherwise
9244      * Prevent multiple instantiations if the script is loaded twice
9245      */
9246     else
9247     {
9248         factory(finesse.restservices.RestCollectionBase, finesse.restservices.Contact);
9249     } 
9250 }(function (RestCollectionBase, Contact) {
9251     var Contacts = RestCollectionBase.extend(/** @lends finesse.restservices.Contacts.prototype */{
9252         
9253         /**
9254          * @class
9255          * JavaScript representation of a Contacts collection object. Also exposes
9256          * methods to operate on the object against the server.
9257          * @augments finesse.restservices.RestCollectionBase
9258          * @constructs
9259          * @see finesse.restservices.Contact
9260          * @see finesse.restservices.PhoneBook
9261          * @example
9262          *  _contacts = _phonebook.getContacts( {
9263          *      onCollectionAdd : _handleContactAdd,
9264          *      onCollectionDelete : _handleContactDelete,
9265          *      onLoad : _handleContactsLoaded
9266          *  });
9267          *  
9268          * _contactCollection = _contacts.getCollection();
9269          * for (var contactId in _contactCollection) {
9270          *     if (_contactCollection.hasOwnProperty(contactId)) {
9271          *         _contact = _contactCollection[contactId];
9272          *         etc...
9273          *     }
9274          * }
9275          */
9276         _fakeConstuctor: function () {
9277             /* This is here to hide the real init constructor from the public docs */
9278         },
9279         
9280         /** 
9281          * @private
9282          * JavaScript representation of a Contacts collection object. Also exposes
9283          * methods to operate on the object against the server.
9284          *
9285          * @param {Object} options
9286          *     An object with the following properties:<ul>
9287          *         <li><b>id:</b> The id of the object being constructed</li>
9288          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
9289          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
9290          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
9291          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
9292          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
9293          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
9294          *             <li><b>content:</b> {String} Raw string of response</li>
9295          *             <li><b>object:</b> {Object} Parsed object of response</li>
9296          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
9297          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
9298          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
9299          *             </ul></li>
9300          *         </ul></li>
9301          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
9302          **/
9303         init: function (options) {
9304             this._super(options);           
9305         },
9306 
9307         /**
9308          * @private
9309          * Gets the REST class for the current object - this is the Contacts class.
9310          */
9311         getRestClass: function () {
9312             return Contacts;
9313         },
9314 
9315         /**
9316          * @private
9317          * Gets the REST class for the objects that make up the collection. - this
9318          * is the Contact class.
9319          */
9320         getRestItemClass: function () {
9321             return Contact;
9322         },
9323 
9324         /**
9325          * @private
9326          * Gets the REST type for the current object - this is a "Contacts".
9327          */
9328         getRestType: function () {
9329             return "Contacts";
9330         },
9331         
9332         /**
9333          * @private
9334          * Gets the REST type for the objects that make up the collection - this is "Contacts".
9335          */
9336         getRestItemType: function () {
9337             return "Contact";
9338         },
9339 
9340         /**
9341          * @private
9342          * Override default to indicates that the collection supports making
9343          * requests.
9344          */
9345         supportsRequests: true,
9346 
9347         /**
9348          * @private
9349          * Override default to indicates that the collection subscribes to its objects.
9350          */
9351         supportsRestItemSubscriptions: false,
9352         
9353         /**
9354          * @private
9355          * Retrieve the Contacts.  This call will re-query the server and refresh the collection.
9356          *
9357          * @returns {finesse.restservices.Contacts}
9358          *     This Contacts object, to allow cascading.
9359          */
9360         get: function () {
9361             // set loaded to false so it will rebuild the collection after the get
9362             this._loaded = false;
9363             // reset collection
9364             this._collection = {};
9365             // perform get
9366             this._synchronize();
9367             return this;
9368         }
9369         
9370     });
9371     
9372     window.finesse = window.finesse || {};
9373     window.finesse.restservices = window.finesse.restservices || {};
9374     window.finesse.restservices.Contacts = Contacts;
9375     
9376     
9377     return Contacts;
9378 }));
9379 
9380 /**
9381  * JavaScript representation of the Finesse PhoneBook object.
9382  *
9383  * @requires finesse.clientservices.ClientServices
9384  * @requires Class
9385  * @requires finesse.FinesseBase
9386  * @requires finesse.restservices.RestBase
9387  */
9388 
9389 /** @private */
9390 (function (factory) {
9391     
9392 
9393     // Define as an AMD module if possible
9394     if ( typeof define === 'function' && define.amd )
9395     {
9396         define('restservices/PhoneBook',['restservices/RestBase',
9397 				'restservices/Contacts'], factory);
9398     }
9399     /* Define using browser globals otherwise
9400      * Prevent multiple instantiations if the script is loaded twice
9401      */
9402     else
9403     {
9404         factory(finesse.restservices.RestBase,
9405 				finesse.restservices.Contacts);
9406     } 
9407 }(function (RestBase, Contacts) {
9408     var PhoneBook = RestBase.extend(/** @lends finesse.restservices.PhoneBook.prototype */{
9409 
9410         _contacts: null,
9411 
9412         /**
9413          * @class
9414          * A PhoneBook is a list of Contacts available to a User for quick dial.
9415          * 
9416          * @augments finesse.restservices.RestBase
9417          * @see finesse.restservices.Contacts
9418          * @constructs
9419          */
9420         _fakeConstuctor: function () {
9421             /* This is here to hide the real init constructor from the public docs */
9422         },
9423         
9424         /** 
9425          * @private
9426          * JavaScript representation of a PhoneBook object. Also exposes
9427          * methods to operate on the object against the server.
9428          *
9429          * @param {Object} options
9430          *     An object with the following properties:<ul>
9431          *         <li><b>id:</b> The id of the object being constructed</li>
9432          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
9433          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
9434          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
9435          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
9436          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
9437          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
9438          *             <li><b>content:</b> {String} Raw string of response</li>
9439          *             <li><b>object:</b> {Object} Parsed object of response</li>
9440          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
9441          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
9442          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
9443          *             </ul></li>
9444          *         </ul></li>
9445          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
9446          **/
9447         init: function (options) {
9448             this._super(options);
9449         },
9450 
9451         /**
9452          * @private
9453          * Gets the REST class for the current object - this is the PhoneBook class.
9454          * @returns {Object} The PhoneBook class.
9455          */
9456         getRestClass: function () {
9457             return PhoneBook;
9458         },
9459 
9460         /**
9461          * @private
9462          * Gets the REST type for the current object - this is a "PhoneBook".
9463          * @returns {String} The PhoneBook string.
9464          */
9465         getRestType: function () {
9466             return "PhoneBook";
9467         },
9468 
9469         /**
9470          * @private
9471          * Override default to indicate that this object doesn't support making
9472          * requests.
9473          */
9474         supportsRequests: false,
9475 
9476         /**
9477          * @private
9478          * Override default to indicate that this object doesn't support subscriptions.
9479          */
9480         supportsSubscriptions: false,
9481 
9482         /**
9483          * Getter for the name of the Phone Book.
9484          * @returns {String} The name.
9485          */
9486         getName: function () {
9487             this.isLoaded();
9488             return this.getData().name;
9489         },
9490 
9491         /**
9492          * Getter for the type flag.
9493          * @returns {String} The type.
9494          */
9495         getType: function () {
9496             this.isLoaded();
9497             return this.getData().type;
9498         },
9499 
9500         /**
9501          * @private
9502          * Getter for the Uri value.
9503          * @returns {String} The Uri.
9504          */
9505         getUri: function () {
9506             this.isLoaded();
9507             return this.getData().uri;
9508         },
9509 
9510         /**
9511          * Getter for a Contacts collection object that is associated with PhoneBook.
9512          * @param {finesse.interfaces.RequestHandlers} handlers
9513          *     An object containing the handlers for the request
9514          * @returns {finesse.restservices.Contacts}
9515          *     A Contacts collection object.
9516          */
9517         getContacts: function (callbacks) {
9518             var options = callbacks || {};
9519             options.parentObj = this;
9520             this.isLoaded();
9521 
9522             if (this._contacts === null) {
9523                 this._contacts = new Contacts(options);
9524             }
9525 
9526             return this._contacts;
9527         },
9528 
9529         /**
9530          * Getter for <contacts> node within PhoneBook - sometimes it's just a URI, sometimes it is a Contacts collection
9531          * @returns {String} uri to contacts
9532          *          or {finesse.restservices.Contacts} collection
9533          */
9534         getEmbeddedContacts: function(){
9535             this.isLoaded();
9536             return this.getData().contacts;
9537         },
9538 
9539         /** @private */
9540         createPutSuccessHandler: function(phonebook, contentBody, successHandler){
9541             return function (rsp) {
9542                 // Update internal structure based on response. Here we
9543                 // inject the contentBody from the PUT request into the
9544                 // rsp.object element to mimic a GET as a way to take
9545                 // advantage of the existing _processResponse method.
9546                 rsp.object = contentBody;
9547                 phonebook._processResponse(rsp);
9548 
9549                 //Remove the injected PhoneBook object before cascading response
9550                 rsp.object = {};
9551                 
9552                 //cascade response back to consumer's response handler
9553                 successHandler(rsp);
9554             };
9555         },
9556 
9557         /** @private */
9558         createPostSuccessHandler: function (phonebook, contentBody, successHandler) {
9559             return function (rsp) {
9560                 rsp.object = contentBody;
9561                 phonebook._processResponse(rsp);
9562 
9563                 //Remove the injected PhoneBook object before cascading response
9564                 rsp.object = {};
9565 
9566                 //cascade response back to consumer's response handler
9567                 successHandler(rsp);
9568             };
9569         },
9570 
9571         /**
9572          * @private
9573          * Add a PhoneBook.
9574          * @param {Object} newValues
9575          * @param {String} newValues.name Name of PhoneBook
9576          * @param {String} newValues.type Type of PhoneBook
9577          * @param {finesse.interfaces.RequestHandlers} handlers
9578          *     An object containing the handlers for the request
9579          * @returns {finesse.restservices.PhoneBook}
9580          *     This PhoneBook object, to allow cascading
9581          */
9582         add: function (newValues, handlers) {
9583             // this.isLoaded();
9584             var contentBody = {};
9585 
9586             contentBody[this.getRestType()] = {
9587                 "name": newValues.name,
9588                 "type": newValues.type
9589             };
9590 
9591             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
9592             handlers = handlers || {};
9593 
9594             this.restRequest(this.getRestUrl(), {
9595                 method: 'POST',
9596                 success: this.createPostSuccessHandler(this, contentBody, handlers.success),
9597                 error: handlers.error,
9598                 content: contentBody
9599             });
9600 
9601             return this; // Allow cascading
9602         },
9603 
9604         /**
9605          * @private
9606          * Update a PhoneBook.
9607          * @param {Object} newValues
9608          * @param {String} newValues.name Name of PhoneBook
9609          * @param {String} newValues.type Type of PhoneBook
9610          * @param {finesse.interfaces.RequestHandlers} handlers
9611          *     An object containing the handlers for the request
9612          * @returns {finesse.restservices.PhoneBook}
9613          *     This PhoneBook object, to allow cascading
9614          */
9615         update: function (newValues, handlers) {
9616             this.isLoaded();
9617             var contentBody = {};
9618 
9619             contentBody[this.getRestType()] = {
9620                 "uri": this.getId(),
9621                 "name": newValues.name,
9622                 "type": newValues.type
9623             };
9624 
9625             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
9626             handlers = handlers || {};
9627 
9628             this.restRequest(this.getRestUrl(), {
9629                 method: 'PUT',
9630                 success: this.createPutSuccessHandler(this, contentBody, handlers.success),
9631                 error: handlers.error,
9632                 content: contentBody
9633             });
9634 
9635             return this; // Allow cascading
9636         },
9637 
9638 
9639         /**
9640          * Delete a PhoneBook.
9641          * @param {finesse.interfaces.RequestHandlers} handlers
9642          *     An object containing the handlers for the request
9643          * @returns {finesse.restservices.PhoneBook}
9644          *     This PhoneBook object, to allow cascading
9645          */
9646         "delete": function ( handlers) {
9647             this.isLoaded();
9648 
9649             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
9650             handlers = handlers || {};
9651 
9652             this.restRequest(this.getRestUrl(), {
9653                 method: 'DELETE',
9654                 success: this.createPutSuccessHandler(this, {}, handlers.success),
9655                 error: handlers.error,
9656                 content: undefined
9657             });
9658 
9659             return this; // Allow cascading
9660         }
9661 
9662 
9663 
9664     });
9665     
9666     window.finesse = window.finesse || {};
9667     window.finesse.restservices = window.finesse.restservices || {};
9668     window.finesse.restservices.PhoneBook = PhoneBook;
9669     
9670     return PhoneBook;
9671 }));
9672 
9673 /**
9674 * JavaScript representation of the Finesse PhoneBooks collection
9675 * object which contains a list of PhoneBook objects.
9676  *
9677  * @requires finesse.clientservices.ClientServices
9678  * @requires Class
9679  * @requires finesse.FinesseBase
9680  * @requires finesse.restservices.RestBase
9681  * @requires finesse.restservices.Dialog
9682  * @requires finesse.restservices.RestCollectionBase
9683  */
9684 /** @private */
9685 (function (factory) {
9686     
9687 
9688     // Define as an AMD module if possible
9689     if ( typeof define === 'function' && define.amd )
9690     {
9691         define('restservices/PhoneBooks', ['restservices/RestCollectionBase',
9692                  'restservices/PhoneBook'], factory );
9693     }
9694     /* Define using browser globals otherwise
9695      * Prevent multiple instantiations if the script is loaded twice
9696      */
9697     else
9698     {
9699         factory(finesse.restservices.RestCollectionBase, finesse.restservices.PhoneBook);
9700     } 
9701 }(function (RestCollectionBase, PhoneBook) {
9702     var PhoneBooks = RestCollectionBase.extend(/** @lends finesse.restservices.PhoneBooks.prototype */{
9703         
9704         /**
9705          * @class
9706          * JavaScript representation of a PhoneBooks collection object. 
9707          * @augments finesse.restservices.RestCollectionBase
9708          * @constructs
9709          * @see finesse.restservices.PhoneBook
9710          * @see finesse.restservices.Contacts
9711          * @see finesse.restservices.Contact
9712          * @example
9713          *  _phoneBooks = _user.getPhoneBooks( {
9714          *      onCollectionAdd : _handlePhoneBookAdd,
9715          *      onCollectionDelete : _handlePhoneBookDelete,
9716          *      onLoad : _handlePhoneBooksLoaded
9717          *  });
9718          *  
9719          * _phoneBookCollection = _phoneBooks.getCollection();
9720          * for (var phoneBookId in _phoneBookCollection) {
9721          *     if (_phoneBookCollection.hasOwnProperty(phoneBookId)) {
9722          *         _phoneBook = _phoneBookCollection[phoneBookId];
9723          *         etc...
9724          *     }
9725          * }
9726         */
9727         _fakeConstuctor: function () {
9728             /* This is here to hide the real init constructor from the public docs */
9729         },
9730         
9731        /**
9732          * @private
9733          *
9734          * @param {Object} options
9735          *     An object with the following properties:<ul>
9736          *         <li><b>id:</b> The id of the object being constructed</li>
9737          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
9738          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
9739          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
9740          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
9741          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
9742          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
9743          *             <li><b>content:</b> {String} Raw string of response</li>
9744          *             <li><b>object:</b> {Object} Parsed object of response</li>
9745          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
9746          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
9747          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
9748          *             </ul></li>
9749          *         </ul></li>
9750          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
9751          **/
9752         init: function (options) {
9753             this._super(options);           
9754         },
9755 
9756         /**
9757          * @private
9758          * Gets the REST class for the current object - this is the PhoneBooks class.
9759          */
9760         getRestClass: function () {
9761             return PhoneBooks;
9762         },
9763 
9764         /**
9765          * @private
9766          * Gets the REST class for the objects that make up the collection. - this
9767          * is the PhoneBook class.
9768          */
9769         getRestItemClass: function () {
9770             return PhoneBook;
9771         },
9772 
9773         /**
9774          * @private
9775          * Gets the REST type for the current object - this is a "PhoneBooks".
9776          */
9777         getRestType: function () {
9778             return "PhoneBooks";
9779         },
9780         
9781         /**
9782          * @private
9783          * Gets the REST type for the objects that make up the collection - this is "PhoneBooks".
9784          */
9785         getRestItemType: function () {
9786             return "PhoneBook";
9787         },
9788 
9789         /**
9790          * @private
9791          * Override default to indicates that the collection supports making
9792          * requests.
9793          */
9794         supportsRequests: true,
9795 
9796         /**
9797          * @private
9798          * Override default to indicates that the collection subscribes to its objects.
9799          */
9800         supportsRestItemSubscriptions: false,
9801         
9802         /**
9803          * @private
9804          * Retrieve the PhoneBooks.  This call will re-query the server and refresh the collection.
9805          *
9806          * @returns {finesse.restservices.PhoneBooks}
9807          *     This PhoneBooks object, to allow cascading.
9808          */
9809         get: function () {
9810             // set loaded to false so it will rebuild the collection after the get
9811             this._loaded = false;
9812             // reset collection
9813             this._collection = {};
9814             // perform get
9815             this._synchronize();
9816             return this;
9817         }
9818         
9819     });
9820     
9821     window.finesse = window.finesse || {};
9822     window.finesse.restservices = window.finesse.restservices || {};
9823     window.finesse.restservices.PhoneBooks = PhoneBooks;
9824     
9825     return PhoneBooks;
9826 }));
9827 
9828 /**
9829  * JavaScript representation of the Finesse WorkflowAction object.
9830  *
9831  * @requires finesse.clientservices.ClientServices
9832  * @requires Class
9833  * @requires finesse.FinesseBase
9834  * @requires finesse.restservices.RestBase
9835  */
9836 
9837 /*jslint browser: true, nomen: true, sloppy: true, forin: true */
9838 /*global define,finesse */
9839 
9840 /** @private */
9841 (function (factory) {
9842     
9843 
9844     // Define as an AMD module if possible
9845     if ( typeof define === 'function' && define.amd )
9846     {
9847         define('restservices/WorkflowAction', ['restservices/RestBase'], factory );
9848     }
9849     /* Define using browser globals otherwise
9850      * Prevent multiple instantiations if the script is loaded twice
9851      */
9852     else
9853     {
9854         factory(finesse.restservices.RestBase);
9855     } 
9856 }(function (RestBase) {
9857 
9858     var WorkflowAction = RestBase.extend({
9859 
9860         _contacts: null,
9861 
9862         actionTypes: [
9863             {
9864                 name: 'BROWSER_POP',
9865                 params: [
9866                     {
9867                         name: 'windowName',
9868                         type: 'text'
9869                     },
9870                     {
9871                         name: 'path',
9872                         type: 'systemVariableSingleLineEditor'
9873                     }
9874                 ]
9875             },
9876             {
9877                 name: 'HTTP_REQUEST',
9878                 params: [
9879                     {
9880                         name: 'method',
9881                         type: 'dropdown',
9882                         values: ['POST', 'PUT']
9883                     },
9884                     {
9885                         name: 'location',
9886                         type: 'dropdown',
9887                         values: ['FINESSE', 'OTHER']
9888                     },
9889                     {
9890                         name: 'contentType',
9891                         type: 'text'
9892                     },
9893                     {
9894                         name: 'path',
9895                         type: 'systemVariableSingleLineEditor'
9896                     },
9897                     {
9898                         name: 'body',
9899                         type: 'systemVariableMultiLineEditor'
9900                     }
9901                 ]
9902             }            
9903             // more action type definitions here
9904         ],
9905 
9906         /**
9907          * @class
9908          * A WorkflowAction is an action (e.g. Browser Pop, Rest Request) defined in a
9909          * Workflow and triggered by a system event (Call Received, Call Ended, etc.).
9910          * 
9911          * @augments finesse.restservices.RestBase
9912          * @see finesse.restservices.Workflow
9913          * @constructs
9914          */
9915         _fakeConstuctor: function () {
9916             /* This is here to hide the real init constructor from the public docs */
9917         },
9918         
9919         /**
9920          * @private
9921          * JavaScript representation of a WorkflowAction object. Also exposes
9922          * methods to operate on the object against the server.
9923          *
9924          * @param {Object} options
9925          *     An object with the following properties:<ul>
9926          *         <li><b>id:</b> The id of the object being constructed</li>
9927          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
9928          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
9929          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
9930          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
9931          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
9932          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
9933          *             <li><b>content:</b> {String} Raw string of response</li>
9934          *             <li><b>object:</b> {Object} Parsed object of response</li>
9935          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
9936          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
9937          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
9938          *             </ul></li>
9939          *         </ul></li>
9940          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
9941          **/
9942         init: function (options) {
9943             this._super(options);
9944         },
9945 
9946         /**
9947          * @private
9948          * Gets the REST class for the current object - this is the WorkflowAction class.
9949          * @returns {Object} The WorkflowAction class.
9950          */
9951         getRestClass: function () {
9952             return finesse.restservices.WorkflowAction;
9953         },
9954 
9955         /**
9956          * @private
9957          * Gets the REST type for the current object - this is a "WorkflowAction".
9958          * @returns {String} The WorkflowAction string.
9959          */
9960         getRestType: function () {
9961             return "WorkflowAction";
9962         },
9963 
9964         /**
9965          * @private
9966          * Override default to indicate that this object doesn't support making
9967          * requests.
9968          */
9969         supportsRequests: false,
9970 
9971         /**
9972          * @private
9973          * Override default to indicate that this object doesn't support subscriptions.
9974          */
9975         supportsSubscriptions: false,
9976 
9977         /**
9978          * Getter for the name.
9979          * @returns {String} The name.
9980          */
9981         getName: function () {
9982             this.isLoaded();
9983             return this.getData().name;
9984         },
9985 
9986         /**
9987          * Getter for the type flag.
9988          * @returns {String} The type.
9989          */
9990         getType: function () {
9991             this.isLoaded();
9992             return this.getData().type;
9993         },
9994 
9995         /**
9996          * @private
9997          * Getter for the Uri value.
9998          * @returns {String} The Uri.
9999          */
10000         getUri: function () {
10001             this.isLoaded();
10002             return this.getData().uri;
10003         },
10004 
10005         /**
10006          * @private
10007          * Getter for the handledBy value.
10008          * @returns {String} handledBy.
10009          */
10010         getHandledBy: function () {
10011             this.isLoaded();
10012             return this.getData().handledBy;
10013         },
10014 
10015         /**
10016          * Getter for the parameters.
10017          * @returns {Object} key = param name, value = param value
10018          */
10019         getParams: function () {
10020             var map = {},
10021                 params = this.getData().params.Param,
10022                 i,
10023                 param;
10024 
10025             for(i=0; i<params.length; i+=1){
10026                 param = params[i];
10027                 map[param.name] = param.value || "";
10028             }
10029 
10030             return map;
10031         },
10032 
10033         /**
10034          * Getter for the ActionVariables
10035          * @returns {Object} key = action variable name, value = Object{name, type, node, testValue}
10036          */
10037         getActionVariables: function() {
10038             var map = {},
10039                 actionVariablesParent = this.getData().actionVariables,
10040                 actionVariables,
10041                 i,
10042                 actionVariable;
10043 
10044             if (actionVariablesParent === null ||  typeof(actionVariablesParent) === "undefined" || actionVariablesParent.length === 0){
10045                 return map;
10046             }
10047             actionVariables = actionVariablesParent.ActionVariable;
10048 
10049             if(actionVariables.length > 0){
10050                 for(i=0; i<actionVariables.length; i+=1){
10051                     actionVariable = actionVariables[i];
10052                     // escape nulls to empty string
10053                     actionVariable.name = actionVariable.name || "";
10054                     actionVariable.type = actionVariable.type || "";
10055                     actionVariable.node = actionVariable.node || "";
10056                     actionVariable.testValue = actionVariable.testValue || "";
10057                     map[actionVariable.name] = actionVariable;
10058                 }
10059             } else {
10060                 map[actionVariables.name] = actionVariables;
10061             }
10062 
10063             return map;
10064         },
10065 
10066         /** @private */
10067         createPutSuccessHandler: function(action, contentBody, successHandler){
10068             return function (rsp) {
10069                 // Update internal structure based on response. Here we
10070                 // inject the contentBody from the PUT request into the
10071                 // rsp.object element to mimic a GET as a way to take
10072                 // advantage of the existing _processResponse method.
10073                 rsp.object = contentBody;
10074                 action._processResponse(rsp);
10075 
10076                 //Remove the injected WorkflowAction object before cascading response
10077                 rsp.object = {};
10078                 
10079                 //cascade response back to consumer's response handler
10080                 successHandler(rsp);
10081             };
10082         },
10083 
10084         /** @private */
10085         createPostSuccessHandler: function (action, contentBody, successHandler) {
10086             return function (rsp) {
10087                 rsp.object = contentBody;
10088                 action._processResponse(rsp);
10089 
10090                 //Remove the injected WorkflowAction object before cascading response
10091                 rsp.object = {};
10092 
10093                 //cascade response back to consumer's response handler
10094                 successHandler(rsp);
10095             };
10096         },
10097 
10098         /**
10099          * @private
10100          * Build params array out of all the values coming into add or update methods
10101          * paramMap is a map of params.. we need to translate it into an array of Param objects
10102          * where path and windowName are params for the BROWSER_POP type
10103          */
10104         buildParamsForRest: function(paramMap){
10105             var params = {"Param": []},
10106                 i;
10107             for(i in paramMap){
10108                 if(paramMap.hasOwnProperty(i)){
10109                     params.Param.push({name: i, value: paramMap[i]});
10110                 }
10111             }
10112             return params;
10113         },
10114 
10115         /**
10116          * @private
10117          * Build actionVariables array out of all the values coming into add or update methods
10118          * actionVariableMap is a map of actionVariables.. we need to translate it into an array of ActionVariable objects
10119          * where path and windowName are params for the BROWSER_POP type
10120          */
10121         buildActionVariablesForRest: function(actionVariableMap){
10122             var actionVariables = {"ActionVariable": []},
10123                 i,
10124                 actionVariable;
10125             for(i in actionVariableMap){
10126                 if(actionVariableMap.hasOwnProperty(i)){
10127                     // {name: "callVariable1", type: "SYSTEM", node: "", testValue: "<blink>"}
10128                     actionVariable = {
10129                         "name": actionVariableMap[i].name,
10130                         "type": actionVariableMap[i].type,
10131                         "node": actionVariableMap[i].node,
10132                         "testValue": actionVariableMap[i].testValue
10133                     };
10134                     actionVariables.ActionVariable.push(actionVariable);
10135                 }
10136             }
10137             return actionVariables;
10138         },
10139 
10140         /**
10141          * Add
10142          */
10143         add: function (newValues, handlers) {
10144             var contentBody = {};
10145 
10146             contentBody[this.getRestType()] = {
10147                 "name": newValues.name,
10148                 "type": newValues.type,
10149                 "handledBy": newValues.handledBy,
10150                 "params": this.buildParamsForRest(newValues.params),
10151                 "actionVariables": this.buildActionVariablesForRest(newValues.actionVariables)
10152             };
10153 
10154             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
10155             handlers = handlers || {};
10156 
10157             this.restRequest(this.getRestUrl(), {
10158                 method: 'POST',
10159                 success: this.createPostSuccessHandler(this, contentBody, handlers.success),
10160                 error: handlers.error,
10161                 content: contentBody
10162             });
10163 
10164             return this; // Allow cascading
10165         },
10166 
10167         /**
10168          * @private
10169          * Update
10170          */
10171         update: function (newValues, handlers) {
10172             this.isLoaded();
10173             var contentBody = {};
10174             
10175             contentBody[this.getRestType()] = {
10176                 "uri": this.getId(),
10177                 "name": newValues.name,
10178                 "type": newValues.type,
10179                 "handledBy": newValues.handledBy,
10180                 "params": this.buildParamsForRest(newValues.params),
10181                 "actionVariables": this.buildActionVariablesForRest(newValues.actionVariables)
10182             };
10183 
10184             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
10185             handlers = handlers || {};
10186 
10187             this.restRequest(this.getRestUrl(), {
10188                 method: 'PUT',
10189                 success: this.createPutSuccessHandler(this, contentBody, handlers.success),
10190                 error: handlers.error,
10191                 content: contentBody
10192             });
10193 
10194             return this; // Allow cascading
10195         },
10196 
10197 
10198         /**
10199          * @private
10200          * Delete
10201          */
10202         "delete": function ( handlers) {
10203             this.isLoaded();
10204 
10205             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
10206             handlers = handlers || {};
10207 
10208             this.restRequest(this.getRestUrl(), {
10209                 method: 'DELETE',
10210                 success: this.createPutSuccessHandler(this, {}, handlers.success),
10211                 error: handlers.error,
10212                 content: undefined
10213             });
10214 
10215             return this; // Allow cascading
10216         }
10217 
10218 
10219 
10220     });
10221 
10222     window.finesse = window.finesse || {};
10223     window.finesse.restservices = window.finesse.restservices || {};
10224     window.finesse.restservices.WorkflowAction = WorkflowAction;
10225     
10226     return WorkflowAction;
10227 }));
10228 
10229 /**
10230 * JavaScript representation of the Finesse WorkflowActions collection
10231 * object which contains a list of WorkflowAction objects.
10232  *
10233  * @requires finesse.clientservices.ClientServices
10234  * @requires Class
10235  * @requires finesse.FinesseBase
10236  * @requires finesse.restservices.RestBase
10237  * @requires finesse.restservices.Dialog
10238  * @requires finesse.restservices.RestCollectionBase
10239  */
10240 
10241 /** @private */
10242 (function (factory) {
10243     
10244 
10245     // Define as an AMD module if possible
10246     if ( typeof define === 'function' && define.amd )
10247     {
10248         define('restservices/WorkflowActions', ['restservices/RestCollectionBase',
10249                  'restservices/RestBase',
10250                  'restservices/WorkflowAction'], factory );
10251     }
10252     /* Define using browser globals otherwise
10253      * Prevent multiple instantiations if the script is loaded twice
10254      */
10255     else
10256     {
10257         factory(finesse.restservices.RestCollectionBase, finesse.restservices.RestBase, finesse.restservices.WorkflowAction);
10258     } 
10259 }(function (RestCollectionBase, RestBase, WorkflowAction) {
10260 
10261     var WorkflowActions = RestCollectionBase.extend({
10262         
10263         /**
10264          * @class
10265          * JavaScript representation of a WorkflowActions collection object. 
10266          * @augments finesse.restservices.RestCollectionBase
10267          * @constructs
10268          * @see finesse.restservices.WorkflowAction
10269          * @see finesse.restservices.Workflow
10270          * @see finesse.restservices.Workflows
10271          * @example
10272          *  _workflowActions = _user.getWorkflowActions( {
10273          *      onCollectionAdd : _handleWorkflowActionAdd,
10274          *      onCollectionDelete : _handleWorkflowActionDelete,
10275          *      onLoad : _handleWorkflowActionsLoaded
10276          *  });
10277         */
10278         _fakeConstuctor: function () {
10279             /* This is here to hide the real init constructor from the public docs */
10280         },
10281         
10282         /**
10283          * @private
10284          * JavaScript representation of a WorkflowActions collection object. Also exposes
10285          * methods to operate on the object against the server.
10286          *
10287          * @param {Object} options
10288          *     An object with the following properties:<ul>
10289          *         <li><b>id:</b> The id of the object being constructed</li>
10290          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
10291          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
10292          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
10293          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
10294          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
10295          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
10296          *             <li><b>content:</b> {String} Raw string of response</li>
10297          *             <li><b>object:</b> {Object} Parsed object of response</li>
10298          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
10299          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
10300          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
10301          *             </ul></li>
10302          *         </ul></li>
10303          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
10304          **/
10305         init: function (options) {
10306             this._super(options);           
10307         },
10308 
10309         /**
10310          * @private
10311          * Gets the REST class for the current object - this is the WorkflowActions class.
10312          */
10313         getRestClass: function () {
10314             return WorkflowActions;
10315         },
10316 
10317         /**
10318          * @private
10319          * Gets the REST class for the objects that make up the collection. - this
10320          * is the WorkflowAction class.
10321          */
10322         getRestItemClass: function () {
10323             return WorkflowAction;
10324         },
10325 
10326         /**
10327          * @private
10328          * Gets the REST type for the current object - this is a "WorkflowActions".
10329          */
10330         getRestType: function () {
10331             return "WorkflowActions";
10332         },
10333         
10334         /**
10335          * @private
10336          * Gets the REST type for the objects that make up the collection - this is "WorkflowActions".
10337          */
10338         getRestItemType: function () {
10339             return "WorkflowAction";
10340         },
10341 
10342         /**
10343          * @private
10344          * Override default to indicates that the collection supports making
10345          * requests.
10346          */
10347         supportsRequests: true,
10348 
10349         /**
10350          * @private
10351          * Override default to indicates that the collection subscribes to its objects.
10352          */
10353         supportsRestItemSubscriptions: false,
10354         
10355         /**
10356          * @private
10357          * Retrieve the WorkflowActions.
10358          *
10359          * @returns {finesse.restservices.WorkflowActions}
10360          *     This WorkflowActions object to allow cascading.
10361          */
10362         get: function () {
10363             // set loaded to false so it will rebuild the collection after the get
10364             this._loaded = false;
10365             // reset collection
10366             this._collection = {};
10367             // perform get
10368             this._synchronize();
10369             return this;
10370         }
10371     });
10372 
10373     window.finesse = window.finesse || {};
10374     window.finesse.restservices = window.finesse.restservices || {};
10375     window.finesse.restservices.WorkflowActions = WorkflowActions;
10376         
10377     return WorkflowActions;
10378 }));
10379 
10380 /**
10381  * JavaScript representation of the Finesse Workflow object.
10382  *
10383  * @requires finesse.clientservices.ClientServices
10384  * @requires Class
10385  * @requires finesse.FinesseBase
10386  * @requires finesse.restservices.RestBase
10387  */
10388 
10389 /*jslint browser: true, nomen: true, sloppy: true, forin: true */
10390 /*global define,finesse */
10391 
10392 /** @private */
10393 (function (factory) {
10394     
10395 
10396     if (typeof define === 'function' && define.amd) {
10397         // Define as an AMD module if possible
10398         define('restservices/Workflow',['restservices/RestBase',
10399 				'restservices/WorkflowActions'], factory);
10400     } else {
10401         /* Define using browser globals otherwise
10402          * Prevent multiple instantiations if the script is loaded twice
10403          */
10404         factory(finesse.restservices.RestBase,
10405 				finesse.restservices.WorkflowActions);
10406     }
10407 }(function (RestBase, WorkflowActions) {
10408 
10409     var Workflow = RestBase.extend({
10410 
10411         /**
10412          * @class
10413          * JavaScript representation of a Workflow object. Also exposes
10414          * methods to operate on the object against the server.
10415          *
10416          * @param {Object} options
10417          *     An object with the following properties:<ul>
10418          *         <li><b>id:</b> The id of the object being constructed</li>
10419          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
10420          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
10421          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
10422          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
10423          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
10424          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
10425          *             <li><b>content:</b> {String} Raw string of response</li>
10426          *             <li><b>object:</b> {Object} Parsed object of response</li>
10427          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
10428          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
10429          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
10430          *             </ul></li>
10431          *         </ul></li>
10432          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
10433          * @constructs
10434          **/
10435         init: function (options) {
10436             this._super(options);
10437         },
10438 
10439         /**
10440          * @private
10441          * Gets the REST class for the current object - this is the Workflow class.
10442          * @returns {Object} The Workflow class.
10443          */
10444         getRestClass: function () {
10445             return Workflow;
10446         },
10447 
10448         /**
10449          * @private
10450          * Gets the REST type for the current object - this is a "Workflow".
10451          * @returns {String} The Workflow string.
10452          */
10453         getRestType: function () {
10454             return "Workflow";
10455         },
10456 
10457         /**
10458          * @private
10459          * Override default to indicate that this object doesn't support making
10460          * requests.
10461          */
10462         supportsRequests: false,
10463 
10464         /**
10465          * @private
10466          * Override default to indicate that this object doesn't support subscriptions.
10467          */
10468         supportsSubscriptions: false,
10469 
10470         /**
10471          * @private
10472          * Getter for the Uri value.
10473          * @returns {String} The Uri.
10474          */
10475         getUri: function () {
10476             this.isLoaded();
10477             return this.getData().uri;
10478         },
10479 
10480         /**
10481          * Getter for the name.
10482          * @returns {String} The name.
10483          */
10484         getName: function () {
10485             this.isLoaded();
10486             return this.getData().name;
10487         },
10488 
10489         /**
10490          * Getter for the description.
10491          * @returns {String} The description.
10492          */
10493         getDescription: function () {
10494             this.isLoaded();
10495             return this.getData().description;
10496         },
10497 
10498         /**
10499          * Getter for the trigger set.
10500          * @returns {String} The trigger set.
10501          */
10502         getTriggerSet: function () {
10503             this.isLoaded();
10504             return this.getData().TriggerSet;
10505         },
10506 
10507         /**
10508          * Getter for the condition set.
10509          * @returns {String} The condition set.
10510          */
10511         getConditionSet: function () {
10512             this.isLoaded();
10513             return this.getData().ConditionSet;
10514         },
10515         
10516         /**
10517          * Getter for the assigned workflowActions.
10518          * @returns {String} The workflowActions object.
10519          */
10520         getWorkflowActions: function () {
10521             this.isLoaded();
10522             var workflowActions = this.getData().workflowActions;
10523             if (workflowActions === null) {
10524                 workflowActions = "";
10525             }
10526             return workflowActions;
10527         },
10528 
10529         createPutSuccessHandler: function (workflow, contentBody, successHandler) {
10530             return function (rsp) {
10531                 // Update internal structure based on response. Here we
10532                 // inject the contentBody from the PUT request into the
10533                 // rsp.object element to mimic a GET as a way to take
10534                 // advantage of the existing _processResponse method.
10535                 rsp.object = contentBody;
10536                 workflow._processResponse(rsp);
10537 
10538                 //Remove the injected Workflow object before cascading response
10539                 rsp.object = {};
10540 
10541                 //cascade response back to consumer's response handler
10542                 successHandler(rsp);
10543             };
10544         },
10545 
10546         createPostSuccessHandler: function (workflow, contentBody, successHandler) {
10547             return function (rsp) {
10548                 rsp.object = contentBody;
10549                 workflow._processResponse(rsp);
10550 
10551                 //Remove the injected Workflow object before cascading response
10552                 rsp.object = {};
10553 
10554                 //cascade response back to consumer's response handler
10555                 successHandler(rsp);
10556             };
10557         },
10558 
10559         /**
10560          * @private
10561          * Add
10562          */
10563         add: function (newValues, handlers) {
10564             // this.isLoaded();
10565             var contentBody = {};
10566 
10567             contentBody[this.getRestType()] = {
10568                 "name": newValues.name,
10569                 "description": newValues.description,
10570                 "TriggerSet" : newValues.TriggerSet,
10571                 "ConditionSet" : newValues.ConditionSet,
10572                 "workflowActions" : newValues.workflowActions
10573             };
10574 
10575             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
10576             handlers = handlers || {};
10577 
10578             this.restRequest(this.getRestUrl(), {
10579                 method: 'POST',
10580                 success: this.createPostSuccessHandler(this, contentBody, handlers.success),
10581                 error: handlers.error,
10582                 content: contentBody
10583             });
10584 
10585             return this; // Allow cascading
10586         },
10587 
10588         /**
10589          * @private
10590          * Update
10591          */
10592         update: function (newValues, handlers) {
10593             this.isLoaded();
10594             var contentBody = {};
10595 
10596             contentBody[this.getRestType()] = {
10597                 "uri": this.getId(),
10598                 "name": newValues.name,
10599                 "description": newValues.description,
10600                 "TriggerSet" : newValues.TriggerSet,
10601                 "ConditionSet" : newValues.ConditionSet,
10602                 "workflowActions" : newValues.workflowActions
10603             };
10604 
10605             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
10606             handlers = handlers || {};
10607 
10608             this.restRequest(this.getRestUrl(), {
10609                 method: 'PUT',
10610                 success: this.createPutSuccessHandler(this, contentBody, handlers.success),
10611                 error: handlers.error,
10612                 content: contentBody
10613             });
10614 
10615             return this; // Allow cascading
10616         },
10617 
10618 
10619         /**
10620          * @private
10621          * Delete
10622          */
10623         "delete": function (handlers) {
10624             this.isLoaded();
10625 
10626             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
10627             handlers = handlers || {};
10628 
10629             this.restRequest(this.getRestUrl(), {
10630                 method: 'DELETE',
10631                 success: this.createPutSuccessHandler(this, {}, handlers.success),
10632                 error: handlers.error,
10633                 content: undefined
10634             });
10635 
10636             return this; // Allow cascading
10637         }
10638 
10639 
10640 
10641     });
10642 
10643     window.finesse = window.finesse || {};
10644     window.finesse.restservices = window.finesse.restservices || {};
10645     window.finesse.restservices.Workflow = Workflow;
10646 
10647     return Workflow;
10648 }));
10649 
10650 /**
10651 * JavaScript representation of the Finesse workflows collection
10652 * object which contains a list of workflow objects.
10653  *
10654  * @requires finesse.clientservices.ClientServices
10655  * @requires Class
10656  * @requires finesse.FinesseBase
10657  * @requires finesse.restservices.RestBase
10658  * @requires finesse.restservices.Dialog
10659  * @requires finesse.restservices.RestCollectionBase
10660  */
10661 
10662 /** @private */
10663 (function (factory) {
10664     
10665 
10666     // Define as an AMD module if possible
10667     if ( typeof define === 'function' && define.amd )
10668     {
10669         define('restservices/Workflows', ['restservices/RestCollectionBase',
10670                  'restservices/RestBase',
10671                  'restservices/Workflow'], factory );
10672     }
10673     /* Define using browser globals otherwise
10674      * Prevent multiple instantiations if the script is loaded twice
10675      */
10676     else
10677     {
10678         factory(finesse.restservices.RestCollectionBase, finesse.restservices.RestBase, finesse.restservices.Workflow);
10679     } 
10680 }(function (RestCollectionBase, RestBase, Workflow) {
10681 
10682     var Workflows = RestCollectionBase.extend({
10683 
10684         /**
10685          * @class
10686          * JavaScript representation of a workflows collection object. Also exposes
10687          * methods to operate on the object against the server.
10688          *
10689          * @param {Object} options
10690          *     An object with the following properties:<ul>
10691          *         <li><b>id:</b> The id of the object being constructed</li>
10692          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
10693          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
10694          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
10695          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
10696          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
10697          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
10698          *             <li><b>content:</b> {String} Raw string of response</li>
10699          *             <li><b>object:</b> {Object} Parsed object of response</li>
10700          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
10701          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
10702          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
10703          *             </ul></li>
10704          *         </ul></li>
10705          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
10706          *  @constructs
10707          **/
10708         init: function (options) {
10709             this._super(options);
10710         },
10711 
10712         /**
10713          * @private
10714          * Gets the REST class for the current object - this is the workflows class.
10715          */
10716         getRestClass: function () {
10717             return Workflows;
10718         },
10719 
10720         /**
10721          * @private
10722          * Gets the REST class for the objects that make up the collection. - this
10723          * is the workflow class.
10724          */
10725         getRestItemClass: function () {
10726             return Workflow;
10727         },
10728 
10729         /**
10730          * @private
10731          * Gets the REST type for the current object - this is a "workflows".
10732          */
10733         getRestType: function () {
10734             return "Workflows";
10735         },
10736 
10737         /**
10738          * @private
10739          * Gets the REST type for the objects that make up the collection - this is "workflows".
10740          */
10741         getRestItemType: function () {
10742             return "Workflow";
10743         },
10744 
10745         /**
10746          * @private
10747          * Override default to indicates that the collection supports making requests.
10748          */
10749         supportsRequests: true,
10750 
10751         /**
10752          * @private
10753          * Override default to indicates that the collection does not subscribe to its objects.
10754          */
10755         supportsRestItemSubscriptions: false,
10756 
10757         /**
10758          * @private
10759          * Retrieve the workflows. This call will re-query the server and refresh the collection.
10760          *
10761          * @returns {finesse.restservices.workflows}
10762          *     This workflows object to allow cascading.
10763          */
10764         get: function () {
10765             // set loaded to false so it will rebuild the collection after the get
10766             this._loaded = false;
10767             // reset collection
10768             this._collection = {};
10769             // perform get
10770             this._synchronize();
10771             return this;
10772         }
10773     });
10774 
10775     window.finesse = window.finesse || {};
10776     window.finesse.restservices = window.finesse.restservices || {};
10777     window.finesse.restservices.Workflows = Workflows;
10778         
10779     return Workflows;
10780 }));
10781 
10782 /**
10783  * JavaScript representation of the Finesse MediaPropertiesLayout object
10784  *
10785  * @requires finesse.clientservices.ClientServices
10786  * @requires Class
10787  * @requires finesse.FinesseBase
10788  * @requires finesse.restservices.RestBase
10789  */
10790 
10791 /** The following comment is to prevent jslint errors about 
10792  * using variables before they are defined.
10793  */
10794 /*global finesse*/
10795 
10796 /** @private */
10797 (function (factory) {
10798     
10799 
10800     // Define as an AMD module if possible
10801     if ( typeof define === 'function' && define.amd )
10802     {
10803         define('restservices/MediaPropertiesLayout', ['restservices/RestBase'], factory );
10804     }
10805     /* Define using browser globals otherwise
10806      * Prevent multiple instantiations if the script is loaded twice
10807      */
10808     else
10809     {
10810         factory(finesse.restservices.RestBase);
10811     } 
10812 }(function (RestBase) {
10813     var MediaPropertiesLayout = RestBase.extend(/** @lends finesse.restservices.MediaPropertiesLayout.prototype */{
10814 
10815         /**
10816          * @class
10817          * The MediaPropertiesLayout handles which call variables are associated with Dialogs.
10818          * 
10819          * @augments finesse.restservices.RestBase
10820          * @see finesse.restservices.Dialog#getMediaProperties
10821          * @see finesse.restservices.User#getMediaPropertiesLayout
10822          * @constructs
10823          */
10824         _fakeConstuctor: function () {
10825             /* This is here to hide the real init constructor from the public docs */
10826         },
10827         
10828         /**
10829          * @private
10830          * JavaScript representation of a MediaPropertiesLayout object. Also exposes
10831          * methods to operate on the object against the server.
10832          *
10833          * @param {Object} options
10834          *     An object with the following properties:<ul>
10835          *         <li><b>id:</b> The id of the object being constructed</li>
10836          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
10837          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
10838          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
10839          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
10840          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
10841          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
10842          *             <li><b>content:</b> {String} Raw string of response</li>
10843          *             <li><b>object:</b> {Object} Parsed object of response</li>
10844          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
10845          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
10846          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
10847          *             </ul></li>
10848          *         </ul></li>
10849          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
10850          **/
10851         init: function (options) {
10852             this._super(options);
10853         },
10854 
10855         /**
10856          * @private
10857          * Gets the REST class for the current object - this is the MediaPropertiesLayout object.
10858          */
10859         getRestClass: function () {
10860             return MediaPropertiesLayout;
10861         },
10862 
10863         /**
10864          * @private
10865          * Gets the REST type for the current object - this is a "MediaPropertiesLayout".
10866          */
10867         getRestType: function () {
10868             return "MediaPropertiesLayout";
10869         },
10870 
10871         /**
10872          * @private
10873          * Overrides the parent class.  Returns the url for the MediaPropertiesLayout resource
10874          */
10875         getRestUrl: function () {
10876             return ("/finesse/api/User/" + this.getId() + "/" + this.getRestType());
10877         },
10878 
10879         /**
10880          * @private
10881          * Returns whether this object supports subscriptions
10882          */
10883         supportsSubscriptions: false,
10884 
10885         /**
10886          * Retrieve the media properties layout. This call will re-query the server and refresh the layout object.
10887          * @returns {finesse.restservices.MediaPropertiesLayout}
10888          *     This MediaPropertiesLayout object to allow cascading
10889          */
10890         get: function () {
10891             this._synchronize();
10892 
10893             return this; //Allow cascading
10894         },
10895 
10896         /**
10897          * Gets the data for this object.
10898          * 
10899          * Performs safe conversion from raw API data to ensure that the returned layout object
10900          * always has a header with correct entry fields, and exactly two columns with lists of entries.
10901          *
10902          * @returns {finesse.restservices.MediaPropertiesLayout.Object} Data in columns (unless only one defined).
10903          */
10904         getData: function () {
10905 
10906             var layout = this._data, result, _addColumnData;
10907 
10908             result = this.getEmptyData();
10909 
10910             /**
10911              * @private
10912              */
10913             _addColumnData = function (entryData, colIndex) {
10914 
10915                 if (!entryData) {
10916                     //If there's no entry data at all, rewrite entryData to be an empty collection of entries
10917                     entryData = {};
10918                 } else if (entryData.mediaProperty) {
10919                     //If entryData contains the keys for a single entry rather than being a collection of entries,
10920                     //rewrite it to be a collection containing a single entry
10921                     entryData = { "": entryData };
10922                 }
10923 
10924                 //Add each of the entries in the list to the column
10925                 jQuery.each(entryData, function (i, entryData) {
10926 
10927                     //If the entry has no displayName specified, explicitly set it to the empty string
10928                     if (!entryData.displayName) {
10929                         entryData.displayName = "";
10930                     }
10931 
10932                     result.columns[colIndex].push(entryData);
10933 
10934                 });
10935 
10936             };
10937 
10938             //The header should only contain a single entry
10939             if (layout.header && layout.header.entry) {
10940 
10941                 //If the entry has no displayName specified, explicitly set it to the empty string
10942                 if (!layout.header.entry.displayName) {
10943                     layout.header.entry.displayName = "";
10944                 }
10945 
10946                 result.header = layout.header.entry;
10947 
10948             } else {
10949 
10950                 throw "MediaPropertiesLayout.getData() - Header does not contain an entry";
10951 
10952             }
10953 
10954             //If the column object contains an entry object that wasn't part of a list of entries,
10955             //it must be a single right-hand entry object (left-hand entry object would be part of a list.)
10956             //Force the entry object to be the 2nd element in an otherwise-empty list.
10957             if (layout.column && layout.column.entry) {
10958                 layout.column = [
10959                     null,
10960                     { "entry": layout.column.entry }
10961                 ];
10962             }
10963 
10964             if (layout.column && layout.column.length > 0 && layout.column.length <= 2) {
10965 
10966                 //Render left column entries
10967                 if (layout.column[0] && layout.column[0].entry) {
10968                     _addColumnData(layout.column[0].entry, 0);
10969                 }
10970 
10971                 //Render right column entries
10972                 if (layout.column[1] && layout.column[1].entry) {
10973                     _addColumnData(layout.column[1].entry, 1);
10974                 }
10975 
10976             }
10977 
10978             return result;
10979 
10980         },
10981 
10982         /**
10983          * @private
10984          * Empty/template version of getData().
10985          *
10986          * Used by getData(), and by callers of getData() in error cases.
10987          */
10988         getEmptyData: function () {
10989 
10990             return {
10991                 header : {
10992                     displayName: null,
10993                     mediaProperty: null
10994                 },
10995                 columns : [[], []]
10996             };
10997 
10998         },
10999 
11000         /**
11001          * @private
11002          * Set the layout of this MediaPropertiesLayout.
11003          * @param {String} layout
11004          *     The layout you are setting
11005          * @param {finesse.interfaces.RequestHandlers} handlers
11006          *     An object containing the handlers for the request
11007          * @returns {finesse.restservices.MediaPropertiesLayout}
11008          *     This MediaPropertiesLayout object to allow cascading
11009          */
11010         setLayout: function (layout, handlers) {
11011 
11012             var contentBody = {};
11013 
11014             contentBody[this.getRestType()] = layout;
11015 
11016             //Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
11017             handlers = handlers || {};
11018 
11019             this.restRequest(this.getRestUrl(), {
11020                 method: 'PUT',
11021                 success: handlers.success,
11022                 error: handlers.error,
11023                 content: contentBody
11024             });
11025 
11026             return this; // Allow cascading
11027         }
11028 
11029     });
11030     
11031     MediaPropertiesLayout.Object = /** @lends finesse.restservices.MediaPropertiesLayout.Object.prototype */ {
11032         /**
11033          * @class Format of MediaPropertiesLayout Object.<br>
11034          * Object { <ul>
11035          *      <li>header : { <ul>
11036          *          <li>dispayName {String} 
11037          *          <li>mediaProperty {String}</ul>}
11038          *      <li>columns : { <ul>
11039          *          <li>[ [] , [] ]
11040          *          </ul>
11041          *      where column arrays consists of the same Object format as header.<br>
11042          *          }</ul>
11043          *      }<br>         
11044          * @constructs
11045          */
11046         _fakeConstructor : function () {} // For JS Doc to work need a constructor so that the lends/constructs build the doc properly
11047         
11048     };
11049 
11050 	window.finesse = window.finesse || {};
11051     window.finesse.restservices = window.finesse.restservices || {};
11052     window.finesse.restservices.MediaPropertiesLayout = MediaPropertiesLayout;
11053     
11054     return MediaPropertiesLayout;
11055 }));
11056 
11057 /**
11058  * JavaScript representation of the Finesse User object
11059  *
11060  * @requires finesse.clientservices.ClientServices
11061  * @requires Class
11062  * @requires finesse.FinesseBase
11063  * @requires finesse.restservices.RestBase
11064  */
11065 
11066 /** @private */
11067 (function (factory) {
11068     
11069 
11070     // Define as an AMD module if possible
11071     if ( typeof define === 'function' && define.amd )
11072     {
11073         define('restservices/User', ['restservices/RestBase',
11074                  'restservices/Dialogs',
11075                  'restservices/ClientLog',
11076                  'restservices/Queues',
11077                  'restservices/WrapUpReasons',
11078                  'restservices/PhoneBooks',
11079                  'restservices/Workflows',
11080                  'restservices/MediaPropertiesLayout',
11081                  'utilities/Utilities'], factory );
11082     }
11083     /* Define using browser globals otherwise
11084      * Prevent multiple instantiations if the script is loaded twice
11085      */
11086     else
11087     {
11088         factory(finesse.restservices.RestBase, 
11089         finesse.restservices.Dialogs, 
11090         finesse.restservices.ClientLog,
11091         finesse.restservices.Queues,
11092         finesse.restservices.WrapUpReasons,
11093         finesse.restservices.PhoneBooks,
11094         finesse.restservices.Workflows,
11095         finesse.restservices.MediaPropertiesLayout,
11096         finesse.utilities.Utilities);
11097     } 
11098 }(function (RestBase, 
11099             Dialogs, 
11100             ClientLog,
11101             Queues,
11102             WrapUpReasons,
11103             PhoneBooks,
11104             Workflows,
11105             MediaPropertiesLayout,
11106             Utilities) {
11107     
11108     var User = RestBase.extend(/** @lends finesse.restservices.User.prototype */{
11109 
11110         _dialogs : null,
11111         _clientLogObj : null,
11112         _wrapUpReasons : null,
11113         _phoneBooks : null,
11114         _workflows : null,
11115         _mediaPropertiesLayout : null,
11116         _queues : null,
11117         
11118         /**
11119          * @class
11120          * The User represents a Finesse Agent or Supervisor.
11121          *
11122          * @param {Object} options
11123          *     An object with the following properties:<ul>
11124          *         <li><b>id:</b> The id of the object being constructed</li>
11125          *         <li><b>onLoad(this): (optional)</b> callback handler for when the object is successfully loaded from the server</li>
11126          *         <li><b>onChange(this): (optional)</b> callback handler for when an update notification of the object is received</li>
11127          *         <li><b>onAdd(this): (optional)</b> callback handler for when a notification that the object is created is received</li>
11128          *         <li><b>onDelete(this): (optional)</b> callback handler for when a notification that the object is deleted is received</li>
11129          *         <li><b>onError(rsp): (optional)</b> callback handler for if loading of the object fails, invoked with the error response object:<ul>
11130          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
11131          *             <li><b>content:</b> {String} Raw string of response</li>
11132          *             <li><b>object:</b> {Object} Parsed object of response</li>
11133          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
11134          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
11135          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
11136          *             </ul></li>
11137          *         </ul></li>
11138          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
11139          * @augments finesse.restservices.RestBase
11140          * @constructs
11141          * @example
11142          *      _user = new finesse.restservices.User({
11143          *                      id: _id, 
11144          *                      onLoad : _handleUserLoad,
11145          *                      onChange : _handleUserChange
11146          *      });
11147          **/
11148         init: function (options) {
11149             this._super(options);
11150         },
11151         
11152         Callbacks: {},
11153     
11154         /**
11155          * @private
11156          * Gets the REST class for the current object - this is the User object.
11157          */
11158         getRestClass: function () {
11159             return User;
11160         },
11161     
11162         /**
11163         * @private
11164          * Gets the REST type for the current object - this is a "User".
11165          */
11166         getRestType: function () {
11167             return "User";
11168         },
11169         /**
11170          * @private
11171          * overloading this to return URI
11172          */
11173         getXMPPNodePath: function () {
11174             return this.getRestUrl();
11175         },
11176         /**
11177         * @private
11178          * Returns whether this object supports subscriptions
11179          */
11180         supportsSubscriptions: function () {
11181             return true;
11182         },
11183     
11184         /**
11185          * Getter for the firstName of this User.
11186          * @returns {String}
11187          *     The firstName for this User
11188          */
11189         getFirstName: function () {
11190             this.isLoaded();
11191             return Utilities.convertNullToEmptyString(this.getData().firstName);
11192         },
11193     
11194         /**
11195          * Getter for the lastName of this User.
11196          * @returns {String}
11197          *     The lastName for this User
11198          */
11199         getLastName: function () {
11200             this.isLoaded();
11201             return Utilities.convertNullToEmptyString(this.getData().lastName);
11202         },
11203     
11204         /**
11205          * Getter for the extension of this User.
11206          * @returns {String}
11207          *     The extension, if any, of this User
11208          */
11209         getExtension: function () {
11210             this.isLoaded();
11211             return Utilities.convertNullToEmptyString(this.getData().extension);
11212         },
11213         
11214         /**
11215          * Getter for the id of the Team of this User
11216          * @returns {String}
11217          *     The current (or last fetched) id of the Team of this User
11218          */
11219         getTeamId: function () {
11220             this.isLoaded();
11221             return this.getData().teamId;
11222         },
11223         
11224         /**
11225          * Getter for the name of the Team of this User
11226          * @returns {String}
11227          *     The current (or last fetched) name of the Team of this User
11228          */
11229         getTeamName: function () {
11230             this.isLoaded();
11231             return this.getData().teamName;
11232         },
11233         
11234         /**
11235          * Is user an agent?
11236          * @returns {Boolean} True if user has role of agent, else false.
11237          */
11238         hasAgentRole: function () {
11239             this.isLoaded();
11240             return this.hasRole("Agent");
11241         },
11242     
11243         /**
11244          * Is user a supervisor?
11245          * @returns {Boolean} True if user has role of supervisor, else false.
11246          */
11247         hasSupervisorRole: function () {
11248             this.isLoaded();
11249             return this.hasRole("Supervisor");
11250         },
11251     
11252         /**
11253          * @private
11254          * Checks to see if user has "theRole"
11255          * @returns {Boolean}
11256          */
11257         hasRole: function (theRole) {
11258             this.isLoaded();
11259             var result = false, i, roles, len;
11260     
11261             roles = this.getData().roles.role;
11262             len = roles.length;
11263             if (typeof roles === 'string') {
11264                 if (roles === theRole) {
11265                     result = true;
11266                 }
11267             } else {
11268                 for (i = 0; i < len ; i = i + 1) {
11269                     if (roles[i] === theRole) {
11270                         result = true;
11271                         break;
11272                     }
11273                 }
11274             }
11275     
11276             return result;
11277         },
11278 
11279         /**
11280          * Getter for the pending state of this User.
11281          * @returns {String}
11282          *     The pending state of this User
11283          * @see finesse.restservices.User.States
11284          */
11285         getPendingState: function () {
11286             this.isLoaded();
11287             return Utilities.convertNullToEmptyString(this.getData().pendingState);
11288         },
11289     
11290         /**
11291          * Getter for the state of this User.
11292          * @returns {String}
11293          *     The current (or last fetched) state of this User
11294          * @see finesse.restservices.User.States
11295          */
11296         getState: function () {
11297             this.isLoaded();
11298             return this.getData().state;
11299         },
11300 
11301         /**
11302          * Getter for the state change time of this User.
11303          * @returns {String}
11304          *     The state change time of this User
11305          */
11306         getStateChangeTime: function () {
11307             this.isLoaded();
11308             return this.getData().stateChangeTime;
11309         },
11310         
11311         /**
11312          * Getter for the wrap-up mode of this User.
11313          * @see finesse.restservices.User.WrapUpMode
11314          * @returns {String} The wrap-up mode of this user that is a value of {@link finesse.restservices.User.WrapUpMode}
11315          */
11316         getWrapUpOnIncoming: function () {
11317             this.isLoaded();
11318             return this.getData().settings.wrapUpOnIncoming;
11319         },
11320         
11321         /**
11322          * Is User required to go into wrap-up?
11323          * @see finesse.restservices.User.WrapUpMode
11324          * @return {Boolean}
11325          *      True if this agent is required to go into wrap-up.
11326          */
11327         isWrapUpRequired: function () {
11328             return (this.getWrapUpOnIncoming() === User.WrapUpMode.REQUIRED || 
11329                     this.getWrapUpOnIncoming() === User.WrapUpMode.REQUIRED_WITH_WRAP_UP_DATA);
11330         },
11331     
11332         /**
11333          * Checks to see if the user is considered a mobile agent by checking for
11334          * the existence of the mobileAgent node.
11335          * @returns {Boolean}
11336          *      True if this agent is a mobile agent.
11337          */
11338         isMobileAgent: function () {
11339             this.isLoaded();
11340             var ma = this.getData().mobileAgent;
11341             return ma !== null && typeof ma === "object";
11342         },
11343     
11344         /**
11345          * Getter for the mobile agent work mode.
11346          * @returns {finesse.restservices.User.WorkMode}
11347          *      If available, return the mobile agent work mode, otherwise null.
11348          */
11349         getMobileAgentMode: function () {
11350             this.isLoaded();
11351             if (this.isMobileAgent()) {
11352                 return this.getData().mobileAgent.mode;
11353             }
11354             return null;
11355         },
11356     
11357         /**
11358          * Getter for the mobile agent dial number.
11359          * @returns {String}
11360          *      If available, return the mobile agent dial number, otherwise null.
11361          */
11362         getMobileAgentDialNumber: function () {
11363             this.isLoaded();
11364             if (this.isMobileAgent()) {
11365                 return this.getData().mobileAgent.dialNumber;
11366             }
11367             return null;
11368         },
11369     
11370         /**
11371          * Getter for a Dialogs collection object that is associated with User.
11372          * @param {finesse.interfaces.RestObjectHandlers} [handlers] Object that sets callback handlers (only 
11373          * applicable when Object has not been previously created).
11374          * @returns {finesse.restservices.Dialogs}
11375          *     A Dialogs collection object.
11376          */
11377         getDialogs: function (callbacks) {
11378             var options = callbacks || {};
11379             options.parentObj = this;
11380             this.isLoaded();
11381     
11382             if (this._dialogs === null) {
11383                 this._dialogs = new Dialogs(options);
11384             }
11385     
11386             return this._dialogs;
11387         },
11388         
11389         /**
11390          * @private
11391          * Getter for a ClientLog object that is associated with User.
11392          * @param {finesse.interfaces.RestObjectHandlers} [handlers] Object that sets callback handlers (only 
11393          * applicable when Object has not been previously created).
11394          * @returns {finesse.restservices.ClientLog}
11395          *     A ClientLog collection object.
11396          */
11397         getClientLog: function (callbacks) {
11398             var options = callbacks || {};
11399             options.parentObj = this;
11400             this.isLoaded();
11401            
11402             if (this._clientLogObj === null) {
11403                 this._clientLogObj = new ClientLog(options);
11404             }
11405             else {
11406                 if(options.onLoad && typeof options.onLoad === "function") {
11407                 options.onLoad(this._clientLogObj);
11408                 }
11409             }
11410             return this._clientLogObj;
11411         },
11412        
11413         /**
11414          * Getter for a Queues collection object that is associated with User.
11415          * @param {finesse.interfaces.RestObjectHandlers} [handlers] Object that sets callback handlers (only 
11416          * applicable when Object has not been previously created).
11417          * @returns {finesse.restservices.Queues}
11418          *     A Queues collection object.
11419          */
11420         getQueues: function (callbacks) {
11421             var options = callbacks || {};
11422             options.parentObj = this;
11423             this.isLoaded();
11424     
11425             if (this._queues === null) {
11426                 this._queues = new Queues(options);
11427             }
11428     
11429             return this._queues;
11430         },
11431 
11432         /**
11433          * Getter for a WrapUpReasons collection object that is associated with User.
11434          * @param {finesse.interfaces.RestObjectHandlers} [handlers] Object that sets callback handlers (only 
11435          * applicable when Object has not been previously created).
11436          * @returns {finesse.restservices.WrapUpReasons}
11437          *     A WrapUpReasons collection object.
11438          */
11439         getWrapUpReasons: function (callbacks) {
11440             var options = callbacks || {};
11441             options.parentObj = this;
11442             this.isLoaded();
11443     
11444             if (this._wrapUpReasons === null) {
11445                 this._wrapUpReasons = new WrapUpReasons(options);
11446             }
11447     
11448             return this._wrapUpReasons;
11449         },
11450 
11451         /**
11452          * Getter for a PhoneBooks collection object that is associated with User.
11453          * @param {finesse.interfaces.RestObjectHandlers} [handlers] Object that sets callback handlers (only 
11454          * applicable when Object has not been previously created).
11455          * @returns {finesse.restservices.PhoneBooks}
11456          *     A PhoneBooks collection object.
11457          */
11458         getPhoneBooks: function (callbacks) {
11459             var options = callbacks || {};
11460             options.parentObj = this;
11461             this.isLoaded();
11462     
11463             if (this._phoneBooks === null) {
11464                 this._phoneBooks = new PhoneBooks(options);
11465             }
11466     
11467             return this._phoneBooks;
11468         },
11469 
11470         /**
11471          * @private
11472          * Loads the Workflows collection object that is associated with User and
11473          * 'returns' them to the caller via the handlers.
11474          * @param {finesse.interfaces.RestObjectHandlers} [handlers] Object that sets callback handlers (only 
11475          * applicable when Object has not been previously created).
11476          * @see finesse.restservices.Workflow
11477          * @see finesse.restservices.Workflows
11478          * @see finesse.restservices.RestCollectionBase
11479          */
11480         loadWorkflows: function (callbacks) {
11481             var options = callbacks || {};
11482             options.parentObj = this;
11483             this.isLoaded();
11484 
11485             if (this._workflows === null) {
11486                 this._workflows = new Workflows(options);
11487             } else {
11488                 this._workflows.refresh();
11489             }
11490 
11491         },
11492 
11493         /**
11494          * Getter for a MediaPropertiesLayout object that is associated with User.
11495          * @param {finesse.interfaces.RestObjectHandlers} [handlers] Object that sets callback handlers (only 
11496          * applicable when Object has not been previously created).
11497          * @returns {finesse.restservices.MediaPropertiesLayout}
11498          *     The MediaPropertiesLayout object associated with this user
11499          */
11500         getMediaPropertiesLayout: function (callbacks) {
11501             var options = callbacks || {};
11502             options.parentObj = this;
11503             options.id = this._id;
11504     
11505             this.isLoaded();
11506             if (this._mediaPropertiesLayout === null) {
11507                 this._mediaPropertiesLayout = new MediaPropertiesLayout(options);
11508             }
11509             return this._mediaPropertiesLayout;
11510         },
11511     
11512         /**
11513          * Getter for the supervised Teams this User (Supervisor) supervises, if any.
11514          * @see finesse.restservices.Team
11515          * @returns {Array}
11516          *     An array of Teams supervised by this User (Supervisor)
11517          */
11518         getSupervisedTeams: function () {
11519             this.isLoaded();
11520     
11521             try {
11522                 return Utilities.getArray(this.getData().teams.Team);
11523             } catch (e) {
11524                 return [];
11525             }
11526     
11527         },
11528     
11529         /**
11530          * Perform an agent login for this user, associating him with the
11531          * specified extension.
11532          * @param {Object} params
11533          *     An object containing properties for agent login.
11534          * @param {String} params.extension
11535          *     The extension to associate with this user
11536          * @param {Object} [params.mobileAgent]
11537          *     A mobile agent object containing the mode and dial number properties.
11538          * @param {finesse.interfaces.RequestHandlers} params.handlers
11539          * @see finesse.interfaces.RequestHandlers
11540          * @returns {finesse.restservices.User}
11541          *     This User object, to allow cascading
11542          * @private
11543          */
11544         _login: function (params) {
11545             var handlers, contentBody = {},
11546             restType = this.getRestType();
11547             
11548             // Protect against null dereferencing.
11549             params = params || {};
11550     
11551             contentBody[restType] = {
11552                 "state": User.States.LOGIN,
11553                 "extension": params.extension
11554             };
11555     
11556             // Create mobile agent node if available.
11557             if (typeof params.mobileAgent === "object") {
11558                 contentBody[restType].mobileAgent = {
11559                     "mode": params.mobileAgent.mode,
11560                     "dialNumber": params.mobileAgent.dialNumber
11561                 };
11562             }
11563     
11564             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
11565             handlers = params.handlers || {};
11566     
11567             this.restRequest(this.getRestUrl(), {
11568                 method: 'PUT',
11569                 success: handlers.success,
11570                 error: handlers.error,
11571                 content: contentBody
11572             });
11573     
11574             return this; // Allow cascading
11575         },
11576     
11577         /**
11578          * Perform an agent login for this user, associating him with the
11579          * specified extension.
11580          * @param {String} extension
11581          *     The extension to associate with this user
11582          * @param {finesse.interfaces.RequestHandlers} handlers
11583          *     An object containing the handlers for the request
11584          * @returns {finesse.restservices.User}
11585          *     This User object, to allow cascading
11586          */
11587         login: function (extension, handlers) {
11588             this.isLoaded();
11589             var params = {
11590                 "extension": extension,
11591                 "handlers": handlers
11592             };
11593             return this._login(params);
11594         },
11595     
11596         /**
11597          * Perform an agent login for this user, associating him with the
11598          * specified extension.
11599          * @param {String} extension
11600          *     The extension to associate with this user
11601          * @param {String} mode
11602          *     The mobile agent work mode as defined in finesse.restservices.User.WorkMode.
11603          * @param {String} extension
11604          *     The external dial number desired to be used by the mobile agent.
11605          * @param {finesse.interfaces.RequestHandlers} handlers
11606          *     An object containing the handlers for the request
11607          * @returns {finesse.restservices.User}
11608          *     This User object, to allow cascading
11609          */
11610         loginMobileAgent: function (extension, mode, dialNumber, handlers) {
11611             this.isLoaded();
11612             var params = {
11613                 "extension": extension,
11614                 "mobileAgent": {
11615                     "mode": mode,
11616                     "dialNumber": dialNumber
11617                 },
11618                 "handlers": handlers
11619             };
11620             return this._login(params);
11621         },
11622     
11623         /**
11624          * Perform an agent logout for this user.
11625          * @param {String} reasonCode
11626          *     The reason this user is logging out.  Pass null for no reason.
11627          * @param {finesse.interfaces.RequestHandlers} handlers
11628          *     An object containing the handlers for the request
11629          * @returns {finesse.restservices.User}
11630          *     This User object, to allow cascading
11631          */
11632         logout: function (reasonCode, handlers) {
11633             return this.setState("LOGOUT", reasonCode, handlers);
11634         },
11635     
11636         /**
11637          * Set the state of the user.
11638          * @param {String} newState
11639          *     The state you are setting
11640          * @param {ReasonCode} reasonCode
11641          *     The reason this user is logging out.  Pass null for no reason.
11642          * @param {finesse.interfaces.RequestHandlers} handlers
11643          *     An object containing the handlers for the request
11644          * @see finesse.restservices.User.States
11645          * @returns {finesse.restservices.User}
11646          *     This User object, to allow cascading
11647          */
11648         setState: function (newState, reasonCode, handlers) {
11649             this.isLoaded();
11650     
11651             var options, contentBody = {};
11652     
11653             if (!reasonCode) {
11654                 contentBody[this.getRestType()] = {
11655                     "state": newState
11656                 };
11657             } else {
11658                 contentBody[this.getRestType()] = {
11659                     "state": newState,
11660                     "reasonCodeId": reasonCode.id
11661                 };
11662             }
11663     
11664             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
11665             handlers = handlers || {};
11666     
11667             options = {
11668                 method: 'PUT',
11669                 success: handlers.success,
11670                 error: handlers.error,
11671                 content: contentBody
11672             };
11673     
11674             // After removing the selective 202 handling, we should be able to just use restRequest
11675             this.restRequest(this.getRestUrl(), options);
11676     
11677             return this; // Allow cascading
11678         },
11679     
11680         /**
11681          * Make call to a particular phone number.
11682          *
11683          * @param {String} 
11684          *     The number to call
11685          * @param {finesse.interfaces.RequestHandlers} handlers
11686          *     An object containing the handlers for the request
11687          * @returns {finesse.restservices.User}
11688          *     This User object, to allow cascading
11689          */ 
11690         makeCall: function (number, handlers) {
11691             this.isLoaded();
11692     
11693             this.getDialogs().createNewCallDialog(number, this.getExtension(), handlers);
11694     
11695             return this; // Allow cascading
11696         },
11697     
11698         /**
11699          * Make a silent monitor call to a particular agent's phone number.
11700          *
11701          * @param {String} 
11702          *     The number to call
11703          * @param {finesse.interfaces.RequestHandlers} handlers
11704          *     An object containing the handlers for the request
11705          * @returns {finesse.restservices.User}
11706          *     This User object, to allow cascading
11707          */
11708         makeSMCall: function (number, handlers) {
11709             this.isLoaded();
11710     
11711             var actionType = "SILENT_MONITOR";
11712     
11713             this.getDialogs().createNewSuperviseCallDialog(number, this.getExtension(), actionType, handlers);
11714     
11715             return this; // Allow cascading
11716         },
11717         
11718     
11719         /**
11720          * Make a silent monitor call to a particular agent's phone number.
11721          *
11722          * @param {String}
11723          *     The number to call
11724          * @param {String} dialogUri
11725          *     The associated dialog uri of SUPERVISOR_MONITOR call
11726          * @param {finesse.interfaces.RequestHandlers} handlers
11727          *     An object containing the handlers for the request
11728          * @see finesse.restservices.dialog
11729          * @returns {finesse.restservices.User}
11730          *     This User object, to allow cascading
11731          */
11732         makeBargeCall:function (number, dialogURI, handlers) {
11733             this.isLoaded();
11734             var actionType = "BARGE_CALL";
11735             this.getDialogs().createNewBargeCall( this.getExtension(), number, actionType, dialogURI,handlers);
11736     
11737             return this; // Allow cascading
11738         },
11739         
11740         /**
11741          * Returns true if the user's current state will result in a pending state change. A pending state
11742          * change is a request to change state that does not result in an immediate state change. For
11743          * example if an agent attempts to change to the NOT_READY state while in the TALKING state, the
11744          * agent will not change state until the call ends.
11745          *
11746          * The current set of states that result in pending state changes is as follows:
11747          *     TALKING
11748          *     HOLD
11749          *     RESERVED_OUTBOUND_PREVIEW
11750          *  @returns {Boolean} True if there is a pending state change.
11751          *  @see finesse.restservices.User.States
11752          */
11753         isPendingStateChange: function () {
11754             var state = this.getState();
11755             return state && ((state === User.States.TALKING) || (state === User.States.HOLD) || (state === User.States.RESERVED_OUTBOUND_PREVIEW));
11756         },
11757         
11758         /**
11759          * Returns true if the user's current state is WORK or WORK_READY. This is used so
11760          * that a pending state is not cleared when moving into wrap up (work) mode. 
11761          * Note that we don't add this as a pending state, since changes while in wrap up
11762          * occur immediately (and we don't want any "pending state" to flash on screen.
11763          * 
11764          * @see finesse.restservices.User.States
11765          * @returns {Boolean} True if user is in wrap-up mode.
11766          */
11767         isWrapUp: function () {
11768             var state = this.getState();
11769             return state && ((state === User.States.WORK) || (state === User.States.WORK_READY));
11770         },
11771     
11772         /**
11773          * @private
11774          * Parses a uriString to retrieve the id portion
11775          * @param {String} uriString
11776          * @return {String} id
11777          */
11778         _parseIdFromUriString : function (uriString) {
11779             return Utilities.getId(uriString);
11780         },
11781 
11782         /**
11783          * Gets the user's Reason Code label.
11784          * Works for both Not Ready and Logout reason codes
11785          * @return {String} the reason code label, or empty string if none
11786          */
11787         getReasonCodeLabel : function () {
11788             this.isLoaded();
11789 
11790             if (this.getData().reasonCode) {
11791                 return this.getData().reasonCode.label;
11792             } else {
11793                 return "";
11794             }
11795         },
11796     
11797         /**
11798          * Gets the user's Not Ready reason code.
11799          * @return {String} Reason Code Id, or undefined if not set or indeterminate
11800          */
11801         getNotReadyReasonCodeId : function () {
11802             this.isLoaded();
11803     
11804             var reasoncodeIdResult, finesseServerReasonCodeId;
11805             finesseServerReasonCodeId = this.getData().reasonCodeId;
11806     
11807             //FinesseServer will give "-l" => we will set to undefined (for convenience)
11808             if (finesseServerReasonCodeId !== "-1") {
11809                 reasoncodeIdResult = finesseServerReasonCodeId;
11810             }
11811     
11812             return reasoncodeIdResult;
11813         },
11814     
11815         /**
11816          * Performs a GET against the Finesse server looking up the reasonCodeId specified.
11817          * Note that there is no return value; use the success handler to process a
11818          * valid return.
11819          * @param {finesse.interfaces.RequestHandlers} handlers
11820          *     An object containing the handlers for the request
11821          * @param {String} reasonCodeId The id for the reason code to lookup
11822          * 
11823          */
11824         getReasonCodeById : function (handlers, reasonCodeId)
11825         {
11826             var self = this, contentBody, reasonCode, url;
11827             contentBody = {};
11828     
11829             url = this.getRestUrl() + "/ReasonCode/" + reasonCodeId;
11830             this.restRequest(url, {
11831                 method: 'GET',
11832                 success: function (rsp) {
11833                     reasonCode = {
11834                         uri: rsp.object.ReasonCode.uri,
11835                         label: rsp.object.ReasonCode.label,
11836                         id: self._parseIdFromUriString(rsp.object.ReasonCode.uri)
11837                     };
11838                     handlers.success(reasonCode);
11839                 },
11840                 error: function (rsp) {
11841                     handlers.error(rsp);
11842                 },
11843                 content: contentBody
11844             });
11845         },
11846     
11847         /**
11848          * Performs a GET against Finesse server retrieving all the specified type of reason codes.
11849          * @param {String} type (LOGOUT or NOT_READY)
11850          * @param {finesse.interfaces.RequestHandlers} handlers
11851          *     An object containing the handlers for the request
11852          */
11853         _getReasonCodesByType : function (type, handlers)
11854         {
11855             var self = this, contentBody = {}, url, reasonCodes, i, reasonCodeArray;
11856     
11857             url = this.getRestUrl() + "/ReasonCodes?category=" + type;
11858             this.restRequest(url, {
11859                 method: 'GET',
11860                 success: function (rsp) {
11861                     reasonCodes = [];
11862     
11863                     reasonCodeArray = rsp.object.ReasonCodes.ReasonCode;
11864                     if (reasonCodeArray === undefined) {
11865                         reasonCodes = undefined;
11866                     } else if (reasonCodeArray[0] !== undefined) {
11867                         for (i = 0; i < reasonCodeArray.length; i = i + 1) {
11868                             reasonCodes[i] = {
11869                                 label: rsp.object.ReasonCodes.ReasonCode[i].label,
11870                                 id: self._parseIdFromUriString(rsp.object.ReasonCodes.ReasonCode[i].uri)
11871                             };
11872                         }
11873                     } else {
11874                         reasonCodes[0] = {
11875                             label: rsp.object.ReasonCodes.ReasonCode.label,
11876                             id: self._parseIdFromUriString(rsp.object.ReasonCodes.ReasonCode.uri)
11877                         };
11878                     }
11879                     handlers.success(reasonCodes);
11880                 },
11881                 error: function (rsp) {
11882                     handlers.error(rsp);
11883                 },
11884                 content: contentBody
11885             });
11886         },
11887     
11888         /**
11889          * Performs a GET against Finesse server retrieving all the Signout reason codes.
11890          * Note that there is no return value; use the success handler to process a
11891          * valid return.
11892          * @param {finesse.interfaces.RequestHandlers} handlers
11893          *     An object containing the handlers for the request
11894          */
11895         getSignoutReasonCodes : function (handlers)
11896         {
11897             this._getReasonCodesByType("LOGOUT", handlers);
11898         },
11899     
11900         /**
11901          * Performs a GET against Finesse server retrieving all the Not Ready reason codes.
11902          * Note that there is no return value; use the success handler to process a
11903          * valid return.
11904          * @param {finesse.interfaces.RequestHandlers} handlers
11905          *     An object containing the handlers for the request
11906          */
11907         getNotReadyReasonCodes : function (handlers)
11908         {
11909             this._getReasonCodesByType("NOT_READY", handlers);
11910         }
11911     });
11912     
11913     User.States = /** @lends finesse.restservices.User.States.prototype */ {
11914             /**
11915              * User Login.  Note that while this is an action, is not technically a state, since a 
11916              * logged-in User will always be in a specific state (READY, NOT_READY, TALKING, etc.).
11917              */
11918             LOGIN: "LOGIN",
11919             /**
11920              * User is logged out.
11921              */
11922             LOGOUT: "LOGOUT",
11923             /**
11924              * User is not ready. Note that in UCCX implementations, the user is in this state while on a non-routed call.
11925              */
11926             NOT_READY: "NOT_READY",
11927             /**
11928              * User is ready for calls.
11929              */
11930             READY: "READY",
11931             /**
11932              * User has a call coming in, but has not answered it.
11933              */
11934             RESERVED: "RESERVED",
11935             /**
11936              * User has an outbound call being made, but has not been connected to it.
11937              */
11938             RESERVED_OUTBOUND: "RESERVED_OUTBOUND",
11939             /**
11940              * User has an outbound call's preview information being displayed, but has not acted on it.
11941              */
11942             RESERVED_OUTBOUND_PREVIEW: "RESERVED_OUTBOUND_PREVIEW",
11943             /**
11944              * User is on a call.  Note that in UCCX implementations, this is for routed calls only.
11945              */
11946             TALKING: "TALKING",
11947             /**
11948              * User is on hold.  Note that in UCCX implementations, the user remains in TALKING state while on hold.
11949              */
11950             HOLD: "HOLD",
11951             /**
11952              * User is wrap-up/work mode.  This mode is typically configured to time out, after which the user becomes NOT_READY.
11953              */
11954             WORK: "WORK",
11955             /**
11956              * This is the same as WORK, except that after time out user becomes READY.
11957              */
11958             WORK_READY: "WORK_READY",
11959             /**
11960              * @class Possible User state values.
11961              * @constructs
11962              */
11963             _fakeConstructor : function () {} // For JS Doc to work need a constructor so that the lends/constructs build the doc properly
11964           
11965         };
11966     
11967     User.WorkMode = { /** @lends finesse.restservices.User.WorkMode.prototype */
11968         /**
11969          * Mobile agent is connected (dialed) for each incoming call received.
11970          */
11971         CALL_BY_CALL: "CALL_BY_CALL",
11972         /**
11973          * Mobile agent is connected (dialed) at login.
11974          */
11975         NAILED_CONNECTION: "NAILED_CONNECTION",
11976         /**
11977          * @class Possible Mobile Agent Work Mode Types.
11978          * @constructs
11979          */
11980         _fakeConstructor : function () {} // For JS Doc to work need a constructor so that the lends/constructs build the doc properly
11981         
11982     };
11983 
11984     User.WrapUpMode = { /** @lends finesse.restservices.User.WrapUpMode.prototype */
11985         /**
11986          * Agent must go into wrap-up when call ends
11987          */
11988         REQUIRED: "REQUIRED",
11989         /**
11990          * Agent must go into wrap-up when call ends and must enter wrap-up data
11991          */
11992         REQUIRED_WITH_WRAP_UP_DATA: "REQUIRED_WITH_WRAP_UP_DATA",
11993         /**
11994          * Agent can choose to go into wrap-up on a call-by-call basis when the call ends
11995          */
11996         OPTIONAL: "OPTIONAL",
11997         /**
11998          * Agent is not allowed to go into wrap-up when call ends.
11999          */
12000         NOT_ALLOWED: "NOT_ALLOWED",
12001         /**
12002          * @class Possible Wrap-up Mode Types.
12003          * @constructs
12004          */
12005         _fakeConstructor : function () {} // For JS Doc to work need a constructor so that the lends/constructs build the doc properly
12006         
12007     };
12008 
12009     window.finesse = window.finesse || {};
12010     window.finesse.restservices = window.finesse.restservices || {};
12011     window.finesse.restservices.User = User;
12012         
12013     return User;
12014 }));
12015 
12016 /**
12017  * JavaScript representation of the Finesse Users collection
12018  * object which contains a list of Users objects.
12019  *
12020  * @requires finesse.clientservices.ClientServices
12021  * @requires Class
12022  * @requires finesse.FinesseBase
12023  * @requires finesse.restservices.RestBase
12024  * @requires finesse.restservices.RestCollectionBase
12025  * @requires finesse.restservices.User
12026  */
12027 
12028 /** @private */
12029 (function (factory) {
12030     
12031 
12032     // Define as an AMD module if possible
12033     if ( typeof define === 'function' && define.amd )
12034     {
12035         define('restservices/Users', ['restservices/RestCollectionBase',
12036                  'restservices/RestBase',
12037                  'restservices/User'], factory );
12038     }
12039     /* Define using browser globals otherwise
12040      * Prevent multiple instantiations if the script is loaded twice
12041      */
12042     else
12043     {
12044         factory(finesse.restservices.RestCollectionBase, finesse.restservices.RestBase, finesse.restservices.User);
12045     }
12046 }(function (RestCollectionBase, RestBase, User) {
12047 
12048 	var Users = RestCollectionBase.extend(/** @lends finesse.restservices.Users.prototype */{
12049 
12050     /**
12051      * @class
12052      * JavaScript representation of a Users collection object. 
12053      * While there is no method provided to retrieve all Users, this collection is
12054      * used to return the Users in a supervised Team.
12055      * @augments finesse.restservices.RestCollectionBase
12056      * @constructs
12057      * @see finesse.restservices.Team
12058      * @see finesse.restservices.User
12059      * @see finesse.restservices.User#getSupervisedTeams
12060      * @example
12061      *  // Note: The following method gets an Array of Teams, not a Collection.
12062      *  _teams = _user.getSupervisedTeams();
12063      *  if (_teams.length > 0) {
12064      *      _team0Users = _teams[0].getUsers();
12065      *  }
12066      */
12067     _fakeConstuctor: function () {
12068         /* This is here to hide the real init constructor from the public docs */
12069     },
12070         
12071     /**
12072      * @private
12073      * JavaScript representation of the Finesse Users collection
12074      * object which contains a list of Users objects.
12075      *
12076 	 * @param {Object} options
12077 	 *     An object with the following properties:<ul>
12078      *         <li><b>id:</b> The id of the object being constructed</li>
12079      *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
12080      *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
12081      *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
12082      *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
12083      *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
12084      *             <li><b>status:</b> {Number} The HTTP status code returned</li>
12085      *             <li><b>content:</b> {String} Raw string of response</li>
12086      *             <li><b>object:</b> {Object} Parsed object of response</li>
12087      *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
12088      *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
12089      *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
12090      *             </ul></li>
12091      *         </ul></li>
12092      *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
12093      **/
12094 	init: function (options) {
12095 		this._super(options);
12096 	},
12097 
12098 	/**
12099      * @private
12100 	 * Gets the REST class for the current object - this is the Users class.
12101 	 */
12102 	getRestClass: function () {
12103 	    return Users;
12104 	},
12105 
12106 	/**
12107      * @private
12108 	 * Gets the REST class for the objects that make up the collection. - this
12109 	 * is the User class.
12110 	 */
12111 	getRestItemClass: function () {
12112 		return User;
12113 	},
12114 
12115 	/**
12116      * @private
12117 	 * Gets the REST type for the current object - this is a "Users".
12118 	 */
12119 	getRestType: function () {
12120 	    return "Users";
12121 	},
12122 
12123 	/**
12124      * @private
12125 	 * Gets the REST type for the objects that make up the collection - this is "User".
12126 	 */
12127 	getRestItemType: function () {
12128 	    return "User";
12129 	},
12130 
12131 	/**
12132      * @private
12133      * Gets the node path for the current object - this is the team Users node
12134      * @returns {String} The node path
12135      */
12136     getXMPPNodePath: function () {
12137 		return this.getRestUrl();
12138     },
12139 
12140     /**
12141      * @private
12142      * Overloading _doGET to reroute the GET to /Team/id from /Team/id/Users
12143      * This needs to be done because the GET /Team/id/Users API is missing
12144      * @returns {Users} This Users (collection) object to allow cascading
12145      */
12146     _doGET: function (handlers) {
12147         var _this = this;
12148         handlers = handlers || {};
12149         // Only do this for /Team/id/Users
12150         if (this._restObj && this._restObj.getRestType() === "Team") {
12151             this._restObj._doGET({
12152                 success: function (rspObj) {
12153                     // Making sure the response was a valid Team
12154                     if (_this._restObj._validate(rspObj.object)) {
12155                         // Shimmying the response to look like a Users collection by extracting it from the Team response
12156                         rspObj.object[_this.getRestType()] = rspObj.object[_this._restObj.getRestType()][_this.getRestType().toLowerCase()];
12157                         handlers.success(rspObj);
12158                     } else {
12159                         handlers.error(rspObj);
12160                     }
12161                 },
12162                 error: handlers.error
12163             });
12164             return this; // Allow cascading
12165         } else {
12166             return this._super(handlers);
12167         }
12168     },
12169 
12170 	/**
12171      * @private
12172      * Override default to indicates that the collection doesn't support making
12173 	 * requests.
12174 	 */
12175 	supportsRequests: false,
12176 
12177     /**
12178      * @private
12179      * Indicates that this collection handles the subscription for its items
12180      */
12181     handlesItemSubscription: true,
12182 	
12183     /**
12184      * @private
12185      * Override default to indicate that we need to subscribe explicitly
12186      */
12187     explicitSubscription: true
12188     
12189 	});
12190 
12191     window.finesse = window.finesse || {};
12192     window.finesse.restservices = window.finesse.restservices || {};
12193     window.finesse.restservices.Users = Users;
12194 
12195 	return Users;
12196 }));
12197 
12198 /**
12199  * JavaScript representation of the Finesse Team Not Ready Reason Code Assignment object.
12200  *
12201  * @requires finesse.clientservices.ClientServices
12202  * @requires Class
12203  * @requires finesse.FinesseBase
12204  * @requires finesse.restservices.RestBase
12205  */
12206 
12207 /** @private */
12208 (function (factory) {
12209     
12210 
12211     // Define as an AMD module if possible
12212     if ( typeof define === 'function' && define.amd )
12213     {
12214         define('restservices/TeamNotReadyReasonCode', ['restservices/RestBase'], factory );
12215     }
12216     /* Define using browser globals otherwise
12217      * Prevent multiple instantiations if the script is loaded twice
12218      */
12219     else
12220     {
12221         factory(finesse.restservices.RestBase);
12222     } 
12223 }(function (RestBase) {
12224     
12225     var TeamNotReadyReasonCode = RestBase.extend( {
12226 
12227         /**
12228          * @class
12229          * JavaScript representation of a Team Not Ready ReasonCode object. Also exposes
12230          * methods to operate on the object against the server.
12231          *
12232          * @param {Object} options
12233          *     An object with the following properties:<ul>
12234          *         <li><b>id:</b> The id of the object being constructed</li>
12235          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
12236          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
12237          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
12238          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
12239          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
12240          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
12241          *             <li><b>content:</b> {String} Raw string of response</li>
12242          *             <li><b>object:</b> {Object} Parsed object of response</li>
12243          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
12244          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
12245          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
12246          *             </ul></li>
12247          *         </ul></li>
12248          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
12249          * @constructs
12250          **/
12251         init: function (options) {
12252             this._super(options);
12253         },
12254     
12255         /**
12256          * @private
12257          * Gets the REST class for the current object - this is the TeamNotReadyReasonCode class.
12258          * @returns {Object} The TeamNotReadyReasonCode class.
12259          */
12260         getRestClass: function () {
12261             return TeamNotReadyReasonCode;
12262         },
12263     
12264         /**
12265          * @private
12266          * Gets the REST type for the current object - this is a "ReasonCode".
12267          * @returns {String} The ReasonCode string.
12268          */
12269         getRestType: function () {
12270             return "ReasonCode";
12271         },
12272     
12273         /**
12274          * @private
12275          * Override default to indicate that this object doesn't support making
12276          * requests.
12277          */
12278         supportsRequests: false,
12279     
12280         /**
12281          * @private
12282          * Override default to indicate that this object doesn't support subscriptions.
12283          */
12284         supportsSubscriptions: false,
12285     
12286         /**
12287          * Getter for the category.
12288          * @returns {String} The category.
12289          */
12290         getCategory: function () {
12291             this.isLoaded();
12292             return this.getData().category;
12293         },
12294     
12295         /**
12296          * Getter for the code.
12297          * @returns {String} The code.
12298          */
12299         getCode: function () {
12300             this.isLoaded();
12301             return this.getData().code;
12302         },
12303     
12304         /**
12305          * Getter for the label.
12306          * @returns {String} The label.
12307          */
12308         getLabel: function () {
12309             this.isLoaded();
12310             return this.getData().label;
12311         },
12312     
12313         /**
12314          * Getter for the forAll value.
12315          * @returns {String} The forAll.
12316          */
12317         getForAll: function () {
12318             this.isLoaded();
12319             return this.getData().forAll;
12320         },
12321     
12322         /**
12323          * Getter for the Uri value.
12324          * @returns {String} The Uri.
12325          */
12326         getUri: function () {
12327             this.isLoaded();
12328             return this.getData().uri;
12329         }
12330 
12331     });
12332     
12333     window.finesse = window.finesse || {};
12334     window.finesse.restservices = window.finesse.restservices || {};
12335     window.finesse.restservices.TeamNotReadyReasonCode = TeamNotReadyReasonCode;
12336         
12337     return TeamNotReadyReasonCode;
12338 }));
12339 
12340 /**
12341 * JavaScript representation of the Finesse TeamNotReadyReasonCodes collection
12342 * object which contains a list of TeamNotReadyReasonCode objects.
12343  *
12344  * @requires finesse.clientservices.ClientServices
12345  * @requires Class
12346  * @requires finesse.FinesseBase
12347  * @requires finesse.restservices.RestBase
12348  * @requires finesse.restservices.Dialog
12349  * @requires finesse.restservices.RestCollectionBase
12350  */
12351 
12352 /** @private */
12353 (function (factory) {
12354     
12355 
12356     // Define as an AMD module if possible
12357     if ( typeof define === 'function' && define.amd )
12358     {
12359         define('restservices/TeamNotReadyReasonCodes', ['restservices/RestCollectionBase',
12360                  'restservices/RestBase',
12361                  'restservices/TeamNotReadyReasonCode'], factory );
12362     }
12363     /* Define using browser globals otherwise
12364      * Prevent multiple instantiations if the script is loaded twice
12365      */
12366     else
12367     {
12368         factory(finesse.restservices.RestCollectionBase, finesse.restservices.RestBase, finesse.restservices.TeamNotReadyReasonCode);
12369     }
12370 }(function (RestCollectionBase, RestBase, TeamNotReadyReasonCode) {
12371     
12372     var TeamNotReadyReasonCodes = RestCollectionBase.extend( {
12373 
12374       /**
12375        * @class
12376        * JavaScript representation of a TeamNotReadyReasonCodes collection object. Also exposes
12377        * methods to operate on the object against the server.
12378        *
12379        * @param {Object} options
12380        *     An object with the following properties:<ul>
12381        *         <li><b>id:</b> The id of the object being constructed</li>
12382        *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
12383        *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
12384        *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
12385        *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
12386        *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
12387        *             <li><b>status:</b> {Number} The HTTP status code returned</li>
12388        *             <li><b>content:</b> {String} Raw string of response</li>
12389        *             <li><b>object:</b> {Object} Parsed object of response</li>
12390        *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
12391        *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
12392        *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
12393        *             </ul></li>
12394        *         </ul></li>
12395        *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
12396        * @augments finesse.restservices.RestCollectionBase
12397        * @constructs
12398        **/
12399       init: function (options) {
12400           this._super(options);
12401       },
12402     
12403       /**
12404        * @private
12405        * Gets the REST class for the current object - this is the TeamNotReadyReasonCodes class.
12406        */
12407       getRestClass: function () {
12408           return TeamNotReadyReasonCodes;
12409       },
12410     
12411       /**
12412        * @private
12413        * Gets the REST class for the objects that make up the collection. - this
12414        * is the TeamNotReadyReasonCode class.
12415        */
12416       getRestItemClass: function () {
12417           return TeamNotReadyReasonCode;
12418       },
12419     
12420       /**
12421        * @private
12422        * Gets the REST type for the current object - this is a "ReasonCodes".
12423        */
12424       getRestType: function () {
12425           return "ReasonCodes";
12426       },
12427     
12428       /**
12429        * @private
12430        * Overrides the parent class.  Returns the url for the NotReadyReasonCodes resource
12431        */
12432       getRestUrl: function () {
12433           // return ("/finesse/api/" + this.getRestType() + "?category=NOT_READY");
12434           var restObj = this._restObj,
12435               restUrl = "";
12436           //Prepend the base REST object if one was provided.
12437           //Otherwise prepend with the default webapp name.
12438           if (restObj instanceof RestBase) {
12439               restUrl += restObj.getRestUrl();
12440           }
12441           else {
12442               restUrl += "/finesse/api";
12443           }
12444           //Append the REST type.
12445           restUrl += "/ReasonCodes?category=NOT_READY";
12446           //Append ID if it is not undefined, null, or empty.
12447           if (this._id) {
12448               restUrl += "/" + this._id;
12449           }
12450           return restUrl;
12451       },
12452     
12453       /**
12454        * @private
12455        * Gets the REST type for the objects that make up the collection - this is "ReasonCode".
12456        */
12457       getRestItemType: function () {
12458           return "ReasonCode";
12459       },
12460     
12461       /**
12462        * @private
12463        * Override default to indicates that the collection supports making
12464        * requests.
12465        */
12466       supportsRequests: true,
12467     
12468       /**
12469        * @private
12470        * Override default to indicate that this object doesn't support subscriptions.
12471        */
12472       supportsRestItemSubscriptions: false,
12473     
12474       /**
12475        * @private
12476        * Retrieve the Not Ready Reason Codes.
12477        *
12478        * @returns {TeamNotReadyReasonCodes}
12479        *     This TeamNotReadyReasonCodes object to allow cascading.
12480        */
12481       get: function () {
12482           // set loaded to false so it will rebuild the collection after the get
12483           this._loaded = false;
12484           // reset collection
12485           this._collection = {};
12486           // perform get
12487           this._synchronize();
12488           return this;
12489       },
12490     
12491       /**
12492        * @private
12493        * Set up the PutSuccessHandler for TeamNotReadyReasonCodes
12494        * @param {Object} reasonCodes
12495        * @param {String} contentBody
12496        * @param successHandler    
12497        * @return {function}
12498        */
12499       createPutSuccessHandler: function (reasonCodes, contentBody, successHandler) {
12500           return function (rsp) {
12501               // Update internal structure based on response. Here we
12502               // inject the contentBody from the PUT request into the
12503               // rsp.object element to mimic a GET as a way to take
12504               // advantage of the existing _processResponse method.
12505               rsp.object = contentBody;
12506               reasonCodes._processResponse(rsp);
12507     
12508               //Remove the injected contentBody object before cascading response
12509               rsp.object = {};
12510     
12511               //cascade response back to consumer's response handler
12512               successHandler(rsp);
12513           };
12514       },
12515     
12516       /**
12517        * @private
12518        * Perform the REST API PUT call to update the reason code assignments for the team
12519        * @param {string[]} newValues
12520        * @param handlers     
12521        */
12522       update: function (newValues, handlers) {
12523           this.isLoaded();
12524           var contentBody = {}, contentBodyInner = [], i, innerObject = {};
12525     
12526           contentBody[this.getRestType()] = {
12527           };
12528     
12529           for (i in newValues) {
12530               if (newValues.hasOwnProperty(i)) {
12531                   innerObject = {
12532                       "uri": newValues[i]
12533                   };
12534                   contentBodyInner.push(innerObject);
12535               }
12536           }
12537     
12538           contentBody[this.getRestType()] = {
12539               "ReasonCode" : contentBodyInner
12540           };
12541     
12542           // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
12543           handlers = handlers || {};
12544     
12545           this.restRequest(this.getRestUrl(), {
12546               method: 'PUT',
12547               success: this.createPutSuccessHandler(this, contentBody, handlers.success),
12548               error: handlers.error,
12549               content: contentBody
12550           });
12551     
12552           return this; // Allow cascading
12553       }
12554   });
12555   
12556     window.finesse = window.finesse || {};
12557     window.finesse.restservices = window.finesse.restservices || {};
12558     window.finesse.restservices.TeamNotReadyReasonCodes = TeamNotReadyReasonCodes;
12559     
12560   return TeamNotReadyReasonCodes;
12561 }));
12562 
12563 /**
12564  * JavaScript representation of the Finesse Team Wrap Up Reason object.
12565  *
12566  * @requires finesse.clientservices.ClientServices
12567  * @requires Class
12568  * @requires finesse.FinesseBase
12569  * @requires finesse.restservices.RestBase
12570  */
12571 /** @private */
12572 (function (factory) {
12573     
12574 
12575     // Define as an AMD module if possible
12576     if ( typeof define === 'function' && define.amd )
12577     {
12578         define('restservices/TeamWrapUpReason',['restservices/RestBase'], factory);
12579     }
12580     /* Define using browser globals otherwise
12581      * Prevent multiple instantiations if the script is loaded twice
12582      */
12583     else
12584     {
12585         factory(finesse.restservices.RestBase);
12586     } 
12587 }(function (RestBase) {
12588 
12589 	var TeamWrapUpReason = RestBase.extend({
12590 
12591     /**
12592      * @class
12593      * JavaScript representation of a TeamWrapUpReason object. Also exposes
12594      * methods to operate on the object against the server.
12595      *
12596      * @param {Object} options
12597      *     An object with the following properties:<ul>
12598      *         <li><b>id:</b> The id of the object being constructed</li>
12599      *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
12600      *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
12601      *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
12602      *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
12603      *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
12604      *             <li><b>status:</b> {Number} The HTTP status code returned</li>
12605      *             <li><b>content:</b> {String} Raw string of response</li>
12606      *             <li><b>object:</b> {Object} Parsed object of response</li>
12607      *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
12608      *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
12609      *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
12610      *             </ul></li>
12611      *         </ul></li>
12612      *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
12613      * @constructs
12614      **/
12615     init: function (options) {
12616         this._super(options);
12617     },
12618 
12619     /**
12620      * @private
12621      * Gets the REST class for the current object - this is the TeamWrapUpReason class.
12622      * @returns {Object} The TeamWrapUpReason class.
12623      */
12624     getRestClass: function () {
12625         return TeamWrapUpReason;
12626     },
12627 
12628     /**
12629      * @private
12630      * Gets the REST type for the current object - this is a "WrapUpReason".
12631      * @returns {String} The WrapUpReason string.
12632      */
12633     getRestType: function () {
12634         return "WrapUpReason";
12635     },
12636 
12637     /**
12638      * @private
12639      * Override default to indicate that this object doesn't support making
12640      * requests.
12641      */
12642     supportsRequests: false,
12643 
12644     /**
12645      * @private
12646      * Override default to indicate that this object doesn't support subscriptions.
12647      */
12648     supportsSubscriptions: false,
12649 
12650     /**
12651      * Getter for the label.
12652      * @returns {String} The label.
12653      */
12654     getLabel: function () {
12655         this.isLoaded();
12656         return this.getData().label;
12657     },
12658 
12659     /**
12660      * @private
12661      * Getter for the forAll value.
12662      * @returns {Boolean} True if global
12663      */
12664     getForAll: function () {
12665         this.isLoaded();
12666         return this.getData().forAll;
12667     },
12668 
12669     /**
12670      * @private
12671      * Getter for the Uri value.
12672      * @returns {String} The Uri.
12673      */
12674     getUri: function () {
12675         this.isLoaded();
12676         return this.getData().uri;
12677     }
12678 	});
12679 
12680     window.finesse = window.finesse || {};
12681     window.finesse.restservices = window.finesse.restservices || {};
12682     window.finesse.restservices.TeamWrapUpReason = TeamWrapUpReason;
12683 
12684 	return TeamWrapUpReason;
12685 }));
12686 
12687 /**
12688 * JavaScript representation of the Finesse Team Wrap-Up Reasons collection
12689 * object which contains a list of Wrap-Up Reasons objects.
12690  *
12691  * @requires finesse.clientservices.ClientServices
12692  * @requires Class
12693  * @requires finesse.FinesseBase
12694  * @requires finesse.restservices.RestBase
12695  * @requires finesse.restservices.Dialog
12696  * @requires finesse.restservices.RestCollectionBase
12697  */
12698 /** @private */
12699 (function (factory) {
12700     
12701 
12702     // Define as an AMD module if possible
12703     if ( typeof define === 'function' && define.amd )
12704     {
12705         define('restservices/TeamWrapUpReasons', ['restservices/RestCollectionBase',
12706                  'restservices/RestBase',
12707                  'restservices/TeamWrapUpReason'], factory );
12708     }
12709     /* Define using browser globals otherwise
12710      * Prevent multiple instantiations if the script is loaded twice
12711      */
12712     else
12713     {
12714         factory(finesse.restservices.RestCollectionBase, finesse.restservices.RestBase, finesse.restservices.TeamWrapUpReason);
12715     } 
12716 }(function (RestCollectionBase, RestBase, TeamWrapUpReason) {
12717 
12718 	var TeamWrapUpReasons = RestCollectionBase.extend({
12719 
12720     /**
12721      * @class
12722      * JavaScript representation of a TeamWrapUpReasons collection object. Also exposes
12723      * methods to operate on the object against the server.
12724      *
12725      * @param {Object} options
12726      *     An object with the following properties:<ul>
12727      *         <li><b>id:</b> The id of the object being constructed</li>
12728      *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
12729      *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
12730      *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
12731      *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
12732      *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
12733      *             <li><b>status:</b> {Number} The HTTP status code returned</li>
12734      *             <li><b>content:</b> {String} Raw string of response</li>
12735      *             <li><b>object:</b> {Object} Parsed object of response</li>
12736      *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
12737      *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
12738      *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
12739      *             </ul></li>
12740      *         </ul></li>
12741      *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
12742      * @constructs
12743      **/
12744     init: function (options) {
12745         this._super(options);
12746     },
12747 
12748     /**
12749      * @private
12750      * Gets the REST class for the current object - this is the TeamWrapUpReasons class.
12751      */
12752     getRestClass: function () {
12753         return TeamWrapUpReasons;
12754     },
12755 
12756     /**
12757      * @private
12758      * Gets the REST class for the objects that make up the collection. - this
12759      * is the TeamWrapUpReason class.
12760      */
12761     getRestItemClass: function () {
12762         return TeamWrapUpReason;
12763     },
12764 
12765     /**
12766      * @private
12767      * Gets the REST type for the current object - this is a "WrapUpReasons".
12768      */
12769     getRestType: function () {
12770         return "WrapUpReasons";
12771     },
12772 
12773     /**
12774      * @private
12775      * Gets the REST type for the objects that make up the collection - this is "WrapUpReason".
12776      */
12777     getRestItemType: function () {
12778         return "WrapUpReason";
12779     },
12780 
12781     /**
12782      * @private
12783      * Override default to indicates that the collection supports making
12784      * requests.
12785      */
12786     supportsRequests: true,
12787 
12788     /**
12789      * @private
12790      * Override default to indicate that this object doesn't support subscriptions.
12791      */
12792     supportsRestItemSubscriptions: false,
12793 
12794     /**
12795      * Retrieve the Team Wrap Up Reasons.
12796      *
12797      * @returns {finesse.restservices.TeamWrapUpReasons}
12798      *     This TeamWrapUpReasons object to allow cascading.
12799      */
12800     get: function () {
12801         // set loaded to false so it will rebuild the collection after the get
12802         this._loaded = false;
12803         // reset collection
12804         this._collection = {};
12805         // perform get
12806         this._synchronize();
12807         return this;
12808     },
12809 
12810     /**
12811      * Set up the PutSuccessHandler for TeamWrapUpReasons
12812      * @param {Object} wrapUpReasons
12813      * @param {Object} contentBody
12814      * @param successHandler
12815      * @returns response
12816      */
12817     createPutSuccessHandler: function (wrapUpReasons, contentBody, successHandler) {
12818         return function (rsp) {
12819             // Update internal structure based on response. Here we
12820             // inject the contentBody from the PUT request into the
12821             // rsp.object element to mimic a GET as a way to take
12822             // advantage of the existing _processResponse method.
12823             rsp.object = contentBody;
12824             
12825             wrapUpReasons._processResponse(rsp);
12826 
12827             //Remove the injected contentBody object before cascading response
12828             rsp.object = {};
12829 
12830             //cascade response back to consumer's response handler
12831             successHandler(rsp);
12832         };
12833     },
12834 
12835     /**    
12836      * Perform the REST API PUT call to update the reason code assignments for the team
12837      * @param {String Array} newValues
12838      * @param handlers
12839      * @returns {Object} this
12840      */
12841     update: function (newValues, handlers) {
12842         this.isLoaded();
12843         var contentBody = {}, contentBodyInner = [], i, innerObject = {};
12844 
12845         contentBody[this.getRestType()] = {
12846         };
12847 
12848         for (i in newValues) {
12849             if (newValues.hasOwnProperty(i)) {
12850                 innerObject = {
12851                     "uri": newValues[i]
12852                 };
12853                 contentBodyInner.push(innerObject);
12854             }
12855         }
12856 
12857         contentBody[this.getRestType()] = {
12858             "WrapUpReason" : contentBodyInner
12859         };
12860 
12861         // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
12862         handlers = handlers || {};
12863 
12864         this.restRequest(this.getRestUrl(), {
12865             method: 'PUT',
12866             success: this.createPutSuccessHandler(this, contentBody, handlers.success),
12867             error: handlers.error,
12868             content: contentBody
12869         });
12870 
12871         return this; // Allow cascading
12872     }
12873 	});
12874 
12875     window.finesse = window.finesse || {};
12876     window.finesse.restservices = window.finesse.restservices || {};
12877     window.finesse.restservices.TeamWrapUpReasons = TeamWrapUpReasons;
12878 
12879 	return TeamWrapUpReasons;
12880 }));
12881 
12882 /**
12883  * JavaScript representation of a TeamSignOutReasonCode.
12884  *
12885  * @requires finesse.clientservices.ClientServices
12886  * @requires Class
12887  * @requires finesse.FinesseBase
12888  * @requires finesse.restservices.RestBase
12889  */
12890 
12891 /** @private */
12892 (function (factory) {
12893     
12894 
12895     // Define as an AMD module if possible
12896     if ( typeof define === 'function' && define.amd )
12897     {
12898         define('restservices/TeamSignOutReasonCode', ['restservices/RestBase'], factory );
12899     }
12900     /* Define using browser globals otherwise
12901      * Prevent multiple instantiations if the script is loaded twice
12902      */
12903     else
12904     {
12905         factory(finesse.restservices.RestBase);
12906     }
12907 }(function (RestBase) {
12908     var TeamSignOutReasonCode = RestBase.extend({
12909 
12910         /**
12911          * @class
12912          * JavaScript representation of a TeamSignOutReasonCode object. Also exposes
12913          * methods to operate on the object against the server.
12914          *
12915          * @param {Object} options
12916          *     An object with the following properties:<ul>
12917          *         <li><b>id:</b> The id of the object being constructed</li>
12918          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
12919          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
12920          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
12921          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
12922          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
12923          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
12924          *             <li><b>content:</b> {String} Raw string of response</li>
12925          *             <li><b>object:</b> {Object} Parsed object of response</li>
12926          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
12927          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
12928          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
12929          *             </ul></li>
12930          *         </ul></li>
12931          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
12932          * @constructs
12933          * @ignore
12934          **/
12935         init: function (options) {
12936             this._super(options);
12937         },
12938 
12939         /**
12940          * @private
12941          * Gets the REST class for the current object - this is the TeamSignOutReasonCode class.
12942          * @returns {Object} The TeamSignOutReasonCode class.
12943          */
12944         getRestClass: function () {
12945             return TeamSignOutReasonCode;
12946         },
12947 
12948         /**
12949          * @private
12950          * Gets the REST type for the current object - this is a "ReasonCode".
12951          * @returns {String} The ReasonCode string.
12952          */
12953         getRestType: function () {
12954             return "ReasonCode";
12955         },
12956 
12957         /**
12958          * @private
12959          * Override default to indicate that this object doesn't support making
12960          * requests.
12961          */
12962         supportsRequests: false,
12963 
12964         /**
12965          * @private
12966          * Override default to indicate that this object doesn't support subscriptions.
12967          */
12968         supportsSubscriptions: false,
12969 
12970         /**
12971          * Getter for the category.
12972          * @returns {String} The category.
12973          */
12974         getCategory: function () {
12975             this.isLoaded();
12976             return this.getData().category;
12977         },
12978 
12979         /**
12980          * Getter for the code.
12981          * @returns {String} The code.
12982          */
12983         getCode: function () {
12984             this.isLoaded();
12985             return this.getData().code;
12986         },
12987 
12988         /**
12989          * Getter for the label.
12990          * @returns {String} The label.
12991          */
12992         getLabel: function () {
12993             this.isLoaded();
12994             return this.getData().label;
12995         },
12996 
12997         /**
12998          * Getter for the forAll value.
12999          * @returns {String} The forAll.
13000          */
13001         getForAll: function () {
13002             this.isLoaded();
13003             return this.getData().forAll;
13004         },
13005 
13006         /**
13007          * Getter for the Uri value.
13008          * @returns {String} The Uri.
13009          */
13010         getUri: function () {
13011             this.isLoaded();
13012             return this.getData().uri;
13013         }
13014 
13015     });
13016 
13017     window.finesse = window.finesse || {};
13018     window.finesse.restservices = window.finesse.restservices || {};
13019     window.finesse.restservices.TeamSignOutReasonCode = TeamSignOutReasonCode;
13020     
13021     return TeamSignOutReasonCode;
13022 }));
13023 
13024 /**
13025 * JavaScript representation of the TeamSignOutReasonCodes collection
13026 * object which contains a list of TeamSignOutReasonCode objects.
13027  *
13028  * @requires finesse.clientservices.ClientServices
13029  * @requires Class
13030  * @requires finesse.FinesseBase
13031  * @requires finesse.restservices.RestBase
13032  * @requires finesse.restservices.Dialog
13033  * @requires finesse.restservices.RestCollectionBase
13034  */
13035 
13036 /** @private */
13037 (function (factory) {
13038     
13039 
13040     // Define as an AMD module if possible
13041     if ( typeof define === 'function' && define.amd )
13042     {
13043         define('restservices/TeamSignOutReasonCodes', ['restservices/RestCollectionBase',
13044                  'restservices/RestBase',
13045                  'restservices/TeamSignOutReasonCode'], factory );
13046     }
13047     /* Define using browser globals otherwise
13048      * Prevent multiple instantiations if the script is loaded twice
13049      */
13050     else
13051     {
13052         factory(finesse.restservices.RestCollectionBase, finesse.restservices.RestBase, finesse.restservices.TeamSignOutReasonCode);
13053     } 
13054 }(function (RestCollectionBase, RestBase, TeamSignOutReasonCode) {
13055     
13056     var TeamSignOutReasonCodes = RestCollectionBase.extend({
13057         /**
13058          * @class
13059          * JavaScript representation of a TeamSignOutReasonCodes collection object. Also exposes
13060          * methods to operate on the object against the server.
13061          *
13062          * @param {Object} options
13063          *     An object with the following properties:<ul>
13064          *         <li><b>id:</b> The id of the object being constructed</li>
13065          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
13066          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
13067          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
13068          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
13069          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
13070          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
13071          *             <li><b>content:</b> {String} Raw string of response</li>
13072          *             <li><b>object:</b> {Object} Parsed object of response</li>
13073          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
13074          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
13075          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
13076          *             </ul></li>
13077          *         </ul></li>
13078          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
13079          * @constructs
13080          **/
13081         init: function (options) {
13082             this._super(options);
13083         },
13084 
13085         /**
13086          * @private
13087          * Gets the REST class for the current object - this is the TeamSignOutReasonCodes class.
13088          */
13089         getRestClass: function () {
13090             return TeamSignOutReasonCodes;
13091         },
13092 
13093         /**
13094          * @private
13095          * Gets the REST class for the objects that make up the collection. - this
13096          * is the TeamSignOutReasonCode class.
13097          */
13098         getRestItemClass: function () {
13099             return TeamSignOutReasonCode;
13100         },
13101 
13102         /**
13103          * @private
13104          * Gets the REST type for the current object - this is a "ReasonCodes".
13105          */
13106         getRestType: function () {
13107             return "ReasonCodes";
13108         },
13109 
13110         /**
13111          * Overrides the parent class.  Returns the url for the SignOutReasonCodes resource
13112          */
13113         getRestUrl: function () {
13114             var restObj = this._restObj, restUrl = "";
13115 
13116             //Prepend the base REST object if one was provided.
13117             //Otherwise prepend with the default webapp name.
13118             if (restObj instanceof RestBase) {
13119                 restUrl += restObj.getRestUrl();
13120             } else {
13121                 restUrl += "/finesse/api";
13122             }
13123             //Append the REST type.
13124             restUrl += "/ReasonCodes?category=LOGOUT";
13125             //Append ID if it is not undefined, null, or empty.
13126             if (this._id) {
13127                 restUrl += "/" + this._id;
13128             }
13129             return restUrl;
13130         },
13131 
13132         /**
13133          * @private
13134          * Gets the REST type for the objects that make up the collection - this is "ReasonCode".
13135          */
13136         getRestItemType: function () {
13137             return "ReasonCode";
13138         },
13139 
13140         /**
13141          * @private
13142          * Override default to indicates that the collection supports making requests.
13143          */
13144         supportsRequests: true,
13145 
13146         /**
13147          * @private
13148          * Override default to indicates that the collection does not subscribe to its objects.
13149          */
13150         supportsRestItemSubscriptions: false,
13151 
13152         /**
13153          * Retrieve the Sign Out Reason Codes.
13154          *
13155          * @returns {finesse.restservices.TeamSignOutReasonCodes}
13156          *     This TeamSignOutReasonCodes object to allow cascading.
13157          */
13158         get: function () {
13159             // set loaded to false so it will rebuild the collection after the get
13160             this._loaded = false;
13161             // reset collection
13162             this._collection = {};
13163             // perform get
13164             this._synchronize();
13165             return this;
13166         },
13167 
13168         /* We only use PUT and GET on Reason Code team assignments
13169          * @param {Object} contact
13170          * @param {Object} contentBody
13171          * @param {Function} successHandler
13172          */
13173         createPutSuccessHandler: function (contact, contentBody, successHandler) {
13174             return function (rsp) {
13175                 // Update internal structure based on response. Here we
13176                 // inject the contentBody from the PUT request into the
13177                 // rsp.object element to mimic a GET as a way to take
13178                 // advantage of the existing _processResponse method.
13179                 rsp.object = contentBody;
13180                 contact._processResponse(rsp);
13181 
13182                 //Remove the injected contentBody object before cascading response
13183                 rsp.object = {};
13184 
13185                 //cascade response back to consumer's response handler
13186                 successHandler(rsp);
13187             };
13188         },
13189 
13190         /**
13191          * Update - This should be all that is needed.
13192          * @param {Object} newValues
13193          * @param {Object} handlers
13194          * @returns {finesse.restservices.TeamSignOutReasonCodes}
13195          *     This TeamSignOutReasonCodes object to allow cascading.
13196          */
13197         update: function (newValues, handlers) {
13198             this.isLoaded();
13199             var contentBody = {}, contentBodyInner = [], i, innerObject = {};
13200 
13201             contentBody[this.getRestType()] = {
13202             };
13203 
13204             for (i in newValues) {
13205                 if (newValues.hasOwnProperty(i)) {
13206                     innerObject = {
13207                         "uri": newValues[i]
13208                     };
13209                     contentBodyInner.push(innerObject);
13210                 }
13211             }
13212 
13213             contentBody[this.getRestType()] = {
13214                 "ReasonCode" : contentBodyInner
13215             };
13216 
13217             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
13218             handlers = handlers || {};
13219 
13220             this.restRequest(this.getRestUrl(), {
13221                 method: 'PUT',
13222                 success: this.createPutSuccessHandler(this, contentBody, handlers.success),
13223                 error: handlers.error,
13224                 content: contentBody
13225             });
13226 
13227             return this; // Allow cascading
13228         }
13229 
13230     });
13231     
13232     window.finesse = window.finesse || {};
13233     window.finesse.restservices = window.finesse.restservices || {};
13234     window.finesse.restservices.TeamSignOutReasonCodes = TeamSignOutReasonCodes;
13235     
13236     return TeamSignOutReasonCodes;
13237 }));
13238 
13239 /**
13240  * JavaScript representation of the Finesse PhoneBook Assignment object.
13241  *
13242  * @requires finesse.clientservices.ClientServices
13243  * @requires Class
13244  * @requires finesse.FinesseBase
13245  * @requires finesse.restservices.RestBase
13246  */
13247 
13248 /**
13249  * The following comment prevents JSLint errors concerning undefined global variables.
13250  * It tells JSLint that these identifiers are defined elsewhere.
13251  */
13252 /*jslint bitwise:true, browser:true, nomen:true, regexp:true, sloppy:true, white:true */
13253 
13254 /** The following comment is to prevent jslint errors about 
13255  * using variables before they are defined.
13256  */
13257 /*global $, jQuery, Handlebars, dojox, dojo, finesse */
13258 
13259 /** @private */
13260 (function (factory) {
13261     
13262 
13263     // Define as an AMD module if possible
13264     if ( typeof define === 'function' && define.amd )
13265     {
13266         define('restservices/TeamPhoneBook', ['restservices/RestBase'], factory );
13267     }
13268     /* Define using browser globals otherwise
13269      * Prevent multiple instantiations if the script is loaded twice
13270      */
13271     else
13272     {
13273         factory(finesse.restservices.RestBase);
13274     }
13275 }(function (RestBase) {
13276     var TeamPhoneBook = RestBase.extend({
13277 
13278         /**
13279          * @class
13280          * JavaScript representation of a PhoneBook object. Also exposes
13281          * methods to operate on the object against the server.
13282          *
13283          * @param {Object} options
13284          *     An object with the following properties:<ul>
13285          *         <li><b>id:</b> The id of the object being constructed</li>
13286          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
13287          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
13288          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
13289          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
13290          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
13291          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
13292          *             <li><b>content:</b> {String} Raw string of response</li>
13293          *             <li><b>object:</b> {Object} Parsed object of response</li>
13294          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
13295          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
13296          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
13297          *             </ul></li>
13298          *         </ul></li>
13299          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
13300          * @constructs
13301          **/
13302         init: function (options) {
13303             this._super(options);
13304         },
13305 
13306         /**
13307          * @private
13308          * Gets the REST class for the current object - this is the PhoneBooks class.
13309          * @returns {Object} The PhoneBooks class.
13310          */
13311         getRestClass: function () {
13312             return TeamPhoneBook;
13313         },
13314 
13315         /**
13316          * @private
13317          * Gets the REST type for the current object - this is a "PhoneBook".
13318          * @returns {String} The PhoneBook string.
13319          */
13320         getRestType: function () {
13321             return "PhoneBook";
13322         },
13323 
13324         /**
13325          * @private
13326          * Override default to indicate that this object doesn't support making
13327          * requests.
13328          */
13329         supportsRequests: false,
13330 
13331         /**
13332          * @private
13333          * Override default to indicate that this object doesn't support subscriptions.
13334          */
13335         supportsSubscriptions: false,
13336 
13337         /**
13338          * Getter for the name.
13339          * @returns {String} The name.
13340          */
13341         getName: function () {
13342             this.isLoaded();
13343             return this.getData().name;
13344         },
13345 
13346         /**
13347          * Getter for the Uri value.
13348          * @returns {String} The Uri.
13349          */
13350         getUri: function () {
13351             this.isLoaded();
13352             return this.getData().uri;
13353         }
13354 
13355     });
13356 
13357     window.finesse = window.finesse || {};
13358     window.finesse.restservices = window.finesse.restservices || {};
13359     window.finesse.restservices.TeamPhoneBook = TeamPhoneBook;
13360     
13361     return TeamPhoneBook;
13362 }));
13363 
13364 /**
13365 * JavaScript representation of the Finesse PhoneBook Assignments collection
13366 * object which contains a list of Not Ready Reason Codes objects.
13367  *
13368  * @requires finesse.clientservices.ClientServices
13369  * @requires Class
13370  * @requires finesse.FinesseBase
13371  * @requires finesse.restservices.RestBase
13372  * @requires finesse.restservices.Dialog
13373  * @requires finesse.restservices.RestCollectionBase
13374  */
13375 
13376 /**
13377  * The following comment prevents JSLint errors concerning undefined global variables.
13378  * It tells JSLint that these identifiers are defined elsewhere.
13379  */
13380 /*jslint bitwise:true, browser:true, nomen:true, regexp:true, sloppy:true, white:true */
13381 
13382 /** The following comment is to prevent jslint errors about 
13383  * using variables before they are defined.
13384  */
13385 /*global $, jQuery, Handlebars, dojox, dojo, finesse */
13386 
13387 /** @private */
13388 (function (factory) {
13389     
13390 
13391     // Define as an AMD module if possible
13392     if ( typeof define === 'function' && define.amd )
13393     {
13394         define('restservices/TeamPhoneBooks', ['restservices/RestCollectionBase',
13395                  'restservices/RestBase',
13396                  'restservices/TeamPhoneBook'], factory );
13397     }
13398     /* Define using browser globals otherwise
13399      * Prevent multiple instantiations if the script is loaded twice
13400      */
13401     else
13402     {
13403         factory(finesse.restservices.RestCollectionBase, finesse.restservices.RestBase, finesse.restservices.TeamPhoneBook);
13404     } 
13405 }(function (RestCollectionBase, RestBase, TeamPhoneBook) {
13406     var TeamPhoneBooks = RestCollectionBase.extend({
13407         
13408         /**
13409          * @class
13410          * JavaScript representation of a TeamPhoneBooks collection object. Also exposes
13411          * methods to operate on the object against the server.
13412          *
13413          * @param {Object} options
13414          *     An object with the following properties:<ul>
13415          *         <li><b>id:</b> The id of the object being constructed</li>
13416          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
13417          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
13418          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
13419          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
13420          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
13421          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
13422          *             <li><b>content:</b> {String} Raw string of response</li>
13423          *             <li><b>object:</b> {Object} Parsed object of response</li>
13424          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
13425          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
13426          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
13427          *             </ul></li>
13428          *         </ul></li>
13429          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
13430          * @constructs
13431          **/
13432         init: function (options) {
13433             this._super(options);           
13434         },
13435 
13436         /**
13437          * @private
13438          * Gets the REST class for the current object - this is the TeamPhoneBooks class.
13439          */
13440         getRestClass: function () {
13441             return TeamPhoneBooks;
13442         },
13443 
13444         /**
13445          * @private
13446          * Gets the REST class for the objects that make up the collection. - this
13447          * is the TeamPhoneBooks class.
13448          */
13449         getRestItemClass: function () {
13450             return TeamPhoneBook;
13451         },
13452 
13453         /**
13454          * @private
13455          * Gets the REST type for the current object - this is a "ReasonCodes".
13456          */
13457         getRestType: function () {
13458             return "PhoneBooks";
13459         },
13460         
13461         /**
13462          * Overrides the parent class.  Returns the url for the PhoneBooks resource
13463          */
13464         getRestUrl: function () {
13465             // return ("/finesse/api/" + this.getRestType() + "?category=NOT_READY");
13466             var restObj = this._restObj,
13467             restUrl = "";
13468             //Prepend the base REST object if one was provided.
13469             if (restObj instanceof RestBase) {
13470                 restUrl += restObj.getRestUrl();
13471             }
13472             //Otherwise prepend with the default webapp name.
13473             else {
13474                 restUrl += "/finesse/api";
13475             }
13476             //Append the REST type.
13477             restUrl += "/PhoneBooks";
13478             //Append ID if it is not undefined, null, or empty.
13479             if (this._id) {
13480                 restUrl += "/" + this._id;
13481             }
13482             return restUrl;        
13483         },
13484         
13485         /**
13486          * @private
13487          * Gets the REST type for the objects that make up the collection - this is "ReasonCode".
13488          */
13489         getRestItemType: function () {
13490             return "PhoneBook";
13491         },
13492 
13493         /**
13494          * @private
13495          * Override default to indicates that the collection supports making
13496          * requests.
13497          */
13498         supportsRequests: true,
13499 
13500         /**
13501          * @private
13502          * Override default to indicates that the collection subscribes to its objects.
13503          */
13504         supportsRestItemSubscriptions: false,
13505         
13506         /**
13507          * Retrieve the Not Ready Reason Codes.
13508          *
13509          * @returns {finesse.restservices.TeamPhoneBooks}
13510          *     This TeamPhoneBooks object to allow cascading.
13511          */
13512         get: function () {
13513             // set loaded to false so it will rebuild the collection after the get
13514             /** @private */
13515             this._loaded = false;
13516             // reset collection
13517             /** @private */
13518             this._collection = {};
13519             // perform get
13520             this._synchronize();
13521             return this;
13522         },
13523 
13524         /* We only use PUT and GET on Reason Code team assignments 
13525          */
13526         createPutSuccessHandler: function(contact, contentBody, successHandler){
13527             return function (rsp) {
13528                 // Update internal structure based on response. Here we
13529                 // inject the contentBody from the PUT request into the
13530                 // rsp.object element to mimic a GET as a way to take
13531                 // advantage of the existing _processResponse method.
13532                 rsp.object = contentBody;
13533                 contact._processResponse(rsp);
13534 
13535                 //Remove the injected Contact object before cascading response
13536                 rsp.object = {};
13537                 
13538                 //cascade response back to consumer's response handler
13539                 successHandler(rsp);
13540             };
13541         },
13542 
13543         /**
13544          * Update - This should be all that is needed.
13545          */
13546         update: function (newValues, handlers) {
13547             this.isLoaded();
13548             var contentBody = {}, contentBodyInner = [], i, innerObject;
13549 
13550             contentBody[this.getRestType()] = {
13551             };
13552         
13553             for (i in newValues) {
13554                 if (newValues.hasOwnProperty(i)) {
13555                     innerObject = {};
13556                     innerObject = {
13557                         "uri": newValues[i]
13558                     };
13559                     contentBodyInner.push(innerObject);
13560                 }
13561             }
13562 
13563             contentBody[this.getRestType()] = {
13564                 "PhoneBook" : contentBodyInner
13565             };
13566 
13567             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
13568             handlers = handlers || {};
13569 
13570             this.restRequest(this.getRestUrl(), {
13571                 method: 'PUT',
13572                 success: this.createPutSuccessHandler(this, contentBody, handlers.success),
13573                 error: handlers.error,
13574                 content: contentBody
13575             });
13576 
13577             return this; // Allow cascading
13578         }       
13579         
13580     });
13581         
13582     window.finesse = window.finesse || {};
13583     window.finesse.restservices = window.finesse.restservices || {};
13584     window.finesse.restservices.TeamPhoneBooks = TeamPhoneBooks;
13585     
13586     return TeamPhoneBooks;
13587 }));
13588 
13589 /**
13590  * JavaScript representation of the Finesse LayoutConfig object
13591  * @requires ClientServices
13592  * @requires finesse.FinesseBase
13593  * @requires finesse.restservices.RestBase
13594  */
13595 
13596 /** @private */
13597 (function (factory) {
13598     
13599 
13600     // Define as an AMD module if possible
13601     if ( typeof define === 'function' && define.amd )
13602     {
13603         define('restservices/LayoutConfig', ['restservices/RestBase'], factory );
13604     }
13605     /* Define using browser globals otherwise
13606      * Prevent multiple instantiations if the script is loaded twice
13607      */
13608     else
13609     {
13610         factory(finesse.restservices.RestBase);
13611     } 
13612 }(function (RestBase) {
13613     /** @private */
13614 	var LayoutConfig = RestBase.extend({
13615 
13616 		/**
13617 		 * @class
13618 		 * JavaScript representation of a LayoutConfig object. Also exposes methods to operate
13619 		 * on the object against the server.
13620 		 *
13621 		 * @param {String} id
13622 		 *     Not required...
13623 		 * @param {Object} callbacks
13624 		 *     An object containing callbacks for instantiation and runtime
13625 		 * @param {Function} callbacks.onLoad(this)
13626 		 *     Callback to invoke upon successful instantiation
13627 		 * @param {Function} callbacks.onLoadError(rsp)
13628 		 *     Callback to invoke on instantiation REST request error
13629 		 *     as passed by finesse.clientservices.ClientServices.ajax()
13630 		 *     {
13631 		 *         status: {Number} The HTTP status code returned
13632 		 *         content: {String} Raw string of response
13633 		 *         object: {Object} Parsed object of response
13634 		 *         error: {Object} Wrapped exception that was caught
13635 		 *         error.errorType: {String} Type of error that was caught
13636 		 *         error.errorMessage: {String} Message associated with error
13637 		 *     }
13638 		 * @param {Function} callbacks.onChange(this)
13639 		 *     Callback to invoke upon successful update
13640 		 * @param {Function} callbacks.onError(rsp)
13641 		 *     Callback to invoke on update error (refresh or event)
13642 		 *     as passed by finesse.clientservices.ClientServices.ajax()
13643 		 *     {
13644 		 *         status: {Number} The HTTP status code returned
13645 		 *         content: {String} Raw string of response
13646 		 *         object: {Object} Parsed object of response
13647 		 *         error: {Object} Wrapped exception that was caught
13648 		 *         error.errorType: {String} Type of error that was caught
13649 		 *         error.errorMessage: {String} Message associated with error
13650 		 *     }
13651 		 *  
13652 	     * @constructs
13653 		 */
13654 		init: function (callbacks) {
13655 			this._super("", callbacks);
13656 			//when post is performed and id is empty
13657 			/*if (id === "") {
13658 				this._loaded = true;
13659 			}*/
13660 	        this._layoutxml = {};
13661 		},
13662 	
13663 		/**
13664 		 * Returns REST class of LayoutConfig object
13665 		 */
13666 		getRestClass: function () {
13667 			return LayoutConfig;
13668 		},
13669 	
13670 		/**
13671 		 * The type of this REST object is LayoutConfig
13672 		 */
13673 		getRestType: function () {
13674 			return "LayoutConfig";
13675 		},
13676 
13677 		/**
13678 		 * Gets the REST URL of this object.
13679 		 * 
13680 		 * If the parent has an id, the id is appended.
13681 		 * On occasions of POST, it will not have an id.
13682 		 */
13683 		getRestUrl: function () {
13684 			var layoutUri = "/finesse/api/" + this.getRestType() + "/default";
13685 			/*if (this._id) {
13686 				layoutUri = layoutUri + "/" + this._id;
13687 			}*/
13688 			return layoutUri;
13689 		},
13690 	
13691 		/**
13692 		 * This API does not support subscription
13693 		 */
13694 		supportsSubscriptions: false,
13695 		
13696 		keepRestResponse: true,
13697 
13698 
13699 		/**
13700 		 * Gets finesselayout.xml retrieved from the API call
13701 		 */
13702 		getLayoutxml: function () {
13703 			this.isLoaded();
13704 			var layoutxml = this.getData().layoutxml;
13705 
13706             // We need to unescape everything that is unallowed in xml so consumers don't have to deal with it (used in tandem with update())
13707             layoutxml = layoutxml.replace(/&/g,"&");
13708 
13709             return layoutxml;
13710 		},
13711 	
13712 		/**
13713 		 * Gets the type of this LayoutConfig object
13714 		 */
13715 		/*
13716 		getType: function () {
13717 			this.isLoaded();
13718 			return this.getData().type;
13719 		},*/
13720 	
13721 		/**
13722 		 * Retrieve the LayoutConfig settings.
13723 		 * If the id is not provided the API call will fail.
13724 		 * @returns {LayoutConfig}
13725 		 *     This LayoutConfig object to allow cascading.
13726 		 */
13727 		get: function () {      
13728 			this._synchronize();
13729 			return this;
13730 		},
13731 
13732 		/**
13733 		 * Closure handle updating of the internal data for the LayoutConfig object
13734 		 * upon a successful update (PUT) request before calling the intended
13735 		 * success handler provided by the consumer
13736 		 * 
13737 		 * @param {Object}
13738 		 *            layoutconfig Reference to this LayoutConfig object
13739 		 * @param {Object}
13740 		 *            LayoutConfig Object that contains the  settings to be
13741 		 *            submitted in the api request
13742 		 * @param {Function}
13743 		 *            successHandler The success handler specified by the consumer
13744 		 *            of this object
13745 		 * @returns {LayoutConfig} This LayoutConfig object to allow cascading
13746 		 */
13747 	
13748 		createPutSuccessHandler: function (layoutconfig, contentBody, successHandler) {
13749 			return function (rsp) {			
13750 				// Update internal structure based on response. Here we
13751 				// inject the contentBody from the PUT request into the
13752 				// rsp.object element to mimic a GET as a way to take
13753 				// advantage of the existing _processResponse method.
13754 				rsp.content = contentBody;
13755 				rsp.object.LayoutConfig = {};
13756 				rsp.object.LayoutConfig.finesseLayout = contentBody;
13757 				layoutconfig._processResponse(rsp);
13758 	
13759 				//Remove the injected layoutConfig object before cascading response
13760 				rsp.object.LayoutConfig = {};
13761 	
13762 				//cascade response back to consumer's response handler
13763 				successHandler(rsp);
13764 			};
13765 		},
13766 	
13767 		/**
13768 		 *  Update LayoutConfig
13769 		 * @param {Object} finesselayout
13770 		 *     The XML for FinesseLayout being stored
13771 		 * 
13772 		 * @param {Object} handlers
13773 		 *     An object containing callback handlers for the request. Optional.
13774 		 * @param {Function} options.success(rsp)
13775 		 *     A callback function to be invoked for a successful request.
13776 		 *     {
13777 		 *         status: {Number} The HTTP status code returned
13778 		 *         content: {String} Raw string of response
13779 		 *         object: {Object} Parsed object of response
13780 		 *     }
13781 		 * @param {Function} options.error(rsp)
13782 		 *     A callback function to be invoked for an unsuccessful request.
13783 		 *     {
13784 		 *         status: {Number} The HTTP status code returned
13785 		 *         content: {String} Raw string of response
13786 		 *         object: {Object} Parsed object of response (HTTP errors)
13787 		 *         error: {Object} Wrapped exception that was caught
13788 		 *         error.errorType: {String} Type of error that was caught
13789 		 *         error.errorMessage: {String} Message associated with error
13790 		 *     }
13791 		 * @returns {finesse.restservices.LayoutConfig}
13792 		 *     This LayoutConfig object to allow cascading
13793 		 */
13794 	
13795 		update: function (layoutxml, handlers) {
13796 			this.isLoaded();
13797 			var contentBody = {};
13798 
13799 			// We need to escape everything that is unallowed in xml so consumers don't have to deal with it (used in tandem with getLayoutxml())
13800 			layoutxml = layoutxml.replace(/&(?!amp;)/g, "&");
13801 
13802 			contentBody[this.getRestType()] = {
13803 				"layoutxml": finesse.utilities.Utilities.translateHTMLEntities(layoutxml, true)
13804 			};
13805 
13806 			// Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
13807 			handlers = handlers || {};
13808 
13809 			this.restRequest(this.getRestUrl(), {
13810 				method: 'PUT',
13811 				success: this.createPutSuccessHandler(this, layoutxml, handlers.success),
13812 				error: handlers.error,
13813 				content: contentBody
13814 			});
13815 
13816 			return this; // Allow cascading
13817 		}
13818 	
13819 		/**
13820 		 *TODO createPostSuccessHandler needs to be debugged to make it working
13821 		 * Closure handle creating new  LayoutConfig object
13822 		 * upon a successful create (POST) request before calling the intended
13823 		 * success handler provided by the consumer
13824 		 * 
13825 		 * @param {Object}
13826 		 *            layoutconfig Reference to this LayoutConfig object
13827 		 * @param {Object}
13828 		 *            LayoutConfig Object that contains the  settings to be
13829 		 *            submitted in the api request
13830 		 * @param {Function}
13831 		 *            successHandler The success handler specified by the consumer
13832 		 *            of this object
13833 		 * @returns {finesse.restservices.LayoutConfig} This LayoutConfig object to allow cascading
13834 		 */
13835 	/*
13836 		createPostSuccessHandler: function (layoutconfig, contentBody, successHandler) {
13837 			return function (rsp) {
13838 	
13839 				rsp.object = contentBody;
13840 				layoutconfig._processResponse(rsp);
13841 	
13842 				//Remove the injected layoutConfig object before cascading response
13843 				rsp.object = {};
13844 	
13845 				//cascade response back to consumer's response handler
13846 				successHandler(rsp);
13847 			};
13848 		}, */
13849 	
13850 		/**
13851 		 * TODO Method needs to be debugged to make POST working
13852 		 *  Add LayoutConfig
13853 		 * @param {Object} finesselayout
13854 		 *     The XML for FinesseLayout being stored
13855 		 * 
13856 		 * @param {Object} handlers
13857 		 *     An object containing callback handlers for the request. Optional.
13858 		 * @param {Function} options.success(rsp)
13859 		 *     A callback function to be invoked for a successful request.
13860 		 *     {
13861 		 *         status: {Number} The HTTP status code returned
13862 		 *         content: {String} Raw string of response
13863 		 *         object: {Object} Parsed object of response
13864 		 *     }
13865 		 * @param {Function} options.error(rsp)
13866 		 *     A callback function to be invoked for an unsuccessful request.
13867 		 *     {
13868 		 *         status: {Number} The HTTP status code returned
13869 		 *         content: {String} Raw string of response
13870 		 *         object: {Object} Parsed object of response (HTTP errors)
13871 		 *         error: {Object} Wrapped exception that was caught
13872 		 *         error.errorType: {String} Type of error that was caught
13873 		 *         error.errorMessage: {String} Message associated with error
13874 		 *     }
13875 		 * @returns {finesse.restservices.LayoutConfig}
13876 		 *     This LayoutConfig object to allow cascading
13877 		 */
13878 	/*
13879 		add: function (layoutxml, handlers) {
13880 			this.isLoaded();
13881 			var contentBody = {};
13882 	
13883 	
13884 			contentBody[this.getRestType()] = {
13885 					"layoutxml": layoutxml,
13886 					"type": "current"
13887 			    };
13888 	
13889 			// Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
13890 			handlers = handlers || {};
13891 	
13892 			this.restRequest(this.getRestUrl(), {
13893 				method: 'POST',
13894 				success: this.createPostSuccessHandler(this, contentBody, handlers.success),
13895 				error: handlers.error,
13896 				content: contentBody
13897 			});
13898 	
13899 			return this; // Allow cascading
13900 		} */
13901 	});
13902 	
13903 	window.finesse = window.finesse || {};
13904     window.finesse.restservices = window.finesse.restservices || {};
13905     window.finesse.restservices.LayoutConfig = LayoutConfig;
13906     
13907 	return LayoutConfig;
13908 	
13909 }));
13910 
13911 /**
13912  * JavaScript representation of the Finesse LayoutConfig object for a Team.
13913  *
13914  * @requires finesse.clientservices.ClientServices
13915  * @requires Class
13916  * @requires finesse.FinesseBase
13917  * @requires finesse.restservices.RestBase
13918  * @requires finesse.utilities.Utilities
13919  * @requires finesse.restservices.LayoutConfig
13920  */
13921 
13922 /** The following comment is to prevent jslint errors about 
13923  * using variables before they are defined.
13924  */
13925 /*global Exception */
13926 
13927 /** @private */
13928 (function (factory) {
13929     
13930 
13931     // Define as an AMD module if possible
13932     if ( typeof define === 'function' && define.amd )
13933     {
13934         define('restservices/TeamLayoutConfig', ['restservices/RestBase',
13935                  'utilities/Utilities',
13936                  'restservices/LayoutConfig'], factory );
13937     }
13938     /* Define using browser globals otherwise
13939      * Prevent multiple instantiations if the script is loaded twice
13940      */
13941     else
13942     {
13943         factory(finesse.restservices.RestBase, finesse.utilities.Utilities, finesse.restservices.LayoutConfig);
13944     }
13945 }(function (RestBase, Utilities, LayoutConfig) {
13946     
13947     var TeamLayoutConfig = RestBase.extend({
13948       // Keep the restresponse so we can parse the layoutxml out of it in getLayoutXML()
13949       keepRestResponse: true,
13950     
13951       /**
13952        * @class
13953        * JavaScript representation of a LayoutConfig object for a Team. Also exposes
13954        * methods to operate on the object against the server.
13955        *
13956        * @param {Object} options
13957        *     An object with the following properties:<ul>
13958        *         <li><b>id:</b> The id of the object being constructed</li>
13959        *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
13960        *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
13961        *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
13962        *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
13963        *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
13964        *             <li><b>status:</b> {Number} The HTTP status code returned</li>
13965        *             <li><b>content:</b> {String} Raw string of response</li>
13966        *             <li><b>object:</b> {Object} Parsed object of response</li>
13967        *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
13968        *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
13969        *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
13970        *             </ul></li>
13971        *         </ul></li>
13972        *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
13973        * @constructs
13974        **/
13975       init: function (options) {
13976           this._super(options);
13977       },
13978     
13979       /**
13980        * @private
13981        * Gets the REST class for the current object - this is the LayoutConfigs class.
13982        * @returns {Object} The LayoutConfigs class.
13983        */
13984       getRestClass: function () {
13985           return TeamLayoutConfig;
13986       },
13987     
13988       /**
13989        * @private
13990        * Gets the REST type for the current object - this is a "LayoutConfig".
13991        * @returns {String} The LayoutConfig string.
13992        */
13993       getRestType: function () {
13994           return "TeamLayoutConfig";
13995       },
13996     
13997       /**
13998        * @private
13999        * Override default to indicate that this object doesn't support making
14000        * requests.
14001        */
14002       supportsRequests: false,
14003     
14004       /**
14005        * @private
14006        * Override default to indicate that this object doesn't support subscriptions.
14007        */
14008       supportsSubscriptions: false,
14009     
14010       /**
14011        * Getter for the category.
14012        * @returns {String} The category.
14013        */
14014       getLayoutXML: function () {
14015           this.isLoaded();
14016           var layoutxml = this.getData().layoutxml;
14017 
14018           // We need to unescape everything that is unallowed in xml so consumers don't have to deal with it (used in tandem with put())
14019           layoutxml = layoutxml.replace(/&/g,"&");
14020 
14021           return layoutxml;
14022       },
14023     
14024       /**
14025        * Getter for the code.
14026        * @returns {String} The code.
14027        */
14028       getUseDefault: function () {
14029           this.isLoaded();
14030           return this.getData().useDefault;
14031       },
14032       
14033       /**
14034        * Retrieve the TeamLayoutConfig.
14035        *
14036        * @returns {finesse.restservices.TeamLayoutConfig}
14037        */
14038       get: function () {
14039           // this._id is needed, but is not used in this object.. we're overriding getRestUrl anyway
14040           this._id = "0";
14041           // set loaded to false so it will rebuild the collection after the get
14042           this._loaded = false;
14043           // reset collection
14044           this._collection = {};
14045           // perform get
14046           this._synchronize();
14047           return this;
14048       },
14049     
14050       createPutSuccessHandler: function(contact, contentBody, successHandler){
14051           return function (rsp) {
14052               // Update internal structure based on response. Here we
14053               // inject the contentBody from the PUT request into the
14054               // rsp.object element to mimic a GET as a way to take
14055               // advantage of the existing _processResponse method.
14056               rsp.object = contentBody;
14057               contact._processResponse(rsp);
14058     
14059               //Remove the injected Contact object before cascading response
14060               rsp.object = {};
14061               
14062               //cascade response back to consumer's response handler
14063               successHandler(rsp);
14064           };
14065       },
14066       
14067       put: function (newValues, handlers) {
14068           // this._id is needed, but is not used in this object.. we're overriding getRestUrl anyway
14069           this._id = "0";
14070           this.isLoaded();
14071 
14072           // We need to escape everything that is unallowed in xml so consumers don't have to deal with it (used in tandem with getLayoutxml())
14073           var layoutxml = newValues.layoutXML.replace(/&(?!amp;)/g, "&"),
14074               contentBody = {};
14075           
14076           contentBody[this.getRestType()] = {
14077               "useDefault": newValues.useDefault,
14078               // The LayoutConfig restservice javascript class only translates ampersands, so we'll do that also
14079               "layoutxml": finesse.utilities.Utilities.translateHTMLEntities(layoutxml, true)
14080           };
14081     
14082           // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
14083           handlers = handlers || {};
14084     
14085           this.restRequest(this.getRestUrl(), {
14086               method: 'PUT',
14087               success: this.createPutSuccessHandler(this, contentBody, handlers.success),
14088               error: handlers.error,
14089               content: contentBody
14090           });
14091     
14092           return this; // Allow cascading
14093       },
14094     
14095       getRestUrl: function(){
14096           // return team's url + /LayoutConfig
14097           // eg: /api/Team/1/LayoutConfig
14098           if(this._restObj === undefined){
14099               throw new Exception("TeamLayoutConfig instances must have a parent team object.");
14100           }
14101           return this._restObj.getRestUrl() + '/LayoutConfig';
14102       }
14103     
14104       });
14105         
14106     window.finesse = window.finesse || {};
14107     window.finesse.restservices = window.finesse.restservices || {};
14108     window.finesse.restservices.TeamLayoutConfig = TeamLayoutConfig;
14109       
14110       return TeamLayoutConfig;
14111 }));
14112 
14113 /**
14114  * JavaScript representation of a TeamWorkflow.
14115  *
14116  * @requires finesse.clientservices.ClientServices
14117  * @requires Class
14118  * @requires finesse.FinesseBase
14119  * @requires finesse.restservices.RestBase
14120  */
14121 /** @private */
14122 (function (factory) {
14123     
14124 
14125     // Define as an AMD module if possible
14126     if ( typeof define === 'function' && define.amd )
14127     {
14128         define('restservices/TeamWorkflow', ['restservices/RestBase'], factory );
14129     }
14130     /* Define using browser globals otherwise
14131      * Prevent multiple instantiations if the script is loaded twice
14132      */
14133     else
14134     {
14135         factory(finesse.restservices.RestBase);
14136     } 
14137 }(function (RestBase) {
14138 
14139     var TeamWorkflow = RestBase.extend({
14140 
14141         /**
14142          * @class
14143          * JavaScript representation of a TeamWorkflow object. Also exposes
14144          * methods to operate on the object against the server.
14145          *
14146          * @param {Object} options
14147          *     An object with the following properties:<ul>
14148          *         <li><b>id:</b> The id of the object being constructed</li>
14149          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
14150          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
14151          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
14152          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
14153          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
14154          *             <li><b>status:</b> {Number} The HTTP status description returned</li>
14155          *             <li><b>content:</b> {String} Raw string of response</li>
14156          *             <li><b>object:</b> {Object} Parsed object of response</li>
14157          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
14158          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
14159          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
14160          *             </ul></li>
14161          *         </ul></li>
14162          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
14163          * @constructs
14164          **/
14165         init: function (options) {
14166             this._super(options);
14167         },
14168 
14169         /**
14170          * @private
14171          * Gets the REST class for the current object - this is the TeamWorkflow class.
14172          * @returns {Object} The TeamWorkflow class.
14173          */
14174         getRestClass: function () {
14175             return TeamWorkflow;
14176         },
14177 
14178         /**
14179          * @private
14180          * Gets the REST type for the current object - this is a "Workflow".
14181          * @returns {String} The Workflow string.
14182          */
14183         getRestType: function () {
14184             return "Workflow";
14185         },
14186 
14187         /**
14188          * @private
14189          * Override default to indicate that this object doesn't support making
14190          * requests.
14191          */
14192         supportsRequests: false,
14193 
14194         /**
14195          * @private
14196          * Override default to indicate that this object doesn't support subscriptions.
14197          */
14198         supportsSubscriptions: false,
14199 
14200         /**
14201          * Getter for the name.
14202          * @returns {String} The name.
14203          */
14204         getName: function () {
14205             this.isLoaded();
14206             return this.getData().name;
14207         },
14208 
14209         /**
14210          * Getter for the description.
14211          * @returns {String} The description.
14212          */
14213         getDescription: function () {
14214             this.isLoaded();
14215             return this.getData().description;
14216         },
14217 
14218         /**
14219          * Getter for the Uri value.
14220          * @returns {String} The Uri.
14221          */
14222         getUri: function () {
14223             this.isLoaded();
14224             return this.getData().uri;
14225         }
14226 
14227     });
14228     
14229 	window.finesse = window.finesse || {};
14230     window.finesse.restservices = window.finesse.restservices || {};
14231     window.finesse.restservices.TeamWorkflow = TeamWorkflow;
14232 
14233     return TeamWorkflow;
14234 }));
14235 
14236 /**
14237 * JavaScript representation of the TeamWorkflows collection
14238 * object which contains a list of TeamWorkflow objects.
14239  *
14240  * @requires finesse.clientservices.ClientServices
14241  * @requires Class
14242  * @requires finesse.FinesseBase
14243  * @requires finesse.restservices.RestBase
14244  * @requires finesse.restservices.Dialog
14245  * @requires finesse.restservices.RestCollectionBase
14246  */
14247 /** @private */
14248 (function (factory) {
14249     
14250 
14251     // Define as an AMD module if possible
14252     if ( typeof define === 'function' && define.amd )
14253     {
14254         define('restservices/TeamWorkflows', ['restservices/RestCollectionBase',
14255                  'restservices/TeamWorkflow',
14256                  'restservices/RestBase'], factory );
14257     }
14258     /* Define using browser globals otherwise
14259      * Prevent multiple instantiations if the script is loaded twice
14260      */
14261     else
14262     {
14263         factory(finesse.restservices.RestCollectionBase, finesse.restservices.TeamWorkflow, finesse.restservices.RestBase);
14264     } 
14265 }(function (RestCollectionBase, TeamWorkflow, RestBase) {
14266 
14267     var TeamWorkflows = RestCollectionBase.extend({
14268     
14269         /**
14270          * @class
14271          * JavaScript representation of a TeamWorkflows collection object. Also exposes
14272          * methods to operate on the object against the server.
14273          *
14274          * @param {Object} options
14275          *     An object with the following properties:<ul>
14276          *         <li><b>id:</b> The id of the object being constructed</li>
14277          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
14278          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
14279          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
14280          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
14281          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
14282          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
14283          *             <li><b>content:</b> {String} Raw string of response</li>
14284          *             <li><b>object:</b> {Object} Parsed object of response</li>
14285          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
14286          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
14287          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
14288          *             </ul></li>
14289          *         </ul></li>
14290          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
14291          * @constructs
14292          **/
14293         init: function (options) {
14294             this._super(options);
14295         },
14296 
14297         /**
14298          * @private
14299          * Gets the REST class for the current object - this is the TeamWorkflows class.
14300          */
14301         getRestClass: function () {
14302             return TeamWorkflows;
14303         },
14304 
14305         /**
14306          * @private
14307          * Gets the REST class for the objects that make up the collection. - this
14308          * is the TeamWorkflow class.
14309          */
14310         getRestItemClass: function () {
14311             return TeamWorkflow;
14312         },
14313 
14314         /**
14315          * @private
14316          * Gets the REST type for the current object - this is a "Workflows".
14317          */
14318         getRestType: function () {
14319             return "Workflows";
14320         },
14321 
14322         /**
14323          * Overrides the parent class.  Returns the url for the Workflows resource
14324          */
14325         getRestUrl: function () {
14326             var restObj = this._restObj, restUrl = "";
14327 
14328             //Prepend the base REST object if one was provided.
14329             //Otherwise prepend with the default webapp name.
14330             if (restObj instanceof RestBase) {
14331                 restUrl += restObj.getRestUrl();
14332             } else {
14333                 restUrl += "/finesse/api/Team";
14334             }
14335             //Append ID if it is not undefined, null, or empty.
14336             if (this._id) {
14337                 restUrl += "/" + this._id;
14338             }
14339             //Append the REST type.
14340             restUrl += "/Workflows";
14341             
14342             return restUrl;
14343         },
14344 
14345         /**
14346          * @private
14347          * Gets the REST type for the objects that make up the collection - this is "Workflow".
14348          */
14349         getRestItemType: function () {
14350             return "Workflow";
14351         },
14352 
14353         /**
14354          * @private
14355          * Override default to indicates that the collection supports making requests.
14356          */
14357         supportsRequests: true,
14358 
14359         /**
14360          * @private
14361          * Override default to indicates that the collection does not subscribe to its objects.
14362          */
14363         supportsRestItemSubscriptions: false,
14364 
14365         /**
14366          * Retrieve the Sign Out Reason Codes.
14367          *
14368          * @returns {finesse.restservices.TeamWorkflows}
14369          *     This TeamWorkflows object to allow cascading.
14370          */
14371         get: function () {
14372             // set loaded to false so it will rebuild the collection after the get
14373             this._loaded = false;
14374             // reset collection
14375             this._collection = {};
14376             // perform get
14377             this._synchronize();
14378             return this;
14379         },
14380 
14381         /* We only use PUT and GET on Reason Code team assignments
14382          * @param {Object} contact
14383          * @param {Object} contentBody
14384          * @param {Function} successHandler
14385          */
14386         createPutSuccessHandler: function (contact, contentBody, successHandler) {
14387             return function (rsp) {
14388                 // Update internal structure based on response. Here we
14389                 // inject the contentBody from the PUT request into the
14390                 // rsp.object element to mimic a GET as a way to take
14391                 // advantage of the existing _processResponse method.
14392                 rsp.object = contentBody;
14393                 contact._processResponse(rsp);
14394 
14395                 //Remove the injected contentBody object before cascading response
14396                 rsp.object = {};
14397 
14398                 //cascade response back to consumer's response handler
14399                 successHandler(rsp);
14400             };
14401         },
14402 
14403         /**
14404          * Update - This should be all that is needed.
14405          * @param {Object} newValues
14406          * @param {Object} handlers
14407          * @returns {finesse.restservices.TeamWorkflows}
14408          *     This TeamWorkflows object to allow cascading.
14409          */
14410         update: function (newValues, handlers) {
14411             this.isLoaded();
14412             var contentBody = {}, contentBodyInner = [], i, innerObject = {};
14413 
14414             contentBody[this.getRestType()] = {
14415             };
14416 
14417             for (i in newValues) {
14418                 if (newValues.hasOwnProperty(i)) {
14419                     innerObject = {
14420                         "uri": newValues[i]
14421                     };
14422                     contentBodyInner.push(innerObject);
14423                 }
14424             }
14425 
14426             contentBody[this.getRestType()] = {
14427                 "Workflow" : contentBodyInner
14428             };
14429 
14430             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
14431             handlers = handlers || {};
14432 
14433             this.restRequest(this.getRestUrl(), {
14434                 method: 'PUT',
14435                 success: this.createPutSuccessHandler(this, contentBody, handlers.success),
14436                 error: handlers.error,
14437                 content: contentBody
14438             });
14439 
14440             return this; // Allow cascading
14441         }
14442 
14443     });
14444     
14445 	window.finesse = window.finesse || {};
14446     window.finesse.restservices = window.finesse.restservices || {};
14447     window.finesse.restservices.TeamWorkflows = TeamWorkflows;
14448     
14449     return TeamWorkflows;
14450 }));
14451 
14452 /**
14453  * JavaScript representation of the Finesse Team REST object.
14454  *
14455  * @requires finesse.clientservices.ClientServices
14456  * @requires Class
14457  * @requires finesse.FinesseBase
14458  * @requires finesse.restservices.RestBase
14459  * @requires finesse.restservices.RestCollectionBase
14460  * @requires finesse.restservices.User
14461  * @requires finesse.restservices.Users
14462  */
14463 
14464 /**
14465  * The following comment prevents JSLint errors concerning undefined global variables.
14466  * It tells JSLint that these identifiers are defined elsewhere.
14467  */
14468 /*jslint bitwise:true, browser:true, nomen:true, regexp:true, sloppy:true, white:true */
14469 
14470 /** The following comment is to prevent jslint errors about 
14471  * using variables before they are defined.
14472  */
14473 /*global $, jQuery, Handlebars, dojox, dojo, finesse */
14474 
14475 /** @private */
14476 (function (factory) {
14477     
14478 
14479     // Define as an AMD module if possible
14480     if ( typeof define === 'function' && define.amd )
14481     {
14482         define('restservices/Team', ['restservices/RestBase',
14483                  'utilities/Utilities',
14484                  'restservices/Users',
14485                  'restservices/TeamNotReadyReasonCodes',
14486                  'restservices/TeamWrapUpReasons',
14487                  'restservices/TeamSignOutReasonCodes',
14488                  'restservices/TeamPhoneBooks',
14489                  'restservices/TeamLayoutConfig',
14490                  'restservices/TeamWorkflows'], factory );
14491     }
14492     /* Define using browser globals otherwise
14493      * Prevent multiple instantiations if the script is loaded twice
14494      */
14495     else
14496     {
14497         factory(finesse.restservices.RestBase,
14498                 finesse.utilities.Utilities,
14499                 finesse.restservices.Users,
14500                 finesse.restservices.TeamNotReadyReasonCodes,
14501                 finesse.restservices.TeamWrapUpReasons,
14502                 finesse.restservices.TeamSignOutReasonCodes,
14503                 finesse.restservices.TeamPhoneBooks,
14504                 finesse.restservices.TeamLayoutConfig,
14505                 finesse.restservices.TeamWorkflows);
14506     }
14507 }(function (RestBase, Utilities, Users, TeamNotReadyReasonCodes, TeamWrapUpReasons, TeamSignOutReasonCodes, TeamPhoneBooks, TeamLayoutConfig, TeamWorkflows) {
14508     var Team = RestBase.extend(/** @lends finesse.restservices.Team.prototype */{
14509         
14510         _teamLayoutConfig: null,
14511 
14512         /**
14513          * @class
14514          * A Team is a set of Agent Users, typically supervised by one or more Supervisor Users.
14515          *
14516          * @augments finesse.restservices.RestBase
14517          * @see finesse.restservices.User#getSupervisedTeams
14518          * @see finesse.restservices.Users
14519          * @constructs
14520          */
14521         _fakeConstuctor: function () {
14522             /* This is here to hide the real init constructor from the public docs */
14523         },
14524         
14525         /**
14526          * @private
14527          * @class
14528          * JavaScript representation of a Team object. Also exposes methods to operate
14529          * on the object against the server.
14530          *
14531          * @param {Object} options
14532          *     An object with the following properties:<ul>
14533          *         <li><b>id:</b> The id of the object being constructed</li>
14534          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
14535          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
14536          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
14537          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
14538          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
14539          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
14540          *             <li><b>content:</b> {String} Raw string of response</li>
14541          *             <li><b>object:</b> {Object} Parsed object of response</li>
14542          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
14543          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
14544          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
14545          *             </ul></li>
14546          *         </ul></li>
14547          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
14548          **/
14549         init: function (options) {
14550             this._super(options);
14551         },
14552     
14553         /**
14554          * @private
14555          * Gets the REST class for the current object - this is the Team class.
14556          * @returns {Object} The Team constructor.
14557          */
14558         getRestClass: function () {
14559             return finesse.restesrvices.Team;
14560         },
14561     
14562         /**
14563          * @private
14564          * Gets the REST type for the current object - this is a "Team".
14565          * @returns {String} The Team string.
14566          */
14567         getRestType: function () {
14568             return "Team";
14569         },
14570     
14571         /**
14572          * @private
14573          * Override default to indicate that this object doesn't support making
14574          * requests.
14575          */
14576         supportsSubscriptions: false,
14577     
14578         /**
14579          * Getter for the team id.
14580          * @returns {String} The team id.
14581          */
14582         getId: function () {
14583             this.isLoaded();
14584             return this.getData().id;
14585         },
14586     
14587         /**
14588          * Getter for the team name.
14589          * @returns {String} The team name
14590          */
14591         getName: function () {
14592             this.isLoaded();
14593             return this.getData().name;
14594         },
14595     
14596         /**
14597          * @private
14598          * Getter for the team uri.
14599          * @returns {String} The team uri
14600          */
14601         getUri: function () {
14602             this.isLoaded();
14603             return this.getData().uri;        
14604         },
14605     
14606         /**
14607          * Constructs and returns a collection of Users.
14608          * @param {finesse.interfaces.RestObjectHandlers} [handlers] Object that sets callback handlers.
14609          * @returns {finesse.restservices.Users} Users collection of User objects.
14610          */
14611         getUsers: function (options) {
14612             this.isLoaded();
14613             options = options || {};
14614     
14615             options.parentObj = this;
14616             // We are using getData() instead of getData.Users because the superclass (RestCollectionBase)
14617             // for Users needs the "Users" key to validate the provided payload matches the class type.
14618             options.data = this.getData();
14619     
14620             return new Users(options);
14621         },
14622     
14623         /**
14624          * @private
14625          * Getter for a teamNotReadyReasonCodes collection object that is associated with Team.
14626          * @param callbacks
14627          * @returns {teamNotReadyReasonCodes}
14628          *     A teamNotReadyReasonCodes collection object.
14629          */
14630         getTeamNotReadyReasonCodes: function (callbacks) {
14631             var options = callbacks || {};
14632             options.parentObj = this;
14633             this.isLoaded();
14634     
14635             if (!this._teamNotReadyReasonCodes) {
14636                 this._teamNotReadyReasonCodes = new TeamNotReadyReasonCodes(options);
14637             }
14638     
14639             return this._teamNotReadyReasonCodes;
14640         },
14641     
14642         /**
14643          * @private
14644          * Getter for a teamWrapUpReasons collection object that is associated with Team.
14645          * @param callbacks
14646          * @returns {teamWrapUpReasons}
14647          *     A teamWrapUpReasons collection object.
14648          */
14649         getTeamWrapUpReasons: function (callbacks) {
14650             var options = callbacks || {};
14651             options.parentObj = this;
14652             this.isLoaded();
14653     
14654             if (!this._teamWrapUpReasons) {
14655                 this._teamWrapUpReasons = new TeamWrapUpReasons(options);
14656             }
14657     
14658             return this._teamWrapUpReasons;
14659         },
14660     
14661         /**
14662          * @private
14663          * Getter for a teamSignOutReasonCodes collection object that is associated with Team.
14664          * @param callbacks
14665          * @returns {teamSignOutReasonCodes}
14666          *     A teamSignOutReasonCodes collection object.
14667          */
14668     
14669         getTeamSignOutReasonCodes: function (callbacks) {
14670             var options = callbacks || {};
14671             options.parentObj = this;
14672             this.isLoaded();
14673     
14674             if (!this._teamSignOutReasonCodes) {
14675                 this._teamSignOutReasonCodes = new TeamSignOutReasonCodes(options);
14676             }
14677     
14678             return this._teamSignOutReasonCodes;
14679         },
14680     
14681         /**
14682          * @private
14683          * Getter for a teamPhoneBooks collection object that is associated with Team.
14684          * @param callbacks
14685          * @returns {teamPhoneBooks}
14686          *     A teamPhoneBooks collection object.
14687          */
14688         getTeamPhoneBooks: function (callbacks) {
14689             var options = callbacks || {};
14690             options.parentObj = this;
14691             this.isLoaded();
14692     
14693             if (!this._phonebooks) {
14694                 this._phonebooks = new TeamPhoneBooks(options);
14695             }
14696     
14697             return this._phonebooks;
14698         },
14699     
14700         /**
14701          * @private
14702          * Getter for a teamWorkflows collection object that is associated with Team.
14703          * @param callbacks
14704          * @returns {teamWorkflows}
14705          *     A teamWorkflows collection object.
14706          */
14707         getTeamWorkflows: function (callbacks) {
14708             var options = callbacks || {};
14709             options.parentObj = this;
14710             this.isLoaded();
14711     
14712             if (!this._workflows) {
14713                 this._workflows = new TeamWorkflows(options);
14714             }
14715     
14716             return this._workflows;
14717         },
14718     
14719         /**
14720          * @private
14721          * Getter for a teamLayoutConfig object that is associated with Team.
14722          * @param callbacks
14723          * @returns {teamLayoutConfig}
14724          */
14725         getTeamLayoutConfig: function (callbacks) {
14726             var options = callbacks || {};
14727             options.parentObj = this;
14728             this.isLoaded();
14729     
14730             if (this._teamLayoutConfig === null) {
14731                 this._teamLayoutConfig = new TeamLayoutConfig(options);
14732             }
14733     
14734             return this._teamLayoutConfig;
14735         }
14736     
14737     });
14738     
14739     window.finesse = window.finesse || {};
14740     window.finesse.restservices = window.finesse.restservices || {};
14741     window.finesse.restservices.Team = Team;
14742     
14743     return Team;    
14744 }));
14745 
14746 /**
14747  * JavaScript representation of the Finesse Teams collection.
14748  * object which contains a list of Team objects
14749  * @requires finesse.clientservices.ClientServices
14750  * @requires Class
14751  * @requires finesse.FinesseBase
14752  * @requires finesse.restservices.RestBase
14753  * @requires finesse.restservices.RestCollectionBase
14754  */
14755 
14756 /** @private */
14757 (function (factory) {
14758     
14759 
14760     // Define as an AMD module if possible
14761     if ( typeof define === 'function' && define.amd )
14762     {
14763         define('restservices/Teams', ['restservices/RestCollectionBase',
14764                  'restservices/Team'], factory );
14765     }
14766     /* Define using browser globals otherwise
14767      * Prevent multiple instantiations if the script is loaded twice
14768      */
14769     else
14770     {
14771         factory(finesse.restservices.RestCollectionBase, finesse.restservices.Team);
14772     } 
14773 }(function (RestCollectionBase, Team) {
14774     /** @private */
14775     var Teams = RestCollectionBase.extend({
14776 
14777         /**
14778          * @class
14779          * JavaScript representation of a Teams collection object. Also exposes methods to operate
14780          * on the object against the server.
14781          *
14782          * @param {Object} options
14783          *     An object with the following properties:<ul>
14784          *         <li><b>id:</b> The id of the object being constructed</li>
14785          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
14786          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
14787          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
14788          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
14789          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
14790          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
14791          *             <li><b>content:</b> {String} Raw string of response</li>
14792          *             <li><b>object:</b> {Object} Parsed object of response</li>
14793          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
14794          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
14795          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
14796          *             </ul></li>
14797          *         </ul></li>
14798          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
14799          * @constructs
14800          **/
14801         init: function (options) {
14802             this._super(options);
14803         },
14804 
14805         /**
14806          * @private
14807          * Gets the REST class for the current object - this is the Teams class.
14808          * @returns {Object} The Teams constructor.
14809          */
14810         getRestClass: function () {
14811             return Teams;
14812         },
14813 
14814         /**
14815          * @private
14816          * Gets the REST class for the objects that make up the collection. - this
14817          * is the Team class.
14818          */
14819         getRestItemClass: function () {
14820             return Team;
14821         },
14822 
14823         /**
14824          * @private
14825          * Gets the REST type for the current object - this is a "Teams".
14826          * @returns {String} The Teams string.
14827          */
14828         getRestType: function () {
14829             return "Teams";
14830         },
14831         
14832         /**
14833          * @private
14834          * Gets the REST type for the objects that make up the collection - this is "Team".
14835          */
14836         getRestItemType: function () {
14837             return "Team";
14838         },
14839 
14840         /**
14841          * @private
14842          * Override default to indicates that the collection supports making
14843          * requests.
14844          */
14845         supportsRequests: true,
14846 
14847         /**
14848          * @private
14849          * Override default to indicate that this object doesn't support subscriptions.
14850          */
14851         supportsRestItemSubscriptions: false,
14852         
14853         /**
14854          * @private
14855          * Retrieve the Teams.  This call will re-query the server and refresh the collection.
14856          *
14857          * @returns {finesse.restservices.Teams}
14858          *     This Teams object to allow cascading.
14859          */
14860         get: function () {
14861             // set loaded to false so it will rebuild the collection after the get
14862             this._loaded = false;
14863             // reset collection
14864             this._collection = {};
14865             // perform get
14866             this._synchronize();
14867             return this;
14868         }
14869 
14870     });
14871 
14872     window.finesse = window.finesse || {};
14873     window.finesse.restservices = window.finesse.restservices || {};
14874     window.finesse.restservices.Teams = Teams;
14875     
14876     return Teams;
14877 }));
14878 
14879 /**
14880  * JavaScript representation of the Finesse SystemInfo object
14881  *
14882  * @requires finesse.clientservices.ClientServices
14883  * @requires Class
14884  * @requires finesse.FinesseBase
14885  * @requires finesse.restservices.RestBase
14886  */
14887 
14888 /** @private */
14889 (function (factory) {
14890     
14891 
14892     // Define as an AMD module if possible
14893     if ( typeof define === 'function' && define.amd )
14894     {
14895         define('restservices/SystemInfo', ['restservices/RestBase'], factory );
14896     }
14897     /* Define using browser globals otherwise
14898      * Prevent multiple instantiations if the script is loaded twice
14899      */
14900     else
14901     {
14902         factory(finesse.restservices.RestBase);
14903     } 
14904 }(function (RestBase) {
14905     
14906     var SystemInfo = RestBase.extend(/** @lends finesse.restservices.SystemInfo.prototype */{
14907         /**
14908          * @private
14909          * Returns whether this object supports subscriptions
14910          */
14911         supportsSubscriptions: false,
14912 
14913         doNotRefresh: true,
14914       
14915         /**
14916          * @class
14917          * JavaScript representation of a SystemInfo object.
14918          * 
14919          * @augments finesse.restservices.RestBase
14920          * @see finesse.restservices.SystemInfo.Statuses
14921          * @constructs
14922          */
14923         _fakeConstuctor: function () {
14924             /* This is here to hide the real init constructor from the public docs */
14925         },
14926         
14927          /**
14928          * @private
14929          * JavaScript representation of a SystemInfo object. Also exposes methods to operate
14930          * on the object against the server.
14931          *
14932          * @param {Object} options
14933          *     An object with the following properties:<ul>
14934          *         <li><b>id:</b> The id of the object being constructed</li>
14935          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
14936          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
14937          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
14938          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
14939          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
14940          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
14941          *             <li><b>content:</b> {String} Raw string of response</li>
14942          *             <li><b>object:</b> {Object} Parsed object of response</li>
14943          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
14944          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
14945          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
14946          *             </ul></li>
14947          *         </ul></li>
14948          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
14949          **/
14950         init: function (id, callbacks, restObj)
14951         {
14952             this._super(id, callbacks, restObj);
14953         },
14954 
14955         /**
14956          * @private
14957          * Gets the REST class for the current object - this is the SystemInfo object.
14958          */
14959         getRestClass: function () {
14960             return SystemInfo;
14961         },
14962 
14963         /**
14964          * @private
14965          * Gets the REST type for the current object - this is a "SystemInfo".
14966          */
14967         getRestType: function ()
14968         {
14969             return "SystemInfo";
14970         },
14971         
14972         _validate: function (obj)
14973         {
14974             return true;
14975         },
14976         
14977         /**
14978          * Returns the status of the Finesse system.
14979          *   IN_SERVICE if the Finesse API reports that it is in service,
14980          *   OUT_OF_SERVICE otherwise.
14981          * @returns {finesse.restservices.SystemInfo.Statuses} System Status
14982          */
14983         getStatus: function () {
14984             this.isLoaded();
14985             return this.getData().status;
14986         },
14987         
14988         /**
14989          * Returns the current timestamp from this SystemInfo object.
14990          *   This is used to calculate time drift delta between server and client.
14991          *  @returns {String} Time (GMT): yyyy-MM-dd'T'HH:mm:ss'Z'
14992          */
14993         getCurrentTimestamp: function () {
14994             this.isLoaded();
14995             return this.getData().currentTimestamp;
14996         },
14997         
14998         /**
14999          * Getter for the xmpp domain of the system.
15000          * @returns {String} The xmpp domain corresponding to this SystemInfo object.
15001          */
15002         getXmppDomain: function () {
15003             this.isLoaded();
15004             return this.getData().xmppDomain;
15005         },
15006         
15007         /**
15008          * Getter for the xmpp pubsub domain of the system.
15009          * @returns {String} The xmpp pubsub domain corresponding to this SystemInfo object.
15010          */
15011         getXmppPubSubDomain: function () {
15012             this.isLoaded();
15013             return this.getData().xmppPubSubDomain;
15014         },
15015 
15016         /**
15017          * Getter for the deployment type (UCCE or UCCX).
15018          * @returns {String} "UCCE" or "UCCX"
15019          */ 
15020         getDeploymentType: function () {
15021             this.isLoaded();
15022             return this.getData().deploymentType;
15023         },
15024 
15025         /**
15026          * Returns whether this is a single node deployment or not by checking for the existence of the secondary node in SystemInfo.
15027          * @returns {Boolean} True for single node deployments, false otherwise.
15028          */ 
15029         isSingleNode: function () {
15030             var secondary = this.getData().secondaryNode;
15031             if (secondary && secondary.host) {
15032                 return false;
15033             }
15034             return true;
15035         },
15036 
15037         /**
15038          * Checks all arguments against the primary and secondary hosts (FQDN) and returns the match.
15039          * This is useful for getting the FQDN of the current Finesse server.
15040          * @param {String} ...arguments[]... - any number of arguments to match against
15041          * @returns {String} FQDN (if properly configured) of the matched host of the primary or secondary node, or undefined if no match is found.
15042          */ 
15043         getThisHost: function () {
15044             var i,
15045             primary = this.getData().primaryNode,
15046             secondary = this.getData().secondaryNode;
15047 
15048             for (i = 0; (i < arguments.length); i = i + 1) {
15049                 if (primary && arguments[i] === primary.host) {
15050                     return primary.host;
15051                 } else if (secondary && arguments[i] === secondary.host) {
15052                     return secondary.host;
15053                 }
15054             }
15055         },
15056 
15057         /**
15058          * Checks all arguments against the primary and secondary hosts (FQDN) and returns the other node.
15059          * This is useful for getting the FQDN of the other Finesse server, i.e. for failover purposes.
15060          * @param {String} arguments - any number of arguments to match against
15061          * @returns {String} FQDN (if properly configured) of the alternate node, defaults to primary if no match is found, undefined for single node deployments.
15062          */ 
15063         getAlternateHost: function () {
15064             var i,
15065             isPrimary = false,
15066             primary = this.getData().primaryNode,
15067             secondary = this.getData().secondaryNode,
15068             xmppDomain = this.getData().xmppDomain,
15069             alternateHost;
15070 
15071             if (primary && primary.host) {
15072                     if (xmppDomain === primary.host) {
15073                         isPrimary = true;
15074                     }
15075                 if (secondary && secondary.host) {
15076                     if (isPrimary) {
15077                         return secondary.host;
15078                     }
15079                     return primary.host;
15080                 }
15081             }
15082         }
15083     });
15084     
15085     SystemInfo.Statuses = /** @lends finesse.restservices.SystemInfo.Statuses.prototype */ { 
15086         /** 
15087          * Finesse is in service. 
15088          */
15089         IN_SERVICE: "IN_SERVICE",
15090         /** 
15091          * Finesse is not in service. 
15092          */
15093         OUT_OF_SERVICE: "OUT_OF_SERVICE",
15094         /**
15095          * @class SystemInfo status values.
15096          * @constructs
15097          */
15098         _fakeConstructor : function () {} // For JS Doc to work need a constructor so that the lends/constructs build the doc properly
15099 
15100     };
15101     
15102     window.finesse = window.finesse || {};
15103     window.finesse.restservices = window.finesse.restservices || {};
15104     window.finesse.restservices.SystemInfo = SystemInfo;
15105     
15106     return SystemInfo;
15107 }));
15108 
15109 /**
15110  * Provides standard way resolve message keys with substitution
15111  *
15112  * @requires finesse.container.I18n or gadgets.Prefs
15113  */
15114 
15115 // Add Utilities to the finesse.utilities namespace
15116 var finesse = finesse || {};
15117 finesse.utilities = finesse.utilities || {};
15118 
15119 (function (factory) {
15120     
15121 
15122     // Define as an AMD module if possible
15123     if ( typeof define === 'function' && define.amd )
15124     {
15125         define('utilities/I18n', [], factory );
15126     }
15127     /* Define using browser globals otherwise
15128      * Prevent multiple instantiations if the script is loaded twice
15129      */
15130     else
15131     {
15132         finesse.utilities.I18n = factory();
15133     }
15134 }(function () {
15135     var I18n = (function () {
15136 
15137         /**
15138          * Shortcut to finesse.container.I18n.getMsg or gadgets.Prefs.getMsg
15139          * @private
15140          */
15141         var _getMsg;
15142 
15143         return {
15144             /**
15145              * Provides a message resolver for this utility singleton.
15146              * @param {Function} getMsg
15147              *     A function that returns a string given a message key.
15148              *     If the key is not found, this function must return 
15149              *     something that tests false (i.e. undefined or "").
15150              */
15151             setGetter : function (getMsg) {
15152                 _getMsg = getMsg;
15153             },
15154 
15155             /**
15156              * Resolves the given message key, also performing substitution.
15157              * This generic utility will use a custom function to resolve the key
15158              * provided by finesse.utilities.I18n.setGetter. Otherwise, it will 
15159              * discover either finesse.container.I18n.getMsg or gadgets.Prefs.getMsg
15160              * upon the first invocation and store that reference for efficiency.
15161              * 
15162              * Since this will construct a new gadgets.Prefs object, it is recommended
15163              * for gadgets to explicitly provide the setter to prevent duplicate
15164              * gadgets.Prefs objects. This does not apply if your gadget does not need
15165              * access to gadgets.Prefs other than getMsg. 
15166              * 
15167              * @param {String} key
15168              *     The key to lookup
15169              * @param {String} arguments
15170              *     Arguments for substitution
15171              * @returns {String/Function}
15172              *     The resolved string if successful, otherwise a function that returns
15173              *     a '???' string that can also be casted into a string.
15174              */
15175             getString : function (key) {
15176                 var prefs, i, retStr, noMsg, getFailed = "";
15177                 if (!_getMsg) {
15178                     if (finesse.container && finesse.container.I18n) {
15179                         _getMsg = finesse.container.I18n.getMsg;
15180                     } else if (gadgets) {
15181                         prefs = new gadgets.Prefs();
15182                         _getMsg = prefs.getMsg;
15183                     }
15184                 }
15185                 
15186                 try {
15187                     retStr = _getMsg(key);
15188                 } catch (e) {
15189                     getFailed = "finesse.utilities.I18n.getString(): invalid _getMsg";
15190                 }
15191                 
15192                 if (retStr) { // Lookup was successful, perform substitution (if any)
15193                     for (i = 1; i < arguments.length; i += 1) {
15194                         retStr = retStr.replace(new RegExp("\\{" + (i - 1) + "\\}", "g"), arguments[i]);
15195                     }
15196                     //in order to fix French text with single quotes in it, we need to replace \' with '
15197                     return retStr.replace(/\\'/g, "'");
15198                 }
15199                 // We want a function because jQuery.html() and jQuery.text() is smart enough to invoke it.
15200                 /** @private */
15201                 noMsg = function () {
15202                     return "???" + key + "???" + getFailed;
15203                 };
15204                 // We overload the toString() of this "function" to allow JavaScript to cast it into a string
15205                 // For example, var myMsg = "something " + finesse.utilities.I18n.getMsg("unresolvable.key");
15206                 /** @private */
15207                 noMsg.toString = function () {
15208                     return "???" + key + "???" + getFailed;
15209                 };
15210                 return noMsg;
15211 
15212             }
15213         };
15214     }());
15215     
15216     return I18n;
15217 }));
15218 
15219 /**
15220  * Logging.js: provides simple logging for clients to use and overrides synchronous native methods: alert(), confirm(), and prompt().
15221  * 
15222  * On Firefox, it will hook into console for logging.  On IE, it will log to the status bar. 
15223  */
15224 // Add Utilities to the finesse.utilities namespace
15225 var finesse = finesse || {};
15226 finesse.utilities = finesse.utilities || {};
15227 
15228 (function (factory) {
15229     
15230 
15231     // Define as an AMD module if possible
15232     if ( typeof define === 'function' && define.amd )
15233     {
15234         define('utilities/Logger', [], factory );
15235     }
15236     /* Define using browser globals otherwise
15237      * Prevent multiple instantiations if the script is loaded twice
15238      */
15239     else
15240     {
15241         finesse.utilities.Logger = factory();
15242     }
15243 }(function () {
15244     var Logger = (function () {
15245         
15246         var
15247         
15248         /** @private **/
15249         debugOn,
15250         
15251         /**
15252          * Pads a single digit number for display purposes (e.g. '4' shows as '04')
15253          * @param num is the number to pad to 2 digits
15254          * @returns a two digit padded string
15255          * @private
15256          */
15257         padTwoDigits = function (num) {        
15258             return (num < 10) ? '0' + num : num;  
15259         },
15260         
15261         /**
15262          * Checks to see if we have a console - this allows us to support Firefox or IE.
15263          * @returns {Boolean} True for Firefox, False for IE
15264          * @private
15265          */
15266         hasConsole = function () {
15267             var retval = false;
15268             try
15269             {
15270                 if (window.console !== undefined) 
15271                 {
15272                     retval = true;
15273                 }
15274             } 
15275             catch (err)
15276             {
15277                 retval = false;
15278             }
15279               
15280             return retval;
15281         },
15282         
15283         /**
15284          * Gets a timestamp.
15285          * @returns {String} is a timestamp in the following format: HH:MM:SS
15286          * @private
15287          */
15288         getTimeStamp = function () {
15289             var date = new Date(), timeStr;
15290             timeStr = padTwoDigits(date.getHours()) + ":" + padTwoDigits(date.getMinutes()) + ":" + padTwoDigits(date.getSeconds());
15291 
15292             return timeStr;
15293         };
15294         
15295         return {
15296             /**
15297              * Enable debug mode. Debug mode may impact performance on the UI.
15298              *
15299              * @param {Boolean} enable
15300              *      True to enable debug logging.
15301              * @private
15302              */
15303             setDebug : function (enable) {
15304                 debugOn = enable;
15305             },
15306             
15307             /**
15308              * Logs a string as DEBUG.
15309              * 
15310              * @param str is the string to log. 
15311              * @private
15312              */
15313             log : function (str) {
15314                 var timeStr = getTimeStamp();
15315                 
15316                 if (debugOn) {
15317                     if (hasConsole())
15318                     {
15319                         window.console.log(timeStr + ": " + "DEBUG" + " - " + str);
15320                     }
15321                 }
15322             },
15323             
15324             /**
15325              * Logs a string as INFO.
15326              * 
15327              * @param str is the string to log. 
15328              * @private
15329              */
15330             info : function (str) {
15331                 var timeStr = getTimeStamp();
15332                 
15333                 if (hasConsole())
15334                 {
15335                     window.console.info(timeStr + ": " + "INFO" + " - " + str);
15336                 }
15337             },
15338             
15339             /**
15340              * Logs a string as WARN.
15341              * 
15342              * @param str is the string to log. 
15343              * @private
15344              */
15345             warn : function (str) {
15346                 var timeStr = getTimeStamp();
15347                 
15348                 if (hasConsole())
15349                 {
15350                     window.console.warn(timeStr + ": " + "WARN" + " - " + str);
15351                 }
15352             },
15353             /**
15354              * Logs a string as ERROR.
15355              * 
15356              * @param str is the string to log. 
15357              * @private
15358              */
15359             error : function (str) {
15360                 var timeStr = getTimeStamp();
15361                 
15362                 if (hasConsole())
15363                 {
15364                     window.console.error(timeStr + ": " + "ERROR" + " - " + str);
15365                 }
15366             }
15367         };
15368     }());
15369     
15370     return Logger;
15371 }));
15372 
15373 /**
15374  * Allows gadgets to call the log function to publish client logging messages over the hub.
15375  *
15376  * @requires OpenAjax
15377  */
15378 /** @private */
15379 (function (factory) {
15380     
15381 
15382     // Define as an AMD module if possible
15383     if ( typeof define === 'function' && define.amd )
15384     {
15385         define('cslogger/ClientLogger',[], factory );
15386     }
15387     
15388     /* Define using browser globals otherwise
15389      * Prevent multiple instantiations if the script is loaded twice
15390      */
15391     else
15392     {
15393         factory();
15394     }
15395     
15396 }(function () {
15397 
15398     var ClientLogger = ( function () { /** @lends finesse.cslogger.ClientLogger.prototype */
15399         var _hub, _logTopic, _originId, _sessId, _host,
15400             MONTH = { 0 : "Jan", 1 : "Feb", 2 : "Mar", 3 : "Apr", 4 : "May", 5 : "Jun", 
15401                       6 : "Jul", 7 : "Aug", 8 : "Sep", 9 : "Oct", 10 : "Nov", 11 : "Dec"},
15402  
15403         /**
15404          * Gets timestamp drift stored in sessionStorage
15405          * @returns drift in seconds if it is set in sessionStorage otherwise returns undefined.
15406          * @private
15407         */
15408         getTsDrift = function() {
15409             if (window.sessionStorage.getItem('clientTimestampDrift') !== null) {
15410                 return parseInt(window.sessionStorage.getItem('clientTimestampDrift'), 10);
15411             }
15412             else { 
15413                 return undefined;
15414             }
15415         },
15416          
15417         /**
15418           * Sets timestamp drift in sessionStorage
15419           * @param delta is the timestamp drift between server.and client.
15420           * @private
15421          */
15422         setTsDrift = function(delta) {
15423              window.sessionStorage.setItem('clientTimestampDrift', delta.toString());
15424         },
15425           
15426         /**
15427          * Gets Finesse server timezone offset from GMT in seconds 
15428          * @returns offset in seconds if it is set in sessionStorage otherwise returns undefined.
15429          * @private
15430         */
15431         getServerOffset = function() {
15432             if (window.sessionStorage.getItem('serverTimezoneOffset') !== null) {
15433                 return parseInt(window.sessionStorage.getItem('serverTimezoneOffset'), 10);
15434             }
15435             else { 
15436                 return undefined;
15437             }
15438         },
15439          
15440         /**
15441           * Sets server timezone offset 
15442           * @param sec is the server timezone GMT offset in seconds.
15443           * @private
15444          */
15445         setServerOffset = function(sec) {
15446              window.sessionStorage.setItem('serverTimezoneOffset', sec.toString());
15447         },
15448  
15449         /**
15450          * Checks to see if we have a console.
15451          * @returns Whether the console object exists.
15452          * @private
15453          */
15454         hasConsole = function () {
15455             try {
15456                 if (window.console !== undefined) {
15457                     return true;
15458                 }
15459             } 
15460             catch (err) {
15461               // ignore and return false
15462             }
15463     
15464             return false;
15465         },
15466         
15467         /**
15468          * Gets a short form (6 character) session ID from sessionStorage
15469          * @private
15470         */
15471         getSessId = function() {
15472             if (!_sessId) {
15473                //when _sessId not defined yet, initiate it
15474                if (window.sessionStorage.getItem('enableLocalLog') === 'true') {
15475                   _sessId= " "+window.sessionStorage.getItem('finSessKey');
15476                }
15477                else {
15478                   _sessId=" ";
15479                }
15480             }
15481             return _sessId;
15482          },
15483 
15484         /**
15485          * Pads a single digit number for display purposes (e.g. '4' shows as '04')
15486          * @param num is the number to pad to 2 digits
15487          * @returns a two digit padded string
15488          * @private
15489          */
15490         padTwoDigits = function (num)
15491         {
15492             return (num < 10) ? '0' + num : num;
15493         },
15494         
15495         /**
15496          * Pads a single digit number for display purposes (e.g. '4' shows as '004')
15497          * @param num is the number to pad to 3 digits
15498          * @returns a three digit padded string
15499          * @private
15500          */
15501         padThreeDigits = function (num)
15502         {
15503             if (num < 10)
15504             {
15505               return '00'+num;
15506             }
15507             else if (num < 100)
15508             {
15509               return '0'+num;
15510             }
15511             else  
15512             {
15513                return num;
15514             }
15515         },
15516               
15517         /**
15518          * Compute the "hour"
15519          * 
15520          * @param s is time in seconds
15521          * @returns {String} which is the hour
15522          * @private
15523          */
15524         ho = function (s) {
15525              return ((s/60).toString()).split(".")[0];
15526         },
15527           
15528         /**
15529          * Gets local timezone offset string.
15530          * 
15531          * @param t is the time in seconds
15532          * @param s is the separator character between hours and minutes, e.g. ':'
15533          * @returns {String} is local timezone GMT offset in the following format: [+|-]hh[|:]MM
15534          * @private
15535          */
15536         getGmtOffString = function (min,s) {
15537             var t, sign;
15538             if (min<0) {
15539                t = -min;
15540                sign = "-";
15541             }
15542             else {
15543                t = min;
15544                sign = "+";
15545             }
15546             
15547             if (s===':') {
15548                 return sign+padTwoDigits(ho(t))+s+padTwoDigits(t%60);
15549             }
15550             else {
15551                 return sign+padTwoDigits(ho(t))+padTwoDigits(t%60);
15552             }    
15553         },
15554 
15555         /**
15556          * Gets short form of a month name in English 
15557          * 
15558          * @param monthNum is zero-based month number 
15559          * @returns {String} is short form of month name in English
15560          * @private
15561          */
15562         getMonthShortStr = function (monthNum) {
15563             var result;
15564             try {
15565                 result = MONTH[monthNum];
15566             } 
15567             catch (err) {
15568                 if (hasConsole()) {
15569                     window.console.log("Month must be between 0 and 11");
15570                 }
15571             }
15572             return result;
15573         },
15574           
15575         /**
15576           * Gets a timestamp.
15577           * @param aDate is a javascript Date object
15578           * @returns {String} is a timestamp in the following format: yyyy-mm-ddTHH:MM:ss.SSS [+|-]HH:MM
15579           * @private
15580           */
15581         getDateTimeStamp = function (aDate)
15582         {
15583             var date, off, timeStr;
15584             if (aDate === null) {
15585                 date = new Date();
15586             }
15587             else {
15588                 date = aDate;
15589             }
15590             off = -1*date.getTimezoneOffset();
15591             timeStr = date.getFullYear().toString() + "-" +
15592                       padTwoDigits(date.getMonth()+1) + "-" +
15593                       padTwoDigits (date.getDate()) + "T"+
15594                       padTwoDigits(date.getHours()) + ":" + 
15595                       padTwoDigits(date.getMinutes()) + ":" +
15596                       padTwoDigits(date.getSeconds())+"." + 
15597                       padThreeDigits(date.getMilliseconds()) + " "+
15598                       getGmtOffString(off, ':');
15599     
15600             return timeStr;
15601         },
15602         
15603         /**
15604          * Gets drift-adjusted timestamp.
15605          * @param aTimestamp is a timestamp in milliseconds
15606          * @param drift is a timestamp drift in milliseconds
15607          * @param serverOffset is a timezone GMT offset in minutes
15608          * @returns {String} is a timestamp in the Finesse server log format, e.g. Jan 07 2104 HH:MM:ss.SSS -0500
15609          * @private
15610          */
15611         getDriftedDateTimeStamp = function (aTimestamp, drift, serverOffset)
15612         {
15613            var date, timeStr, localOffset;
15614            if (aTimestamp === null) {
15615                return "--- -- ---- --:--:--.--- -----";
15616            }
15617            else if (drift === undefined || serverOffset === undefined) {
15618                if (hasConsole()) {
15619                    window.console.log("drift or serverOffset must be a number");
15620                }
15621                return "--- -- ---- --:--:--.--- -----";
15622            }
15623            else {
15624                //need to get a zone diff in minutes
15625                localOffset = (new Date()).getTimezoneOffset();
15626                date = new Date(aTimestamp+drift+(localOffset+serverOffset)*60000);
15627                timeStr = getMonthShortStr(date.getMonth()) + " "+
15628                          padTwoDigits (date.getDate())+ " "+
15629                          date.getFullYear().toString() + " "+
15630                          padTwoDigits(date.getHours()) + ":" + 
15631                          padTwoDigits(date.getMinutes()) + ":" +
15632                          padTwoDigits(date.getSeconds())+"." + 
15633                          padThreeDigits(date.getMilliseconds())+" "+
15634                          getGmtOffString(serverOffset, '');
15635                 return timeStr;
15636             }
15637         },
15638     
15639         /**
15640         * Logs a message to a hidden textarea element on the page
15641         *
15642         * @param msg is the string to log.
15643         * @private
15644         */
15645         writeToLogOutput = function (msg) {
15646             var logOutput = document.getElementById("finesseLogOutput");
15647     
15648             if (logOutput === null)
15649             {
15650                 logOutput = document.createElement("textarea");
15651                 logOutput.id = "finesseLogOutput";
15652                 logOutput.style.display = "none";
15653                 document.body.appendChild(logOutput);
15654             }
15655     
15656             if (logOutput.value === "")
15657             {
15658                 logOutput.value = msg;
15659             }
15660             else
15661             {
15662                 logOutput.value = logOutput.value + "\n" + msg;
15663             }
15664         },
15665 
15666         /*
15667          * Logs a message to console 
15668         * @param str is the string to log.         * @private
15669          */
15670         logToConsole = function (str)
15671         {
15672             var now, msg, timeStr, driftedTimeStr, sessKey=getSessId();
15673             now = new Date();
15674             timeStr = getDateTimeStamp(now);
15675             if (getTsDrift() !== undefined) {
15676                 driftedTimeStr = getDriftedDateTimeStamp(now.getTime(), getTsDrift(), getServerOffset());
15677             }
15678             else {
15679                driftedTimeStr = getDriftedDateTimeStamp(null, 0, 0);
15680             }
15681             msg = timeStr + ":"+sessKey+": "+ _host + ": "+driftedTimeStr+ ": " + str;
15682             // Log to console
15683             if (hasConsole()) {
15684                 window.console.log(msg);
15685             }
15686     
15687             //Uncomment to print logs to hidden textarea.
15688             //writeToLogOutput(msg);
15689     
15690             return msg;
15691         };
15692         return {
15693     
15694             /**
15695              * Publishes a Log Message over the hub.
15696              *
15697              * @param {String} message
15698              *     The string to log.
15699              * @example
15700              * _clientLogger.log("This is some important message for MyGadget");
15701              * 
15702              */
15703             log : function (message) {
15704                 if(_hub) {
15705                     _hub.publish(_logTopic, logToConsole(_originId + message));
15706                 }
15707             },
15708             
15709             /**
15710              * @class
15711              * Allows gadgets to call the log function to publish client logging messages over the hub.
15712              * 
15713              * @constructs
15714              */
15715             _fakeConstuctor: function () {
15716                 /* This is here so we can document init() as a method rather than as a constructor. */
15717             },
15718             
15719             /**
15720              * Initiates the client logger with a hub a gadgetId and gadget's config object.
15721              * @param {Object} hub
15722              *      The hub to communicate with.
15723              * @param {String} gadgetId
15724              *      A unique string to identify which gadget is doing the logging.
15725              * @param {Object} config
15726              *      The config object used to get host name for that thirdparty gadget
15727              * @example
15728              * var _clientLogger = finesse.cslogger.ClientLogger;
15729              * _clientLogger.init(gadgets.Hub, "MyGadgetId", config);
15730              * 
15731              */
15732             init: function (hub, gadgetId, config) {
15733                 _hub = hub;
15734                 _logTopic = "finesse.clientLogging." + gadgetId;
15735                 _originId = gadgetId + " : ";
15736                 if ((config === undefined) || (config === "undefined")) 
15737                 {
15738                      _host = ((finesse.container && finesse.container.Config && finesse.container.Config.host)?finesse.container.Config.host : "?.?.?.?");
15739                  } 
15740                 else 
15741                 {
15742                      _host = ((config && config.host)?config.host : "?.?.?.?");
15743                  }
15744             }
15745         };
15746     }());
15747     
15748     window.finesse = window.finesse || {};
15749     window.finesse.cslogger = window.finesse.cslogger || {};
15750     window.finesse.cslogger.ClientLogger = ClientLogger;
15751     
15752     finesse = finesse || {};
15753     /** @namespace Supports writing messages to a central log. */
15754     finesse.cslogger = finesse.cslogger || {};
15755 
15756     return ClientLogger;
15757  }));
15758 
15759 /* using variables before they are defined.
15760  */
15761 /*global navigator,unescape,sessionStorage,localStorage,_initSessionList,_initSessionListComplete */
15762 
15763 /**
15764  * Allows each gadget to communicate with the server to send logs.
15765  */
15766 
15767 /**
15768  * @class
15769  * @private
15770  * Allows each product to initialize its method of storage
15771  */
15772 (function (factory) {
15773     
15774 
15775     // Define as an AMD module if possible
15776     if ( typeof define === 'function' && define.amd )
15777     {
15778         define('cslogger/FinesseLogger',["clientservices/ClientServices"], factory );
15779     }
15780     
15781     /* Define using browser globals otherwise
15782      * Prevent multiple instantiations if the script is loaded twice
15783      */
15784     else
15785     {
15786         factory(finesse.clientservices.ClientServices);
15787     }
15788     
15789 }(function (ClientServices) {
15790     window.finesse = window.finesse || {};
15791     window.finesse.cslogger = window.finesse.cslogger || {};
15792     /** @private */
15793     window.finesse.cslogger.FinesseLogger = (function () { 
15794 
15795         var
15796 
15797         /**
15798          * Array use to collect ongoing logs in memory
15799          * @private
15800          */
15801         _logArray = [],
15802 
15803         /**
15804          * The final data string sent to the server, =_logArray.join
15805          * @private
15806          */
15807         _logStr = "",
15808 
15809         /**
15810          * Keep track of size of log
15811          * @private
15812          */
15813         _logSize = 0,
15814 
15815         /**
15816          * Flag to keep track show/hide of send log link
15817          * @private
15818          */
15819         _sendLogShown = false,
15820 
15821         /**
15822          * Flag to keep track if local log initialized
15823          * @private
15824          */
15825         _loggingInitialized = false,
15826         
15827 
15828         /**
15829          * local log size limit
15830          * @private
15831          */
15832         _maxLocalStorageSize = 5000000,
15833 
15834         /**
15835          * half local log size limit
15836          * @private
15837          */
15838         _halfMaxLocalStorageSize = 0.5*_maxLocalStorageSize,
15839 
15840         
15841         /**
15842          * threshold for purge 
15843          * @private
15844          */
15845         _purgeStartPercent = 0.75,
15846         
15847         /**
15848          * log item prefix 
15849          * @private
15850          */
15851         _linePrefix = null,
15852         
15853         /**
15854          * locallog session 
15855          * @private
15856          */
15857         _session = null,
15858         
15859         /**
15860          * Flag to keep track show/hide of send log link
15861          * @private
15862          */
15863         _sessionKey = null,
15864         /**
15865          * Log session metadata 
15866          * @private
15867          */
15868         _logInfo = {},
15869         
15870         /**
15871          * Flag to find sessions 
15872          * @private
15873          */
15874         _findSessionsObj = null,
15875 
15876         /**
15877          * Wrap up console.log esp. for IE9 
15878          * @private
15879          */
15880         _myConsoleLog = function (str) {
15881             if (window.console !== undefined) {
15882               window.console.log(str);
15883             }
15884         },
15885         /**
15886          * Initialize the Local Logging
15887          * @private
15888          */
15889         _initLogging = function () {
15890             if (_loggingInitialized) {
15891                 return;
15892             }
15893             //Build a new store
15894             _session = sessionStorage.getItem("finSessKey");
15895             //if the _session is null or empty, skip the init
15896             if (!_session) {
15897               return;
15898             }
15899             _sessionKey = "Fi"+_session;
15900             _linePrefix = _sessionKey + "_";
15901             _logInfo = {};
15902             _logInfo.name = _session;
15903             _logInfo.size = 0;
15904             _logInfo.head = 0;
15905             _logInfo.tail = 0;
15906             _logInfo.startTime = new Date().getTime();
15907             _loggingInitialized = true;
15908             _initSessionList();
15909         },
15910         
15911         /**
15912          * get total data size 
15913          *
15914          * @return {Integer} which is the amount of data stored in local storage.
15915          * @private
15916          */
15917         _getTotalData = function ()
15918         {
15919             var sessName, sessLogInfoStr,sessLogInfoObj, sessionsInfoObj, totalData = 0,
15920             sessionsInfoStr = localStorage.getItem("FinesseSessionsInfo");
15921             if (!sessionsInfoStr) {
15922                  return 0;
15923             }
15924             sessionsInfoObj = JSON.parse(sessionsInfoStr);
15925 
15926             for (sessName in sessionsInfoObj.sessions)
15927             {
15928                 if (sessionsInfoObj.sessions.hasOwnProperty(sessName)) {
15929                     sessLogInfoStr = localStorage.getItem("Fi" + sessName);
15930                     if (!sessLogInfoStr) {
15931                         _myConsoleLog("_getTotalData failed to get log info for "+sessName);
15932                     }
15933                     else {
15934                        sessLogInfoObj = JSON.parse(sessLogInfoStr);
15935                        totalData = totalData + sessLogInfoObj.size;
15936                     }
15937                 }
15938             }
15939 
15940               return totalData;
15941         },
15942         
15943         /**
15944          * Remove lines from tail up until store size decreases to half of max size limit.
15945          *
15946          * @private
15947          */
15948         _purgeCurrentSession = function() {
15949             var curStoreSize, purgedSize=0, line, tailKey, secLogInfoStr, logInfoStr, theLogInfo;
15950             curStoreSize = _getTotalData();
15951             if (curStoreSize < _halfMaxLocalStorageSize) {
15952                return;
15953             }
15954             logInfoStr = localStorage.getItem(_sessionKey);
15955             if (!logInfoStr) {
15956                return;
15957             }
15958             theLogInfo = JSON.parse(logInfoStr);
15959             //_myConsoleLog("Starting _purgeCurrentSession() - currentStoreSize=" + curStoreSize);
15960             while(curStoreSize > _halfMaxLocalStorageSize) {
15961                try {
15962                    tailKey = _sessionKey+"_"+theLogInfo.tail;
15963                    line = localStorage.getItem(tailKey);
15964                    if (line) {
15965                        purgedSize = purgedSize +line.length;
15966                        localStorage.removeItem(tailKey);
15967                        curStoreSize = curStoreSize - line.length;
15968                        theLogInfo.size = theLogInfo.size - line.length;
15969                    }
15970                }
15971                catch (err) {
15972                    _myConsoleLog("purgeCurrentSession encountered err="+err);
15973                }
15974                if (theLogInfo.tail < theLogInfo.head) {
15975                    theLogInfo.tail = theLogInfo.tail  + 1;
15976                }
15977                else {
15978                    break;
15979                }
15980             }
15981             //purge stops here, we need to update session's meta data in storage
15982             secLogInfoStr = localStorage.getItem(_sessionKey);
15983             if (!secLogInfoStr) {
15984                 //somebody cleared the localStorage
15985                 return;
15986             }
15987             
15988             //_myConsoleLog("In _purgeCurrentSession() - after purging current session, currentStoreSize=" + curStoreSize);
15989             //_myConsoleLog("In _purgeCurrentSession() - after purging purgedSize=" + purgedSize);
15990             //_myConsoleLog("In _purgeCurrentSession() - after purging logInfo.size=" + theLogInfo.size);
15991             //_myConsoleLog("In _purgeCurrentSession() - after purging logInfo.tail=" + theLogInfo.tail);
15992             localStorage.setItem(_sessionKey, JSON.stringify(theLogInfo));
15993             _myConsoleLog("Done _purgeCurrentSession() - currentStoreSize=" + curStoreSize);
15994         },
15995        
15996         /**
15997          * Purge a session 
15998          *
15999          * @param sessionName is the name of the session
16000          * @return {Integer} which is the current amount of data purged
16001          * @private
16002          */
16003         _purgeSession = function (sessionName) {
16004               var theLogInfo, logInfoStr, sessionsInfoStr, sessionsInfoObj;
16005               //Get the session logInfo
16006               logInfoStr = localStorage.getItem("Fi" + sessionName);
16007               if (!logInfoStr) {
16008                  _myConsoleLog("_purgeSession failed to get logInfo for "+sessionName);
16009                  return 0;
16010               }
16011               theLogInfo = JSON.parse(logInfoStr);
16012               
16013               //Note: This assumes that we don't crash in the middle of purging
16014               //=> if we do then it should get deleted next time
16015               //Purge tail->head
16016               while (theLogInfo.tail <= theLogInfo.head)
16017               {
16018                   try {
16019                       localStorage.removeItem("Fi" + sessionName + "_" + theLogInfo.tail);
16020                       theLogInfo.tail = theLogInfo.tail + 1;
16021                   }
16022                   catch (err) {
16023                       _myConsoleLog("In _purgeSession err="+err);
16024                       break;
16025                   }
16026               }
16027 
16028               //Remove the entire session
16029               localStorage.removeItem("Fi" + sessionName);
16030 
16031               //Update FinesseSessionsInfo
16032               sessionsInfoStr = localStorage.getItem("FinesseSessionsInfo");
16033               if (!sessionsInfoStr) {
16034                  _myConsoleLog("_purgeSession could not get sessions Info, it was cleared?");
16035                  return 0;
16036               }
16037               sessionsInfoObj = JSON.parse(sessionsInfoStr);
16038               if (sessionsInfoObj.sessions !== null)
16039               {
16040                  delete sessionsInfoObj.sessions[sessionName];
16041               
16042                  sessionsInfoObj.total = sessionsInfoObj.total - 1;
16043                  sessionsInfoObj.lastWrittenBy = _session;
16044                  localStorage.setItem("FinesseSessionsInfo", JSON.stringify(sessionsInfoObj));
16045               }
16046               
16047               return theLogInfo.size;
16048         },
16049         
16050          /**
16051           * purge old sessions
16052           * 
16053           * @param storeSize
16054 	  * @return {Boolean} whether purging reaches its target
16055           * @private
16056          */
16057          _purgeOldSessions = function (storeSize) {
16058              var sessionsInfoStr, purgedSize = 0, sessName, sessions, curStoreSize, activeSession, sessionsInfoObj;
16059              sessionsInfoStr = localStorage.getItem("FinesseSessionsInfo");
16060              if (!sessionsInfoStr) {
16061                 _myConsoleLog("Could not get FinesseSessionsInfo");
16062                 return true;
16063              }
16064              sessionsInfoObj = JSON.parse(sessionsInfoStr);
16065              curStoreSize = _getTotalData();
16066              
16067              activeSession = _session;
16068              sessions = sessionsInfoObj.sessions;
16069              for (sessName in sessions) {
16070                 if (sessions.hasOwnProperty(sessName)) {
16071                     if (sessName !== activeSession) {
16072                         purgedSize = purgedSize + _purgeSession(sessName);
16073                         if ((curStoreSize-purgedSize) < _halfMaxLocalStorageSize) {
16074                             return true;
16075                         }
16076                     }
16077                 }
16078              }
16079             //purge is not done, so return false
16080             return false;
16081          },
16082          
16083        /**
16084         * handle insert error
16085         *
16086         * @param error
16087         * @private
16088         */
16089         _insertLineHandleError = function (error) {
16090             _myConsoleLog(error);
16091         },
16092 
16093         /**
16094          * check storage data size and if need purge
16095          * @private
16096          */
16097         _checkSizeAndPurge = function () {
16098             var purgeIsDone=false, totalSize = _getTotalData();
16099             if (totalSize > 0.75*_maxLocalStorageSize) {
16100                _myConsoleLog("in _checkSizeAndPurge, totalSize ("+totalSize+") exceeds limit");
16101                purgeIsDone = _purgeOldSessions(totalSize);
16102                if (purgeIsDone) {
16103                   _myConsoleLog("in _checkSizeAndPurge after purging old session, purge is done");
16104                }
16105                else {
16106                   //after all old sessions purged, still need purge
16107                   totalSize = _getTotalData();
16108                   if (totalSize > 0.75*_maxLocalStorageSize) {
16109                       _myConsoleLog("in _checkSizeAndPurge after purging old session,still needs purging, now storeSize ("+totalSize+")");
16110                      _purgeCurrentSession();
16111                      _myConsoleLog("in _checkSizeAndPurge done purging current session.");
16112                   }
16113                }
16114             }
16115         },
16116         
16117         /**
16118          * check if the session is already in meta data  
16119          * 
16120          * @param metaData
16121          * @param sessionName
16122          * @return {Boolean} true if session has metaData (false otherwise)
16123          * @private
16124          */
16125         _sessionsInfoContains = function (metaData, sessionName) {
16126            if (metaData && metaData.sessions && metaData.sessions.hasOwnProperty(sessionName)) {
16127               return true;
16128            }
16129            return false;
16130         },
16131         
16132         
16133         /**
16134          * setup sessions in local storage 
16135          * 
16136          * @param logInfo
16137          * @private
16138          */
16139         _getAndSetNumberOfSessions = function (logInfo) {
16140             var numOfSessionsPass1, numOfSessionsPass2, l;
16141             numOfSessionsPass1 = localStorage.getItem("FinesseSessionsInfo");
16142             if (numOfSessionsPass1 === null) {
16143                 //Init first time
16144                 numOfSessionsPass1 = {};
16145                 numOfSessionsPass1.total = 1;
16146                 numOfSessionsPass1.sessions = {};
16147                 numOfSessionsPass1.sessions[logInfo.name] = logInfo.startTime;
16148                 numOfSessionsPass1.lastWrittenBy = logInfo.name;
16149                 localStorage.setItem("FinesseSessionsInfo", JSON.stringify(numOfSessionsPass1));
16150             }
16151             else {
16152                 numOfSessionsPass1 = JSON.parse(numOfSessionsPass1);
16153                 //check if the session is already in the FinesseSessionSInfo
16154                 if (_sessionsInfoContains(numOfSessionsPass1, logInfo.name)) {
16155                     return;
16156                 }             
16157                 //Save numOfSessionsPass1
16158                 numOfSessionsPass1.total = parseInt(numOfSessionsPass1.total, 10) + 1;
16159                 numOfSessionsPass1.sessions[logInfo.name] = logInfo.startTime;
16160                 numOfSessionsPass1.lastWrittenBy = logInfo.name;
16161                 localStorage.setItem("FinesseSessionsInfo", JSON.stringify(numOfSessionsPass1));
16162                 numOfSessionsPass2 = localStorage.getItem("FinesseSessionsInfo");
16163                 if (!numOfSessionsPass2) {
16164                    _myConsoleLog("Could not get FinesseSessionsInfo");
16165                    return;
16166                 }
16167                 numOfSessionsPass2 = JSON.parse(numOfSessionsPass2);
16168                 //in future we need to confirm the numOfSessionsPass2 is the same as numOfSessionsPass1
16169                 ////if (numOfSessionsPass1.lastWrittenBy !== numOfSessionsPass2.lastWrittenBy) {
16170                 ////    _myConsoleLog("Rebuild sessions");
16171                 ////    _sessionTimerId = setTimeout(_initSessionList, 10000);
16172                 ////}
16173                 ////else {
16174                 ////    _sessionTimerId = null;
16175                 ////callback(numOfSessionsPass2.sessions);
16176                 ////}
16177             }
16178             if (!localStorage.getItem(_sessionKey)) {
16179                 localStorage.setItem(_sessionKey, JSON.stringify(_logInfo));
16180             }
16181         },
16182         
16183         
16184         /**
16185          * init session list 
16186          * @private
16187          */
16188         _initSessionList = function () {
16189             _getAndSetNumberOfSessions(_logInfo);
16190         },
16191         
16192        /**
16193         * do the real store of log line
16194         * 
16195         * @param line
16196         * @private
16197         */
16198         _persistLine = function (line) {
16199             var key, logInfoStr;
16200             logInfoStr = localStorage.getItem(_sessionKey);
16201             if (logInfoStr === null) {
16202                return;
16203             }
16204             _logInfo = JSON.parse(logInfoStr);
16205             _logInfo.head = _logInfo.head + 1;
16206             key = _linePrefix + _logInfo.head;
16207             localStorage.setItem(key, line);
16208             //Save the size
16209             _logInfo.size = _logInfo.size + line.length;
16210             if (_logInfo.tail === 0) {
16211                 _logInfo.tail = _logInfo.head;
16212             }
16213         
16214             localStorage.setItem(_sessionKey, JSON.stringify(_logInfo));
16215             _checkSizeAndPurge();
16216         },
16217         
16218         /**
16219          * Insert a line into the localStorage.
16220          *
16221          * @param line line to be inserted 
16222          * @private
16223         */
16224         _insertLine = function (line) {
16225             //_myConsoleLog("_insertLine: [" + line + "]");
16226             //Write the next line to localStorage
16227             try {
16228                //Persist the line 
16229                _persistLine(line);
16230             }
16231             catch (err) {
16232                _myConsoleLog("error in _insertLine(), err="+err);
16233                //_insertLineHandleError(err);
16234             }
16235         },
16236          
16237         
16238         /**
16239          * Clear the local storage
16240          * @private
16241          */
16242         _clearLocalStorage = function() {
16243             localStorage.clear();
16244 
16245         },
16246 
16247         /**
16248          * Collect logs when onCollect called
16249          *
16250          * @param data
16251          * @private
16252          */
16253         _collectMethod = function(data) {
16254           //Size of log should not exceed 1.5MB
16255           var info, maxLength = 1572864;
16256           
16257           //add size buffer equal to the size of info to be added when publish
16258           info = navigator.userAgent + "
";
16259           info = escape(info);
16260 
16261             //If log was empty previously, fade in buttons
16262             if (!_sendLogShown) {
16263                 //call the fadeInSendLog() in Footer
16264                 finesse.modules.Footer.sendLogAppear();
16265                 _sendLogShown = true;
16266                 _logSize = info.length;
16267             }
16268             
16269             //if local storage logging is enabled, then insert the log into local storage
16270             if (window.sessionStorage.getItem('enableLocalLog')==='true') {
16271                 if (data) {
16272                    if (data.length>0 && data.substring(0,1) === '\n') {
16273                       _insertLine(data.substring(1));
16274                    }
16275                    else {
16276                       _insertLine(data);
16277                    }
16278                 }
16279             }
16280               
16281             //escape all data to get accurate size (shindig will escape when it builds request)
16282             //escape 6 special chars for XML: &<>"'\n
16283             data = data.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/>/g, ">").replace(/</g, "<").replace(/\n/g, "
");
16284             data = escape(data+"\n");
16285 
16286             if (data.length < maxLength){
16287                 //make room for new data if log is exceeding max length
16288                 while (_logSize + data.length > maxLength) {
16289                     _logSize -= (_logArray.shift()).length;
16290                 }
16291             }
16292 
16293             //Else push the log into memory, increment the log size
16294             _logArray.push(data);
16295 
16296             //inc the size accordingly
16297             _logSize+=data.length;
16298 
16299         };
16300 
16301         return {
16302 
16303             /**
16304              * @private
16305              * Initiate FinesseLogger.
16306              */
16307             init: function () {
16308                 ClientServices.subscribe("finesse.clientLogging.*", _collectMethod);
16309                 _initLogging();
16310             },
16311 
16312             /**
16313              * @private
16314              * Clear all items stored in localStorage.
16315             */
16316             clear : function () {
16317                _clearLocalStorage();
16318             },
16319 
16320             /**
16321              * @private
16322              * Initialize the local storage logging.
16323             */
16324             initLocalLog: function () {
16325                _initLogging();
16326             },
16327 
16328             /**
16329              * @private
16330              * Inserts a line into the localStorage.
16331              * @param line to insert
16332             */
16333             localLog : function (line) {
16334                _insertLine(line);
16335             },
16336 
16337            /**
16338             * @ignore
16339             * Publish logs to server and clear the memory
16340             *
16341             * @param userObj
16342             * @param options
16343             * @param callBack
16344             */
16345             publish: function(userObj, options, callBack) {
16346                 // Avoid null references.
16347                 options = options || {};
16348                 callBack = callBack || {};
16349 
16350                 if (callBack.sending === "function") {
16351                     callBack.sending();
16352                 }
16353 
16354                 //logs the basic version and machine info and escaped new line
16355                 _logStr = navigator.userAgent + "
";
16356                 
16357                 //join the logs to correct string format
16358                 _logStr += unescape(_logArray.join(""));
16359 
16360                 //turning log string to JSON obj
16361                 var logObj = {
16362                         ClientLog: {
16363                         logData : _logStr //_logStr
16364                     }
16365                 },
16366                 tmpOnAdd = (options.onAdd && typeof options.onAdd === "function")? options.onAdd : function(){};
16367                 /** @private */
16368                 options.onAdd = function(){
16369                     tmpOnAdd();
16370                     _logArray.length = 0; _logSize =0;
16371                     _sendLogShown = false;
16372                     };
16373                 //adding onLoad to the callbacks, this is the subscribe success case for the first time user subscribe to the client log node
16374                 /** @private */
16375                 options.onLoad = function (clientLogObj) {
16376                     clientLogObj.sendLogs(logObj,{
16377                             error: callBack.error
16378                         });
16379                     };
16380 
16381                 userObj.getClientLog(options);
16382             }
16383         };
16384     }());
16385 }));
16386 
16387 /**
16388  *  Contains a list of topics used for containerservices pubsub.
16389  *
16390  */
16391 
16392 /**
16393  * @class
16394  * Contains a list of topics with some utility functions.
16395  */
16396 /** @private */
16397 (function (factory) {
16398     
16399 
16400     // Define as an AMD module if possible
16401     if ( typeof define === 'function' && define.amd )
16402     {
16403         define('containerservices/Topics',[], factory );
16404     }
16405     
16406     /* Define using browser globals otherwise
16407      * Prevent multiple instantiations if the script is loaded twice
16408      */
16409     else
16410     {
16411         factory();
16412     }
16413     
16414 }(function () {
16415 
16416     var Topics = (function () {
16417 
16418     /**
16419      * The namespace prepended to all Finesse topics.
16420      */
16421     this.namespace = "finesse.containerservices";
16422 
16423     /**
16424      * @private
16425      * Gets the full topic name with the ContainerServices namespace prepended.
16426      * @param {String} topic
16427      *     The topic category.
16428      * @returns {String}
16429      *     The full topic name with prepended namespace.
16430      */
16431     var _getNSTopic = function (topic) {
16432         return this.namespace + "." + topic;
16433     };
16434 
16435 
16436 
16437     /** @scope finesse.containerservices.Topics */
16438     return {
16439         /** 
16440          * @private
16441          * request channel. */
16442         REQUESTS: _getNSTopic("requests"),
16443 
16444         /** 
16445          * @private
16446          * reload gadget channel. */
16447         RELOAD_GADGET: _getNSTopic("reloadGadget"),
16448 
16449         /**
16450          * @private
16451          * Convert a Finesse REST URI to a OpenAjax compatible topic name.
16452          */
16453         getTopic: function (restUri) {
16454             //The topic should not start with '/' else it will get replaced with
16455             //'.' which is invalid.
16456             //Thus, remove '/' if it is at the beginning of the string
16457             if (restUri.indexOf('/') === 0) {
16458                 restUri = restUri.substr(1);
16459             }
16460 
16461             //Replace every instance of "/" with ".". This is done to follow the
16462             //OpenAjaxHub topic name convention.
16463             return restUri.replace(/\//g, ".");
16464         }
16465     };
16466 	}());
16467 	
16468 	window.finesse = window.finesse || {};
16469     window.finesse.containerservices = window.finesse.containerservices || {};
16470     window.finesse.containerservices.Topics = Topics;
16471     
16472     /** @namespace JavaScript class objects and methods to handle gadget container services.*/
16473     finesse.containerservices = finesse.containerservices || {};
16474 
16475 	return Topics;
16476 
16477  }));
16478 
16479 /** The following comment is to prevent jslint errors about 
16480  * using variables before they are defined.
16481  */
16482 /*global finesse*/
16483 
16484 /**
16485  * Per containerservices request, publish to the OpenAjax gadget pubsub infrastructure.
16486  *
16487  * @requires OpenAjax, finesse.containerservices.Topics
16488  */
16489 
16490 /** @private */
16491 (function (factory) {
16492     
16493 
16494     // Define as an AMD module if possible
16495     if ( typeof define === 'function' && define.amd )
16496     {
16497         define('containerservices/MasterPublisher',["utilities/Utilities",
16498                 "containerservices/Topics"], factory );
16499     }
16500     
16501     /* Define using browser globals otherwise
16502      * Prevent multiple instantiations if the script is loaded twice
16503      */
16504     else
16505     {
16506         factory(finesse.utilities.Utilities, finesse.containerservices.Topics);
16507     }
16508     
16509 }(function (Utilities, Topics) {
16510 
16511     var MasterPublisher = function () {
16512 
16513     var
16514     
16515     /**
16516      * Reference to the gadget pubsub Hub instance.
16517      * @private
16518      */
16519     _hub = gadgets.Hub,
16520 
16521     /**
16522      * Reference to the Topics class.
16523      * @private
16524      */
16525     _topics = Topics,
16526     
16527     /**
16528      * Reference to conversion utilities class.
16529      * @private
16530      */
16531     _utils = Utilities,
16532     
16533     /**
16534      * References to ClientServices logger methods
16535      * @private
16536      */
16537     _logger = {
16538         log: finesse.clientservices.ClientServices.log
16539     },
16540     
16541    /**
16542      * The types of possible request types supported when listening to the
16543      * requests channel. Each request type could result in different operations.
16544      * @private
16545      */
16546     _REQTYPES = {
16547 		ACTIVETAB: "ActiveTabReq",
16548 		SET_ACTIVETAB: "SetActiveTabReq",
16549         RELOAD_GADGET: "ReloadGadgetReq"
16550     },
16551 
16552     /**
16553      * Handles client requests made to the request topic. The type of the
16554      * request is described in the "type" property within the data payload. Each
16555      * type can result in a different operation.
16556      * @param {String} topic
16557      *     The topic which data was published to.
16558      * @param {Object} data
16559      *     The data containing requests information published by clients.
16560      * @param {String} data.type
16561      *     The type of the request. Supported: "ActiveTabReq", "SetActiveTabReq", "ReloadGadgetReq"
16562      * @param {Object} data.data
16563      *     May contain data relevant for the particular requests.
16564      * @param {String} [data.invokeID]
16565      *     The ID used to identify the request with the response. The invoke ID
16566      *     will be included in the data in the publish to the topic. It is the
16567      *     responsibility of the client to correlate the published data to the
16568      *     request made by using the invoke ID.
16569      * @private
16570      */
16571     _clientRequestHandler = function (topic, data) {
16572     
16573         //Ensure a valid data object with "type" and "data" properties.
16574         if (typeof data === "object" &&
16575                 typeof data.type === "string" &&
16576                 typeof data.data === "object") {
16577 			switch (data.type) {
16578 			case _REQTYPES.ACTIVETAB:
16579                 _hub.publish("finesse.containerservices.activeTab", finesse.container.Tabs.getActiveTab());
16580                 break;
16581             case _REQTYPES.SET_ACTIVETAB:
16582                 if (typeof data.data.id === "string") {
16583                     _logger.log("Handling request to activate tab: " + data.data.id);
16584                     if (!finesse.container.Tabs.activateTab(data.data.id)) {
16585                         _logger.log("No tab found with id: " + data.data.id);
16586                     }
16587                 }
16588                 break;
16589             case _REQTYPES.RELOAD_GADGET:
16590                 _hub.publish("finesse.containerservices.reloadGadget", data.data);
16591                 break;
16592 			default:
16593 				break;
16594 			}
16595         }
16596     };
16597 
16598     (function () {
16599 
16600         //Listen to a request channel to respond to any requests made by other
16601         //clients because the Master may have access to useful information.
16602         _hub.subscribe(_topics.REQUESTS, _clientRequestHandler);
16603     }());
16604 
16605     //BEGIN TEST CODE//
16606     /**
16607      * Test code added to expose private functions that are used by unit test
16608      * framework. This section of code is removed during the build process
16609      * before packaging production code. The [begin|end]TestSection are used
16610      * by the build to identify the section to strip.
16611      * @ignore
16612      */
16613     this.beginTestSection = 0;
16614 
16615     /**
16616      * @ignore
16617      */
16618     this.getTestObject = function () {
16619         //Load mock dependencies.
16620         var _mock = new MockControl();
16621         _hub = _mock.createMock(gadgets.Hub);
16622 
16623         return {
16624             //Expose mock dependencies
16625             mock: _mock,
16626             hub: _hub,
16627 			
16628             //Expose internal private functions
16629             reqtypes: _REQTYPES,
16630             
16631             clientRequestHandler: _clientRequestHandler
16632 
16633         };
16634     };
16635 
16636 
16637     /**
16638      * @ignore
16639      */
16640     this.endTestSection = 0;
16641     //END TEST CODE//
16642 	};
16643 	
16644 	window.finesse = window.finesse || {};
16645     window.finesse.containerservices = window.finesse.containerservices || {};
16646     window.finesse.containerservices.MasterPublisher = MasterPublisher;
16647 	
16648 	return MasterPublisher;
16649  }));
16650 
16651 /**
16652  * JavaScript representation of the Finesse WorkflowActionEvent object.
16653  *
16654  * @requires finesse.FinesseBase
16655  */
16656 
16657 /** The following comment is to prevent jslint errors about 
16658  * using variables before they are defined.
16659  */
16660 /*global FinesseBase: true, publisher:true, define:true, finesse:true, window:true */
16661 /** @private */
16662 (function (factory) {
16663     
16664 
16665     // Define as an AMD module if possible
16666     if ( typeof define === 'function' && define.amd )
16667     {
16668         define('containerservices/WorkflowActionEvent', ["FinesseBase"], factory );
16669     }
16670     /* Define using browser globals otherwise
16671      * Prevent multiple instantiations if the script is loaded twice
16672      */
16673     else
16674     {
16675         factory(finesse.FinesseBase);
16676     }
16677 }(function (FinesseBase) {
16678     var WorkflowActionEvent = FinesseBase.extend(/** @lends finesse.containerservices.WorkflowActionEvent.prototype */{
16679         /**
16680          * Reference to the WorkflowActionEvent name
16681          * This will be set by setWorkflowActionEvent
16682          * @private
16683          */
16684         _name: null,
16685 
16686         /**
16687          * Reference to the WorkflowActionEvent type
16688          * This will be set by setWorkflowActionEvent
16689          * @private
16690          */
16691         _type: null,
16692 
16693         /**
16694          * Reference to the WorkflowActionEvent handledBy value
16695          * This will be set by setWorkflowActionEvent
16696          * @private
16697          */
16698         _handledBy: null,
16699 
16700         /**
16701          * Reference to the WorkflowActionEvent params array
16702          * This will be set by setWorkflowActionEvent
16703          * @private
16704          */
16705         _params: [],
16706 
16707         /**
16708          * Reference to the WorkflowActionEvent actionVariables array
16709          * This will be set by setWorkflowActionEvent
16710          * @private
16711          */            
16712         _actionVariables: [], 
16713         
16714         /**
16715          * @class
16716          * JavaScript representation of a WorkflowActionEvent object.
16717          * The WorkflowActionEvent object is delivered as the payload of
16718          * a WorkflowAction callback.  This can be subscribed to by using
16719          * {@link finesse.containerservices.ContainerServices#addHandler} with a 
16720          * topic of {@link finesse.containerservices.ContainerServices.Topics#WORKFLOW_ACTION_EVENT}. 
16721          * Gadgets should key on events with a handleBy value of "OTHER".
16722          * 
16723          * @constructs
16724          **/
16725         init: function () {
16726             this._super();
16727         },        
16728 
16729         /**
16730 	     * Validate that the passed in object is a WorkflowActionEvent object
16731 	     * and sets the variables if it is
16732 	     * @param maybeWorkflowActionEvent A possible WorkflowActionEvent object to be evaluated and set if 
16733 	     *                                 it validates successfully.
16734 	     * @returns {Boolean} Whether it is valid or not.
16735          * @private
16736 	     */
16737 	    setWorkflowActionEvent: function(maybeWorkflowActionEvent) {
16738 	        var returnValue;
16739 	
16740 	        if (maybeWorkflowActionEvent.hasOwnProperty("name") === true &&
16741 	                maybeWorkflowActionEvent.hasOwnProperty("type") === true &&
16742                     maybeWorkflowActionEvent.hasOwnProperty("handledBy") === true &&
16743 	                maybeWorkflowActionEvent.hasOwnProperty("params") === true &&
16744 	                maybeWorkflowActionEvent.hasOwnProperty("actionVariables") === true) {
16745 	            this._name = maybeWorkflowActionEvent.name;
16746 	            this._type = maybeWorkflowActionEvent.type;
16747                 this._handledBy = maybeWorkflowActionEvent.handledBy;
16748 	            this._params = maybeWorkflowActionEvent.params;
16749 	            this._actionVariables = maybeWorkflowActionEvent.actionVariables;
16750 	            returnValue = true;
16751 	        } else {
16752 	            returnValue = false;
16753 	        }
16754 	
16755 	        return returnValue;
16756 	    },
16757 	
16758 	    /**
16759 	     * Getter for the WorkflowActionEvent name.
16760 	     * @returns {String} The name of the WorkflowAction.
16761 	     */
16762 	    getName: function () {
16763 	        // escape nulls to empty string
16764 	        return this._name || "";
16765 	    },
16766 	
16767 	    /**
16768 	     * Getter for the WorkflowActionEvent type.
16769 	     * @returns {String} The type of the WorkflowAction (BROWSER_POP, HTTP_REQUEST).
16770 	     */
16771 	    getType: function () {
16772 	        // escape nulls to empty string
16773 	        return this._type || "";
16774 	    },
16775 	
16776         /**
16777          * Getter for the WorkflowActionEvent handledBy value. Gadgets should look for
16778          * events with a handleBy of "OTHER".
16779          * @see finesse.containerservices.WorkflowActionEvent.HandledBy
16780          * @returns {String} The handledBy value of the WorkflowAction that is a value of {@link finesse.containerservices.WorkflowActionEvent.HandledBy}.
16781          */
16782         getHandledBy: function () {
16783             // escape nulls to empty string
16784             return this._handledBy || "";
16785         },
16786 
16787 
16788 	    /**
16789 	     * Getter for the WorkflowActionEvent Params map.
16790 	     * @returns {Object} key = param name, value = Object{name, value, expandedValue}
16791 	     * BROWSER_POP<ul>
16792 	     * <li>windowName : Name of window to pop into, or blank to always open new window.
16793 	     * <li>path : URL to open.</ul>
16794 	     * HTTP_REQUEST<ul>
16795 	     * <li>method : "PUT" or "POST".
16796 	     * <li>location : "FINESSE" or "OTHER".
16797 	     * <li>contentType : MIME type of request body, if applicable, e.g. "text/plain".
16798 	     * <li>path : Request URL.
16799 	     * <li>body : Request content for POST requests.</ul>
16800 	     */
16801 	    getParams: function () {
16802 	        var map = {},
16803 	            params = this._params,
16804 	            i,
16805 	            param;
16806 	
16807 	        if (params === null || params.length === 0) {
16808 	            return map;
16809 	        }
16810 	
16811 	        for (i = 0; i < params.length; i += 1) {
16812 	            param = params[i];
16813 	            // escape nulls to empty string
16814 	            param.name = param.name || "";
16815 	            param.value = param.value || "";
16816 	            param.expandedValue = param.expandedValue || "";
16817 	            map[param.name] = param;
16818 	        }
16819 	
16820 	        return map;
16821 	    },
16822 	    
16823 	    /**
16824 	     * Getter for the WorkflowActionEvent ActionVariables map
16825 	     * @returns {Object} key = action variable name, value = Object{name, type, node, testValue, actualValue}
16826 	     */
16827 	    getActionVariables: function() {
16828 	        var map = {},
16829 	            actionVariables = this._actionVariables,
16830 	            i,
16831 	            actionVariable;
16832 	
16833 	        if (actionVariables === null || actionVariables.length === 0) {
16834 	            return map;
16835 	        }
16836 	
16837 	        for (i = 0; i < actionVariables.length; i += 1) {
16838 	            actionVariable = actionVariables[i];
16839 	            // escape nulls to empty string
16840 	            actionVariable.name = actionVariable.name || "";
16841 	            actionVariable.type = actionVariable.type || "";
16842 	            actionVariable.node = actionVariable.node || "";
16843 	            actionVariable.testValue = actionVariable.testValue || "";
16844 	            actionVariable.actualValue = actionVariable.actualValue || "";
16845 	            map[actionVariable.name] = actionVariable;
16846 	        }
16847 	
16848 	        return map;
16849 	    }
16850     }); 
16851     
16852     
16853     WorkflowActionEvent.HandledBy = /** @lends finesse.containerservices.WorkflowActionEvent.HandledBy.prototype */ {
16854         /**
16855          * This specifies that Finesse will handle this WorkflowActionEvent.  A 3rd Party can do additional processing
16856          * with the action, but first and foremost Finesse will handle this WorkflowAction.
16857          */
16858         FINESSE: "FINESSE",
16859 
16860         /**
16861          * This specifies that a 3rd Party will handle this WorkflowActionEvent.  Finesse's Workflow Engine Executor will 
16862          * ignore this action and expects Gadget Developers to take action.
16863          */
16864         OTHER: "OTHER",
16865         
16866         /**
16867          * @class This is the set of possible HandledBy values used for WorkflowActionEvent from ContainerServices.  This
16868          * is provided from the {@link finesse.containerservices.WorkflowActionEvent#getHandledBy} method.
16869          * @constructs
16870          */
16871         _fakeConstructor : function () {} // For JS Doc to work need a constructor so that the lends/constructs build the doc properly
16872     };    
16873     
16874     window.finesse = window.finesse || {};
16875     window.finesse.containerservices = window.finesse.containerservices || {};
16876     window.finesse.containerservices.WorkflowActionEvent = WorkflowActionEvent;
16877     
16878     return WorkflowActionEvent;
16879 }));
16880 
16881 /**
16882  * JavaScript representation of the Finesse TimerTickEvent
16883  *
16884  * @requires finesse.FinesseBase
16885  */
16886 
16887 /** The following comment is to prevent jslint errors about 
16888  * using variables before they are defined.
16889  */
16890 /*global FinesseBase: true, publisher:true, define:true, finesse:true, window:true */
16891 /** @private */
16892 (function (factory) {
16893     
16894 
16895     // Define as an AMD module if possible
16896     if ( typeof define === 'function' && define.amd )
16897     {
16898         define('containerservices/TimerTickEvent', ["FinesseBase"], factory );
16899     }
16900     /* Define using browser globals otherwise
16901      * Prevent multiple instantiations if the script is loaded twice
16902      */
16903     else
16904     {
16905         factory(finesse.FinesseBase);
16906     }
16907 }(function (FinesseBase) {
16908     var TimerTickEvent = FinesseBase.extend(/** @lends finesse.containerservices.TimerTickEvent.prototype */{
16909         /**
16910          * date the TimerTickEvent was queued 
16911          * @private
16912          */
16913         _dateQueued: null,
16914 
16915         /**
16916          * the frequency of the timer tick (in miiliseconds)
16917          * @private
16918          */
16919         _tickFrequency: 1000,
16920 
16921         /**
16922          * @class
16923          * JavaScript representation of a TimerTickEvent object.
16924          * The TimerTickEvent object is delivered as the payload of
16925          * a TimerTickEvent callback.  This can be subscribed to by using
16926          * {@link finesse.containerservices.ContainerServices#addHandler} with a 
16927          * topic of {@link finesse.containerservices.ContainerServices.Topics#TIMER_TICK_EVENT}. 
16928          * 
16929          * @constructs
16930          **/
16931         init: function (tickFrequency, dateQueued) {
16932             this._super();
16933             
16934             this._tickFrequency = tickFrequency;
16935             this._dateQueued = dateQueued;
16936         },
16937 
16938        /**
16939          * Get the "tickFrequency" field
16940          * @param {int} which is the "TickFrequency" field
16941          * @private
16942          */
16943         getTickFrequency: function () {
16944             return this._tickFrequency;
16945         },
16946 
16947         /**
16948          * Getter for the TimerTickEvent "DateQueued" field. 
16949          * @returns {Date} which is a Date object when the TimerTickEvent was queued
16950          */
16951         getDateQueued: function () {
16952             return this._dateQueued;
16953         }
16954 
16955     });
16956     
16957     window.finesse = window.finesse || {};
16958     window.finesse.containerservices = window.finesse.containerservices || {};
16959     window.finesse.containerservices.TimerTickEvent = TimerTickEvent;
16960     
16961     return TimerTickEvent;
16962 }));
16963 
16964 /**
16965  * JavaScript representation of the Finesse GadgetViewChangedEvent object.
16966  *
16967  * @requires finesse.FinesseBase
16968  */
16969 
16970 /** The following comment is to prevent jslint errors about 
16971  * using variables before they are defined.
16972  */
16973 /*global FinesseBase: true, publisher:true, define:true, finesse:true, window:true */
16974 /** @private */
16975 (function (factory) {
16976     
16977 
16978     // Define as an AMD module if possible
16979     if ( typeof define === 'function' && define.amd )
16980     {
16981         define('containerservices/GadgetViewChangedEvent', ["FinesseBase"], factory );
16982     }
16983     /* Define using browser globals otherwise
16984      * Prevent multiple instantiations if the script is loaded twice
16985      */
16986     else
16987     {
16988         factory(finesse.FinesseBase);
16989     }
16990 }(function (FinesseBase) {
16991     var GadgetViewChangedEvent = FinesseBase.extend(/** @lends finesse.containerservices.GadgetViewChangedEvent.prototype */{
16992         /**
16993          * Reference to the gadget id
16994          * @private
16995          */
16996         _gadgetId: null,
16997 
16998         /**
16999          * Reference to the tab id
17000          * @private
17001          */
17002         _tabId: null,
17003 
17004         /**
17005          * Reference to the maxAvailableHeight
17006          * @private
17007          */
17008         _maxAvailableHeight: null,
17009 
17010         /**
17011          * Reference to the view
17012          * E.g. 'default' or 'canvas'
17013          * @private
17014          */
17015         _view: null,
17016         
17017         /**
17018          * @class
17019          * JavaScript representation of a GadgetViewChangedEvent object.
17020          * The GadgetViewChangedEvent object is delivered as the payload of
17021          * a GadgetViewChangedEvent callback.  This can be subscribed to by using
17022          * {@link finesse.containerservices.ContainerServices#addHandler} with a 
17023          * topic of {@link finesse.containerservices.ContainerServices.Topics#GADGET_VIEW_CHANGED_EVENT}. 
17024          * 
17025          * @constructs
17026          **/
17027         init: function (gadgetId, tabId, maxAvailableHeight, view) {
17028             this._super();
17029 
17030             this._gadgetId = gadgetId;
17031             this._tabId = tabId;
17032             this._maxAvailableHeight = maxAvailableHeight;
17033             this._view = view;
17034         },
17035     
17036         /**
17037          * Getter for the gadget id.
17038          * @returns {String} The identifier for the gadget changing view.
17039          */
17040         getGadgetId: function () {
17041             // escape nulls to empty string
17042             return this._gadgetId || "";
17043         },
17044     
17045         /**
17046          * Getter for the maximum available height.
17047          * @returns {String} The maximum available height for the gadget's view.
17048          */
17049         getMaxAvailableHeight: function () {
17050             // escape nulls to empty string
17051             return this._maxAvailableHeight || "";
17052         },
17053 
17054         /**
17055          * Getter for the tab id.
17056          * @returns {String} The identifier for the tab where the gadget changing view resides.
17057          */
17058         getTabId: function () {
17059             // escape nulls to empty string
17060             return this._tabId || "";
17061         },
17062 
17063         /**
17064          * Getter for the view.
17065          * @returns {String} The view type the gadget is changing to.
17066          */
17067         getView: function () {
17068             // escape nulls to empty string
17069             return this._view || "";
17070         }
17071     });
17072     
17073     window.finesse = window.finesse || {};
17074     window.finesse.containerservices = window.finesse.containerservices || {};
17075     window.finesse.containerservices.GadgetViewChangedEvent = GadgetViewChangedEvent;
17076     
17077     return GadgetViewChangedEvent;
17078 }));
17079 
17080 /**
17081  * JavaScript representation of the Finesse MaxAvailableHeightChangedEvent object.
17082  *
17083  * @requires finesse.FinesseBase
17084  */
17085 
17086 /** The following comment is to prevent jslint errors about 
17087  * using variables before they are defined.
17088  */
17089 /*global FinesseBase: true, publisher:true, define:true, finesse:true, window:true */
17090 /** @private */
17091 (function (factory) {
17092     
17093 
17094     // Define as an AMD module if possible
17095     if ( typeof define === 'function' && define.amd )
17096     {
17097         define('containerservices/MaxAvailableHeightChangedEvent', ["FinesseBase"], factory );
17098     }
17099     /* Define using browser globals otherwise
17100      * Prevent multiple instantiations if the script is loaded twice
17101      */
17102     else
17103     {
17104         factory(finesse.FinesseBase);
17105     }
17106 }(function (FinesseBase) {
17107     var MaxAvailableHeightChangedEvent = FinesseBase.extend(/** @lends finesse.containerservices.MaxAvailableHeightChangedEvent.prototype */{
17108 
17109         /**
17110          * Reference to the maxAvailableHeight
17111          * @private
17112          */
17113         _maxAvailableHeight: null,
17114         
17115         /**
17116          * @class
17117          * JavaScript representation of a MaxAvailableHeightChangedEvent object.
17118          * The MaxAvailableHeightChangedEvent object is delivered as the payload of
17119          * a MaxAvailableHeightChangedEvent callback.  This can be subscribed to by using
17120          * {@link finesse.containerservices.ContainerServices#addHandler} with a 
17121          * topic of {@link finesse.containerservices.ContainerServices.Topics#MAX_AVAILABLE_HEIGHT_CHANGED_EVENT}. 
17122          * 
17123          * @constructs
17124          **/
17125         init: function (maxAvailableHeight) {
17126             this._super();
17127 
17128             this._maxAvailableHeight = maxAvailableHeight;
17129         },
17130     
17131         /**
17132          * Getter for the maximum available height.
17133          * @returns {String} The maximum available height for a gadget in canvas view
17134          */
17135         getMaxAvailableHeight: function () {
17136             // escape nulls to empty string
17137             return this._maxAvailableHeight || "";
17138         }
17139     });
17140     
17141     window.finesse = window.finesse || {};
17142     window.finesse.containerservices = window.finesse.containerservices || {};
17143     window.finesse.containerservices.MaxAvailableHeightChangedEvent = MaxAvailableHeightChangedEvent;
17144     
17145     return MaxAvailableHeightChangedEvent;
17146 }));
17147 
17148 /**
17149  * Exposes a set of API wrappers that will hide the dirty work of
17150  *     constructing Finesse API requests and consuming Finesse events.
17151  *
17152  * @requires OpenAjax, jQuery 1.5, finesse.utilities.Utilities
17153  */
17154 
17155 /** The following comment is to prevent jslint errors about using variables before they are defined. */
17156 /*global window:true, gadgets:true, publisher:true, define:true, finesse:true, _tabTracker:true, _workflowActionEventTracker:true, _masterReloader:true, frameElement:true, $:true, parent:true, MockControl:true, _getNotifierReference:true, _gadgetViewChanged:true, _maxAvailableHeightChanged:true */
17157 /*jslint nomen: true, unparam: true, sloppy: true, white: true */
17158 /** @private */
17159 (function (factory) {
17160     
17161 
17162     // Define as an AMD module if possible
17163     if ( typeof define === 'function' && define.amd )
17164     {
17165         define('containerservices/ContainerServices',["utilities/Utilities",
17166                 "restservices/Notifier",
17167                 "containerservices/Topics",
17168                 "containerservices/MasterPublisher",
17169                 "containerservices/WorkflowActionEvent",
17170                 "containerservices/TimerTickEvent",
17171                 "containerservices/GadgetViewChangedEvent",
17172                 "containerservices/MaxAvailableHeightChangedEvent"], factory );
17173     }
17174     
17175     /* Define using browser globals otherwise
17176      * Prevent multiple instantiations if the script is loaded twice
17177      */
17178     else
17179     {
17180         factory(finesse.utilities.Utilities, finesse.restservices.Notifier, finesse.containerservices.Topics, finesse.containerservices.MasterPublisher, finesse.containerservices.WorkflowActionEvent);
17181     }
17182     
17183 }(function (Utilities, Notifier, Topics, MasterPublisher, WorkflowActionEvent) {
17184 
17185     var ContainerServices = ( function () { /** @lends finesse.containerservices.ContainerServices.prototype */
17186 
17187     var
17188 
17189     /**
17190      * Shortcut reference to the Utilities singleton
17191      * This will be set by init()
17192      * @private
17193      */
17194     _util,
17195 
17196     /**
17197      * Shortcut reference to the gadget pubsub Hub instance.
17198      * This will be set by init()
17199      * @private
17200      */
17201     _hub,
17202 
17203     /**
17204      * Boolean whether this instance is master or not
17205      * @private
17206      */
17207     _master = false,
17208 
17209     /**
17210      * Whether the Client Services have been initiated yet.
17211      * @private
17212      */
17213     _inited = false,
17214     
17215     /**
17216      * References to ClientServices logger methods
17217      * @private
17218      */
17219     _logger = {
17220         log: finesse.clientservices.ClientServices.log
17221     },
17222     
17223      /**
17224      * Stores the list of subscription IDs for all subscriptions so that it
17225      * could be retrieve for unsubscriptions.
17226      * @private
17227      */
17228     _subscriptionID = {},
17229     
17230     /**
17231      * Reference to the gadget's parent container
17232      * @private
17233      */
17234     _container,
17235 
17236     /**
17237      * Reference to the MasterPublisher
17238      * @private
17239      */
17240     _publisher,
17241     
17242     /**
17243      * Object that will contain the Notifiers
17244      * @private
17245      */
17246     _notifiers = {},
17247 
17248     /**
17249      * Reference to the tabId that is associated with the gadget
17250      * @private
17251      */
17252     _myTab = null,
17253     
17254     /**
17255      * Reference to the visibility of current gadget
17256      * @private
17257      */
17258     _visible = false,
17259     
17260     /**
17261      * Shortcut reference to the Topics class.
17262      * This will be set by init()
17263      * @private
17264      */
17265     _topics,
17266 
17267     /**
17268      * Associates a topic name with the private handler function.
17269      * Adding a new topic requires that you add this association here 
17270      *  in to keep addHandler generic.
17271      * @param {String} topic : Specifies the callback to retrieve
17272      * @return {Function} The callback function associated with the topic param.
17273      * @private
17274      */
17275     _topicCallback = function (topic) {
17276         var callback, notifier;
17277         switch (topic)
17278         {
17279             case finesse.containerservices.ContainerServices.Topics.ACTIVE_TAB:
17280                 callback = _tabTracker;
17281                 break;
17282             case finesse.containerservices.ContainerServices.Topics.WORKFLOW_ACTION_EVENT:
17283                 callback = _workflowActionEventTracker;
17284                 break;
17285             case finesse.containerservices.ContainerServices.Topics.RELOAD_GADGET_EVENT:
17286                 callback = _masterReloader;
17287                 break;
17288             case finesse.containerservices.ContainerServices.Topics.GADGET_VIEW_CHANGED_EVENT:
17289                 callback = _gadgetViewChanged;
17290                 break;
17291             case finesse.containerservices.ContainerServices.Topics.MAX_AVAILABLE_HEIGHT_CHANGED_EVENT:
17292                 callback = _maxAvailableHeightChanged;
17293                 break;
17294             default:
17295                 callback = function (param) {
17296                      var data = null;
17297                      
17298                      notifier = _getNotifierReference(topic);
17299                      
17300                      if (arguments.length === 1) {
17301                         data = param;
17302                      } else {
17303                         data = arguments;
17304                      }
17305                      notifier.notifyListeners(data);
17306                 };
17307         }
17308         return callback;
17309     },
17310 
17311     /**
17312      * Ensure that ClientServices have been inited.
17313      * @private
17314      */
17315     _isInited = function () {
17316         if (!_inited) {
17317             throw new Error("ContainerServices needs to be inited.");
17318         }
17319     },
17320 
17321     /**
17322      * Retrieves a Notifier reference to a particular topic, and creates one if it doesn't exist.
17323      * @param {String} topic : Specifies the notifier to retrieve
17324      * @return {Notifier} The notifier object.
17325      * @private
17326      */
17327     _getNotifierReference = function (topic) {
17328         if (!_notifiers.hasOwnProperty(topic))
17329         {
17330             _notifiers[topic] = new Notifier();
17331         }
17332 
17333         return _notifiers[topic];
17334     },
17335 
17336     /**
17337      * Utility function to make a subscription to a particular topic. Only one
17338      * callback function is registered to a particular topic at any time.
17339      * @param {String} topic
17340      *     The full topic name. The topic name should follow the OpenAjax
17341      *     convention using dot notation (ex: finesse.api.User.1000).
17342      * @param {Function} callback
17343      *     The function that should be invoked with the data when an event
17344      *     is delivered to the specific topic.
17345      * @returns {Boolean}
17346      *     True if the subscription was made successfully and the callback was
17347      *     been registered. False if the subscription already exist, the
17348      *     callback was not overwritten.
17349      * @private
17350      */
17351     _subscribe = function (topic, callback) {
17352         _isInited();
17353 
17354         //Ensure that the same subscription isn't made twice.
17355         if (!_subscriptionID[topic]) {
17356             //Store the subscription ID using the topic name as the key.
17357             _subscriptionID[topic] = _hub.subscribe(topic,
17358                 //Invoke the callback just with the data object.
17359                 function (topic, data) {
17360                     callback(data);
17361                 });
17362             return true;
17363         }
17364         return false;
17365     },
17366 
17367     /**
17368      * Unsubscribe from a particular topic.
17369      * @param {String} topic : The full topic name.
17370      * @private
17371      */
17372     _unsubscribe = function (topic) {
17373         _isInited();
17374 
17375         //Unsubscribe from the topic using the subscription ID recorded when
17376         //the subscription was made, then delete the ID from data structure.
17377         _hub.unsubscribe(_subscriptionID[topic]);
17378         delete _subscriptionID[topic];
17379     },
17380 
17381     /**
17382      * Get my tab id.
17383      * @returns {String} tabid : The tabid of this container/gadget.
17384      * @private
17385      */
17386     _getMyTab = function () {
17387         if (_myTab === null)
17388         {
17389             try {
17390             _myTab = $(frameElement).closest("div.tab-panel").attr("id").replace("panel_", "");
17391             } catch (err) {
17392                 _logger.log("Error accessing current tab: " + err.message);
17393                _myTab = null;
17394             }
17395         }
17396         return _myTab;
17397     },
17398     
17399     /**
17400      * Callback function that is called when an activeTab message is posted to the Hub.
17401      * Notifies listener functions if this tab is the one that was just made active.
17402      * @param {String} tabId : The tabId which was just made visible.
17403      * @private
17404      */
17405     _tabTracker = function(tabId) {
17406         if (tabId === _getMyTab()) {
17407             if(!_visible) {
17408                 _visible = true;
17409                 _notifiers[finesse.containerservices.ContainerServices.Topics.ACTIVE_TAB].notifyListeners(this);
17410             }
17411         } else {
17412             _visible = false;
17413         }
17414     },
17415     
17416     /**
17417      * Make a request to set a particular tab active. This
17418      * method should be called after {@link finesse.containerservices.ContainerServices#addHandler}
17419      * to ensure the gadget gets properly initialized.
17420      * @param {String} tabId
17421      *    The tabId (not the label text) of the tab to make active.  If the id is invalid, no action will occur.
17422      * @private
17423      */
17424     _activateTab = function ( tabId ) {
17425         _logger.log("Sending request to activate tab: " + tabId);
17426         if(_hub){
17427             var data = {
17428                 type: "SetActiveTabReq",
17429                 data: { id: tabId },
17430                 invokeID: (new Date()).getTime()          
17431             };
17432             _hub.publish(_topics.REQUESTS, data);
17433         } else {
17434             throw new Error("Hub is not defined.");
17435         }
17436         
17437     },
17438 
17439     /**
17440      * Callback function that is called when a gadget view changed message is posted to the Hub.
17441      * @private
17442      */
17443     _gadgetViewChanged = function (data) {
17444         if (data) {
17445             var gadgetViewChangedEvent = new finesse.containerservices.GadgetViewChangedEvent(
17446                 data.gadgetId,
17447                 data.tabId,
17448                 data.maxAvailableHeight,
17449                 data.view);
17450 
17451             _notifiers[finesse.containerservices.ContainerServices.Topics.GADGET_VIEW_CHANGED_EVENT].notifyListeners(gadgetViewChangedEvent);
17452         }
17453     },
17454 
17455     /**
17456      * Callback function that is called when a max available height changed message is posted to the Hub.
17457      * @private
17458      */
17459     _maxAvailableHeightChanged = function (data) {
17460         if (data) {
17461             var maxAvailableHeightChangedEvent = new finesse.containerservices.MaxAvailableHeightChangedEvent(
17462                 data.maxAvailableHeight);
17463 
17464             _notifiers[finesse.containerservices.ContainerServices.Topics.MAX_AVAILABLE_HEIGHT_CHANGED_EVENT].notifyListeners(maxAvailableHeightChangedEvent);
17465         }
17466     },
17467 
17468     /**
17469      * Callback function that is called when a workflowActionEvent message is posted to the Hub.
17470      * Notifies listener functions if the posted object can be converted to a proper WorkflowActionEvent object.
17471      * @param {String} workflowActionEvent : The workflowActionEvent that was posted to the Hub
17472      * @private
17473      */
17474     _workflowActionEventTracker = function(workflowActionEvent) {
17475         var vWorkflowActionEvent = new finesse.containerservices.WorkflowActionEvent();
17476                 
17477         if (vWorkflowActionEvent.setWorkflowActionEvent(workflowActionEvent)) {
17478             _notifiers[finesse.containerservices.ContainerServices.Topics.WORKFLOW_ACTION_EVENT].notifyListeners(vWorkflowActionEvent);
17479         }
17480         // else
17481         // {
17482             //?console.log("Error in ContainerServices : _workflowActionEventTracker - could not map published HUB object to WorkflowActionEvent");
17483         // }
17484 
17485     },
17486 
17487     /**
17488      * Callback function that is called when a reloadGadget event message is posted to the Hub.
17489      *
17490      * Grabs the id of the gadget we want to reload from the data and reload it!
17491      *
17492      * @param {String} topic
17493      *      which topic the event came on (unused)
17494      * @param {Object} data
17495      *      the data published with the event
17496      * @private
17497      */
17498     _masterReloader = function (topic, data) {
17499         var gadgetId = data.gadgetId;
17500         if (gadgetId) {
17501             _container.reloadGadget(gadgetId);
17502         }
17503     },
17504     
17505     /**
17506      * Pulls the gadget id from the url parameters
17507      * @return {String} id of the gadget
17508      * @private
17509      */
17510     _findMyGadgetId = function () {
17511         if (gadgets && gadgets.util && gadgets.util.getUrlParameters()) {
17512             return gadgets.util.getUrlParameters().mid;
17513         }
17514     };
17515 
17516     return {
17517         /**
17518          * @class
17519          * This class provides container-level services for gadget developers, exposing container events by
17520          * calling a set of exposed functions. Gadgets can utilize the container dialogs and 
17521          * event handling (add/remove).
17522          * @example
17523          *    containerServices = finesse.containerservices.ContainerServices.init();
17524          *    containerServices.addHandler(
17525          *      finesse.containerservices.ContainerServices.Topics.ACTIVE_TAB, 
17526          *      function() {
17527          *          clientLogs.log("Gadget is now visible");  // log to Finesse logger
17528          *          // automatically adjust the height of the gadget to show the html
17529          *          gadgets.window.adjustHeight();
17530          *      });
17531          *    containerServices.makeActiveTabReq();
17532          *    
17533          * @constructs
17534          */
17535         _fakeConstuctor: function () {
17536             /* This is here so we can document init() as a method rather than as a constructor. */
17537         },
17538         
17539         /**
17540          * Initialize ContainerServices for use in gadget.
17541          * @param {Boolean} [master=false] Do not use this parameter from your gadget.
17542          * @returns ContainerServices instance.
17543          */
17544         init: function (master) {
17545             if (!_inited) {
17546                 _inited = true;
17547                 // Set shortcuts
17548                 _util = Utilities;
17549 
17550                 //init the hub only when it's available
17551                 if(gadgets.Hub) {
17552                     _hub = gadgets.Hub;
17553                 }
17554 
17555                 if(Topics) {
17556                     _topics = Topics;
17557                 }
17558 
17559                 if (master) {
17560                     _master = true;
17561                     _container = finesse.container.Container;
17562                     _publisher = new MasterPublisher();
17563 
17564                     // subscribe for reloading gadget events
17565                     // we only want the master ContainerServices handling these events
17566                     _hub.subscribe(_topics.RELOAD_GADGET, _topicCallback(_topics.RELOAD_GADGET));
17567                 } else {
17568                     _container = parent.finesse.container.Container;
17569                 }
17570             }
17571             
17572             this.makeActiveTabReq();
17573 
17574             //Return the CS object for object chaining.
17575             return this;
17576         },
17577 
17578         /**
17579          * Shows the jQuery UI Dialog with the specified parameters. The following are the
17580          * default parameters: <ul>
17581          *     <li> Title of "Cisco Finesse".</li>
17582          *     <li>Message of "A generic error has occured".</li>
17583          *     <li>The only button, "Ok", closes the dialog.</li>
17584          *     <li>Modal (blocks other dialogs).</li>
17585          *     <li>Not draggable.</li>
17586          *     <li>Fixed size.</li></ul>
17587          * @param {Object} options
17588          *  An object containing additional options for the dialog.
17589          * @param {String/Boolean} options.title
17590          *  Title to use. undefined defaults to "Cisco Finesse". false to hide
17591          * @param {Function} options.close
17592          *  A function to invoke when the dialog is closed.
17593          * @param {String} options.message
17594          *  The message to display in the dialog.
17595          *  Defaults to "A generic error has occurred."
17596          * @param {Boolean} options.isBlocking
17597          *  Flag indicating whether this dialog will block other dialogs from being shown (Modal).
17598          * @returns {jQuery} JQuery wrapped object of the dialog DOM element.
17599          * @see finesse.containerservices.ContainerServices#hideDialog
17600          */
17601         showDialog: function(options) {
17602             if ((_container.showDialog !== undefined) && (_container.showDialog !== this.showDialog)) {
17603                 return _container.showDialog(options);
17604             }
17605         },
17606         
17607         /**
17608          * Hides the jQuery UI Dialog.
17609          * @returns {jQuery} jQuery wrapped object of the dialog DOM element
17610          * @see finesse.containerservices.ContainerServices#showDialog
17611          */
17612         hideDialog: function() {
17613             if ((_container.hideDialog !== undefined) && (_container.hideDialog !== this.hideDialog)) {
17614                 return _container.hideDialog();
17615             }
17616         },
17617 
17618         /**
17619          *  Reloads the current gadget. 
17620          *  For use from within a gadget only.
17621          */
17622         reloadMyGadget: function () {
17623             var topic, gadgetId, data;
17624 
17625             if (!_master) {
17626                 // first unsubscribe this gadget from all topics on the hub
17627                 for (topic in _notifiers) {
17628                     if (_notifiers.hasOwnProperty(topic)) {
17629                         _unsubscribe(topic);
17630                         delete _notifiers[topic];
17631                     }
17632                 }
17633 
17634                 // send an asynch request to the hub to tell the master container
17635                 // services that we want to refresh this gadget
17636                 gadgetId = _findMyGadgetId();
17637                 data = {
17638                     type: "ReloadGadgetReq",
17639                     data: {gadgetId: gadgetId},
17640                     invokeID: (new Date()).getTime()          
17641                 };
17642                 _hub.publish(_topics.REQUESTS, data);
17643             }            
17644         },
17645 
17646         /**
17647          * Updates the url for this gadget and then reload it.
17648          * 
17649          * This allows the gadget to be reloaded from a different location
17650          * than what is uploaded to the current server. For example, this
17651          * would be useful for 3rd party gadgets to implement their own failover
17652          * mechanisms.
17653          *
17654          * For use from within a gadget only.
17655          *
17656          * @param {String} url
17657          *      url from which to reload gadget
17658          */
17659         reloadMyGadgetFromUrl: function (url) {
17660             if (!_master) {
17661                 var gadgetId = _findMyGadgetId();
17662 
17663                 // update the url in the container
17664                 _container.modifyGadgetUrl(gadgetId, url);
17665 
17666                 // reload it
17667                 this.reloadMyGadget();
17668             }
17669         },
17670         
17671         /**
17672          * Adds a handler for one of the supported topics provided by ContainerServices.  The callbacks provided
17673          * will be invoked when that topic is notified.  
17674          * @param {String} topic
17675          *  The Hub topic to which we are listening.
17676          * @param {Function} callback
17677          *  The callback function to invoke.
17678          * @see finesse.containerservices.ContainerServices.Topics
17679          * @see finesse.containerservices.ContainerServices#removeHandler
17680          */
17681         addHandler: function (topic, callback) {
17682             _isInited();
17683             var notifier = null;
17684             
17685             try {    
17686                 // For backwards compatibility...
17687                 if (topic === "tabVisible") {
17688                     if (window.console && typeof window.console.log === "function") {
17689                         window.console.log("WARNING - Using tabVisible as topic.  This is deprecated.  Use finesse.containerservices.ContainerServices.Topics.ACTIVE_TAB now!");
17690                     }
17691                     
17692                     topic = finesse.containerservices.ContainerServices.Topics.ACTIVE_TAB;
17693                 }
17694                 
17695                 // Add the callback to the notifier.
17696                 _util.validateHandler(callback);
17697             
17698                 notifier = _getNotifierReference(topic);
17699             
17700                 notifier.addListener(callback);
17701             
17702                 // Subscribe to the topic. _subscribe ensures that a topic is only subscribed to once,
17703                 // so attempt to subscribe each time a handler is added. This ensures that a topic is subscribed
17704                 // to only when necessary.
17705                 _subscribe(topic, _topicCallback(topic));
17706             
17707             } catch (err) {
17708                 throw new Error("addHandler(): " + err);
17709             }
17710         }, 
17711         
17712         /**
17713          * Removes a previously-added handler for one of the supported topics.
17714          * @param {String} topic
17715          *  The Hub topic from which we are removing the callback.
17716          * @param {Function} callback
17717          *  The name of the callback function to remove.
17718          * @see finesse.containerservices.ContainerServices.Topics
17719          * @see finesse.containerservices.ContainerServices#addHandler
17720          */
17721         removeHandler: function(topic, callback) {
17722             var notifier = null;
17723             
17724             try {
17725                 _util.validateHandler(callback);
17726     
17727                 notifier = _getNotifierReference(topic);
17728     
17729                 notifier.removeListener(callback);
17730             } catch (err) {
17731                 throw new Error("removeHandler(): " + err);
17732             }
17733         },
17734 
17735         /**
17736          * Returns the visibility of current gadget.  Note that this 
17737          * will not be set until after the initialization of the gadget.
17738          * @return {Boolean} The visibility of current gadget.
17739          */
17740         tabVisible: function(){
17741             return _visible;
17742         },
17743         
17744         /**
17745          * Make a request to check the current tab.  The 
17746          * activeTab event will be invoked if on the active tab.  This
17747          * method should be called after {@link finesse.containerservices.ContainerServices#addHandler}
17748          * to ensure the gadget gets properly initialized.
17749          */
17750         makeActiveTabReq : function () {
17751             if(_hub){
17752                 var data = {
17753                     type: "ActiveTabReq",
17754                     data: {},
17755                     invokeID: (new Date()).getTime()          
17756                 };
17757                 _hub.publish(_topics.REQUESTS, data);
17758             } else {
17759                 throw new Error("Hub is not defined.");
17760             }
17761             
17762         },
17763 
17764         /**
17765          * Make a request to set a particular tab active. This
17766          * method should be called after {@link finesse.containerservices.ContainerServices#addHandler}
17767          * to ensure the gadget gets properly initialized.
17768          * @param {String} tabId
17769          *    The tabId (not the label text) of the tab to make active.  If the id is invalid, no action will occur.
17770          */
17771         activateTab : function (tabId) {
17772             _activateTab(tabId);
17773         },
17774         
17775         /**
17776          * Make a request to set this container's tab active. This
17777          * method should be called after {@link finesse.containerservices.ContainerServices#addHandler}
17778          * to ensure the gadget gets properly initialized.
17779          */
17780         activateMyTab : function () {
17781             _activateTab( _getMyTab() );
17782         },
17783         
17784         /**
17785          * Get the tabId of my container/gadget.
17786          * @returns {String} tabid : The tabid of this container/gadget.
17787          */
17788         getMyTabId : function () {
17789             return _getMyTab();
17790         },
17791 
17792         /**
17793          * Gets the id of the gadget.
17794          * @returns {number} the id of the gadget
17795          */
17796         getMyGadgetId : function () {
17797             return _findMyGadgetId();
17798         },
17799 
17800         //BEGIN TEST CODE//
17801         /**
17802          * Test code added to expose private functions that are used by unit test
17803          * framework. This section of code is removed during the build process
17804          * before packaging production code. The [begin|end]TestSection are used
17805          * by the build to identify the section to strip.
17806          * @ignore
17807          */
17808         beginTestSection : 0,
17809 
17810         /**
17811          * @ignore
17812          */
17813         getTestObject: function () {
17814             //Load mock dependencies.
17815             var _mock = new MockControl();
17816             _util = _mock.createMock(Utilities);
17817             _hub = _mock.createMock(gadgets.Hub);
17818             _inited = true;
17819             return {
17820                 //Expose mock dependencies
17821                 mock: _mock,
17822                 hub: _hub,
17823                 util: _util,
17824                 addHandler: this.addHandler,
17825                 removeHandler: this.removeHandler
17826             };
17827         },
17828 
17829         /**
17830          * @ignore
17831          */
17832        endTestSection: 0
17833         //END TEST CODE//
17834     };
17835     }());
17836     
17837     ContainerServices.Topics = /** @lends finesse.containerservices.ContainerServices.Topics.prototype */ {
17838         /**
17839          * Topic for subscribing to be notified when the active tab changes.
17840          * The provided callback will be invoked when the tab that the gadget 
17841          * that subscribes with this becomes active.  To ensure code is called
17842          * when the gadget is already on the active tab use the 
17843          * {@link finesse.containerservices.ContainerServices#makeActiveTabReq}
17844          * method.
17845          */
17846         ACTIVE_TAB: "finesse.containerservices.activeTab",
17847 
17848         /**
17849          * Topic for WorkflowAction events traffic.
17850          * The provided callback will be invoked when a WorkflowAction needs
17851          * to be handled.  The callback will be passed a {@link finesse.containerservices.WorkflowActionEvent}
17852          * that can be used to interrogate the WorkflowAction and determine to use or not.
17853          */
17854         WORKFLOW_ACTION_EVENT: "finesse.containerservices.workflowActionEvent",
17855         
17856         /**
17857          * Topic for Timer Tick event.
17858          * The provided callback will be invoked when this event is fired.
17859          * The callback will be passed a {@link finesse.containerservices.TimerTickEvent}.
17860          */
17861         TIMER_TICK_EVENT : "finesse.containerservices.timerTickEvent",
17862 
17863         /**
17864          * Topic for Reload Gadget events traffic.
17865          * Only the master ContainerServices instance will handle this event.
17866          */
17867         RELOAD_GADGET_EVENT: "finesse.containerservices.reloadGadget",
17868         
17869         /**
17870          * Topic for listening to gadget view changed events.
17871          * The provided callback will be invoked when a gadget changes view.
17872          * The callback will be passed a {@link finesse.containerservices.GadgetViewChangedEvent}.
17873          */
17874         GADGET_VIEW_CHANGED_EVENT: "finesse.containerservices.gadgetViewChangedEvent",
17875 
17876         /**
17877          * Topic for listening to max available height changed events.
17878          * The provided callback will be invoked when the maximum height available to a maximized gadget changes.
17879          * This event is only meant for maximized gadgets and will not be published unless a maximized gadget exists.
17880          * The callback will be passed a {@link finesse.containerservices.MaxAvailableHeightChangedEvent}.
17881          */
17882         MAX_AVAILABLE_HEIGHT_CHANGED_EVENT: "finesse.containerservices.maxAvailableHeightChangedEvent",
17883 
17884         /**
17885          * @class This is the set of Topics used for subscribing for events from ContainerServices.
17886          * Use {@link finesse.containerservices.ContainerServices#addHandler} to subscribe to the topic.
17887          * 
17888          * @constructs
17889          */
17890         _fakeConstructor : function () {} // For JS Doc to work need a constructor so that the lends/constructs build the doc properly
17891     };
17892     
17893     window.finesse = window.finesse || {};
17894     window.finesse.containerservices = window.finesse.containerservices || {};
17895     window.finesse.containerservices.ContainerServices = ContainerServices;
17896 
17897     return ContainerServices;
17898  }));
17899 
17900 /**
17901  * This "interface" is just a way to easily jsdoc the Object callback handlers.
17902  *
17903  * @requires finesse.clientservices.ClientServices
17904  * @requires Class
17905  */
17906 /** @private */
17907 (function (factory) {
17908     
17909 
17910     // Define as an AMD module if possible
17911     if ( typeof define === 'function' && define.amd )
17912     {
17913         define('interfaces/RestObjectHandlers', ["FinesseBase",
17914                  "utilities/Utilities",
17915                  "restservices/Notifier",
17916                  "clientservices/ClientServices",
17917                  "clientservices/Topics"], factory );
17918     }
17919     /* Define using browser globals otherwise
17920      * Prevent multiple instantiations if the script is loaded twice
17921      */
17922     else
17923     {
17924         factory(finesse.FinesseBase, finesse.utilities.Utilities,
17925                 finesse.restservices.Notifier,
17926                 finesse.clientservices.ClientServices,
17927                 finesse.clientservices.Topics);
17928     } 
17929 }(function () {
17930 
17931     var RestObjectHandlers = ( function () { /** @lends finesse.interfaces.RestObjectHandlers.prototype */
17932         
17933         return {
17934 
17935             /**
17936              * @class
17937              * This "interface" defines REST Object callback handlers, passed as an argument to
17938              * Object getter methods in cases where the Object is going to be created.
17939              * 
17940              * @param {Object} [handlers]
17941              *     An object containing callback handlers for instantiation and runtime
17942              *     Callback to invoke upon successful instantiation, passes in REST object.
17943              * @param {Function} [handlers.onLoad(this)]
17944              *     Callback to invoke upon loading the data for the first time.
17945              * @param {Function} [handlers.onChange(this)]
17946              *     Callback to invoke upon successful update object (PUT)
17947              * @param {Function} [handlers.onAdd(this)]
17948              *     Callback to invoke upon successful update to add object (POST)
17949              * @param {Function} [handlers.onDelete(this)]
17950              *     Callback to invoke upon successful update to delete object (DELETE)
17951              * @param {Function} [handlers.onError(rsp)]
17952              *     Callback to invoke on update error (refresh or event)
17953              *     as passed by finesse.restservices.RestBase.restRequest()<br>
17954              *     {<br>
17955              *         status: {Number} The HTTP status code returned<br>
17956              *         content: {String} Raw string of response<br>
17957              *         object: {Object} Parsed object of response<br>
17958              *         error: {Object} Wrapped exception that was caught<br>
17959              *         error.errorType: {String} Type of error that was caught<br>
17960              *         error.errorMessage: {String} Message associated with error<br>
17961              *     }<br>
17962              *     <br>
17963              * Note that RestCollections have two additional callback handlers:<br>
17964              * <br>
17965              * @param {Function} [handlers.onCollectionAdd(this)]: when an object is added to this collection
17966              * @param {Function} [handlers.onCollectionDelete(this)]: when an object is removed from this collection
17967 
17968              * @constructs
17969              */
17970             _fakeConstuctor: function () {
17971                 /* This is here to enable jsdoc to document this as a class. */
17972             }
17973         };
17974     }());
17975 
17976 window.finesse = window.finesse || {};
17977 window.finesse.interfaces = window.finesse.interfaces || {};
17978 window.finesse.interfaces.RestObjectHandlers = RestObjectHandlers;
17979 
17980 return RestObjectHandlers;
17981 
17982 }));
17983 
17984 
17985 /**
17986  * This "interface" is just a way to easily jsdoc the REST request handlers.
17987  *
17988  * @requires finesse.clientservices.ClientServices
17989  * @requires Class
17990  */
17991 /** @private */
17992 (function (factory) {
17993     
17994 
17995     // Define as an AMD module if possible
17996     if ( typeof define === 'function' && define.amd )
17997     {
17998         define('interfaces/RequestHandlers', ["FinesseBase",
17999                  "utilities/Utilities",
18000                  "restservices/Notifier",
18001                  "clientservices/ClientServices",
18002                  "clientservices/Topics"], factory );
18003     }
18004     /* Define using browser globals otherwise
18005      * Prevent multiple instantiations if the script is loaded twice
18006      */
18007     else
18008     {
18009         factory(finesse.FinesseBase, finesse.utilities.Utilities,
18010                 finesse.restservices.Notifier,
18011                 finesse.clientservices.ClientServices,
18012                 finesse.clientservices.Topics);
18013     } 
18014 }(function () {
18015 
18016     var RequestHandlers = ( function () { /** @lends finesse.interfaces.RequestHandlers.prototype */
18017         
18018         return {
18019 
18020             /**
18021              * @class
18022              * This "interface" defines REST Object callback handlers, passed as an argument to
18023              * Object getter methods in cases where the Object is going to be created.
18024              * 
18025              * @param {Object} handlers
18026              *     An object containing the following (optional) handlers for the request:<ul>
18027              *         <li><b>success(rsp):</b> A callback function for a successful request to be invoked with the following
18028              *         response object as its only parameter:<ul>
18029              *             <li><b>status:</b> {Number} The HTTP status code returned</li>
18030              *             <li><b>content:</b> {String} Raw string of response</li>
18031              *             <li><b>object:</b> {Object} Parsed object of response</li></ul>
18032              *         <li><b>error(rsp):</b> An error callback function for an unsuccessful request to be invoked with the
18033              *         error response object as its only parameter:<ul>
18034              *             <li><b>status:</b> {Number} The HTTP status code returned</li>
18035              *             <li><b>content:</b> {String} Raw string of response</li>
18036              *             <li><b>object:</b> {Object} Parsed object of response (HTTP errors)</li>
18037              *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
18038              *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
18039              *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
18040              *             </ul></li>
18041              *         </ul>
18042 
18043              * @constructs 
18044              */
18045             _fakeConstuctor: function () {
18046                 /* This is here to enable jsdoc to document this as a class. */
18047             }
18048         };
18049     }());
18050 
18051 window.finesse = window.finesse || {};
18052 window.finesse.interfaces = window.finesse.interfaces || {};
18053 window.finesse.interfaces.RequestHandlers = RequestHandlers;
18054 
18055 finesse = finesse || {};
18056 /** @namespace These interfaces are just a convenience for documenting common parameter structures. */
18057 finesse.interfaces = finesse.interfaces || {};
18058 
18059 return RequestHandlers;
18060 
18061 }));
18062 
18063 
18064 (function (factory) {
18065     
18066 
18067     // Define as an AMD module if possible
18068     if ( typeof define === 'function' && define.amd )
18069     {
18070         define('finesse-desktop', [], factory );
18071     }
18072     /* Define using browser globals otherwise
18073      * Prevent multiple instantiations if the script is loaded twice
18074      */
18075     else
18076     {
18077         factory();
18078     }
18079 }(function () {
18080     if (typeof require === 'function') {
18081         (function () {
18082             /*
18083               The 'paths' section lets you define keys to refer to libraries
18084               so you don't have to to refer to them by their full paths everywhere.
18085 
18086               This removes the need to refer to 3rd-party libraries using the '3rdparty' path,
18087               and the need to refer to patched libaries using the '.patched' suffix.
18088 
18089               These keys are usable inside all require() calls inside each gadget module.
18090             */
18091             require.config({
18092                 paths : {
18093                     'Math.uuid' : '../thirdparty/util/Math.uuid',
18094                     'iso8601' : '../thirdparty/util/iso8601'
18095                 },
18096 
18097                 /*
18098                   This 'shim' section lets you specify a dependency tree for all libaries that are NOT AMD modules.
18099                   (AMD modules always contain a 'define()' call. For more information about AMD: https://github.com/amdjs/amdjs-api/wiki/AMD)
18100 
18101                   ** DO NOT list any AMD modules in this 'shim' section. **
18102 
18103                   The format is 'libraryKey': ['dependencyKey1', 'dependencyKey2' ...]. Both keys can refer to any JS module
18104                   or one of the 'path' keys listed above.
18105 
18106                   FOR EXAMPLE:
18107                     dataTables depends on jQuery, but all of the dataTables plugins depend on dataTables.
18108                     We can refer to 'dataTables' and 'dataTables.scroller' as keys on the left side
18109                     since those are aliases defined in the 'paths' section above.
18110 
18111                   NOTE: Most jQuery plugins ARE NOT AMD modules, so when adding a new jQuery plugin that is not an AMD module,
18112                   make sure it has jquery listed as a dependency here (similar to all of the boostrap-* plugins, jquery.cookie, etc.)
18113 
18114                   Official documentation on RequireJS shim configuration: http://requirejs.org/docs/api.html#config-shim
18115                 */
18116                 shim : {
18117                     'Math.uuid' : {
18118                         exports : 'Math'
18119                     }
18120                 }
18121             });
18122             
18123             //All modules in this list (and their dependencies) will be concatenated into one file to be used in the container and gadgets
18124             require(['restservices/Users',
18125                      'restservices/Teams',
18126                      'restservices/SystemInfo',
18127                      'utilities/I18n',
18128                      'utilities/Logger',
18129                      'utilities/SaxParser',
18130                      'cslogger/ClientLogger',
18131                      'cslogger/FinesseLogger',
18132                      'containerservices/ContainerServices',
18133                      'interfaces/RestObjectHandlers',
18134                      'interfaces/RequestHandlers'], function() {
18135                 // Do nothing                
18136             });
18137         }.bind(this)());
18138     }
18139 
18140     // If being used in a gadget, stuff the auth string into the gadget prefs
18141     if (gadgets.Prefs) {
18142         var _prefs = new gadgets.Prefs(),
18143         authString = finesse.utilities.Utilities.getUserAuthString();
18144         _prefs.set("authorization", authString);
18145     }
18146 }));
18147