1 /**
  2  * Cisco Finesse - JavaScript Library
  3  * Version 10.0(1)
  4  * Cisco Systems, Inc.
  5  * http://www.cisco.com/
  6  *
  7  * Portions created or assigned to Cisco Systems, Inc. are
  8  * Copyright (c) 2013 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          * Utility method for getting the current time,
1163          * adjusted by the calculated "drift" to closely
1164          * approximate the server time.  This is used
1165          * when calculating durations based on a server
1166          * timestamp, which otherwise can produce unexpected
1167          * results if the times on client and server are
1168          * off.
1169          * 
1170          * @returns {String}
1171          *     The current server time in milliseconds
1172          */
1173         currentServerTimeMillis : function () {
1174             if (!finesse.container.Config.clientDriftInMillis) {
1175                 finesse.container.Config.clientDriftInMillis = 0;
1176             }
1177             return (new Date()).getTime() + finesse.container.Config.clientDriftInMillis;
1178         },
1179 
1180         /**
1181          * @private
1182          * Generates an RFC1422v4-compliant UUID using pesudorandom numbers.
1183          * @returns {String}
1184          *     An RFC1422v4-compliant UUID using pesudorandom numbers.
1185          **/        
1186         generateUUID: function () {
1187             return Math.uuidCompact();
1188         },
1189 
1190         /** @private */
1191         xml2json: Converter.xml2json,
1192         
1193         
1194         /**
1195          * @private
1196          * Utility method to get the JSON parser either from gadgets.json
1197          * or from window.JSON (which will be initialized by CUIC if 
1198          * browser doesn't support
1199          */
1200         getJSONParser: function() {
1201             var _container = window.gadgets || {},
1202                 parser = _container.json || window.JSON;
1203             return parser;
1204         },
1205 
1206        /**
1207         * @private
1208         * Utility method to convert a javascript object to XML.
1209         * @param {Object} object
1210         *   The object to convert to XML.
1211         * @param {Boolean} escapeFlag
1212         *   If escapeFlag evaluates to true:
1213         *       - XML escaping is done on the element values.
1214         *       - Attributes, #cdata, and #text is not supported.
1215         *       - The XML is unformatted (no whitespace between elements).
1216         *   If escapeFlag evaluates to false:
1217         *       - Element values are written 'as is' (no escaping).
1218         *       - Attributes, #cdata, and #text is supported.
1219         *       - The XML is formatted.
1220         * @returns The XML string.
1221         */
1222         json2xml: function (object, escapeFlag) {
1223             var xml;
1224             if (escapeFlag) {
1225                 xml = this._json2xmlWithEscape(object);
1226             }
1227             else {
1228                 xml = Converter.json2xml(object, '\t');
1229             }
1230             return xml;
1231         },
1232 
1233         /**
1234          * @private
1235          * Utility method to convert XML string into javascript object.
1236          */
1237         xml2JsObj : function (event) {
1238             var parser = this.getJSONParser();
1239             return parser.parse(Converter.xml2json(jQuery.parseXML(event), ""));
1240         },
1241 
1242        /**
1243         * @private
1244         * Utility method to convert an XML string to a javascript object.
1245         * @desc This function calls to the SAX parser and responds to callbacks
1246         *     received from the parser. Entity translation is not handled here.
1247         * @param {String} xml
1248         *   The XML to parse.
1249         * @returns The javascript object.
1250         */
1251         xml2js: function (xml) {
1252             var STATES = {
1253                     INVALID: 0,
1254                     NEW_NODE: 1,
1255                     ATTRIBUTE_NODE: 2,
1256                     TEXT_NODE: 3,
1257                     END_NODE: 4
1258                 },
1259                 state = STATES.INVALID,
1260                 rootObj = {},
1261                 newObj,
1262                 objStack = [rootObj],
1263                 nodeName = "",
1264 
1265                 /**
1266                 * @private
1267                 * Adds a property to the current top JSO.
1268                 * @desc This is also where we make considerations for arrays.
1269                 * @param {String} name
1270                 *   The name of the property to add.
1271                 * @param (String) value
1272                 *     The value of the property to add.
1273                 */
1274                 addProperty = function (name, value) {
1275                     var current = objStack[objStack.length - 1];
1276                     if(current.hasOwnProperty(name) && current[name] instanceof Array){
1277                         current[name].push(value);
1278                     }else if(current.hasOwnProperty(name)){
1279                         current[name] = [current[name], value];
1280                     }else{
1281                         current[name] = value;
1282                     }
1283                 },
1284 
1285                 /**
1286                 * @private
1287                 * The callback passed to the SAX parser which processes events from
1288                 * the SAX parser in order to construct the resulting JSO.
1289                 * @param (String) type
1290                 *     The type of event received.
1291                 * @param (String) data
1292                 *     The data received from the SAX parser. The contents of this
1293                 *     parameter vary based on the type of event.
1294                 */
1295                 xmlFound = function (type, data) {
1296                     switch (type) {
1297                     case "StartElement":
1298                         // Because different node types have different expectations
1299                         // of parenting, we don't push another JSO until we know
1300                         // what content we're getting
1301 
1302                         // If we're already in the new node state, we're running
1303                         // into a child node. There won't be any text here, so
1304                         // create another JSO
1305                         if(state === STATES.NEW_NODE){
1306                             newObj = {};
1307                             addProperty(nodeName, newObj);
1308                             objStack.push(newObj);
1309                         }
1310                         state = STATES.NEW_NODE;
1311                         nodeName = data;
1312                         break;
1313                     case "EndElement":
1314                         // If we're in the new node state, we've found no content
1315                         // set the tag property to null
1316                         if(state === STATES.NEW_NODE){
1317                             addProperty(nodeName, null);
1318                         }else if(state === STATES.END_NODE){
1319                             objStack.pop();
1320                         }
1321                         state = STATES.END_NODE;
1322                         break;
1323                     case "Attribute":
1324                         // If were in the new node state, no JSO has yet been created
1325                         // for this node, create one
1326                         if(state === STATES.NEW_NODE){
1327                             newObj = {};
1328                             addProperty(nodeName, newObj);
1329                             objStack.push(newObj);
1330                         }
1331                         // Attributes are differentiated from child elements by a
1332                         // preceding "@" in the property name
1333                         addProperty("@" + data.name, data.value);
1334                         state = STATES.ATTRIBUTE_NODE;
1335                         break;
1336                     case "Text":
1337                         // In order to maintain backwards compatibility, when no
1338                         // attributes are assigned to a tag, its text contents are
1339                         // assigned directly to the tag property instead of a JSO.
1340 
1341                         // If we're in the attribute node state, then the JSO for
1342                         // this tag was already created when the attribute was
1343                         // assigned, differentiate this property from a child
1344                         // element by naming it "#text"
1345                         if(state === STATES.ATTRIBUTE_NODE){
1346                             addProperty("#text", data);
1347                         }else{
1348                             addProperty(nodeName, data);
1349                         }
1350                         state = STATES.TEXT_NODE;
1351                         break;
1352                     }
1353                 };
1354             SaxParser.parse(xml, xmlFound);
1355             return rootObj;
1356         },
1357 
1358        /**
1359         * @private
1360         * Traverses a plain-old-javascript-object recursively and outputs its XML representation.
1361         * @param {Object} obj
1362         *     The javascript object to be converted into XML.
1363         * @returns {String} The XML representation of the object.
1364         */
1365         js2xml: function (obj) {
1366             var xml = "", i, elem;
1367 
1368             if (obj !== null) {
1369                 if (obj.constructor === Object) {
1370                     for (elem in obj) {
1371                         if (obj[elem] === null || typeof(obj[elem]) === 'undefined') {
1372                             xml += '<' + elem + '/>';
1373                         } else if (obj[elem].constructor === Array) {
1374                             for (i = 0; i < obj[elem].length; i++) {
1375                                 xml += '<' + elem + '>' + this.js2xml(obj[elem][i]) + '</' + elem + '>';
1376                             }
1377                         } else if (elem[0] !== '@') {
1378                             if (this.js2xmlObjIsEmpty(obj[elem])) {
1379                                 xml += '<' + elem + this.js2xmlAtt(obj[elem]) + '/>';
1380                             } else if (elem === "#text") {
1381                                 xml += obj[elem];
1382                             } else {
1383                                 xml += '<' + elem + this.js2xmlAtt(obj[elem]) + '>' + this.js2xml(obj[elem]) + '</' + elem + '>';
1384                             }
1385                         }
1386                     }
1387                 } else {
1388                     xml = obj;
1389                 }
1390             }
1391 
1392             return xml;
1393         },
1394 
1395        /**
1396         * @private
1397         * Utility method called exclusively by js2xml() to find xml attributes.
1398         * @desc Traverses children one layer deep of a javascript object to "look ahead"
1399         * for properties flagged as such (with '@').
1400         * @param {Object} obj
1401         *   The obj to traverse.
1402         * @returns {String} Any attributes formatted for xml, if any.
1403         */
1404         js2xmlAtt: function (obj) {
1405             var elem;
1406 
1407             if (obj !== null) {
1408                 if (obj.constructor === Object) {
1409                     for (elem in obj) {
1410                         if (obj[elem] !== null && typeof(obj[elem]) !== "undefined" && obj[elem].constructor !== Array) {
1411                             if (elem[0] === '@'){
1412                                 return ' ' + elem.substring(1) + '="' + obj[elem] + '"';
1413                             }
1414                         }
1415                     }
1416                 }
1417             }
1418 
1419             return '';
1420         },
1421 
1422        /**
1423         * @private
1424         * Utility method called exclusively by js2xml() to determine if
1425         * a node has any children, with special logic for ignoring attributes.
1426         * @desc Attempts to traverse the elements in the object while ignoring attributes.
1427         * @param {Object} obj
1428         *   The obj to traverse.
1429         * @returns {Boolean} whether or not the JS object is "empty"
1430         */
1431         js2xmlObjIsEmpty: function (obj) {
1432             var elem;
1433 
1434             if (obj !== null) {
1435                 if (obj.constructor === Object) {
1436                     for (elem in obj) {
1437                         if (obj[elem] !== null) {
1438                             if (obj[elem].constructor === Array){
1439                                 return false;
1440                             }
1441 
1442                             if (elem[0] !== '@'){
1443                                 return false;
1444                             }
1445                         } else {
1446                             return false;
1447                         }
1448                     }
1449                 } else {
1450                     return false;
1451                 }
1452             }
1453 
1454             return true;
1455         },
1456 
1457         /**
1458          * Encodes the given string into base64.
1459          *<br>
1460          * <b>NOTE:</b> {input} is assumed to be UTF-8; only the first
1461          * 8 bits of each input element are significant.
1462          *
1463          * @param {String} input
1464          *     The string to convert to base64.
1465          * @returns {String}
1466          *     The converted string.
1467          */
1468         b64Encode: function (input) {
1469             var output = "", idx, data,
1470                 table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
1471 
1472             for (idx = 0; idx < input.length; idx += 3) {
1473                 data =  input.charCodeAt(idx) << 16 |
1474                             input.charCodeAt(idx + 1) << 8 |
1475                             input.charCodeAt(idx + 2);
1476 
1477                 //assume the first 12 bits are valid
1478                 output +=   table.charAt((data >>> 18) & 0x003f) +
1479                             table.charAt((data >>> 12) & 0x003f);
1480                 output +=   ((idx + 1) < input.length) ?
1481                             table.charAt((data >>> 6) & 0x003f) :
1482                             "=";
1483                 output +=   ((idx + 2) < input.length) ?
1484                             table.charAt(data & 0x003f) :
1485                             "=";
1486             }
1487 
1488             return output;
1489         },
1490 
1491         /**
1492          * Decodes the given base64 string.
1493          * <br>
1494          * <b>NOTE:</b> output is assumed to be UTF-8; only the first
1495          * 8 bits of each output element are significant.
1496          *
1497          * @param {String} input
1498          *     The base64 encoded string
1499          * @returns {String}
1500          *     Decoded string
1501          */
1502         b64Decode: function (input) {
1503             var output = "", idx, h, data,
1504                 table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
1505 
1506             for (idx = 0; idx < input.length; idx += 4) {
1507                 h = [
1508                     table.indexOf(input.charAt(idx)),
1509                     table.indexOf(input.charAt(idx + 1)),
1510                     table.indexOf(input.charAt(idx + 2)),
1511                     table.indexOf(input.charAt(idx + 3))
1512                 ];
1513 
1514                 data = (h[0] << 18) | (h[1] << 12) | (h[2] << 6) | h[3];
1515                 if (input.charAt(idx + 2) === '=') {
1516                     data = String.fromCharCode(
1517                         (data >>> 16) & 0x00ff
1518                     );
1519                 } else if (input.charAt(idx + 3) === '=') {
1520                     data = String.fromCharCode(
1521                         (data >>> 16) & 0x00ff,
1522                         (data >>> 8) & 0x00ff
1523                     );
1524                 } else {
1525                     data = String.fromCharCode(
1526                         (data >>> 16) & 0x00ff,
1527                         (data >>> 8) & 0x00ff,
1528                         data & 0x00ff
1529                     );
1530                 }
1531                 output += data;
1532             }
1533 
1534             return output;
1535         },
1536 
1537         /**
1538          * @private
1539          * Extracts the username and the password from the Base64 encoded string.
1540          * @params {String}
1541          *     A base64 encoded string containing credentials that (when decoded)
1542          *     are colon delimited.
1543          * @returns {Object}
1544          *     An object with the following structure:
1545          *     {id:string, password:string}
1546          */
1547         getCredentials: function (authorization) {
1548             var credObj = {},
1549                 credStr = this.b64Decode(authorization),
1550                 colonIndx = credStr.indexOf(":");
1551 
1552             //Check to ensure that string is colon delimited.
1553             if (colonIndx === -1) {
1554                 throw new Error("String is not colon delimited.");
1555             }
1556 
1557             //Extract ID and password.
1558             credObj.id = credStr.substring(0, colonIndx);
1559             credObj.password = credStr.substring(colonIndx + 1);
1560             return credObj;
1561         },
1562 
1563         /**
1564          * Takes a string and removes any spaces within the string.
1565          * @param {String} string
1566          *     The string to remove spaces from
1567          * @returns {String}
1568          *     The string without spaces
1569          */
1570         removeSpaces: function (string) {
1571             return string.split(' ').join('');
1572         },
1573 
1574         /**
1575          * Escapes spaces as encoded " " characters so they can
1576          * be safely rendered by jQuery.text(string) in all browsers.
1577          *
1578          * (Although IE behaves as expected, Firefox collapses spaces if this function is not used.)
1579          *
1580          * @param text
1581          *    The string whose spaces should be escaped
1582          *
1583          * @returns
1584          *    The string with spaces escaped
1585          */
1586         escapeSpaces: function (string) {
1587             return string.replace(/\s/g, '\u00a0');
1588         },
1589 
1590         /**
1591          * Adds a span styled to line break at word edges around the string passed in.
1592          * @param str String to be wrapped in word-breaking style.
1593          * @private
1594          */
1595         addWordWrapping : function (str) {
1596             return '<span style="word-wrap: break-word;">' + str + '</span>';
1597         },
1598 
1599         /**
1600          * Takes an Object and determines whether it is an Array or not.
1601          * @param {Object} obj
1602          *     The Object in question
1603          * @returns {Boolean}
1604          *     true if the object is an Array, else false.
1605          */
1606         isArray: function (obj) {
1607             return obj.constructor.toString().indexOf("Array") !== -1;
1608         },
1609 
1610         /**
1611          * @private
1612          * Takes a data object and returns an array extracted
1613          * @param {Object} data
1614          *     JSON payload
1615          *
1616          * @returns {array}
1617          *     extracted array
1618          */
1619         getArray: function (data) {
1620             if (this.isArray(data)) {
1621                 //Return if already an array.
1622                 return data;
1623             } else {
1624                 //Create an array, iterate through object, and push to array. This
1625                 //should only occur with one object, and therefore one obj in array.
1626                 var arr = [];
1627                 arr.push(data);
1628                 return arr;
1629             }
1630         },
1631 
1632         /**
1633          * @private
1634          * Extracts the ID for an entity given the Finesse REST URI. The ID is
1635          * assumed to be the last element in the URI (after the last "/").
1636          * @param {String} uri
1637          *     The Finesse REST URI to extract the ID from.
1638          * @returns {String}
1639          *     The ID extracted from the REST URI.
1640          */
1641         getId: function (uri) {
1642             if (!uri) {
1643                 return "";
1644             }
1645             var strLoc = uri.lastIndexOf("/");
1646             return uri.slice(strLoc + 1);
1647         },
1648 
1649         /**
1650          * Compares two objects for equality.
1651          * @param {Object} obj1 
1652          *      First of two objects to compare.
1653          * @param {Object} obj2
1654          *      Second of two objects to compare.
1655          */
1656         getEquals: function (objA, objB) {
1657             var key;
1658 
1659             for (key in objA) {
1660                 if (objA.hasOwnProperty(key)) {
1661                     if (!objA[key]) {
1662                         objA[key] = "";
1663                     }
1664 
1665                     if (typeof objB[key] === 'undefined') {
1666                         return false;
1667                     }
1668                     if (typeof objB[key] === 'object') {
1669                         if (!objB[key].equals(objA[key])) {
1670                             return false;
1671                         }
1672                     }
1673                     if (objB[key] !== objA[key]) {
1674                         return false;
1675                     }
1676                 }
1677             }
1678             return true;
1679         },
1680 
1681         /**
1682          * Regular expressions used in translating HTML and XML entities
1683          */
1684         ampRegEx : new RegExp('&', 'gi'),
1685         ampEntityRefRegEx : new RegExp('&', 'gi'),
1686         ltRegEx : new RegExp('<', 'gi'),
1687         ltEntityRefRegEx : new RegExp('<', 'gi'),
1688         gtRegEx : new RegExp('>', 'gi'),
1689         gtEntityRefRegEx : new RegExp('>', 'gi'),
1690         xmlSpecialCharRegEx: new RegExp('[&<>"\']', 'g'),
1691         entityRefRegEx: new RegExp('&[^;]+(?:;|$)', 'g'),
1692 
1693         /**
1694          * Translates between special characters and HTML entities
1695          *
1696          * @param text
1697          *     The text to translate
1698          *
1699          * @param makeEntityRefs
1700          *    If true, encode special characters as HTML entities; if
1701          *    false, decode HTML entities back to special characters
1702          *
1703          * @private
1704          */
1705         translateHTMLEntities: function (text, makeEntityRefs) {
1706             if (typeof(text) !== "undefined" && text !== null && text !== "") {
1707                 if (makeEntityRefs) {
1708                     text = text.replace(this.ampRegEx, '&');
1709                     text = text.replace(this.ltRegEx, '<');
1710                     text = text.replace(this.gtRegEx, '>');
1711                 } else {
1712                     text = text.replace(this.gtEntityRefRegEx, '>');
1713                     text = text.replace(this.ltEntityRefRegEx, '<');
1714                     text = text.replace(this.ampEntityRefRegEx, '&');
1715                 }
1716             }
1717 
1718             return text;
1719         },
1720 
1721         /**
1722          * Translates between special characters and XML entities
1723          *
1724          * @param text
1725          *     The text to translate
1726          *
1727          * @param makeEntityRefs
1728          *    If true, encode special characters as XML entities; if
1729          *    false, decode XML entities back to special characters
1730          *
1731          * @private
1732          */
1733         translateXMLEntities: function (text, makeEntityRefs) {
1734             /** @private */
1735             var escape = function (character) {
1736                 switch (character) {
1737                     case "&":
1738                         return "&";
1739                     case "<":
1740                         return "<";
1741                     case ">":
1742                         return ">";
1743                     case "'":
1744                         return "'";
1745                     case "\"":
1746                         return """;
1747                     default:
1748                         return character;
1749                 }
1750             },
1751             /** @private */
1752             unescape = function (entity) {
1753                 switch (entity) {
1754                     case "&":
1755                         return "&";
1756                     case "<":
1757                         return "<";
1758                     case ">":
1759                         return ">";
1760                     case "'":
1761                         return "'";
1762                     case """:
1763                         return "\"";
1764                     default:
1765                         if (entity.charAt(1) === "#" && entity.charAt(entity.length - 1) === ";") {
1766                             if (entity.charAt(2) === "x") {
1767                                 return String.fromCharCode(parseInt(entity.slice(3, -1), 16));
1768                             } else {
1769                                 return String.fromCharCode(parseInt(entity.slice(2, -1), 10));
1770                             }
1771                         } else {
1772                             throw new Error("Invalid XML entity: " + entity);
1773                         }
1774                 }
1775             };
1776 
1777             if (typeof(text) !== "undefined" && text !== null && text !== "") {
1778                 if (makeEntityRefs) {
1779                     text = text.replace(this.xmlSpecialCharRegEx, escape);
1780                 } else {
1781                     text = text.replace(this.entityRefRegEx, unescape);
1782                 }
1783             }
1784 
1785             return text;
1786         },
1787 
1788         /**
1789          * @private
1790          * Utility method to pad the number with a leading 0 for single digits
1791          * @param (Number) num
1792          *     the number to pad
1793          */
1794         pad : function (num) {
1795             if (num < 10) {
1796                 return "0" + num;
1797             }
1798 
1799             return String(num);
1800         },
1801 
1802         /**
1803          * Utility method to render a timestamp value (in seconds) into HH:MM:SS format.
1804          * @param {Number} time
1805          *     The timestamp in ms to render
1806          * @returns {String}
1807          * Time string in HH:MM:SS format.
1808          */
1809         getDisplayTime : function (time) {
1810             var hour, min, sec, timeStr = "00:00:00";
1811 
1812             if (time && time !== "-1") {
1813                 // calculate hours, minutes, and seconds
1814                 hour = this.pad(Math.floor(time / 3600));
1815                 min = this.pad(Math.floor((time % 3600) / 60));
1816                 sec = this.pad(Math.floor((time % 3600) % 60));
1817                 // construct HH:MM:SS time string
1818                 timeStr = hour + ":" + min + ":" + sec;
1819             }
1820 
1821             return timeStr;
1822         },
1823 
1824         /**
1825          * Checks if the string is null. If it is, return empty string; else return
1826          * the string itself.
1827          * 
1828          * @param  {String} str 
1829          * The string to check
1830          * @return {String}     
1831          * Empty string or string itself
1832          */
1833         convertNullToEmptyString : function (str) {
1834             return str || "";
1835         },
1836 
1837         /**
1838          * Utility method to render a timestamp string (of format
1839          * YYYY-MM-DDTHH:MM:SSZ) into a duration of HH:MM:SS format.
1840          * 
1841          * @param {String} timestamp
1842          *           The timestamp to render
1843          * @param {Date} [now]
1844          *            Optional argument to provide the time from which to
1845          *            calculate the duration instead of using the current time
1846          * @returns {String}
1847          * Duration string in HH:MM:SS format.
1848          */
1849         convertTsToDuration : function (timestamp, now) {
1850             return this.convertTsToDurationWithFormat(timestamp, false, now); 
1851         },
1852         
1853         /**
1854          * Utility method to render a timestamp string (of format
1855          * YYYY-MM-DDTHH:MM:SSZ) into a duration of HH:MM:SS format,
1856          * with optional -1 for null or negative times.
1857          * 
1858          * @param {String} timestamp
1859          *             The timestamp to render
1860          * @param {Boolean} forFormat
1861          *            If True, if duration is null or negative, return -1 so that the duration can be formated
1862          *            as needed in the Gadget. 
1863          * @param {Date} [now]
1864          *             Optional argument to provide the time from which to
1865          *            calculate the duration instead of using the current time
1866          * @returns {String}
1867          * Duration string in HH:MM:SS format.
1868          */
1869         convertTsToDurationWithFormat : function (timestamp, forFormat, now) {
1870             var startTimeInMs, nowInMs, durationInSec = "-1";
1871             
1872             // Calculate duration
1873             if (timestamp && typeof timestamp === "string") {
1874                 // first check it '--' for a msg in grid
1875                 if (timestamp === '--' || timestamp ==="" || timestamp === "-1") {
1876                     return "-1";
1877                 }
1878                 // else try convert string into a time
1879                 startTimeInMs = Date.parse(timestamp);
1880                 if (!isNaN(startTimeInMs)) {
1881                     if (!now || !(now instanceof Date)) {
1882                         nowInMs = this.currentServerTimeMillis();
1883                     } else {
1884                         nowInMs = now.getTime();
1885                     }
1886                     durationInSec = Math.floor((nowInMs - startTimeInMs) / 1000);
1887                     // Since currentServerTime is not exact (lag between sending and receiving
1888                     // messages will differ slightly), treat a slightly negative (less than 1 sec) 
1889                     // value as 0, to avoid "--" showing up when a state first changes.
1890                     if (durationInSec === -1) {
1891                         durationInSec = 0;
1892                     }
1893                     
1894                     if (durationInSec < 0) {
1895                         if (forFormat) {
1896                             return "-1";
1897                         } else {
1898                             return this.getDisplayTime("-1");
1899                         }
1900                     }
1901                 }
1902             }else {
1903                 if(forFormat){
1904                     return "-1";
1905                 }
1906             }
1907             return this.getDisplayTime(durationInSec);
1908          },
1909         /**
1910          * @private
1911          * Adds a new cookie to the page with a default domain.
1912          * @param {String} key
1913          *      the key to assign a value to
1914          * @param {String} value
1915          *      the value to assign to the key
1916          * @param {Number} days
1917          *      number of days (from current) until the cookie should expire
1918          */
1919         addCookie : function (key, value, days) {
1920             var date, expires = "",
1921                 cookie = key + "=" + escape(value);
1922             if (typeof days === "number") {
1923                 date = new Date();
1924                 date.setTime(date.getTime() + (days * 24 * 3600 * 1000));
1925                 cookie += "; expires=" + date.toGMTString();
1926             }
1927             document.cookie = cookie + "; path=/";
1928         },
1929 
1930         /**
1931          * @private
1932          * Get the value of a cookie given a key.
1933          * @param {String} key
1934          *      a key to lookup
1935          * @returns {String}
1936          *      the value mapped to a key, null if key doesn't exist
1937          */
1938         getCookie : function (key) {
1939             var i, pairs, pair;
1940             if (document.cookie) {
1941                 pairs = document.cookie.split(";");
1942                 for (i = 0; i < pairs.length; i += 1) {
1943                     pair = this.trim(pairs[i]).split("=");
1944                     if (pair[0] === key) {
1945                         return unescape(pair[1]);
1946                     }
1947                 }
1948             }
1949             return null;
1950         },
1951 
1952         /**
1953          * @private
1954          * Deletes the cookie mapped to specified key.
1955          * @param {String} key
1956          *      the key to delete
1957          */
1958         deleteCookie : function (key) {
1959             this.addCookie(key, "", -1);
1960         },
1961 
1962         /**
1963          * @private
1964          * Case insensitive sort for use with arrays or Dojox stores
1965          * @param {String} a
1966          *      first value
1967          * @param {String} b
1968          *      second value
1969          */
1970         caseInsensitiveSort: function (a, b) {
1971             var ret = 0, emptyString = "";
1972             a = a + emptyString;
1973             b = b + emptyString;
1974             a = a.toLowerCase();
1975             b = b.toLowerCase();
1976             if (a > b) {
1977                 ret = 1;
1978             }
1979             if (a < b) { 
1980                 ret = -1;
1981             }
1982             return ret;
1983         },
1984 
1985         /**
1986          * @private
1987         * Calls the specified function to render the dojo wijit for a gadget  when the gadget first becomes visible.
1988         *
1989         * The displayWjitFunc function will be called once and only once when the div for our wijit 
1990         * becomes visible for the first time.  This is necessary because some dojo wijits such as the grid
1991         * throw exceptions and do not render properly if they are created in a display:none div.
1992         * If our gadget is visisble the function will be called immediately.
1993         * If our gadget is not yet visisble, then it sets a timer and waits for it to become visible.
1994         * NOTE:  The timer may seem inefficent, originally I tried connecting to the tab onclick handler, but
1995         * there is a problem with dojo.connnect to an iframe's parent node in Internet Explorer. 
1996         * In Firefox the click handler works OK, but it happens before the node is actually visisble, so you
1997         * end up waiting for the node to become visisble anyway.
1998         * @displayWjitFunc:  A function to be called once our gadget has become visisble for th first time.
1999         */  
2000         onGadgetFirstVisible: function (displayWjitFunc) {
2001             var i, q, frameId, gadgetNbr, gadgetTitleId, panelId, panelNode, link, iterval, once = false, active = false, tabId = "#finesse-tab-selector";
2002             try {
2003                 frameId = dojo.attr(window.frameElement, "id"); // Figure out what gadget number we are by looking at our frameset
2004                 gadgetNbr = frameId.match(/\d+$/)[0];  // Strip the number off the end of the frame Id, that's our gadget number
2005                 gadgetTitleId = "#finesse_gadget_" + gadgetNbr + "_title";  // Create a a gadget title id from the number
2006                 
2007                 // Loop through all of the tab panels to find one that has our gadget id
2008                 dojo.query('.tab-panel', window.parent.document).some(function (node, index, arr) {
2009                     q = dojo.query(gadgetTitleId, node);  // Look in this panel for our gadget id
2010                     if (q.length > 0) {  // You found it
2011                         panelNode = node;
2012                         panelId = dojo.attr(panelNode, "id");  // Get panel id  e.g. panel_Workgroups
2013                         active = dojo.hasClass(panelNode, "active");
2014                         tabId = "#tab_" + panelId.slice(6);  // Turn it into a tab id e.g.tab_Workgroups
2015                         return;
2016                     }
2017                 });
2018                 // If panel is already active - execute the function - we're done
2019                 if (active) {
2020                     //?console.log(frameId + " is visible display it");
2021                     setTimeout(displayWjitFunc);
2022                 } 
2023                 // If its not visible - wait for the active class to show up.
2024                 else {
2025                     //?console.log(frameId  + " (" + tabId + ") is NOT active wait for it");
2026                     iterval = setInterval(dojo.hitch(this, function () {
2027                         if (dojo.hasClass(panelNode, "active")) {
2028                             //?console.log(frameId  + " (" + tabId + ") is visible display it");
2029                             clearInterval(iterval);
2030                             setTimeout(displayWjitFunc);
2031                         } 
2032                     }), 250);
2033                 }
2034             } catch (err) {
2035                 //?console.log("Could not figure out what tab " + frameId + " is in: " + err);
2036             }
2037         },
2038 
2039         /**
2040          * @private
2041          * Downloads the specified url using a hidden iframe. In order to cause the browser to download rather than render
2042          * in the hidden iframe, the server code must append the header "Content-Disposition" with a value of 
2043          * "attachment; filename=\"<WhateverFileNameYouWant>\"".
2044          */
2045         downloadFile : function (url) {
2046             var iframe = document.getElementById("download_iframe");
2047 
2048             if (!iframe)
2049             {
2050                 iframe = document.createElement("iframe");
2051                 $(document.body).append(iframe);
2052                 $(iframe).css("display", "none");
2053             }
2054 
2055             iframe.src = url;
2056         },
2057 
2058         /**
2059          * @private
2060          * bitMask has functions for testing whether bit flags specified by integers are set in the supplied value
2061          */
2062         bitMask: {
2063             /** @private */
2064             isSet: function (value, mask) {
2065                 return (value & mask) === mask;
2066             },
2067             /**
2068              * Returns true if all flags in the intArray are set on the specified value
2069              * @private 
2070              */
2071             all: function (value, intArray) {
2072                 var i = intArray.length;
2073                 if (typeof(i) === "undefined")
2074                 {
2075                     intArray = [intArray];
2076                     i = 1;
2077                 }
2078                 while ((i = i - 1) !== -1)
2079                 {
2080                     if (!this.isSet(value, intArray[i]))
2081                     {
2082                         return false;
2083                     }
2084                 }
2085                 return true;
2086             },
2087             /**
2088              * @private
2089              * Returns true if any flags in the intArray are set on the specified value
2090              */
2091             any: function (value, intArray) {
2092                 var i = intArray.length;
2093                 if (typeof(i) === "undefined")
2094                 {
2095                     intArray = [intArray];
2096                     i = 1;
2097                 }
2098                 while ((i = i - 1) !== -1)
2099                 {
2100                     if (this.isSet(value, intArray[i]))
2101                     {
2102                         return true;
2103                     }
2104                 }
2105                 return false;
2106             }
2107         },
2108 
2109         /** @private */
2110         renderDojoGridOffScreen: function (grid) {
2111             var offscreenDiv = $("<div style='position: absolute; left: -5001px; width: 5000px;'></div>")[0];
2112             $(document.body).append(offscreenDiv);
2113             grid.placeAt(offscreenDiv);
2114             grid.startup();
2115             document.body.removeChild(offscreenDiv);
2116             return grid;
2117         },
2118 
2119         /** @private */
2120         initializeSearchInput: function(searchInput, changeCallback, callbackDelay, callbackScope, placeholderText) {
2121             var timerId = null,
2122                 theControl = typeof(searchInput) === "string" ? $("#" + searchInput) : $(searchInput),
2123                 theInputControl = theControl.find("input"),
2124                 theClearButton = theControl.find("a"),
2125                 inputControlWidthWithClear = 204,
2126                 inputControlWidthNoClear = 230,
2127                 sPreviousInput = theInputControl.val(),
2128                 /** @private **/
2129                 toggleClearButton = function(){
2130                     if (theInputControl.val() === "") {
2131                         theClearButton.hide();
2132                         theControl.removeClass("input-append");
2133                         theInputControl.width(inputControlWidthNoClear);
2134                     } else {
2135                         theInputControl.width(inputControlWidthWithClear);
2136                         theClearButton.show();
2137                         theControl.addClass("input-append");
2138                     }
2139                 };
2140 
2141             // set placeholder text
2142             theInputControl.attr('placeholder', placeholderText);
2143 
2144             theInputControl.unbind('keyup').bind('keyup', function() {
2145                 if (sPreviousInput !== theInputControl.val()) {
2146                     window.clearTimeout(timerId);
2147                     sPreviousInput = theInputControl.val();
2148                     timerId = window.setTimeout(function() {
2149                         changeCallback.call((callbackScope || window), theInputControl.val());
2150                         theInputControl[0].focus();
2151                     }, callbackDelay);
2152                 }
2153 
2154                 toggleClearButton();
2155             });
2156 
2157             theClearButton.bind('click', function() {
2158                 theInputControl.val('');
2159                 changeCallback.call((callbackScope || window), '');
2160 
2161                 toggleClearButton();
2162                 theInputControl[0].focus(); // jquery and dojo on the same page break jquery's focus() method
2163             });
2164 
2165             theInputControl.val("");
2166             toggleClearButton();
2167         },
2168 
2169         DataTables: {
2170             /** @private */
2171             createDataTable: function (options, dataTableOptions) {
2172                 var grid,
2173                     table = $('<table cellpadding="0" cellspacing="0" border="0" class="finesse"><thead><tr></tr></thead></table>'),
2174                     headerRow = table.find("tr"),
2175                     defaultOptions = {
2176                         "aaData": [],
2177                         "bPaginate": false,
2178                         "bLengthChange": false,
2179                         "bFilter": false,
2180                         "bInfo": false,
2181                         "sScrollY": "176",
2182                         "oLanguage": {
2183                             "sEmptyTable": "",
2184                             "sZeroRecords": ""
2185                         }
2186                     },
2187                     gridOptions = $.extend({}, defaultOptions, dataTableOptions),
2188                     columnDefs = [],
2189                     columnFormatter;
2190 
2191                 // Create a header cell for each column, and set up the datatable definition for the column
2192                 $(options.columns).each(function (index, column) {
2193                     headerRow.append($("<th></th>"));
2194                     columnDefs[index] = {
2195                         "mData": column.propertyName,
2196                         "sTitle": column.columnHeader,
2197                         "sWidth": column.width,
2198                         "aTargets": [index],
2199                         "bSortable": column.sortable,
2200                         "bVisible": column.visible,
2201                         "mRender": column.render
2202                     };
2203                     if (typeof(column.renderFunction) === "function")
2204                     {
2205                         /** @ignore **/
2206                         columnDefs[index].mRender = /** @ignore **/ function (value, type, dataObject) { 
2207                             var returnValue;
2208 
2209                             //Apply column render logic to value before applying extra render function
2210                             if (typeof(column.render) === "function")
2211                             {
2212                                 value = column.render.call(value, value, value);
2213                             }
2214 
2215                             if (typeof(type) === "string")
2216                             {
2217                                 switch (type)
2218                                 {
2219                                 case "undefined":
2220                                 case "sort":
2221                                     returnValue = value;
2222                                     break;
2223                                 case "set":
2224                                     throw new Error("Unsupported set data in Finesse Grid");
2225                                 case "filter":
2226                                 case "display":
2227                                 case "type":
2228                                     returnValue = column.renderFunction.call(dataObject, value, dataObject);
2229                                     break;
2230                                 default:
2231                                     break;
2232                                 }
2233                             }
2234                             else
2235                             {
2236                                 throw new Error("type param not specified in Finesse DataTable mData");
2237                             }
2238 
2239                             return  returnValue;
2240                         };
2241                     }
2242                 });
2243                 gridOptions.aoColumnDefs = columnDefs;
2244 
2245                 // Set the height
2246                 if (typeof(options.bodyHeightPixels) !== "undefined" && options.bodyHeightPixels !== null)
2247                 {
2248                     gridOptions.sScrollY = options.bodyHeightPixels + "px";
2249                 }
2250 
2251                 // Place it into the DOM
2252                 if (typeof(options.container) !== "undefined" && options.container !== null)
2253                 {
2254                     $(options.container).append(table);
2255                 }
2256 
2257                 // Create the DataTable
2258                 table.dataTable(gridOptions);
2259 
2260                 return table;
2261             }
2262         },
2263         
2264         /**
2265          * @private
2266          * Sets a dojo button to the specified disable state, removing it from
2267          * the tab order if disabling, and restoring it to the tab order if enabling.
2268          * @param {Object} dojoButton Reference to the dijit.form.Button object. This is not the DOM element.
2269          * @param {bool} disabled
2270          */
2271         setDojoButtonDisabledAttribute: function (dojoButton, disabled) {
2272             var labelNode,
2273                 tabIndex;
2274 
2275             dojoButton.set("disabled", disabled);
2276 
2277             // Remove the tabindex attribute on disabled buttons, store it, 
2278             // and replace it when it becomes enabled again
2279             labelNode = $("#" + dojoButton.id + "_label");
2280             if (disabled)
2281             {
2282                 labelNode.data("finesse:dojoButton:tabIndex", labelNode.attr("tabindex"));
2283                 labelNode.removeAttr("tabindex");
2284             }
2285             else
2286             {
2287                 tabIndex = labelNode.data("finesse:dojoButton:tabIndex");
2288                 if (typeof(tabIndex) === "string")
2289                 {
2290                     labelNode.attr("tabindex", Number(tabIndex));
2291                 }
2292             }
2293         },
2294 
2295         /**
2296          * @private
2297          * Measures the given text using the supplied fontFamily and fontSize
2298          * @param  {string} text       text to measure
2299          * @param  {string} fontFamily
2300          * @param  {string} fontSize
2301          * @return {number} pixel width
2302          */
2303         measureText: function (text, fontFamily, fontSize) {
2304             var width,
2305                 element = $("<div></div>").text(text).css({
2306                     "fontSize": fontSize,
2307                     "fontFamily": fontFamily
2308                 }).addClass("offscreen").appendTo(document.body);
2309 
2310             width = element.width();
2311             element.remove();
2312 
2313             return width;
2314         },
2315 
2316         /**
2317          * Adjusts the gadget height. Shindig's gadgets.window.adjustHeight fails when
2318          * needing to resize down in IE. This gets around that by calculating the height
2319          * manually and passing it in.
2320          * @return {undefined}
2321          */
2322         "adjustGadgetHeight": function () {
2323             var bScrollHeight = $("body").height() + 20;
2324             gadgets.window.adjustHeight(bScrollHeight);
2325         },
2326 
2327         /**
2328         * Private helper method for converting a javascript object to xml, where the values of the elements are
2329         * appropriately escaped for XML.
2330         * This is a simple implementation that does not implement cdata or attributes. It is also 'unformatted' in that
2331         * there is no whitespace between elements.
2332         * @param object The javascript object to convert to XML.
2333         * @returns The XML string.
2334         * @private
2335         */
2336         _json2xmlWithEscape: function(object) {
2337             var that = this,
2338                 xml = "",
2339                 m,
2340                 /** @private **/
2341                 toXmlHelper = function(value, name) {
2342                 var xml = "",
2343                     i,
2344                     m;
2345                 if (value instanceof Array) {
2346                     for (i = 0; i < value.length; ++i) {
2347                         xml += toXmlHelper(value[i], name);
2348                     }
2349                 }
2350                 else if (typeof value === "object") {
2351                     xml += "<" + name + ">";
2352                     for (m in value) {
2353                         if (value.hasOwnProperty(m)) {
2354                            xml += toXmlHelper(value[m], m);
2355                         }
2356                     }
2357                     xml += "</" + name + ">";
2358                 }
2359                 else {
2360                     // is a leaf node
2361                     xml += "<" + name + ">" + that.translateHTMLEntities(value.toString(), true) +
2362                         "</" + name + ">";
2363                 }
2364                 return xml;
2365             };
2366             for (m in object) {
2367                 if (object.hasOwnProperty(m)) {
2368                     xml += toXmlHelper(object[m], m);
2369                 }
2370             }
2371             return xml;
2372         },
2373 
2374         /**
2375          * Utility to detect the browser version of IE, whether it is IE9 or IE8 or in compatibility mode.
2376          * If IE is earlier than IE8, version returns undefined.
2377          * 
2378          * @return {Object} browser object has the following form:
2379          * {
2380          *     isIE: {Boolean},
2381          *     version: {String}, // 8 for IE8, 9 or IE9
2382          *     isCompatibilityMode: {Boolean}
2383          * }
2384          */
2385         detectIEBrowserVersion: function () {
2386             var browser = {
2387                 isIE: false,
2388                 isCompatibilityMode: false
2389             },
2390 
2391             useragent = navigator.userAgent,
2392 
2393             appName = navigator.appName;
2394 
2395             // Check to see if app is IE
2396             if (appName.indexOf("Microsoft Internet Explorer") !== -1) {
2397                 browser.isIE = true;
2398                 // Check for Trident version
2399                 if (useragent.indexOf("Trident/5.0") !== -1) { // IE9
2400                     browser.version = "9";
2401                     if (useragent.indexOf("MSIE 9.0") === -1) {
2402                         browser.isCompatibilityMode = true;
2403                     }
2404                 } else if (useragent.indexOf("Trident/4.0") !== -1) { // IE8
2405                     browser.version = "8";
2406                     if (useragent.indexOf("MSIE 8.0") === -1) {
2407                         browser.isCompatibilityMode = true;
2408                     }
2409                 } // Else unsupported IE browser version, return undefined for version
2410             }
2411 
2412             return browser;            
2413         }
2414     };    
2415     
2416     return Utilities;
2417 }));
2418 
2419 /** The following comment is to prevent jslint errors about 
2420  * using variables before they are defined.
2421  */
2422 /*global finesse*/
2423 
2424 /**
2425  * Initiated by the Master to create a shared BOSH connection.
2426  *
2427  * @requires Utilities
2428  */
2429 
2430 /**
2431  * @class
2432  * Establishes a shared event connection by creating a communication tunnel
2433  * with the notification server and consume events which could be published.
2434  * Public functions are exposed to register to the connection status information
2435  * and events.
2436  * @constructor
2437  * @param {String} host
2438  *     The host name/ip of the Finesse server.
2439  * @throws {Error} If required constructor parameter is missing.
2440  */
2441 /** @private */
2442 (function (factory) {
2443     
2444 
2445     // Define as an AMD module if possible
2446     if ( typeof define === 'function' && define.amd )
2447     {
2448         define('clientservices/MasterTunnel',["utilities/Utilities"], factory );
2449     }
2450     
2451     /* Define using browser globals otherwise
2452      * Prevent multiple instantiations if the script is loaded twice
2453      */
2454     else
2455     {
2456         factory(finesse.utilities.Utilities);
2457     }
2458     
2459 }(function (Utilities) {
2460      var MasterTunnel = function (host, scheme) { 
2461         if (typeof host !== "string" || host.length === 0) {
2462             throw new Error("Required host parameter missing.");
2463         }
2464 
2465         var
2466 
2467         /**
2468          * Flag to indicate whether the tunnel frame is loaded.
2469          * @private
2470          */
2471         _isTunnelLoaded = false,
2472 
2473         /**
2474          * Short reference to the Finesse utility.
2475          * @private
2476          */
2477         _util = Utilities,
2478 
2479         /**
2480          * The URL with host and port to the Finesse server.
2481          * @private
2482          */
2483         _tunnelOrigin,
2484 
2485         /**
2486          * Location of the tunnel HTML URL.
2487          * @private
2488          */
2489         _tunnelURL,
2490         
2491         /**
2492          * The port on which to connect to the Finesse server to load the eventing resources.
2493          * @private
2494          */
2495         _tunnelOriginPort,
2496         
2497         /**
2498          * Flag to indicate whether we have processed the tunnel config yet.
2499          * @private
2500          */
2501         _isTunnelConfigInit = false,
2502 
2503         /**
2504          * The tunnel frame window object.
2505          * @private
2506          */
2507         _tunnelFrame,
2508 
2509         /**
2510          * The handler registered with the object to be invoked when an event is
2511          * delivered by the notification server.
2512          * @private
2513          */
2514         _eventHandler,
2515         
2516         /**
2517          * The handler registered with the object to be invoked when presence is
2518          * delivered by the notification server.
2519          * @private
2520          */
2521         _presenceHandler,
2522 
2523         /**
2524          * The handler registered with the object to be invoked when the BOSH
2525          * connection has changed states. The object will contain the "status"
2526          * property and a "resourceID" property only if "status" is "connected".
2527          * @private
2528          */
2529         _connInfoHandler,
2530 
2531         /**
2532          * The last connection status published by the JabberWerx library.
2533          * @private
2534          */
2535         _statusCache,
2536 
2537         /**
2538          * The last event sent by notification server.
2539          * @private
2540          */
2541         _eventCache,
2542 
2543         /**
2544          * The ID of the user logged into notification server.
2545          * @private
2546          */
2547         _id,
2548 
2549         /**
2550          * The domain of the XMPP server, representing the portion of the JID
2551          * following '@': userid@domain.com
2552          * @private
2553          */
2554         _xmppDomain,
2555 
2556         /**
2557          * The password of the user logged into notification server.
2558          * @private
2559          */
2560         _password,
2561 
2562         /**
2563          * The jid of the pubsub service on the XMPP server
2564          * @private
2565          */
2566         _pubsubDomain,
2567 
2568         /**
2569          * The resource to use for the BOSH connection.
2570          * @private
2571          */
2572         _resource,
2573 
2574         /**
2575          * The resource ID identifying the client device (that we receive from the server).
2576          * @private
2577          */
2578         _resourceID,
2579 
2580         /**
2581          * The different types of messages that could be sent to the parent frame.
2582          * The types here should be understood by the parent frame and used to
2583          * identify how the message is formatted.
2584          * @private
2585          */
2586         _TYPES = {
2587             EVENT: 0,
2588             ID: 1,
2589             PASSWORD: 2,
2590             RESOURCEID: 3,
2591             STATUS: 4,
2592             XMPPDOMAIN: 5,
2593             PUBSUBDOMAIN: 6,
2594             SUBSCRIBE: 7,
2595             UNSUBSCRIBE: 8,
2596             PRESENCE: 9,
2597             CONNECT_REQ: 10
2598         },
2599 
2600         _handlers = {
2601             subscribe: {},
2602             unsubscribe: {}
2603         },
2604         
2605 
2606         /**
2607          * Create a connection info object.
2608          * @returns {Object}
2609          *     A connection info object containing a "status" and "resourceID".
2610          * @private
2611          */
2612         _createConnInfoObj = function () {
2613             return {
2614                 status: _statusCache,
2615                 resourceID: _resourceID
2616             };
2617         },
2618 
2619         /**
2620          * Utility function which sends a message to the dynamic tunnel frame
2621          * event frame formatted as follows: "type|message".
2622          * @param {Number} type
2623          *     The category type of the message.
2624          * @param {String} message
2625          *     The message to be sent to the tunnel frame.
2626          * @private
2627          */
2628         _sendMessage = function (type, message) {
2629             message = type + "|" + message;
2630             _util.sendMessage(message, _tunnelFrame, _tunnelOrigin);
2631         },
2632 
2633         /**
2634          * Utility to process the response of a subscribe request from
2635          * the tunnel frame, then invoking the stored callback handler
2636          * with the respective data (error, when applicable)
2637          * @param {String} data
2638          *     The response in the format of "node[|error]"
2639          * @private
2640          */
2641         _processSubscribeResponse = function (data) {
2642             var dataArray = data.split("|"),
2643             node = dataArray[0],
2644             err;
2645             
2646             //Error is optionally the second item in the array
2647             if (dataArray.length) {
2648                 err = dataArray[1];
2649             }
2650             
2651             // These response handlers are short lived and should be removed and cleaned up immediately after invocation.
2652             if (_handlers.subscribe[node]) {
2653                 _handlers.subscribe[node](err);
2654                 delete _handlers.subscribe[node];
2655             }
2656         },
2657 
2658         /**
2659          * Utility to process the response of an unsubscribe request from
2660          * the tunnel frame, then invoking the stored callback handler
2661          * with the respective data (error, when applicable)
2662          * @param {String} data
2663          *     The response in the format of "node[|error]"
2664          * @private
2665          */
2666         _processUnsubscribeResponse = function (data) {
2667             var dataArray = data.split("|"),
2668             node = dataArray[0],
2669             err;
2670             
2671             //Error is optionally the second item in the array
2672             if (dataArray.length) {
2673                 err = dataArray[1];
2674             }
2675             
2676             // These response handlers are short lived and should be removed and cleaned up immediately after invocation.
2677             if (_handlers.unsubscribe[node]) {
2678                 _handlers.unsubscribe[node](err);
2679                 delete _handlers.unsubscribe[node];
2680             }
2681         },
2682 
2683         /**
2684          * Handler for messages delivered by window.postMessage. Listens for events
2685          * published by the notification server, connection status published by
2686          * the JabberWerx library, and the resource ID created when the BOSH
2687          * connection has been established.
2688          * @param {Object} e
2689          *     The message object as provided by the window.postMessage feature.
2690          * @private
2691          */
2692         _messageHandler = function (e) {
2693             var
2694 
2695             //Extract the message type and message data. The expected format is
2696             //"type|data" where type is a number represented by the TYPES object.
2697             delimPos = e.data.indexOf("|"),
2698             type = Number(e.data.substr(0, delimPos)),
2699             data =  e.data.substr(delimPos + 1);
2700             
2701             //Accepts messages and invoke the correct registered handlers.
2702             switch (type) {
2703             case _TYPES.EVENT:
2704                 _eventCache = data;
2705                 if (typeof _eventHandler === "function") {
2706                     _eventHandler(data);
2707                 }
2708                 break;
2709             case _TYPES.STATUS:
2710                 _statusCache = data;
2711 
2712                 //A "loaded" status means that the frame is ready to accept
2713                 //credentials for establishing a BOSH connection.
2714                 if (data === "loaded") {
2715                     _isTunnelLoaded = true;
2716                     if(_resource) {
2717                         _sendMessage(_TYPES.RESOURCEID, _resource);
2718                     }
2719                     _sendMessage(_TYPES.ID, _id);
2720                     _sendMessage(_TYPES.XMPPDOMAIN, _xmppDomain);
2721                     _sendMessage(_TYPES.PASSWORD, _password);
2722                     _sendMessage(_TYPES.PUBSUBDOMAIN, _pubsubDomain);
2723                 } else if (typeof _connInfoHandler === "function") {
2724                     _connInfoHandler(_createConnInfoObj());
2725                 }
2726                 break;
2727             case _TYPES.RESOURCEID:
2728                 _resourceID = data;
2729                 break;
2730             case _TYPES.SUBSCRIBE:
2731                 _processSubscribeResponse(data);
2732                 break;
2733             case _TYPES.UNSUBSCRIBE:
2734                 _processUnsubscribeResponse(data);
2735                 break;
2736             case _TYPES.PRESENCE:
2737                 if (typeof _presenceHandler === "function") {
2738                     _presenceHandler(data);
2739                 }
2740                 break;
2741             default:
2742                 break;
2743             }
2744         },
2745 
2746         /**
2747          * Initialize the tunnel config so that the url can be http or https with the appropriate port
2748          * @private
2749          */
2750         _initTunnelConfig = function () {
2751             if (_isTunnelConfigInit === true) {
2752                 return;
2753             }
2754             
2755             //Initialize tunnel origin
2756             //Determine tunnel origin based on host and scheme
2757             _tunnelOriginPort = (scheme && scheme.indexOf("https") !== -1) ? "7443" : "7071";
2758             if (scheme) {
2759                 _tunnelOrigin = scheme + "://" + host + ":" + _tunnelOriginPort;
2760             } else {
2761                 _tunnelOrigin = "http://" + host + ":" + _tunnelOriginPort;
2762             }
2763             _tunnelURL = _tunnelOrigin + "/tunnel/";
2764             
2765             _isTunnelConfigInit = true;
2766         },
2767 
2768         /**
2769          * Create the tunnel iframe which establishes the shared BOSH connection.
2770          * Messages are sent across frames using window.postMessage.
2771          * @private
2772          */
2773         _createTunnel = function () {
2774             var tunnelID = ((self === parent) ? "tunnel-frame" : "autopilot-tunnel-frame"),
2775             iframe = document.createElement("iframe");         
2776             iframe.style.display = "none";
2777             iframe.setAttribute("id", tunnelID);
2778             iframe.setAttribute("name", tunnelID);
2779             iframe.setAttribute("src", _tunnelURL);
2780             document.body.appendChild(iframe);
2781             _tunnelFrame = window.frames[tunnelID];
2782         };
2783 
2784         /**
2785          * Sends a message via postmessage to the EventTunnel to attempt to connect to the XMPP server
2786          * @private
2787          */
2788         this.makeConnectReq = function () {
2789             _sendMessage(_TYPES.PASSWORD, _password);
2790         };
2791         
2792         /**
2793          * @private
2794          * Returns the host of the Finesse server.
2795          * @returns {String}
2796          *     The host specified during the creation of the object.
2797          */
2798         this.getHost = function () {
2799             return host;
2800         };
2801 
2802         /**
2803          * @private
2804          * The resource ID of the user who is logged into the notification server.
2805          * @returns {String}
2806          *     The resource ID generated by the notification server.
2807          */
2808         this.getResourceID = function () {
2809             return _resourceID;
2810         };
2811 
2812         /**
2813          * @private
2814          * Indicates whether the tunnel frame is loaded.
2815          * @returns {Boolean}
2816          *     True if the tunnel frame is loaded, false otherwise.
2817          */
2818         this.isTunnelLoaded = function () {
2819             return _isTunnelLoaded;
2820         };
2821 
2822         /**
2823          * @private
2824          * The location of the tunnel HTML URL.
2825          * @returns {String}
2826          *     The location of the tunnel HTML URL.
2827          */
2828         this.getTunnelURL = function () {
2829             return _tunnelURL;
2830         };
2831 
2832         /**
2833          * @private
2834          * Tunnels a subscribe request to the eventing iframe.
2835          * @param {String} node
2836          *     The node to subscribe to
2837          * @param {Function} handler
2838          *     Handler to invoke upon success or failure
2839          */
2840         this.subscribe = function (node, handler) {
2841             if (handler && typeof handler !== "function") {
2842                 throw new Error("Parameter is not a function.");
2843             }
2844             _handlers.subscribe[node] = handler;
2845             _sendMessage(_TYPES.SUBSCRIBE, node);
2846         };
2847 
2848         /**
2849          * @private
2850          * Tunnels an unsubscribe request to the eventing iframe.
2851          * @param {String} node
2852          *     The node to unsubscribe from
2853          * @param {Function} handler
2854          *     Handler to invoke upon success or failure
2855          */
2856         this.unsubscribe = function (node, handler) {
2857             if (handler && typeof handler !== "function") {
2858                 throw new Error("Parameter is not a function.");
2859             }
2860             _handlers.unsubscribe[node] = handler;
2861             _sendMessage(_TYPES.UNSUBSCRIBE, node);
2862         };
2863 
2864         /**
2865          * @private
2866          * Registers a handler to be invoked when an event is delivered. Only one
2867          * is registered at a time. If there has already been an event that was
2868          * delivered, the handler will be invoked immediately.
2869          * @param {Function} handler
2870          *     Invoked when an event is delivered through the event connection.
2871          */
2872         this.registerEventHandler = function (handler) {
2873             if (typeof handler !== "function") {
2874                 throw new Error("Parameter is not a function.");
2875             }
2876             _eventHandler = handler;
2877             if (_eventCache) {
2878                 handler(_eventCache);
2879             }
2880         };
2881 
2882         /**
2883          * @private
2884          * Unregisters the event handler completely.
2885          */
2886         this.unregisterEventHandler = function () {
2887             _eventHandler = undefined;
2888         };
2889         
2890         /**
2891          * @private
2892          * Registers a handler to be invoked when a presence event is delivered. Only one
2893          * is registered at a time. 
2894          * @param {Function} handler
2895          *     Invoked when a presence event is delivered through the event connection.
2896          */
2897         this.registerPresenceHandler = function (handler) {
2898             if (typeof handler !== "function") {
2899                 throw new Error("Parameter is not a function.");
2900             }
2901             _presenceHandler = handler;
2902         };
2903         
2904         /**
2905          * @private
2906          * Unregisters the presence event handler completely.
2907          */
2908         this.unregisterPresenceHandler = function () {
2909             _presenceHandler = undefined;
2910         };
2911 
2912         /**
2913          * @private
2914          * Registers a handler to be invoked when a connection status changes. The
2915          * object passed will contain a "status" property, and a "resourceID"
2916          * property, which will contain the most current resource ID assigned to
2917          * the client. If there has already been an event that was delivered, the
2918          * handler will be invoked immediately.
2919          * @param {Function} handler
2920          *     Invoked when a connection status changes.
2921          */
2922         this.registerConnectionInfoHandler = function (handler) {
2923             if (typeof handler !== "function") {
2924                 throw new Error("Parameter is not a function.");
2925             }
2926             _connInfoHandler = handler;
2927             if (_statusCache) {
2928                 handler(_createConnInfoObj());
2929             }
2930         };
2931 
2932         /**
2933          * @private
2934          * Unregisters the connection information handler.
2935          */
2936         this.unregisterConnectionInfoHandler = function () {
2937             _connInfoHandler = undefined;
2938         };
2939 
2940         /**
2941          * @private
2942          * Start listening for events and create a event tunnel for the shared BOSH
2943          * connection.
2944          * @param {String} id
2945          *     The ID of the user for the notification server.
2946          * @param {String} password
2947          *     The password of the user for the notification server.
2948          * @param {String} xmppDomain
2949          *     The XMPP domain of the notification server
2950          * @param {String} pubsubDomain
2951          *     The location (JID) of the XEP-0060 PubSub service
2952          * @param {String} resource
2953          *     The resource to connect to the notification servier with.
2954          */
2955         this.init = function (id, password, xmppDomain, pubsubDomain, resource) {
2956             
2957             if (typeof id !== "string" || typeof password !== "string" || typeof xmppDomain !== "string" || typeof pubsubDomain !== "string") {
2958                 throw new Error("Invalid or missing required parameters.");
2959             }
2960 
2961             _initTunnelConfig();
2962             
2963             _id = id;
2964             _password = password;
2965             _xmppDomain = xmppDomain;
2966             _pubsubDomain = pubsubDomain;
2967             _resource = resource;
2968 
2969             //Attach a listener for messages sent from tunnel frame.
2970             _util.receiveMessage(_messageHandler, _tunnelOrigin);
2971 
2972             //Create the tunnel iframe which will establish the shared connection.
2973             _createTunnel();
2974         };
2975 
2976         //BEGIN TEST CODE//
2977 //        /**
2978 //         * Test code added to expose private functions that are used by unit test
2979 //         * framework. This section of code is removed during the build process
2980 //         * before packaging production code. The [begin|end]TestSection are used
2981 //         * by the build to identify the section to strip.
2982 //         * @ignore
2983 //         */
2984 //        this.beginTestSection = 0;
2985 //
2986 //        /**
2987 //         * @ignore
2988 //         */
2989 //        this.getTestObject = function () {
2990 //            //Load mock dependencies.
2991 //            var _mock = new MockControl();
2992 //            _util = _mock.createMock(finesse.utilities.Utilities);
2993 //
2994 //            return {
2995 //                //Expose mock dependencies
2996 //                mock: _mock,
2997 //                util: _util,
2998 //
2999 //                //Expose internal private functions
3000 //                types: _TYPES,
3001 //                createConnInfoObj: _createConnInfoObj,
3002 //                sendMessage: _sendMessage,
3003 //                messageHandler: _messageHandler,
3004 //                createTunnel: _createTunnel,
3005 //                handlers: _handlers,
3006 //                initTunnelConfig : _initTunnelConfig
3007 //            };
3008 //        };
3009 //
3010 //        /**
3011 //         * @ignore
3012 //         */
3013 //        this.endTestSection = 0;
3014 //        //END TEST CODE//
3015     };
3016     
3017     /** @namespace JavaScript class objects and methods to handle the subscription to Finesse events.*/
3018     finesse.clientservices = finesse.clientservices || {};
3019 
3020     window.finesse = window.finesse || {};
3021     window.finesse.clientservices = window.finesse.clientservices || {};
3022     window.finesse.clientservices.MasterTunnel = MasterTunnel;
3023 
3024 }));
3025 
3026 /**
3027  * Contains a list of topics used for client side pubsub.
3028  *
3029  */
3030 
3031 /** @private */
3032 (function (factory) {
3033     
3034 
3035     // Define as an AMD module if possible
3036     if ( typeof define === 'function' && define.amd )
3037     {
3038         define('clientservices/Topics',[], factory );
3039     }
3040     
3041     /* Define using browser globals otherwise
3042      * Prevent multiple instantiations if the script is loaded twice
3043      */
3044     else
3045     {
3046         factory();
3047     }
3048     
3049 }(function () {
3050     
3051    var Topics = (function () {
3052 
3053         /**
3054          * @private
3055          * The namespace prepended to all Finesse topics.
3056          */
3057         this.namespace = "finesse.info";
3058     
3059         /**
3060          * @private
3061          * Gets the full topic name with the Finesse namespace prepended.
3062          * @param {String} topic
3063          *     The topic category.
3064          * @returns {String}
3065          *     The full topic name with prepended namespace.
3066          */
3067         var _getNSTopic = function (topic) {
3068             return this.namespace + "." + topic;
3069         };
3070         
3071         /** @scope finesse.clientservices.Topics */
3072         return {
3073             /** 
3074              * @private
3075              * Client side request channel. 
3076              */
3077             REQUESTS: _getNSTopic("requests"),
3078     
3079             /** 
3080              * @private
3081              * Client side response channel. 
3082              */
3083             RESPONSES: _getNSTopic("responses"),
3084 
3085             /** 
3086              * @private
3087              * Connection status. 
3088              */
3089             EVENTS_CONNECTION_INFO: _getNSTopic("connection"),
3090             
3091             /** 
3092              * @private
3093              * Presence channel 
3094              */
3095             PRESENCE: _getNSTopic("presence"),
3096     
3097             /**
3098              * @private
3099              * Convert a Finesse REST URI to a OpenAjax compatible topic name.
3100              */
3101             getTopic: function (restUri) {
3102                 //The topic should not start with '/' else it will get replaced with
3103                 //'.' which is invalid.
3104                 //Thus, remove '/' if it is at the beginning of the string
3105                 if (restUri.indexOf('/') === 0) {
3106                     restUri = restUri.substr(1);
3107                 }
3108     
3109                 //Replace every instance of "/" with ".". This is done to follow the
3110                 //OpenAjaxHub topic name convention.
3111                 return restUri.replace(/\//g, ".");
3112             }
3113         };
3114     }());
3115     window.finesse = window.finesse || {};
3116     window.finesse.clientservices = window.finesse.clientservices || {};
3117     /** @private */
3118     window.finesse.clientservices.Topics = Topics;
3119     
3120     return Topics;
3121 }));
3122 
3123 /** The following comment is to prevent jslint errors about 
3124  * using variables before they are defined.
3125  */
3126 /*global finesse*/
3127 
3128 /**
3129  * Registers with the MasterTunnel to receive events, which it
3130  *     could publish to the OpenAjax gadget pubsub infrastructure.
3131  *
3132  * @requires OpenAjax, finesse.clientservices.MasterTunnel, finesse.clientservices.Topics
3133  */
3134 
3135 /** @private */
3136 (function (factory) {
3137     
3138 
3139     // Define as an AMD module if possible
3140     if ( typeof define === 'function' && define.amd )
3141     {
3142         define('clientservices/MasterPublisher',["clientservices/MasterTunnel",
3143                 "clientservices/Topics",
3144                 "utilities/Utilities"], factory );
3145     }
3146     
3147     /* Define using browser globals otherwise
3148      * Prevent multiple instantiations if the script is loaded twice
3149      */
3150     else
3151     {
3152         factory(finesse.clientservices.MasterTunnel, finesse.clientservices.Topics, finesse.utilities.Utilities);
3153     }
3154     
3155 }(function (MasterTunnel, Topics, Utilities) {
3156     
3157      var MasterPublisher = function (tunnel, hub) {
3158         if (!(tunnel instanceof MasterTunnel)) {
3159             throw new Error("Required tunnel object missing or invalid.");
3160         }
3161 
3162         var
3163         
3164         ClientServices = finesse.clientservices.ClientServices,
3165 
3166         /**
3167          * Reference to the gadget pubsub Hub instance.
3168          * @private
3169          */
3170         _hub = hub,
3171 
3172         /**
3173          * Reference to the Topics class.
3174          * @private
3175          */
3176         _topics = Topics,
3177         
3178         /**
3179          * Reference to conversion utilities class.
3180          * @private
3181          */
3182         _utils = Utilities,
3183         
3184         /**
3185          * References to ClientServices logger methods
3186          * @private
3187          */
3188         _logger = {
3189             log: ClientServices.log
3190         },
3191         
3192         /**
3193          * Store the passed in tunnel.
3194          * @private
3195          */
3196         _tunnel = tunnel,
3197 
3198         /**
3199          * Caches the connection info event so that it could be published if there
3200          * is a request for it.
3201          * @private
3202          */
3203         _connInfoCache = {},
3204 
3205         /**
3206          * The types of possible request types supported when listening to the
3207          * requests channel. Each request type could result in different operations.
3208          * @private
3209          */
3210         _REQTYPES = {
3211             CONNECTIONINFO: "ConnectionInfoReq",
3212             SUBSCRIBE: "SubscribeNodeReq",
3213             UNSUBSCRIBE: "UnsubscribeNodeReq",
3214             CONNECT: "ConnectionReq"
3215         },
3216 
3217         /**
3218          * Will store list of nodes that have OF subscriptions created
3219          *     _nodesList[node][subscribing].reqIds[subid]
3220          *     _nodesList[node][active].reqIds[subid]
3221          *     _nodesList[node][unsubscribing].reqIds[subid]
3222          *     _nodesList[node][holding].reqIds[subid]
3223          * @private
3224          */
3225         _nodesList = {},
3226         
3227         /**
3228          * The states that a subscription can be in
3229          * @private
3230          */
3231         _CHANNELSTATES = {
3232             UNINITIALIZED: "Uninitialized",
3233             PENDING: "Pending",
3234             OPERATIONAL: "Operational"
3235         },
3236 
3237         /**
3238           * Checks if the payload is JSON 
3239           * @returns {Boolean}
3240           * @private
3241           */
3242         _isJsonPayload = function(event) {
3243             var delimStart, delimEnd, retval = false;
3244             
3245             try { 
3246               delimStart = event.indexOf('{');
3247               delimEnd = event.lastIndexOf('}');
3248 
3249               if ((delimStart !== -1 ) && (delimEnd === (event.length - 1))) {
3250                 retval = true;  //event contains JSON payload
3251               }
3252             } catch (err) {
3253               _logger.log("MasterPublisher._isJsonPayload() - Caught error: " + err);
3254             }
3255             return retval;
3256         },
3257         
3258                 /**
3259           * Parses a JSON event and then publishes.
3260           *
3261           * @param {String} event
3262           *     The full event payload.
3263           * @throws {Error} If the payload object is malformed.
3264           * @private
3265           */
3266         _parseAndPublishJSONEvent = function(event) {
3267             var topic, eventObj, publishEvent,
3268             delimPos = event.indexOf("{"),
3269             node, parser,
3270             eventJson = event,
3271             returnObj = {node: null, data: null};
3272 
3273             try {
3274                //Extract and strip the node path from the message
3275                if (delimPos > 0) 
3276                {
3277                   //We need to decode the URI encoded node path
3278                   //TODO: make sure this is kosher with OpenAjax topic naming
3279                   node = decodeURI(event.substr(0, delimPos));
3280                   eventJson = event.substr(delimPos);
3281                   
3282                   //Converting the node path to openAjaxhub topic
3283                   topic = _topics.getTopic(node);
3284                   
3285                   returnObj.node = node;
3286                   returnObj.payload = eventJson;
3287                } 
3288                else 
3289                {
3290                   _logger.log("MasterPublisher._parseAndPublishJSONEvent() - [ERROR] node is not given in postMessage: " + eventJson);
3291                   throw new Error("node is not given in postMessage: " + eventJson);
3292                }
3293 
3294                parser = _utils.getJSONParser();
3295 
3296                eventObj = parser.parse(eventJson);
3297                returnObj.data = eventObj;
3298 
3299             } catch (err) {
3300                _logger.log("MasterPublisher._parseAndPublishJSONEvent() - [ERROR] Malformed event payload: " + err);
3301                throw new Error("Malformed event payload : " + err);
3302             }
3303             
3304             _logger.log("MasterPublisher._parseAndPublishJSONEvent() - Received JSON event on node '" + node + "': " + eventJson); 
3305             
3306             publishEvent = {content : event, object : eventObj };
3307 
3308             //Publish event to proper event topic.
3309             if (topic && eventObj) {
3310                _hub.publish(topic, publishEvent);
3311             }
3312         },
3313         
3314         /**
3315           * Parses an XML event and then publishes.
3316           *
3317           * @param {String} event
3318           *     The full event payload.
3319           * @throws {Error} If the payload object is malformed.
3320           * @private
3321           */
3322         _parseAndPublishXMLEvent = function(event) {
3323             var topic, eventObj, publishEvent, restTopic,
3324             delimPos = event.indexOf("<"),
3325             node,
3326             eventXml = event;
3327             
3328             try {
3329                //Extract and strip the node path from the message
3330                if (delimPos > 0) {
3331                   //We need to decode the URI encoded node path
3332                   //TODO: make sure this is kosher with OpenAjax topic naming
3333                   node = decodeURI(event.substr(0, delimPos));
3334                   eventXml = event.substr(delimPos);
3335                   //Converting the node path to openAjaxhub topic
3336                   topic = _topics.getTopic(node);
3337                } else {
3338                   _logger.log("MasterPublisher._parseAndPublishXMLEvent() - [ERROR] node is not given in postMessage: " + eventXml);
3339                   throw new Error("node is not given in postMessage: " + eventXml);
3340                }
3341 
3342                eventObj = _utils.xml2JsObj(eventXml);
3343                   
3344            } catch (err) {
3345                _logger.log("MasterPublisher._parseAndPublishXMLEvent() - [ERROR] Malformed event payload: " + err);
3346                throw new Error("Malformed event payload : " + err);
3347            }
3348            
3349            _logger.log("MasterPublisher._parseAndPublishXMLEvent() - Received XML event on node '" + node + "': " + eventXml);
3350            
3351            publishEvent = {content : event, object : eventObj };
3352 
3353            //Publish event to proper event topic.
3354            if (topic && eventObj) {
3355                _hub.publish(topic, publishEvent);
3356            }
3357         },
3358         
3359         /**
3360          * Publishes events to the appropriate topic. The topic name is determined
3361          * by fetching the source value from the event.
3362          * @param {String} event
3363          *     The full event payload.
3364          * @throws {Error} If the payload object is malformed.
3365          * @private
3366          */
3367         _eventHandler = function (event) {
3368             
3369             //Handle JSON or XML events
3370             if (!_isJsonPayload(event))
3371             {
3372                //XML
3373                _parseAndPublishXMLEvent(event);
3374             }
3375             else
3376             {
3377                //JSON
3378                _parseAndPublishJSONEvent(event);
3379             }
3380         },
3381         
3382         
3383         /**
3384          * Handler for when presence events are sent through the MasterTunnel.
3385          * @returns {Object}
3386          *     A presence xml event.
3387          * @private
3388          */
3389         _presenceHandler = function (event) {
3390             var eventObj = _utils.xml2JsObj(event), publishEvent;
3391             
3392             publishEvent = {content : event, object : eventObj};
3393             
3394             if (eventObj) {
3395                 _hub.publish(_topics.PRESENCE, publishEvent);
3396             }
3397         },
3398 
3399         /**
3400          * Clone the connection info object from cache.
3401          * @returns {Object}
3402          *     A connection info object containing a "status" and "resourceID".
3403          * @private
3404          */
3405         _cloneConnInfoObj = function () {
3406             if (_connInfoCache) {
3407                 return {
3408                     status: _connInfoCache.status,
3409                     resourceID: _connInfoCache.resourceID
3410                 };
3411             } else {
3412                 return null;
3413             }
3414         },
3415 
3416         _cleanupPendingRequests = function () {
3417             var node, curSubid, errObj = {
3418                 error: {
3419                     errorType: "Disconnected",
3420                     errorMessage: "Outstanding request will never complete."
3421                 }
3422             };
3423 
3424             // Iterate through all outstanding subscribe requests to notify them that it will never return
3425             for (node in _nodesList) {
3426                 if (_nodesList.hasOwnProperty(node)) {
3427                     for (curSubid in _nodesList[node].subscribing.reqIds) {
3428                         if (_nodesList[node].subscribing.reqIds.hasOwnProperty(curSubid)) {
3429                             // Notify this outstanding subscribe request to give up and error out
3430                             _hub.publish(_topics.RESPONSES + "." + curSubid, errObj); 
3431                         }
3432                     }
3433                     for (curSubid in _nodesList[node].unsubscribing.reqIds) {
3434                         if (_nodesList[node].unsubscribing.reqIds.hasOwnProperty(curSubid)) {
3435                             // Notify this outstanding unsubscribe request to give up and error out
3436                             _hub.publish(_topics.RESPONSES + "." + curSubid, errObj); 
3437                         }
3438                     }
3439                 }
3440             }
3441         },
3442 
3443         /**
3444          * Publishes the connection info to the connection info topic.
3445          * @param {Object} connInfo
3446          *     The connection info object containing the status and resource ID.
3447          * @private
3448          */
3449         _connInfoHandler = function (connInfo) {
3450             var before = _connInfoCache.status;
3451             _connInfoCache = connInfo;
3452             _logger.log("MasterPublisher._connInfoHandler() - Connection status: " + connInfo.status);
3453             _hub.publish(_topics.EVENTS_CONNECTION_INFO, _cloneConnInfoObj());
3454             if (before === "connected" && connInfo.status !== "connected") {
3455                 // Fail all pending requests when we transition to disconnected
3456                 _cleanupPendingRequests();
3457             }
3458         },
3459 
3460         
3461         /**
3462          * Utility method to bookkeep node subscription requests and determine
3463          * whehter it is necessary to tunnel the request to JabberWerx.
3464          * @param {String} node
3465          *     The node of interest
3466          * @param {String} reqId
3467          *     A unique string identifying the request/subscription
3468          * @private
3469          */
3470         _subscribeNode = function (node, subid) {
3471             if (_connInfoCache.status !== "connected") {
3472                 _hub.publish(_topics.RESPONSES + "." + subid, {
3473                     error: {
3474                         errorType: "Not connected",
3475                         errorMessage: "Cannot subscribe without connection."
3476                     }
3477                 });
3478                 return;
3479             }
3480             // NODE DOES NOT YET EXIST
3481             if (!_nodesList[node]) {
3482                 _nodesList[node] = {
3483                     "subscribing": {
3484                         "reqIds": {},
3485                         "length": 0
3486                     },
3487                     "active": {
3488                         "reqIds": {},
3489                         "length": 0
3490                     },
3491                     "unsubscribing": {
3492                         "reqIds": {},
3493                         "length": 0
3494                     },
3495                     "holding": {
3496                         "reqIds": {},
3497                         "length": 0
3498                     }
3499                 };
3500             }
3501             if (_nodesList[node].active.length === 0) {
3502                 if (_nodesList[node].unsubscribing.length === 0) {
3503                     if (_nodesList[node].subscribing.length === 0) {
3504                         _nodesList[node].subscribing.reqIds[subid] = true;
3505                         _nodesList[node].subscribing.length += 1;
3506 
3507                         _logger.log("MasterPublisher._subscribeNode() - Attempting to subscribe to node '" + node + "'");
3508                         _tunnel.subscribe(node, function (err) {
3509                             var errObj, curSubid;
3510                             if (err) {
3511                                 errObj = {
3512                                     subscribe: {
3513                                         content: err
3514                                     }
3515                                 };
3516 
3517                                 try {
3518                                     errObj.subscribe.object = gadgets.json.parse((_utils.xml2json(jQuery.parseXML(err), "")));
3519                                 } catch (e) {
3520                                     errObj.error = {
3521                                         errorType: "parseError",
3522                                         errorMessage: "Could not serialize XML: " + e
3523                                     };
3524                                 }
3525                                 _logger.log("MasterPublisher._subscribeNode() - Error subscribing to node '" + node + "': " + err);
3526                             } else {
3527                                 _logger.log("MasterPublisher._subscribeNode() - Subscribed to node '" + node + "'");
3528                             }
3529 
3530                             for (curSubid in _nodesList[node].subscribing.reqIds) {
3531                                 if (_nodesList[node].subscribing.reqIds.hasOwnProperty(curSubid)) {
3532                                     _hub.publish(_topics.RESPONSES + "." + curSubid, errObj);
3533                                     if (!err) {
3534                                         _nodesList[node].active.reqIds[curSubid] = true;
3535                                         _nodesList[node].active.length += 1;
3536                                     }
3537                                     delete _nodesList[node].subscribing.reqIds[curSubid];
3538                                     _nodesList[node].subscribing.length -= 1;
3539                                 }
3540                             }
3541                         });
3542                         
3543                     } else { //other ids are subscribing
3544                         _nodesList[node].subscribing.reqIds[subid] = true;
3545                         _nodesList[node].subscribing.length += 1;
3546                     }                       
3547                 } else { //An unsubscribe request is pending, hold onto these subscribes until it is done
3548                     _nodesList[node].holding.reqIds[subid] = true;
3549                     _nodesList[node].holding.length += 1;
3550                 }
3551             } else { // The node has active subscriptions; add this subid and return successful response
3552                 _nodesList[node].active.reqIds[subid] = true;
3553                 _nodesList[node].active.length += 1;
3554                 _hub.publish(_topics.RESPONSES + "." + subid, undefined); 
3555             }
3556         },
3557 
3558         /**
3559          * Utility method to bookkeep node unsubscribe requests and determine
3560          * whehter it is necessary to tunnel the request to JabberWerx.
3561          * @param {String} node
3562          *     The node to unsubscribe from
3563          * @param {String} reqId
3564          *     A unique string identifying the subscription to remove
3565          * @private
3566          */
3567         _unsubscribeNode = function (node, subid) {
3568             if (!_nodesList[node]) { //node DNE, publish success response
3569                 _hub.publish(_topics.RESPONSES + "." + subid, undefined); 
3570             } else {
3571                 if (_connInfoCache.status !== "connected") {
3572                     _hub.publish(_topics.RESPONSES + "." + subid, {
3573                         error: {
3574                             errorType: "Not connected",
3575                             errorMessage: "Cannot unsubscribe without connection."
3576                         }
3577                     });
3578                     return;
3579                 }
3580                 if (_nodesList[node].active.length > 1) {
3581                     delete _nodesList[node].active.reqIds[subid];
3582                     _hub.publish(_topics.RESPONSES + "." + subid, undefined); 
3583                     _nodesList[node].active.length -= 1;
3584                 } else if (_nodesList[node].active.length === 1) { // transition subid from active category to unsubscribing category
3585                     _nodesList[node].unsubscribing.reqIds[subid] = true;
3586                     _nodesList[node].unsubscribing.length += 1;
3587                     delete _nodesList[node].active.reqIds[subid];
3588                     _nodesList[node].active.length -= 1;
3589 
3590                     _logger.log("MasterPublisher._unsubscribeNode() - Attempting to unsubscribe from node '" + node + "'");
3591                     _tunnel.unsubscribe(node, function (err) {
3592                         var errObj, curSubid;
3593                         if (err) {
3594                             errObj = {
3595                                 subscribe: {
3596                                     content: err
3597                                 }
3598                             };
3599 
3600                             try {
3601                                 errObj.subscribe.object = gadgets.json.parse((_utils.xml2json(jQuery.parseXML(err), "")));
3602                             } catch (e) {
3603                                 errObj.error = {
3604                                     errorType: "parseError",
3605                                     errorMessage: "Could not serialize XML: " + e
3606                                 };
3607                             }
3608                             _logger.log("MasterPublisher._unsubscribeNode() - Error unsubscribing from node '" + node + "': " + err);
3609                         } else {
3610                             _logger.log("MasterPublisher._unsubscribeNode() - Unsubscribed from node '" + node + "'");
3611                         }
3612 
3613                         for (curSubid in _nodesList[node].unsubscribing.reqIds) {
3614                             if (_nodesList[node].unsubscribing.reqIds.hasOwnProperty(curSubid)) {
3615                                 // publish to all subids whether unsubscribe failed or succeeded
3616                                 _hub.publish(_topics.RESPONSES + "." + curSubid, errObj); 
3617                                 if (!err) {
3618                                     delete _nodesList[node].unsubscribing.reqIds[curSubid];
3619                                     _nodesList[node].unsubscribing.length -= 1;
3620                                 } else { // Just remove the subid from unsubscribing; the next subscribe request will operate with node already created
3621                                     delete _nodesList[node].unsubscribing.reqIds[curSubid];
3622                                     _nodesList[node].unsubscribing.length -= 1;
3623                                 }   
3624                             }
3625                         }
3626                         
3627                         if (!err && _nodesList[node].holding.length > 0) { // if any subscribe requests came in while unsubscribing from OF, now transition from holding to subscribing
3628                             for (curSubid in _nodesList[node].holding.reqIds) {
3629                                 if (_nodesList[node].holding.reqIds.hasOwnProperty(curSubid)) {
3630                                     delete _nodesList[node].holding.reqIds[curSubid];
3631                                     _nodesList[node].holding.length -= 1;
3632                                     _subscribeNode(node, curSubid);                             
3633                                 }
3634                             }
3635                         }
3636                     });
3637                 } else { // length <= 0?
3638                     _hub.publish(_topics.RESPONSES + "." + subid, undefined);
3639                 }
3640             }
3641         },
3642         
3643         /**
3644          * Handles client requests to establish a BOSH connection.
3645          * @param {String} id
3646          *     id of the xmpp user
3647          * @param {String} password
3648          *     password of the xmpp user
3649          * @param {String} xmppDomain
3650          *     xmppDomain of the xmpp user account
3651          * @private
3652          */
3653         _connect = function (id, password, xmppDomain) {
3654             _tunnel.makeConnectReq(id, password, xmppDomain);
3655         },
3656 
3657         /**
3658          * Handles client requests made to the request topic. The type of the
3659          * request is described in the "type" property within the data payload. Each
3660          * type can result in a different operation.
3661          * @param {String} topic
3662          *     The topic which data was published to.
3663          * @param {Object} data
3664          *     The data containing requests information published by clients.
3665          * @param {String} data.type
3666          *     The type of the request. Supported: "ConnectionInfoReq"
3667          * @param {Object} data.data
3668          *     May contain data relevant for the particular requests.
3669          * @param {String} [data.invokeID]
3670          *     The ID used to identify the request with the response. The invoke ID
3671          *     will be included in the data in the publish to the topic. It is the
3672          *     responsibility of the client to correlate the published data to the
3673          *     request made by using the invoke ID.
3674          * @private
3675          */
3676         _clientRequestHandler = function (topic, data) {
3677             var dataCopy;
3678 
3679             //Ensure a valid data object with "type" and "data" properties.
3680             if (typeof data === "object" &&
3681                     typeof data.type === "string" &&
3682                     typeof data.data === "object") {
3683                 switch (data.type) {
3684                 case _REQTYPES.CONNECTIONINFO:
3685                     //It is possible that Slave clients come up before the Master
3686                     //client. If that is the case, the Slaves will need to make a
3687                     //request for the Master to send the latest connection info to the
3688                     //connectionInfo topic.
3689                     dataCopy = _cloneConnInfoObj();
3690                     if (dataCopy) {
3691                         if (data.invokeID !== undefined) {
3692                             dataCopy.invokeID = data.invokeID;
3693                         }
3694                         _hub.publish(_topics.EVENTS_CONNECTION_INFO, dataCopy);
3695                     }
3696                     break;
3697                 case _REQTYPES.SUBSCRIBE:
3698                     if (typeof data.data.node === "string") {
3699                         _subscribeNode(data.data.node, data.invokeID);
3700                     }
3701                     break;
3702                 case _REQTYPES.UNSUBSCRIBE:
3703                     if (typeof data.data.node === "string") {
3704                         _unsubscribeNode(data.data.node, data.invokeID);
3705                     }
3706                     break;
3707                 case _REQTYPES.CONNECT:
3708                     // Deprecated: Disallow others (non-masters) from administering BOSH connections that are not theirs
3709                     _logger.log("MasterPublisher._clientRequestHandler(): F403: Access denied. Non-master ClientService instances do not have the clearance level to make this request: makeConnectionReq");
3710                     break;
3711                 default:
3712                     break;
3713                 }
3714             }
3715         };
3716 
3717         (function () {
3718             //Register to receive events and connection status from tunnel.
3719             _tunnel.registerEventHandler(_eventHandler);
3720             _tunnel.registerPresenceHandler(_presenceHandler);
3721             _tunnel.registerConnectionInfoHandler(_connInfoHandler);
3722 
3723             //Listen to a request channel to respond to any requests made by other
3724             //clients because the Master may have access to useful information.
3725             _hub.subscribe(_topics.REQUESTS, _clientRequestHandler);
3726         }());
3727 
3728         /**
3729          * @private
3730          * Handles client requests to establish a BOSH connection.
3731          * @param {String} id
3732          *     id of the xmpp user
3733          * @param {String} password
3734          *     password of the xmpp user
3735          * @param {String} xmppDomain
3736          *     xmppDomain of the xmpp user account
3737          */
3738         this.connect = function (id, password, xmppDomain) {
3739           _connect(id, password, xmppDomain);
3740         };
3741 
3742         /**
3743          * @private
3744          * Resets the list of explicit subscriptions
3745          */
3746         this.wipeout = function () {
3747             _cleanupPendingRequests();
3748             _nodesList = {};
3749        };
3750 
3751         //BEGIN TEST CODE//
3752        /**
3753         * Test code added to expose private functions that are used by unit test
3754         * framework. This section of code is removed during the build process
3755         * before packaging production code. The [begin|end]TestSection are used
3756         * by the build to identify the section to strip.
3757         * @ignore
3758         */
3759        this.beginTestSection = 0;
3760 
3761        /**
3762         * @ignore
3763         */
3764        this.getTestObject = function () {
3765            //Load mock dependencies.
3766            var _mock = new MockControl();
3767            _hub = _mock.createMock(gadgets.Hub);
3768            _tunnel = _mock.createMock();
3769 
3770            return {
3771                //Expose mock dependencies
3772                mock: _mock,
3773                hub: _hub,
3774                tunnel: _tunnel,
3775                setTunnel: function (tunnel) {
3776                    _tunnel = tunnel;
3777                },
3778                getTunnel: function () {
3779                    return _tunnel;
3780                },
3781 
3782                //Expose internal private functions
3783                reqtypes: _REQTYPES,
3784                eventHandler: _eventHandler,
3785                presenceHandler: _presenceHandler,
3786                
3787                subscribeNode: _subscribeNode,
3788                unsubscribeNode: _unsubscribeNode,
3789                
3790                getNodeList: function () {
3791                    return _nodesList;
3792                },
3793                setNodeList: function (nodelist) {
3794                    _nodesList = nodelist;
3795                },
3796                
3797                cloneConnInfoObj: _cloneConnInfoObj,
3798                connInfoHandler: _connInfoHandler,
3799                clientRequestHandler: _clientRequestHandler
3800 
3801            };
3802        };
3803 
3804 
3805        /**
3806         * @ignore
3807         */
3808        this.endTestSection = 0;
3809        //END TEST CODE//
3810 
3811     };
3812     
3813     window.finesse = window.finesse || {};
3814     window.finesse.clientservices = window.finesse.clientservices || {};
3815     window.finesse.clientservices.MasterPublisher = MasterPublisher;
3816 
3817 }));
3818 
3819 /** The following comment is to prevent jslint errors about 
3820  * using variables before they are defined.
3821  */
3822 /*global publisher:true */
3823 
3824 /**
3825  * Exposes a set of API wrappers that will hide the dirty work of
3826  *     constructing Finesse API requests and consuming Finesse events.
3827  *
3828  * @requires OpenAjax, jQuery 1.5, finesse.utilities.Utilities
3829  */
3830 
3831 
3832 /**
3833  * Allow clients to make Finesse API requests and consume Finesse events by
3834  * calling a set of exposed functions. The Services layer will do the dirty
3835  * work of establishing a shared BOSH connection (for designated Master
3836  * modules), consuming events for client subscriptions, and constructing API
3837  * requests.
3838  */
3839 /** @private */
3840 (function (factory) {
3841     
3842 
3843     // Define as an AMD module if possible
3844     if ( typeof define === 'function' && define.amd )
3845     {
3846         define('clientservices/ClientServices',["clientservices/MasterTunnel",
3847                 "clientservices/MasterPublisher",
3848                 "clientservices/Topics",
3849                 "utilities/Utilities"], factory );
3850     }
3851     
3852     /* Define using browser globals otherwise
3853      * Prevent multiple instantiations if the script is loaded twice
3854      */
3855     else
3856     {
3857         factory(finesse.clientservices.MasterTunnel, finesse.clientservices.MasterPublisher, finesse.clientservices.Topics, finesse.utilities.Utilities);
3858     }
3859     
3860 }(function (MasterTunnel, MasterPublisher, Topics, Utilities) {
3861     
3862      var ClientServices = (function () {/** @lends finesse.clientservices.ClientServices.prototype */
3863         var
3864 
3865         /**
3866          * Shortcut reference to the master tunnel
3867          * @private
3868          */
3869         _tunnel,
3870 
3871         _publisher,
3872 
3873         /**
3874          * Shortcut reference to the finesse.utilities.Utilities singleton
3875          * This will be set by init()
3876          * @private
3877          */
3878         _util,
3879 
3880         /**
3881          * Shortcut reference to the gadgets.io object.
3882          * This will be set by init()
3883          * @private
3884          */
3885         _io,
3886 
3887         /**
3888          * Shortcut reference to the gadget pubsub Hub instance.
3889          * This will be set by init()
3890          * @private
3891          */
3892         _hub,
3893 
3894         /**
3895          * Logger object set externally by setLogger, defaults to nothing.
3896          * @private
3897          */
3898         _logger = {},
3899 
3900         /**
3901          * Shortcut reference to the Topics class.
3902          * This will be set by init()
3903          * @private
3904          */
3905         _topics,
3906 
3907         /**
3908          * Config object needed to initialize this library
3909          * This must be set by init()
3910          * @private
3911          */
3912         _config,
3913 
3914         /**
3915          * @private
3916          * Whether or not this ClientService instance is a Master.
3917          */
3918         _isMaster = false,
3919 
3920         /**
3921          * @private
3922          * Whether the Client Services have been initiated yet.
3923          */
3924         _inited = false,
3925 
3926         /**
3927          * Stores the list of subscription IDs for all subscriptions so that it
3928          * could be retrieve for unsubscriptions.
3929          * @private
3930          */
3931         _subscriptionID = {},
3932 
3933         /**
3934          * The possible states of the JabberWerx BOSH connection.
3935          * @private
3936          */
3937         _STATUS = {
3938             CONNECTING: "connecting",
3939             CONNECTED: "connected",
3940             DISCONNECTED: "disconnected",
3941             DISCONNECTED_CONFLICT: "conflict",
3942             DISCONNECTED_UNAUTHORIZED: "unauthorized",
3943             DISCONNECTING: "disconnecting",
3944             RECONNECTING: "reconnecting",
3945             UNLOADING: "unloading",
3946             FAILING: "failing",
3947             RECOVERED: "recovered"
3948         },
3949 
3950         _failoverMode = false,
3951 
3952         /**
3953          * Handler function to be invoked when BOSH connection is connecting.
3954          * @private
3955          */
3956         _onConnectingHandler,
3957 
3958         /**
3959          * Handler function to be invoked when BOSH connection is connected
3960          * @private
3961          */
3962         _onConnectHandler,
3963 
3964         /**
3965          * Handler function to be invoked when BOSH connection is disconnecting.
3966          * @private
3967          */
3968         _onDisconnectingHandler,
3969 
3970         /**
3971          * Handler function to be invoked when the BOSH is disconnected.
3972          * @private
3973          */
3974         _onDisconnectHandler,
3975 
3976         /**
3977          * Handler function to be invoked when the BOSH is reconnecting.
3978          * @private
3979          */
3980         _onReconnectingHandler,
3981         
3982         /**
3983          * Handler function to be invoked when the BOSH is unloading.
3984          * @private
3985          */
3986         _onUnloadingHandler,
3987 
3988         /**
3989          * Contains a cache of the latest connection info containing the current
3990          * state of the BOSH connection and the resource ID.
3991          * @private
3992          */
3993         _connInfo,
3994 
3995         /**
3996          * Keeps track of all the objects that need to be refreshed when we recover
3997          * due to our resilient connection. Only objects that we subscribe to will
3998          * be added to this list.
3999          * @private
4000          */
4001         _refreshList = [],
4002 
4003         /**
4004          * @private
4005          * Centralized logger.log method for external logger
4006          * @param {String} msg
4007          *     Message to log
4008          */
4009         _log = function (msg) {
4010             // If the external logger throws up, it stops here.
4011             try {
4012                 if (_logger.log) {
4013                     _logger.log("[ClientServices] " + msg);
4014                 }
4015             } catch (e) { }
4016         },
4017 
4018         /**
4019          * Go through each object in the _refreshList and call its refresh() function
4020          * @private
4021          */
4022         _refreshObjects = function () {
4023             var i;
4024 
4025             // wipe out the explicit subscription list before we refresh objects
4026             if (_publisher) {
4027                 _publisher.wipeout();
4028             }
4029 
4030             // refresh each item in the refresh list
4031             for (i = _refreshList.length - 1; i >= 0; i -= 1) {
4032                 _log("Refreshing " + _refreshList[i].getRestUrl());
4033                 _refreshList[i].refresh(10);
4034             }
4035         },
4036 
4037         /**
4038          * Handler to process connection info publishes.
4039          * @param {Object} data
4040          *     The connection info data object.
4041          * @param {String} data.status
4042          *     The BOSH connection status.
4043          * @param {String} data.resourceID
4044          *     The resource ID for the connection.
4045          * @private
4046          */
4047         _connInfoHandler =  function (data) {
4048 
4049             //Invoke registered handler depending on status received. Due to the
4050             //request topic where clients can make request for the Master to publish
4051             //the connection info, there is a chance that duplicate connection info
4052             //events may be sent, so ensure that there has been a state change
4053             //before invoking the handlers.
4054             if (_connInfo === undefined || _connInfo.status !== data.status) {
4055                 _connInfo = data;
4056                 switch (data.status) {
4057                 case _STATUS.CONNECTING:
4058                     if (_isMaster && _onConnectingHandler) {
4059                         _onConnectingHandler();
4060                     }
4061                     break;
4062                 case _STATUS.CONNECTED:
4063                     if ((_isMaster || !_failoverMode) && _onConnectHandler) {
4064                         _onConnectHandler();
4065                     }
4066                     break;
4067                 case _STATUS.DISCONNECTED:
4068                     if (_isMaster && _onDisconnectHandler) {
4069                         _onDisconnectHandler();
4070                     }
4071                     break;
4072                 case _STATUS.DISCONNECTED_CONFLICT:
4073                     if (_isMaster && _onDisconnectHandler) {
4074                         _onDisconnectHandler("conflict");
4075                     }
4076                     break;
4077                 case _STATUS.DISCONNECTED_UNAUTHORIZED:
4078                     if (_isMaster && _onDisconnectHandler) {
4079                         _onDisconnectHandler("unauthorized");
4080                     }
4081                     break;
4082                 case _STATUS.DISCONNECTING:
4083                     if (_isMaster && _onDisconnectingHandler) {
4084                         _onDisconnectingHandler();
4085                     }
4086                     break;
4087                 case _STATUS.RECONNECTING:
4088                     if (_isMaster && _onReconnectingHandler) {
4089                         _onReconnectingHandler();
4090                     }
4091                     break;
4092                 case _STATUS.UNLOADING:
4093                     if (_isMaster && _onUnloadingHandler) {
4094                         _onUnloadingHandler();
4095                     }
4096                     break;
4097                 case _STATUS.FAILING:
4098                     if (!_isMaster) {
4099                         // Stop
4100                         _failoverMode = true;
4101                         if (_onDisconnectHandler) {
4102                             _onDisconnectHandler();
4103                         }
4104                     }
4105                     break;
4106                 case _STATUS.RECOVERED:
4107                     if (!_isMaster) {
4108                         _failoverMode = false;
4109                         if (_onConnectHandler) {
4110                             _onConnectHandler();
4111                         }
4112                     }
4113                     // Whenever we are recovered, we need to refresh any objects
4114                     // that are stored.
4115                     _refreshObjects();
4116                     break;
4117                 }
4118             }
4119         },
4120 
4121         /**
4122          * Ensure that ClientServices have been inited.
4123          * @private
4124          */
4125         _isInited = function () {
4126             if (!_inited) {
4127                 throw new Error("ClientServices needs to be inited.");
4128             }
4129         },
4130 
4131         /**
4132          * Have the client become the Master by initiating a tunnel to a shared
4133          * event BOSH connection. The Master is responsible for publishing all
4134          * events to the pubsub infrastructure.
4135          * @private
4136          */
4137         _becomeMaster = function () {
4138             _tunnel = new MasterTunnel(_config.host, _config.scheme);
4139             _publisher = new MasterPublisher(_tunnel, _hub);
4140             _tunnel.init(_config.id, _config.password, _config.xmppDomain, _config.pubsubDomain, _config.resource);
4141             _isMaster = true;
4142         },
4143 
4144         /**
4145          * Make a request to the request channel to have the Master publish the
4146          * connection info object.
4147          * @private
4148          */
4149         _makeConnectionInfoReq = function () {
4150             var data = {
4151                 type: "ConnectionInfoReq",
4152                 data: {},
4153                 invokeID: (new Date()).getTime()
4154             };
4155             _hub.publish(_topics.REQUESTS, data);
4156         },
4157 
4158         /**
4159          * Utility method to register a handler which is associated with a
4160          * particular connection status.
4161          * @param {String} status
4162          *     The connection status string.
4163          * @param {Function} handler
4164          *     The handler to associate with a particular connection status.
4165          * @throws {Error}
4166          *     If the handler provided is not a function.
4167          * @private
4168          */
4169         _registerHandler = function (status, handler) {
4170             if (typeof handler === "function") {
4171                 if (_connInfo && _connInfo.status === status) {
4172                     handler();
4173                 }
4174                 switch (status) {
4175                 case _STATUS.CONNECTING:
4176                     _onConnectingHandler = handler;
4177                     break;
4178                 case _STATUS.CONNECTED:
4179                     _onConnectHandler = handler;
4180                     break;
4181                 case _STATUS.DISCONNECTED:
4182                     _onDisconnectHandler = handler;
4183                     break;
4184                 case _STATUS.DISCONNECTING:
4185                     _onDisconnectingHandler = handler;
4186                     break;
4187                 case _STATUS.RECONNECTING:
4188                     _onReconnectingHandler = handler;
4189                     break;
4190                 case _STATUS.UNLOADING:
4191                     _onUnloadingHandler = handler;
4192                     break;
4193                 }
4194 
4195             } else {
4196                 throw new Error("Callback is not a function");
4197             }
4198         };
4199 
4200         return {
4201 
4202             /**
4203              * @private
4204              * Adds an item to the list to be refreshed upon reconnect
4205              * @param {RestBase} object - rest object to be refreshed
4206              */
4207             addToRefreshList: function (object) {
4208                 _refreshList.push(object);
4209             },
4210 
4211             /**
4212              * @private
4213              * Removes the given item from the refresh list
4214              * @param  {RestBase} object - rest object to be removed
4215              */
4216             removeFromRefreshList: function (object) {
4217                 var i;
4218                 for (i = _refreshList.length - 1; i >= 0; i -= 1) {
4219                     if (_refreshList[i] === object) {
4220                         _refreshList.splice(i, 1);
4221                         break;
4222                     }
4223                 }
4224             },
4225 
4226             /**
4227              * @private
4228              * The location of the tunnel HTML URL.
4229              * @returns {String}
4230              *     The location of the tunnel HTML URL.
4231              */
4232             getTunnelURL: function () {
4233                 return _tunnel.getTunnelURL();            
4234             },
4235             
4236             /**
4237              * @private
4238              * Indicates whether the tunnel frame is loaded.
4239              * @returns {Boolean}
4240              *     True if the tunnel frame is loaded, false otherwise.
4241              */
4242             isTunnelLoaded: function () {
4243                 return _tunnel.isTunnelLoaded();            
4244             },
4245             
4246             /**
4247              * @private
4248              * Indicates whether the ClientServices instance is a Master.
4249              * @returns {Boolean}
4250              *     True if this instance of ClientServices is a Master, false otherwise.
4251              */
4252             isMaster: function () {
4253                 return _isMaster;
4254             },
4255 
4256             /**
4257              * @private
4258              * Get the resource ID. An ID is only available if the BOSH connection has
4259              * been able to connect successfully.
4260              * @returns {String}
4261              *     The resource ID string. Null if the BOSH connection was never
4262              *     successfully created and/or the resource ID has not been associated.
4263              */
4264             getResourceID: function () {
4265                 if (_connInfo !== undefined) {
4266                     return _connInfo.resourceID;
4267                 }
4268                 return null;
4269             },
4270             
4271             /*
4272             getHub: function () {
4273                 return _hub;
4274             },
4275         */
4276             /**
4277              * @private
4278              * Add a callback to be invoked when the BOSH connection is attempting
4279              * to connect. If the connection is already trying to connect, the
4280              * callback will be invoked immediately.
4281              * @param {Function} handler
4282              *      An empty param function to be invoked on connecting. Only one
4283              *      handler can be registered at a time. Handlers already registered
4284              *      will be overwritten.
4285              */
4286             registerOnConnectingHandler: function (handler) {
4287                 _registerHandler(_STATUS.CONNECTING, handler);
4288             },
4289 
4290             /**
4291              * @private
4292              * Removes the on connecting callback that was registered.
4293              */
4294             unregisterOnConnectingHandler: function () {
4295                 _onConnectingHandler = undefined;
4296             },
4297 
4298             /**
4299              * @private
4300              * Add a callback to be invoked when the BOSH connection has been
4301              * established. If the connection has already been established, the
4302              * callback will be invoked immediately.
4303              * @param {Function} handler
4304              *      An empty param function to be invoked on connect. Only one handler
4305              *      can be registered at a time. Handlers already registered will be
4306              *      overwritten.
4307              */
4308             registerOnConnectHandler: function (handler) {
4309                 _registerHandler(_STATUS.CONNECTED, handler);
4310             },
4311 
4312             /**
4313              * @private
4314              * Removes the on connect callback that was registered.
4315              */
4316             unregisterOnConnectHandler: function () {
4317                 _onConnectHandler = undefined;
4318             },
4319 
4320             /**
4321              * @private
4322              * Add a callback to be invoked when the BOSH connection goes down. If
4323              * the connection is already down, invoke the callback immediately.
4324              * @param {Function} handler
4325              *      An empty param function to be invoked on disconnected. Only one
4326              *      handler can be registered at a time. Handlers already registered
4327              *      will be overwritten.
4328              */
4329             registerOnDisconnectHandler: function (handler) {
4330                 _registerHandler(_STATUS.DISCONNECTED, handler);
4331             },
4332 
4333             /**
4334              * @private
4335              * Removes the on disconnect callback that was registered.
4336              */
4337             unregisterOnDisconnectHandler: function () {
4338                 _onDisconnectHandler = undefined;
4339             },
4340 
4341             /**
4342              * @private
4343              * Add a callback to be invoked when the BOSH is currently disconnecting. If
4344              * the connection is already disconnecting, invoke the callback immediately.
4345              * @param {Function} handler
4346              *      An empty param function to be invoked on disconnected. Only one
4347              *      handler can be registered at a time. Handlers already registered
4348              *      will be overwritten.
4349              */
4350             registerOnDisconnectingHandler: function (handler) {
4351                 _registerHandler(_STATUS.DISCONNECTING, handler);
4352             },
4353 
4354             /**
4355              * @private
4356              * Removes the on disconnecting callback that was registered.
4357              */
4358             unregisterOnDisconnectingHandler: function () {
4359                 _onDisconnectingHandler = undefined;
4360             },
4361 
4362             /**
4363              * @private
4364              * Add a callback to be invoked when the BOSH connection is attempting
4365              * to connect. If the connection is already trying to connect, the
4366              * callback will be invoked immediately.
4367              * @param {Function} handler
4368              *      An empty param function to be invoked on connecting. Only one
4369              *      handler can be registered at a time. Handlers already registered
4370              *      will be overwritten.
4371              */
4372             registerOnReconnectingHandler: function (handler) {
4373                 _registerHandler(_STATUS.RECONNECTING, handler);
4374             },
4375 
4376             /**
4377              * @private
4378              * Removes the on reconnecting callback that was registered.
4379              */
4380             unregisterOnReconnectingHandler: function () {
4381                 _onReconnectingHandler = undefined;
4382             },
4383             
4384             /**
4385              * @private
4386              * Add a callback to be invoked when the BOSH connection is unloading
4387              * 
4388              * @param {Function} handler
4389              *      An empty param function to be invoked on connecting. Only one
4390              *      handler can be registered at a time. Handlers already registered
4391              *      will be overwritten.
4392              */
4393             registerOnUnloadingHandler: function (handler) {
4394                 _registerHandler(_STATUS.UNLOADING, handler);
4395             },
4396             
4397             /**
4398              * @private
4399              * Removes the on unloading callback that was registered.
4400              */
4401             unregisterOnUnloadingHandler: function () {
4402                 _onUnloadingHandler = undefined;
4403             },
4404 
4405             /**
4406              * @private
4407              * Proxy method for gadgets.io.makeRequest. The will be identical to gadgets.io.makeRequest
4408              * ClientServices will mixin the BASIC Auth string, locale, and host, since the
4409              * configuration is encapsulated in here anyways.
4410              * This removes the dependency
4411              * @param {String} url
4412              *     The relative url to make the request to (the host from the passed in config will be
4413              *     appended). It is expected that any encoding to the URL is already done.
4414              * @param {Function} handler
4415              *     Callback handler for makeRequest to invoke when the response returns.
4416              *     Completely passed through to gadgets.io.makeRequest
4417              * @param {Object} params
4418              *     The params object that gadgets.io.makeRequest expects. Authorization and locale
4419              *     headers are mixed in.
4420              */
4421             makeRequest: function (url, handler, params) {
4422                 var requestedScheme, scheme = "http";
4423                 
4424                 // ClientServices needs to be initialized with a config for restHost, auth, and locale
4425                 _isInited();
4426                 
4427                 // Allow mixin of auth and locale headers
4428                 params = params || {};
4429 
4430                 // Override refresh interval to 0 instead of default 3600 as a way to workaround makeRequest 
4431                 // using GET http method because then the params are added to the url as query params, which 
4432                 // exposes the authorization string in the url. This is a placeholder until oauth comes in
4433                 params[gadgets.io.RequestParameters.REFRESH_INTERVAL] = params[gadgets.io.RequestParameters.REFRESH_INTERVAL] || 0;
4434                 
4435                 params[gadgets.io.RequestParameters.HEADERS] = params[gadgets.io.RequestParameters.HEADERS] || {};
4436                 
4437                 // Add Basic auth to request header
4438                 params[gadgets.io.RequestParameters.HEADERS].Authorization = "Basic " + _config.authorization;
4439                 //Locale
4440                 params[gadgets.io.RequestParameters.HEADERS].locale = _config.locale;
4441 
4442                 //Allow clients to override the scheme:
4443                 //  - If not specified  => we use HTTP
4444                 //  - If null specified => we use _config.scheme
4445                 //  - Otherwise         => we use whatever they provide
4446                 requestedScheme = params.SCHEME; 
4447                 if (!(requestedScheme === undefined || requestedScheme === "undefined")) {
4448                     if (requestedScheme === null) {
4449                        scheme = _config.scheme;
4450                     } else {
4451                        scheme = requestedScheme;
4452                     }
4453                 }
4454                 
4455                 _log("RequestedScheme: " + requestedScheme + "; Scheme: " + scheme);
4456                 gadgets.io.makeRequest(encodeURI(scheme + "://" + _config.restHost + ":" + _config.localhostPort) + url, handler, params);
4457             },
4458 
4459             /**
4460              * @private
4461              * Utility function to make a subscription to a particular topic. Only one
4462              * callback function is registered to a particular topic at any time.
4463              * @param {String} topic
4464              *     The full topic name. The topic name should follow the OpenAjax
4465              *     convention using dot notation (ex: finesse.api.User.1000).
4466              * @param {Function} callback
4467              *     The function that should be invoked with the data when an event
4468              *     is delivered to the specific topic.
4469              * @returns {Boolean}
4470              *     True if the subscription was made successfully and the callback was
4471              *     been registered. False if the subscription already exist, the
4472              *     callback was not overwritten.
4473              */
4474             subscribe: function (topic, callback, disableDuringFailover) {
4475                 _isInited();
4476 
4477                 //Ensure that the same subscription isn't made twice.
4478                 if (!_subscriptionID[topic]) {
4479                     //Store the subscription ID using the topic name as the key.
4480                     _subscriptionID[topic] = _hub.subscribe(topic,
4481                         //Invoke the callback just with the data object.
4482                         function (topic, data) {
4483                             if (!disableDuringFailover || _isMaster || !_failoverMode) {
4484                                 // Halt all intermediate event processing while the master instance attempts to rebuild the connection. This only occurs:
4485                                 // - For RestBase objects (which pass the disableDuringFailover flag), so that intermediary events while recovering are hidden away until everything is all good
4486                                 //    - We shouldn't be halting anything else because we have infrastructure requests that use the hub pub sub
4487                                 // - Master instance will get all events regardless, because it is responsible for managing failover
4488                                 // - If we are not in a failover mode, everything goes
4489                                 // _refreshObjects will reconcile anything that was missed once we are back in action
4490                                 callback(data);
4491                             } 
4492                         });
4493                     return true;
4494                 }
4495                 return false;
4496             },
4497 
4498             /**
4499              * @private
4500              * Unsubscribe from a particular topic.
4501              * @param {String} topic
4502              *     The full topic name.
4503              */
4504             unsubscribe: function (topic) {
4505                 _isInited();
4506 
4507                 //Unsubscribe from the topic using the subscription ID recorded when
4508                 //the subscription was made, then delete the ID from data structure.
4509                 if (_subscriptionID[topic]) {
4510                     _hub.unsubscribe(_subscriptionID[topic]);
4511                     delete _subscriptionID[topic];
4512                 }
4513             },
4514 
4515             /**
4516              * @private
4517              * Make a request to the request channel to have the Master subscribe
4518              * to a node.
4519              * @param {String} node
4520              *     The node to subscribe to.
4521              */
4522             subscribeNode: function (node, handler) {
4523                 if (handler && typeof handler !== "function") {
4524                     throw new Error("ClientServices.subscribeNode: handler is not a function");
4525                 }
4526                 
4527                 // Construct the request to send to MasterPublisher through the OpenAjax Hub
4528                 var data = {
4529                     type: "SubscribeNodeReq",
4530                     data: {node: node},
4531                     invokeID: _util.generateUUID()
4532                 },
4533                 responseTopic = _topics.RESPONSES + "." + data.invokeID,
4534                 _this = this;
4535 
4536                 // We need to first subscribe to the response channel
4537                 this.subscribe(responseTopic, function (rsp) {
4538                     // Since this channel is only used for this singular request,
4539                     // we are not interested anymore.
4540                     // This is also critical to not leaking memory by having OpenAjax
4541                     // store a bunch of orphaned callback handlers that enclose on
4542                     // our entire ClientServices singleton
4543                     _this.unsubscribe(responseTopic);
4544                     if (handler) {
4545                         handler(data.invokeID, rsp);
4546                     }
4547                 });
4548                 // Then publish the request on the request channel
4549                 _hub.publish(_topics.REQUESTS, data);
4550             },
4551 
4552             /**
4553              * @private
4554              * Make a request to the request channel to have the Master unsubscribe
4555              * from a node.
4556              * @param {String} node
4557              *     The node to unsubscribe from.
4558              */
4559             unsubscribeNode: function (node, subid, handler) {
4560                 if (handler && typeof handler !== "function") {
4561                     throw new Error("ClientServices.unsubscribeNode: handler is not a function");
4562                 }
4563                 
4564                 // Construct the request to send to MasterPublisher through the OpenAjax Hub
4565                 var data = {
4566                     type: "UnsubscribeNodeReq",
4567                     data: {
4568                         node: node,
4569                         subid: subid
4570                     },
4571                     invokeID: _util.generateUUID()
4572                 },
4573                 responseTopic = _topics.RESPONSES + "." + data.invokeID,
4574                 _this = this;
4575 
4576                 // We need to first subscribe to the response channel
4577                 this.subscribe(responseTopic, function (rsp) {
4578                     // Since this channel is only used for this singular request,
4579                     // we are not interested anymore.
4580                     // This is also critical to not leaking memory by having OpenAjax
4581                     // store a bunch of orphaned callback handlers that enclose on
4582                     // our entire ClientServices singleton
4583                     _this.unsubscribe(responseTopic);
4584                     if (handler) {
4585                         handler(rsp);
4586                     }
4587                 });
4588                 // Then publish the request on the request channel
4589                 _hub.publish(_topics.REQUESTS, data);
4590             },
4591             
4592             /**
4593              * @private
4594              * Make a request to the request channel to have the Master connect to the XMPP server via BOSH
4595              */
4596             makeConnectionReq : function () {
4597                 // Disallow others (non-masters) from administering BOSH connections that are not theirs
4598                 if (_isMaster && _publisher) {
4599                     _publisher.connect(_config.id, _config.password, _config.xmppDomain);
4600                 } else {
4601                     _log("F403: Access denied. Non-master ClientService instances do not have the clearance level to make this request: makeConnectionReq");
4602                 }
4603             },
4604         
4605             /**
4606              * @private
4607              * Set's the global logger for this Client Services instance.
4608              * @param {Object} logger
4609              *     Logger object with the following attributes defined:<ul>
4610              *         <li><b>log:</b> function (msg) to simply log a message
4611              *     </ul>
4612              */
4613             setLogger: function (logger) {
4614                 // We want to check the logger coming in so we don't have to check every time it is called.
4615                 if (logger && typeof logger === "object" && typeof logger.log === "function") {
4616                     _logger = logger;
4617                 } else {
4618                     // We are resetting it to an empty object so that _logger.log in .log is falsy.
4619                     _logger = {};
4620                 }
4621             },
4622             
4623             /**
4624              * @private
4625              * Centralized logger.log method for external logger
4626              * @param {String} msg
4627              *     Message to log
4628              */
4629             log: _log,
4630 
4631             /**
4632              * @class
4633              * Allow clients to make Finesse API requests and consume Finesse events by
4634              * calling a set of exposed functions. The Services layer will do the dirty
4635              * work of establishing a shared BOSH connection (for designated Master
4636              * modules), consuming events for client subscriptions, and constructing API
4637              * requests.
4638              * 
4639              * @constructs
4640              */
4641             _fakeConstuctor: function () {
4642                 /* This is here so we can document init() as a method rather than as a constructor. */
4643             },
4644             
4645             /**
4646              * Initiates the Client Services with the specified config parameters.
4647              * Enabling the Client Services as Master will trigger the establishment
4648              * of a BOSH event connection.
4649              * @param {Object} config
4650              *     Configuration object containing properties used for making REST requests:<ul>
4651              *         <li><b>host:</b> The Finesse server IP/host as reachable from the browser
4652              *         <li><b>restHost:</b> The Finesse API IP/host as reachable from the gadget container
4653              *         <li><b>id:</b> The ID of the user. This is an optional param as long as the
4654              *         appropriate authorization string is provided, otherwise it is
4655              *         required.</li>
4656              *         <li><b>password:</b> The password belonging to the user. This is an optional param as
4657              *         long as the appropriate authorization string is provided,
4658              *         otherwise it is required.</li>
4659              *         <li><b>authorization:</b> The base64 encoded "id:password" authentication string. This
4660              *         param is provided to allow the ability to hide the password
4661              *         param. If provided, the id and the password extracted from this
4662              *         string will be used over the config.id and config.password.</li>
4663              *     </ul>
4664              * @throws {Error} If required constructor parameter is missing.
4665              * @example
4666              *      finesse.clientservices.ClientServices.init(finesse.gadget.Config);
4667              */
4668             init: function (config) {
4669                 if (!_inited) {
4670                     //Validate the properties within the config object if one is provided.
4671                     if (!(typeof config === "object" &&
4672                          typeof config.host === "string" && config.host.length > 0 && config.restHost && 
4673                          (typeof config.authorization === "string" ||
4674                                  (typeof config.id === "string" &&
4675                                          typeof config.password === "string")))) {
4676                         throw new Error("Config object contains invalid properties.");
4677                     }
4678 
4679                     // Initialize configuration
4680                     _config = config;
4681 
4682                     // Set shortcuts
4683                     _util = Utilities;
4684                     _topics = Topics;
4685                     
4686                     //TODO: document when this is properly supported
4687                     // Allows hub and io dependencies to be passed in. Currently only used for unit tests.
4688                     _hub = config.hub || gadgets.Hub;
4689                     _io = config.io || gadgets.io;
4690 
4691                     //If the authorization string is provided, then use that to
4692                     //extract the ID and the password. Otherwise use the ID and
4693                     //password from the respective ID and password params.
4694                     if (_config.authorization) {
4695                         var creds = _util.getCredentials(_config.authorization);
4696                         _config.id = creds.id;
4697                         _config.password = creds.password;
4698                     }
4699                     else {
4700                         _config.authorization = _util.b64Encode(
4701                                 _config.id + ":" + _config.password);
4702                     }
4703 
4704                     _inited = true;
4705 
4706                     if (_hub) {
4707                         //Subscribe to receive connection information. Since it is possible that
4708                         //the client comes up after the Master comes up, the client will need
4709                         //to make a request to have the Master send the latest connection info.
4710                         //It would be possible that all clients get connection info again.
4711                         this.subscribe(_topics.EVENTS_CONNECTION_INFO, _connInfoHandler);
4712                         _makeConnectionInfoReq();
4713                     }
4714                 }
4715 
4716                 //Return the CS object for object chaining.
4717                 return this;
4718             },
4719 
4720             /**
4721              * @private
4722              * Initializes the BOSH component of this ClientServices instance. This establishes
4723              * the BOSH connection and will trigger the registered handlers as the connection
4724              * status changes respectively:<ul>
4725              *     <li>registerOnConnectingHandler</li>
4726              *     <li>registerOnConnectHandler</li>
4727              *     <li>registerOnDisconnectHandler</li>
4728              *     <li>registerOnDisconnectingHandler</li>
4729              *     <li>registerOnReconnectingHandler</li>
4730              *     <li>registerOnUnloadingHandler</li>
4731              * <ul>
4732              *
4733              * @param {Object} config
4734              *     An object containing the following (optional) handlers for the request:<ul>
4735              *         <li><b>xmppDomain:</b> {String} The domain of the XMPP server. Available from the SystemInfo object.
4736              *         This is used to construct the JID: user@domain.com</li>
4737              *         <li><b>pubsubDomain:</b> {String} The pub sub domain where the pub sub service is running.
4738              *         Available from the SystemInfo object.
4739              *         This is used for creating or removing subscriptions.</li>
4740              *         <li><b>resource:</b> {String} The resource to connect to the notification server with.</li>
4741              *     </ul>
4742              */
4743             initBosh: function (config) {
4744                 //Validate the properties within the config object if one is provided.
4745                 if (!(typeof config === "object" && typeof config.xmppDomain === "string" && typeof config.pubsubDomain === "string")) {
4746                     throw new Error("Config object contains invalid properties.");
4747                 }
4748                 
4749                 // Mixin the required information for establishing the BOSH connection
4750                 _config.xmppDomain = config.xmppDomain;
4751                 _config.pubsubDomain = config.pubsubDomain;
4752                 _config.resource = config.resource;
4753                 
4754                 //Initiate Master launch sequence
4755                 _becomeMaster(); 
4756             },
4757 
4758             /**
4759              * @private
4760              * Sets the failover mode to either FAILING or RECOVERED. This will only occur in the master instance and is meant to be
4761              * used by a stereotypical failover monitor type module to notify non-master instances (i.e. in gadgets)
4762              * @param {Object} failoverMode
4763              *     true if failing, false or something falsy when recovered
4764              */
4765             setFailoverMode: function (failoverMode) {
4766                 if (_isMaster) {
4767                     _hub.publish(_topics.EVENTS_CONNECTION_INFO, {
4768                         status: (failoverMode ? _STATUS.FAILING : _STATUS.RECOVERED)
4769                     });
4770                 }
4771             },
4772 
4773             /**
4774              * @private
4775              * Private accessor used to inject mocked private dependencies for unit testing
4776              */
4777             _getTestObj: function () {
4778                 return {
4779                     setPublisher: function (publisher) {
4780                         _publisher = publisher;
4781                     }
4782                 };
4783             }
4784         };
4785     }());
4786      
4787     window.finesse = window.finesse || {};
4788     window.finesse.clientservices = window.finesse.clientservices || {};
4789     window.finesse.clientservices.ClientServices = ClientServices;
4790     
4791     return ClientServices;
4792 
4793 }));
4794 
4795 /**
4796  * The following comment prevents JSLint errors concerning undefined global variables.
4797  * It tells JSLint that these identifiers are defined elsewhere.
4798  */
4799 /*jslint bitwise:true, browser:true, nomen:true, regexp:true, sloppy:true, white:true */
4800 
4801 /** The following comment is to prevent jslint errors about 
4802  * using variables before they are defined.
4803  */
4804 /*global Handlebars */
4805 
4806 /**
4807  * JavaScript class to implement common notification
4808  *               functionality.
4809  * 
4810  * @requires Class
4811  * @requires finesse.FinesseBase
4812  */
4813 /** @private */
4814  (function (factory) {
4815     
4816 
4817     // Define as an AMD module if possible
4818     if ( typeof define === 'function' && define.amd )
4819     {
4820         define('restservices/Notifier',['FinesseBase',
4821                 'clientservices/ClientServices'], factory );
4822     }
4823     
4824     /* Define using browser globals otherwise
4825      * Prevent multiple instantiations if the script is loaded twice
4826      */
4827     else
4828     {
4829         factory(finesse.FinesseBase, finesse.clientservices.ClientServices);
4830     }   
4831 }(function (FinesseBase, ClientServices) {
4832 	var Notifier = FinesseBase.extend({
4833 		/**
4834          * Initializes the notifier object.
4835          */
4836         init : function () {
4837             this._super();
4838             this._listenerCallback = [];
4839         },
4840 
4841         /**
4842          * Add a listener.
4843          * 
4844          * @param callback_function
4845          * @param scope
4846          *            is the callback function to add
4847          */
4848         addListener : function (callback_function, scope) {
4849             var len = this._listenerCallback.length, i, cb, add = true;
4850             for (i = 0; i < len; i += 1) {
4851                 cb = this._listenerCallback[i].callback;
4852                 if (cb === callback_function) {
4853                     // this callback already exists
4854                     add = false;
4855                     break;
4856                 }
4857             }
4858             if (add) {
4859                 this._listenerCallback.push({ "callback": this._isAFunction(callback_function), "scope": (scope || window) });
4860             }            
4861         },
4862 
4863         /**
4864          * Remove a listener.
4865          * 
4866          * @param callback_function
4867          *            is the callback function to remove
4868          * @return {Boolean} true if removed
4869          */
4870         removeListener : function (callback_function) {
4871 
4872             var result = false, len = this._listenerCallback.length, i, cb;
4873             for (i = len - 1; i >= 0; i -=1) {
4874                 cb = this._listenerCallback[i].callback;
4875                 if (cb === callback_function) {
4876                     this._listenerCallback[i] = undefined;
4877                     this._listenerCallback.splice(i, 1);
4878                     result = true;
4879                     break;
4880                 }
4881             }
4882             
4883             return result;
4884         },
4885 
4886         /**
4887 	 * Removes all listeners
4888 	 * @return {undefined}
4889 	 */
4890 	reset: function () {
4891 		this._listenerCallback = [];
4892 	},
4893 
4894 	/**
4895          * Notify all listeners.
4896          * 
4897          * @param obj
4898          *            is the object that has changed
4899          */
4900         notifyListeners : function (obj) {
4901             var len = this._listenerCallback.length, i, callbackFunction, scope;
4902 
4903             for (i = 0; i < len; i += 1) {
4904                 // Be sure that one bad callback does not prevent other listeners
4905                 // from receiving.
4906                 try {
4907                     callbackFunction = this._listenerCallback[i].callback;
4908                     scope = this._listenerCallback[i].scope;
4909                     if (typeof callbackFunction === 'function') {
4910                         callbackFunction.call(scope, obj);
4911                     }
4912                 } catch (err) {
4913                     ClientServices.log("Exception caught: " + err);
4914                 }
4915             }
4916         },
4917 
4918         /**
4919          * Gets a copy of the listeners.
4920          * @return changeListenerCopy (array of callbacks)
4921          */
4922         getListeners : function () {
4923             var changeListenerCopy = [], len = this._listenerCallback.length, i;
4924 
4925             for (i = 0; i < len; i += 1) {
4926                 changeListenerCopy.push(this._listenerCallback[i].callback);
4927             }
4928 
4929             return changeListenerCopy;
4930         },
4931         
4932         /**
4933          * Verifies that the handler is function.
4934          * @param handler to verify
4935          * @return the handler 
4936          * @throws Error if not a function
4937          */
4938         _isAFunction : function (handler) {
4939             if (handler === undefined || typeof handler === "function") {
4940                 return handler;
4941             } else {
4942                 throw new Error("handler must be a function");
4943             }
4944         }
4945 	});
4946 	
4947 	window.finesse = window.finesse || {};
4948 	window.finesse.restservices = window.finesse.restservices || {};
4949 	window.finesse.restservices.Notifier = Notifier;
4950 
4951 	/** @namespace JavaScript classes and methods that represent REST objects and collections. */
4952     finesse.restservices = finesse.restservices || {};
4953 	
4954 	return Notifier;
4955 }));
4956 
4957 /**
4958  * JavaScript base object that all REST objects should inherit
4959  * from because it encapsulates and provides the common functionality that
4960  * all REST objects need.
4961  *
4962  * @requires finesse.clientservices.ClientServices
4963  * @requires Class
4964  */
4965 
4966 /** @private */
4967 (function (factory) {
4968     
4969 
4970     // Define as an AMD module if possible
4971     if ( typeof define === 'function' && define.amd )
4972     {
4973         define('restservices/RestBase', ["FinesseBase",
4974                  "utilities/Utilities",
4975                  "restservices/Notifier",
4976                  "clientservices/ClientServices",
4977                  "clientservices/Topics"], factory );
4978     }
4979     /* Define using browser globals otherwise
4980      * Prevent multiple instantiations if the script is loaded twice
4981      */
4982     else
4983     {
4984         factory(finesse.FinesseBase, finesse.utilities.Utilities,
4985                 finesse.restservices.Notifier,
4986                 finesse.clientservices.ClientServices,
4987                 finesse.clientservices.Topics);
4988     } 
4989 }(function (FinesseBase, Utilities, Notifier, ClientServices, Topics) {
4990     
4991     var RestBase = FinesseBase.extend(/** @lends finesse.restservices.RestBase.prototype */{
4992 
4993         doNotLog: false,        
4994 
4995         /**
4996          * Used by _processUpdate() and restRequest().
4997          * Maps requestIds to object-wrapped callbacks passed to restRequest(),
4998          * so that one of the callbacks can be fired when a corresponding event is
4999          * received inside _processUpdate().
5000          * @private
5001          */
5002         _pendingCallbacks: {},
5003         
5004         /**
5005          * Gets the REST class for the current object.  This object throws an
5006          * exception because subtype must implement.
5007          * @throws {Error} because subtype must implement
5008          * @private
5009          */
5010         getRestClass: function () {
5011             throw new Error("getRestClass(): Not implemented in subtype.");
5012         },
5013 
5014         /**
5015          * Gets the REST type for the current object.  This object throws an
5016          * exception because subtype must implement.
5017          * @throws {Error} because subtype must implement.
5018          * @private
5019          */
5020         getRestType: function () {
5021             throw new Error("getRestType(): Not implemented in subtype.");
5022         },
5023 
5024         /**
5025          * Gets the node path for the current object.  This object throws an
5026          * exception because subtype must implement.
5027          * @throws {Error} because subtype must implement.
5028          * @private
5029          */
5030         getXMPPNodePath: function () {
5031             throw new Error("getXMPPNodePath(): Not implemented in subtype.");
5032         },
5033         
5034         /**
5035          * Boolean function that specifies whether the REST object supports
5036          * requests. True by default. Subclasses should override if false.
5037          * @private
5038          */
5039         supportsRequests: true,
5040 
5041         /**
5042          * Boolean function that specifies whether the REST object supports
5043          * subscriptions. True by default. Subclasses should override if false.
5044          * @private
5045          */
5046         supportsSubscriptions: true,
5047         
5048         /**
5049          * Boolean function that specifies whether the REST object should retain
5050          * a copy of the REST response. False by default. Subclasses should override if true.
5051          * @private
5052          */
5053         keepRestResponse: false,
5054 
5055         /**
5056          * Boolean function that specifies whether the REST object explicitly
5057          * subscribes. False by default. Subclasses should override if true.
5058          * @private
5059          */
5060         explicitSubscription: false,
5061 
5062         /**
5063          * Boolean function that specifies whether subscribing should be
5064          * automatically done at construction. Defaults to true.
5065          * This be overridden at object construction, not by implementing subclasses
5066          * @private
5067          */
5068         autoSubscribe: true,
5069         
5070         /**
5071          * Private reference to default logger
5072          * @private
5073          */
5074         _logger: {
5075             log: ClientServices.log,
5076             error: ClientServices.log
5077         },
5078 
5079         /**
5080          * @class
5081          * JavaScript representation of a REST object. Also exposes methods to operate
5082          * on the object against the server.  This object is typically extended into individual
5083          * REST Objects (like Dialog, User, etc...), and shouldn't be used directly.
5084          *
5085          * @constructor
5086          * @param {String} id
5087          *     The ID that uniquely identifies the REST object.
5088          * @param {Object} callbacks
5089          *     An object containing callbacks for instantiation and runtime
5090          *     Callback to invoke upon successful instantiation, passes in REST object.
5091          * @param {Function} callbacks.onLoad(this)
5092          *     Callback to invoke upon loading the data for the first time.
5093          * @param {Function} callbacks.onChange(this)
5094          *     Callback to invoke upon successful update object (PUT)
5095          * @param {Function} callbacks.onAdd(this)
5096          *     Callback to invoke upon successful update to add object (POST)
5097          * @param {Function} callbacks.onDelete(this)
5098          *     Callback to invoke upon successful update to delete object (DELETE)
5099          * @param {Function} callbacks.onError(rsp)
5100          *     Callback to invoke on update error (refresh or event)
5101          *     as passed by finesse.restservices.RestBase.restRequest()
5102          *     {
5103          *         status: {Number} The HTTP status code returned
5104          *         content: {String} Raw string of response
5105          *         object: {Object} Parsed object of response
5106          *         error: {Object} Wrapped exception that was caught
5107          *         error.errorType: {String} Type of error that was caught
5108          *         error.errorMessage: {String} Message associated with error
5109          *     }
5110          * @param {RestBase} [restObj]
5111          *     A RestBase parent object which this object has an association with.
5112          * @constructs
5113          */
5114         init: function (options, callbacks, restObj) {
5115             /**
5116               * Initialize the base class
5117               */
5118             var _this = this;
5119 
5120             this._super();
5121 
5122             if (typeof options === "object") {
5123                 this._id = options.id;
5124                 this._restObj = options.parentObj;
5125                 this.autoSubscribe = (options.autoSubscribe === false) ? false : true;
5126                 this.doNotSubscribe = options.doNotSubscribe;
5127                 callbacks = {
5128                     onLoad: options.onLoad,
5129                     onChange: options.onChange,
5130                     onAdd: options.onAdd,
5131                     onDelete: options.onDelete,
5132                     onError: options.onError
5133                 };
5134             } else {
5135                 this._id = options;
5136                 this._restObj = restObj;
5137             }
5138             
5139             // Common stuff
5140             
5141             this._data = {};
5142             
5143             //Contains the full rest response to be processed by upper layers if needed
5144             this._restResponse = undefined;
5145 
5146             this._lastUpdate = {};
5147 
5148             this._util = Utilities;
5149 
5150             //Should be correctly initialized in either a window OR gadget context
5151             this._config = finesse.container.Config;
5152 
5153             // Setup all the notifiers - change, load and error.
5154             this._changeNotifier = new Notifier();
5155             this._loadNotifier = new Notifier();
5156             this._addNotifier = new Notifier();
5157             this._deleteNotifier = new Notifier();
5158             this._errorNotifier = new Notifier();
5159 
5160             this._loaded = false;
5161 
5162             // Protect against null dereferencing of options allowing its
5163             // (nonexistent) keys to be read as undefined
5164             callbacks = callbacks || {};
5165 
5166             this.addHandler('load', callbacks.onLoad);
5167             this.addHandler('change', callbacks.onChange);
5168             this.addHandler('add', callbacks.onAdd);
5169             this.addHandler('delete', callbacks.onDelete);
5170             this.addHandler('error', callbacks.onError);
5171 
5172             // Attempt to get the RestType then synchronize
5173             try {
5174                 this.getRestType();
5175 
5176                 // Only subscribe if this REST object supports subscriptions
5177                 // and autoSubscribe was not requested to be disabled as a construction option
5178                 if (this.supportsSubscriptions && this.autoSubscribe && !this.doNotSubscribe) {
5179                     this.subscribe({
5180                         success: function () {
5181                             //TODO: figure out how to use Function.call() or Function.apply() here...
5182                             //this is exactly the same as the below else case other than the scope of "this"
5183                             if (typeof options === "object" && options.data) {
5184                                 if (!_this._processObject(_this._normalize(options.data))) {
5185                                     // notify of error if we fail to construct
5186                                     _this._errorNotifier.notifyListeners(_this);
5187                                 }
5188                             } else {
5189                                 // Only subscribe if this REST object supports requests
5190                                 if (_this.supportsRequests) {
5191                                     _this._synchronize();
5192                                 }
5193                             }
5194                         },
5195                         error: function (err) {
5196                             _this._errorNotifier.notifyListeners(err);
5197                         }
5198                     });
5199                 } else {
5200                     if (typeof options === "object" && options.data) {
5201                         if (!this._processObject(this._normalize(options.data))) {
5202                             // notify of error if we fail to construct
5203                             this._errorNotifier.notifyListeners(this);
5204                         }
5205                     } else {
5206                         // Only subscribe if this REST object supports requests
5207                         if (this.supportsRequests) {
5208                             this._synchronize();
5209                         }
5210                     }
5211                 }
5212 
5213             } catch (err) {
5214                 this._logger.error('id=' + this._id + ': ' + err);
5215             }
5216         },
5217 
5218         /**
5219          * Determines if the object has a particular property.
5220          * @param obj is the object to examine
5221          * @param property is the property to check for
5222          * @returns {Boolean}
5223          */
5224         hasProperty: function (obj, prop) {
5225             return (obj !== null) && (obj.hasOwnProperty(prop));
5226         },
5227 
5228         /**
5229          * Gets a property from the object.
5230          * @param obj is the object to examine
5231          * @param property is the property to get
5232          * @returns {Property Value} or {Null} if not found
5233          */
5234         getProperty: function (obj, property) {
5235             var result = null;
5236 
5237             if (this.hasProperty(obj, property) === false) {
5238                 result = null;
5239             } else {
5240                 result = obj[property];
5241             }
5242             return result;
5243         },
5244 
5245         /**
5246          * Utility to extracts the ID from the specified REST URI. This is with the
5247          * assumption that the ID is always the last element in the URI after the
5248          * "/" delimiter.
5249          * @param {String} restUri
5250          *     The REST uri (i.e. /finesse/api/User/1000).
5251          * @private
5252          */
5253         _extractId: function (restObj) {
5254             var obj, restUri = "", strLoc;
5255             for (obj in restObj) {
5256                 if (restObj.hasOwnProperty(obj)) {
5257                     restUri = restObj[obj].uri;
5258                     break;
5259                 }
5260             }
5261             return Utilities.getId(restUri);
5262         },
5263 
5264         /**
5265          * Gets the data for this object.
5266          * @returns {Object} which is contained in data
5267          */
5268         getData: function () {
5269             return this._data;
5270         },
5271         
5272         /**
5273          * Gets the complete REST response to the request made
5274          * @returns {Object} which is contained in data
5275          * @private
5276          */
5277         getRestResponse: function () {
5278             return this._restResponse;
5279         },
5280 
5281         /**
5282          * The REST URL in which this object can be referenced.
5283          * @return {String}
5284          *     The REST URI for this object.
5285          * @private
5286          */
5287         getRestUrl: function () {
5288             var
5289             restObj = this._restObj,
5290             restUrl = "";
5291 
5292             //Prepend the base REST object if one was provided.
5293             if (restObj instanceof RestBase) {
5294                 restUrl += restObj.getRestUrl();
5295             }
5296             //Otherwise prepend with the default webapp name.
5297             else {
5298                 restUrl += "/finesse/api";
5299             }
5300 
5301             //Append the REST type.
5302             restUrl += "/" + this.getRestType();
5303 
5304             //Append ID if it is not undefined, null, or empty.
5305             if (this._id) {
5306                 restUrl += "/" + this._id;
5307             }
5308             return restUrl;
5309         },
5310 
5311         /**
5312          * Getter for the id of this RestBase
5313          * @returns {String}
5314          *     The id of this RestBase
5315          */
5316         getId: function () {
5317             return this._id;
5318         },
5319 
5320         /**
5321          * Synchronize this object with the server using REST GET request.
5322          * @private
5323          */
5324         _synchronize: function (retries) {
5325             // Fetch this REST object
5326             if (typeof this._id === "string") {
5327                 var _this = this, isLoaded = this._loaded, _RETRY_INTERVAL = 10 * 1000;
5328 
5329                 this._doGET(
5330                     {
5331                         success: function (rsp) {
5332                             if (!_this._processResponse(rsp)) {
5333                                 if (retries > 0) {
5334                                     setTimeout(function () {
5335                                         _this._synchronize(retries - 1);
5336                                     }, _RETRY_INTERVAL);
5337                                 } else {
5338                                     _this._errorNotifier.notifyListeners(_this);
5339                                 }
5340                             } else {
5341                                 // If this object was already "loaded" prior to
5342                                 // the _doGET request, then call the
5343                                 // changeNotifier
5344                                 if (isLoaded) {
5345                                     _this._changeNotifier.notifyListeners(_this);
5346                                 }
5347                             }
5348                         },
5349                         error: function (rsp) {
5350                             if (retries > 0) {
5351                                 setTimeout(function () {
5352                                     _this._synchronize(retries - 1);
5353                                 }, _RETRY_INTERVAL);
5354                                 
5355                             } else {
5356                                 _this._errorNotifier.notifyListeners(rsp);
5357                             }
5358                         }
5359                     }
5360                 );
5361 
5362             } else {
5363                 throw new Error("Can't construct a <" + this.getRestType() + "> due to invalid id type.");
5364             }
5365         },
5366 
5367         /**
5368          * Adds an handler to this object.
5369          * If notifierType is 'load' and the object has already loaded, the callback is invoked immediately
5370          * @param {String} notifierType
5371          *     The type of notifier to add to ('load', 'change', 'add', 'delete', 'error')
5372          * @param {Function} callback
5373          *     The function callback to invoke.
5374          * @example
5375          *   // Handler for additions to the Dialogs collection object.  
5376          *   // When Dialog (a RestBase object) is created, add a change handler.
5377          *   _handleDialogAdd = function(dialog) {
5378          *      dialog.addHandler('change', _handleDialogChange);
5379          *   }
5380          */
5381         addHandler: function (notifierType, callback, scope) {
5382             var notifier = null;
5383             try {
5384                 Utilities.validateHandler(callback);
5385 
5386                 notifier = this._getNotifierReference(notifierType);
5387 
5388                 notifier.addListener(callback, scope);
5389                 
5390                 // If load handler is added and object has
5391                 // already been loaded, invoke callback
5392                 // immediately
5393                 if (notifierType === 'load' && this._loaded) {
5394                     callback.call((scope || window), this);
5395                 }
5396             } catch (err) {
5397                 this._logger.error('id=' + this._id + ': ' + err);
5398             }
5399         },
5400 
5401         /**
5402          * Removes a handler from this object.
5403          * @param {String} notifierType
5404          *     The type of notifier to remove ('load', 'change', 'add', 'delete', 'error')
5405          * @param {Function} callback
5406          *     The function to remove.
5407          */
5408         removeHandler: function (notifierType, callback) {
5409             var notifier = null;
5410             try {
5411                 Utilities.validateHandler(callback);
5412 
5413                 notifier = this._getNotifierReference(notifierType);
5414 
5415                 if (typeof(callback) === "undefined")
5416                 {
5417                     // Remove all listeners for the type
5418                     notifier.reset();
5419                 }
5420                 else
5421                 {
5422                     // Remove the specified listener
5423                     finesse.utilities.Utilities.validateHandler(callback);
5424                     notifier.removeListener(callback);
5425                 }
5426             } catch (err) {
5427                 this._logger.error('id=' + this._id + ': ' + err);
5428             }
5429         },
5430 
5431         /**
5432          * Utility method gating any operations that require complete instantiation
5433          * @throws Error
5434          *     If this object was not fully instantiated yet
5435          * @returns {finesse.restservices.RestBase}
5436          *     This RestBase object to allow cascading
5437          */
5438         isLoaded: function () {
5439             if (!this._loaded) {
5440                 throw new Error("Cannot operate on object that is not fully instantiated, use onLoad/onLoadError handlers");
5441             }
5442             return this; // Allow cascading
5443         },
5444 
5445 
5446         /**
5447          * Force an update on this object. Since an asynchronous GET is performed,
5448          * it is necessary to have an onChange handler registered in order to be
5449          * notified when the response of this returns.
5450          * @param {Integer} retries
5451          *    The number or retry attempts to make.
5452          * @returns {finesse.restservices.RestBase}
5453          *     This RestBase object to allow cascading
5454          */
5455         refresh: function (retries) {
5456             //Disallow GETs if object doesn't support it.
5457             if (!this.supportsRequests) {
5458                 throw new Error("Object doesn't support request operations.");
5459             }
5460 
5461             this._synchronize(retries);
5462 
5463             return this; // Allow cascading
5464         },
5465 
5466         /**
5467          * Utility method to validate against the known schema of this RestBase
5468          * @param {Object} obj
5469          *     The object to validate
5470          * @returns {Boolean}
5471          *     True if the object fits the schema of this object. This usually
5472          *     means all required keys or nested objects are present.
5473          *     False otherwise.
5474          * @private
5475          */
5476         _validate: function (obj) {
5477             var valid = (typeof obj === "object" && this.hasProperty(obj, this.getRestType()));
5478             if (!valid)
5479             {
5480                 this._logger.error(this.getRestType() + " failed validation! Does your JS REST class return the correct string from getRestType()?");
5481             }
5482             return valid;
5483         },
5484 
5485         /**
5486          * Utility method to fetch this RestBase from the server
5487          * @param {finesse.interfaces.RequestHandlers} handlers
5488          *     An object containing the handlers for the request
5489          * @returns {finesse.restservices.RestBase}
5490          *     This RestBase object to allow cascading
5491          * @private
5492          */
5493         _doGET: function (handlers) {
5494             this.restRequest(this.getRestUrl(), handlers);
5495             return this; // Allow cascading
5496         },
5497 
5498         /**
5499          * Common update event handler used by the pubsub callback closure.
5500          * Processes the update event then notifies listeners.
5501          * @param {Object} scope
5502          *     An object containing callbacks to handle the asynchronous get
5503          * @param {Object} update
5504          *     An object containing callbacks to handle the asynchronous get
5505          * @private
5506          */
5507         _updateEventHandler: function (scope, update) {
5508             if (scope._processUpdate(update)) {
5509                 switch (update.object.Update.event) {
5510                 case "POST":
5511                     scope._addNotifier.notifyListeners(scope);
5512                     break;
5513                 case "PUT":
5514                     scope._changeNotifier.notifyListeners(scope);
5515                     break;
5516                 case "DELETE":
5517                     scope._deleteNotifier.notifyListeners(scope);
5518                     break;
5519                 }
5520             }   
5521         },
5522 
5523         /**
5524          * Utility method to create a callback to be given to OpenAjax to invoke when a message
5525          * is published on the topic of our REST URL (also XEP-0060 node).
5526          * This needs to be its own defined method so that subclasses can have their own implementation.
5527          * @returns {Function} callback(update)
5528          *     The callback to be invoked when an update event is received. This callback will
5529          *     process the update and notify listeners.
5530          * @private
5531          */
5532         _createPubsubCallback: function () {
5533             var _this = this;
5534             return function (update) {
5535                 _this._updateEventHandler(_this, update);
5536             };
5537         },
5538 
5539         /**
5540          * Subscribe to pubsub infra using the REST URL as the topic name.
5541          * @param {finesse.interfaces.RequestHandlers} handlers
5542          *     An object containing the handlers for the request
5543          * @private
5544          */
5545         subscribe: function (callbacks) {
5546             // Only need to do a subscription to client pubsub. No need to trigger
5547             // a subscription on the Finesse server due to implicit subscribe (at
5548             // least for now).
5549             var _this = this,
5550             topic = Topics.getTopic(this.getRestUrl()),
5551             handlers,
5552             successful = ClientServices.subscribe(topic, this._createPubsubCallback(), true);
5553 
5554             callbacks = callbacks || {};
5555 
5556             handlers = {
5557                 /** @private */
5558                 success: function () {
5559                     // Add item to the refresh list in ClientServices to refresh if
5560                     // we recover due to our resilient connection. However, do
5561                     // not add if doNotRefresh flag is set.
5562                     if (!_this.doNotRefresh) {
5563                         ClientServices.addToRefreshList(_this);
5564                     }
5565 
5566                     if (typeof callbacks.success === "function") {
5567                         callbacks.success();
5568                     }
5569                 },
5570                 /** @private */
5571                 error: function (err) {
5572                     if (successful) {
5573                         ClientServices.unsubscribe(topic);
5574                     }
5575 
5576                     if (typeof callbacks.error === "function") {
5577                         callbacks.error(err);
5578                     }
5579                 }
5580             };
5581 
5582             // Request a node subscription only if this object requires explicit subscriptions
5583             if (this.explicitSubscription === true) {
5584                 this._subscribeNode(handlers);
5585             } else {
5586                 if (successful) {
5587                     this._subid = "OpenAjaxOnly";
5588                     handlers.success();
5589                 } else {
5590                     handlers.error();
5591                 }
5592             }
5593 
5594             return this;
5595         },
5596 
5597         /**
5598          * Unsubscribe to pubsub infra using the REST URL as the topic name.
5599          * @param {finesse.interfaces.RequestHandlers} handlers
5600          *     An object containing the handlers for the request
5601          * @private
5602          */
5603         unsubscribe: function (callbacks) {
5604             // Only need to do a subscription to client pubsub. No need to trigger
5605             // a subscription on the Finesse server due to implicit subscribe (at
5606             // least for now).
5607             var _this = this,
5608             topic = Topics.getTopic(this.getRestUrl()),
5609             handlers;
5610 
5611             // no longer keep track of object to refresh on reconnect
5612             ClientServices.removeFromRefreshList(_this);
5613 
5614             callbacks = callbacks || {};
5615 
5616             handlers = {
5617                 /** @private */
5618                 success: function () {
5619                     if (typeof callbacks.success === "function") {
5620                         callbacks.success();
5621                     }
5622                 },
5623                 /** @private */
5624                 error: function (err) {
5625                     if (typeof callbacks.error === "function") {
5626                         callbacks.error(err);
5627                     }
5628                 }
5629             };
5630 
5631             if (this._subid) {
5632                 ClientServices.unsubscribe(topic);
5633                 // Request a node unsubscribe only if this object requires explicit subscriptions
5634                 if (this.explicitSubscription === true) {
5635                     this._unsubscribeNode(handlers);
5636                 } else {
5637                     this._subid = undefined;
5638                     handlers.success();
5639                 }
5640             } else {
5641                 handlers.success();
5642             }
5643 
5644             return this;
5645         },
5646 
5647         /**
5648          * Private utility to perform node subscribe requests for explicit subscriptions
5649          * @param {finesse.interfaces.RequestHandlers} handlers
5650          *     An object containing the handlers for the request
5651          * @private
5652          */
5653         _subscribeNode: function (callbacks) {
5654             var _this = this;
5655 
5656             // Protect against null dereferencing of callbacks allowing its (nonexistent) keys to be read as undefined
5657             callbacks = callbacks || {};
5658 
5659             ClientServices.subscribeNode(this.getXMPPNodePath(), function (subid, err) {
5660                 if (err) {
5661                     if (typeof callbacks.error === "function") {
5662                         callbacks.error(err);
5663                     }
5664                 } else {
5665                     // Store the subid on a successful subscribe
5666                     _this._subid = subid;
5667                     if (typeof callbacks.success === "function") {
5668                         callbacks.success();
5669                     }
5670                 }
5671             });
5672         },
5673 
5674         /**
5675          * Private utility to perform node unsubscribe requests for explicit subscriptions
5676          * @param {finesse.interfaces.RequestHandlers} handlers
5677          *     An object containing the handlers for the request
5678          * @private
5679          */
5680         _unsubscribeNode: function (callbacks) {
5681             var _this = this;
5682 
5683             // Protect against null dereferencing of callbacks allowing its (nonexistent) keys to be read as undefined
5684             callbacks = callbacks || {};
5685 
5686             ClientServices.unsubscribeNode(this.getXMPPNodePath(), this._subid, function (err) {
5687                 _this._subid = undefined;
5688                 if (err) {
5689                     if (typeof callbacks.error === "function") {
5690                         callbacks.error(err);
5691                     }
5692                 } else {
5693                     if (typeof callbacks.success === "function") {
5694                         callbacks.success();
5695                     }
5696                 }
5697             });
5698         },
5699 
5700         /**
5701          * Validate and store the object into the internal data store.
5702          * @param {Object} object
5703          *     The JavaScript object that should match of schema of this REST object.
5704          * @returns {Boolean}
5705          *     True if the object was validated and stored successfully.
5706          * @private
5707          */
5708         _processObject: function (object) {
5709             if (this._validate(object)) {
5710                 this._data = this.getProperty(object, this.getRestType()); // Should clone the object here?
5711 
5712                 // If loaded for the first time, call the load notifiers.
5713                 if (!this._loaded) {
5714                     this._loaded = true;
5715                     this._loadNotifier.notifyListeners(this);
5716                 }
5717 
5718                 return true;
5719             }
5720             return false;
5721         },
5722 
5723         /**
5724          * Normalize the object to mitigate the differences between the backend
5725          * and what this REST object should hold. For example, the backend sends
5726          * send an event with the root property name being lower case. In order to
5727          * match the GET, the property should be normalized to an upper case.
5728          * @param {Object} object
5729          *     The object which should be normalized.
5730          * @returns {Object}
5731          *     Return the normalized object.
5732          * @private
5733          */
5734         _normalize: function (object) {
5735             var
5736             restType = this.getRestType(),
5737             // Get the REST object name with first character being lower case.
5738             objRestType = restType.charAt(0).toLowerCase() + restType.slice(1);
5739 
5740             // Normalize payload to match REST object. The payload for an update
5741             // use a lower case object name as oppose to upper case. Only normalize
5742             // if necessary.
5743             if (!this.hasProperty(object, restType) && this.hasProperty(object, objRestType)) {
5744                 //Since the object is going to be modified, clone the object so that
5745                 //it doesn't affect others (due to OpenAjax publishing to other
5746                 //subscriber.
5747                 object = jQuery.extend(true, {}, object);
5748 
5749                 object[restType] = object[objRestType];
5750                 delete(object[objRestType]);
5751             }
5752             return object;
5753         },
5754 
5755         /**
5756          * Utility method to process the response of a successful get
5757          * @param {Object} rsp
5758          *     The response of a successful get
5759          * @returns {Boolean}
5760          *     True if the update was successfully processed (the response object
5761          *     passed the schema validation) and updated the internal data cache,
5762          *     false otherwise.
5763          * @private
5764          */
5765         _processResponse: function (rsp) {
5766             try {
5767                 if (this.keepRestResponse) {
5768                     this._restResponse = rsp.content;
5769                 }
5770                 return this._processObject(rsp.object);
5771             }
5772             catch (err) {
5773                 this._logger.error(this.getRestType() + ': ' + err);
5774             }
5775             return false;
5776         },
5777 
5778         /**
5779          * Utility method to process the update notification.
5780          * @param {Object} update
5781          *     The payload of an update notification.
5782          * @returns {Boolean}
5783          *     True if the update was successfully processed (the update object
5784          *     passed the schema validation) and updated the internal data cache,
5785          *     false otherwise.
5786          * @private
5787          */
5788         _processUpdate: function (update) {
5789             try {
5790                 var updateObj, requestId, fakeResponse, receivedError;
5791 
5792                 // The backend will send the data object with a lower case. To be
5793                 // consistent with what should be represented in this object, the
5794                 // object name should be upper case. This will normalize the object.
5795                 updateObj = this._normalize(update.object.Update.data);
5796 
5797                 // Store the last event.
5798                 this._lastUpdate = update.object;
5799 
5800                 requestId = this._lastUpdate.Update ? this._lastUpdate.Update.requestId : undefined;
5801 
5802                 if (requestId && this._pendingCallbacks[requestId]) {
5803 
5804                     /*
5805                      * The passed success/error callbacks are expecting to be passed an AJAX response, so construct
5806                      * a simulated/"fake" AJAX response object from the information in the received event.
5807                      * The constructed object should conform to the contract for response objects specified
5808                      * in _createAjaxHandler().
5809                      */
5810                     fakeResponse = {};
5811 
5812                     //The contract says that rsp.content should contain the raw text of the response so we simulate that here.
5813                     //For some reason json2xml has trouble with the native update object, so we serialize a clone of it by
5814                     //doing a parse(stringify(update)).
5815                     fakeResponse.content = this._util.json2xml(gadgets.json.parse(gadgets.json.stringify(update)));
5816 
5817                     fakeResponse.object = {};
5818 
5819                     if (updateObj.apiErrors && updateObj.apiErrors.apiError) { //Error case
5820 
5821                         //TODO: The lowercase -> uppercase ApiErrors translation method below is undesirable, can it be improved?
5822                         receivedError = updateObj.apiErrors.apiError;
5823                         fakeResponse.object.ApiErrors = {};
5824                         fakeResponse.object.ApiErrors.ApiError = {};
5825                         fakeResponse.object.ApiErrors.ApiError.ErrorData = receivedError.errorData || undefined;
5826                         fakeResponse.object.ApiErrors.ApiError.ErrorMessage = receivedError.errorMessage || undefined;
5827                         fakeResponse.object.ApiErrors.ApiError.ErrorType = receivedError.errorType || undefined;
5828 
5829                         /*
5830                          * Since this is the error case, supply the error callback with a '400 BAD REQUEST' status code. We don't know what the real
5831                          * status code should be since the event we're constructing fakeResponse from doesn't include a status code.
5832                          * This is just to conform to the contract for the error callback in _createAjaxHandler().
5833                          **/
5834                         fakeResponse.status = 400;
5835 
5836                     } else { //Success case
5837 
5838                         fakeResponse.object = this._lastUpdate;
5839 
5840                         /*
5841                          * Since this is the success case, supply the success callback with a '200 OK' status code. We don't know what the real
5842                          * status code should be since the event we're constructing fakeResponse from doesn't include a status code.
5843                          * This is just to conform to the contract for the success callback in _createAjaxHandler().
5844                          **/
5845                         fakeResponse.status = 200;
5846                     }
5847 
5848                     try {
5849 
5850                         if (fakeResponse.object.ApiErrors && this._pendingCallbacks[requestId].error) {
5851                             this._pendingCallbacks[requestId].error(fakeResponse);
5852                         } 
5853                         // HTTP 202 is handled as a success, besides, we cannot infer that a non-error is a success.
5854                         /*else if (this._pendingCallbacks[requestId].success) {
5855                             this._pendingCallbacks[requestId].success(fakeResponse);
5856                         }*/
5857 
5858                     } catch (callbackErr) {
5859 
5860                         this._logger.error(this.getRestType() + ": Caught error while firing callback: " + callbackErr);
5861 
5862                     }
5863 
5864                     //Clean up _pendingCallbacks now that we fired a callback corresponding to the received requestId.
5865                     delete this._pendingCallbacks[requestId];
5866 
5867                 } else {
5868                     this._logger.log(this.getRestType() + ": Received the following event with an invalid or unknown requestId:");
5869                     this._logger.log(gadgets.json.stringify(update));
5870                 }
5871 
5872                 return this._processObject(updateObj);
5873             }
5874             catch (err) {
5875                 this._logger.error(this.getRestType() + ': ' + err);
5876             }
5877             return false;
5878         },
5879 
5880         /**
5881          * Utility method to create ajax response handler closures around the
5882          * provided callbacks. Callbacks should be passed through from .ajax().
5883          * makeRequest is responsible for garbage collecting these closures.
5884          * @param {finesse.interfaces.RequestHandlers} handlers
5885          *     An object containing the handlers for the request
5886          * @private
5887          */
5888         _createAjaxHandler: function (options) {
5889             //We should not need to check this again since it has already been done in .restRequest()
5890             //options = options || {};
5891 
5892             //Get a reference to the parent User object
5893             var _this = this;
5894 
5895             return function (rsp) {
5896 
5897                 var requestId, error = false, rspObj;
5898 
5899                 if (options.success || options.error) {
5900                     rspObj = {
5901                         status: rsp.rc,
5902                         content: rsp.text
5903                     };
5904 
5905                     if (!_this.doNotLog) {
5906                         _this._logger.log(_this.getRestType() + ": requestId='" + options.uuid + "', Returned with status=" + rspObj.status + ", content='" + rspObj.content + "'");
5907                     }
5908 
5909                     //Some responses may not have a body.
5910                     if (rsp.text && rsp.text.length > 0) {
5911                         try {
5912                             rspObj.object = _this._util.xml2js(rsp.text);
5913                         } catch (e) {
5914                             error = true;
5915                             rspObj.error = {
5916                                 errorType: "parseError",
5917                                 errorMessage: "Could not serialize XML: " + e
5918                             };
5919                         }
5920                     } else {
5921                         rspObj.object = {};
5922                     }
5923 
5924                     if (!error && rspObj.status >= 200 && rspObj.status < 300) {
5925                         if (options.success) {
5926                             options.success(rspObj);
5927                         }
5928                     } else {
5929                         if (options.error) {
5930                             options.error(rspObj);
5931                         }
5932                     }
5933 
5934                     /*
5935                      * If a synchronous error happened after a non-GET request (usually a validation error), we
5936                      * need to clean up the request's entry in _pendingCallbacks since no corresponding event
5937                      * will arrive later. The corresponding requestId should be present in the response headers.
5938                      *
5939                      * It appears Shindig changes the header keys to lower case, hence 'requestid' instead of
5940                      * 'requestId' below.
5941                      **/
5942                     if (rspObj.status !== 202 && rsp.headers && rsp.headers.requestid) {
5943                         requestId = rsp.headers.requestid[0];
5944                         if (_this._pendingCallbacks[requestId]) {
5945                             delete _this._pendingCallbacks[requestId];
5946                         }
5947                     }
5948                 }
5949             };
5950         },
5951 
5952         /**
5953          * Utility method to make an asynchronous request
5954          * @param {String} url
5955          *     The unencoded URL to which the request is sent (will be encoded)
5956          * @param {Object} options
5957          *     An object containing additional options for the request.
5958          * @param {Object} options.content
5959          *     An object to send in the content body of the request. Will be
5960          *     serialized into XML before sending.
5961          * @param {String} options.method
5962          *     The type of request. Defaults to "GET" when none is specified.
5963          * @param {Function} options.success(rsp)
5964          *     A callback function to be invoked for a successful request.
5965          *     {
5966          *         status: {Number} The HTTP status code returned
5967          *         content: {String} Raw string of response
5968          *         object: {Object} Parsed object of response
5969          *     }
5970          * @param {Function} options.error(rsp)
5971          *     A callback function to be invoked for an unsuccessful request.
5972          *     {
5973          *         status: {Number} The HTTP status code returned
5974          *         content: {String} Raw string of response
5975          *         object: {Object} Parsed object of response
5976          *         error: {Object} Wrapped exception that was caught
5977          *         error.errorType: {String} Type of error that was caught
5978          *         error.errorMessage: {String} Message associated with error
5979          *     }
5980          * @private
5981         */
5982         restRequest: function (url, options) {
5983 
5984             var params, encodedUrl;
5985 
5986             params = {};
5987 
5988             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
5989             options = options || {};
5990             options.success = this._util.validateHandler(options.success);
5991             options.error = this._util.validateHandler(options.error);
5992 
5993             // Request Headers
5994             params[gadgets.io.RequestParameters.HEADERS] = {};
5995 
5996             // HTTP method is a passthrough to gadgets.io.makeRequest, makeRequest defaults to GET
5997             params[gadgets.io.RequestParameters.METHOD] = options.method;
5998 
5999             //true if this should be a GET request, false otherwise
6000             if (!options.method || options.method === "GET") {
6001                 //Disable caching for GETs
6002                 if (url.indexOf("?") > -1) {
6003                     url += "&";
6004                 } else {
6005                     url += "?";
6006                 }
6007                 url += "nocache=" + this._util.currentTimeMillis();
6008             } else {
6009                 /**
6010                  * If not GET, generate a requestID and add it to the headers, then wrap
6011                  * callbacks into an object and store it in _pendingCallbacks.
6012                  * If we receive a synchronous error response instead of a 202 as expected,
6013              * the AJAX handler will clean up _pendingCallbacks.
6014                  **/
6015                 /*
6016                  * TODO: Clean up _pendingCallbacks if an entry persists after a certain amount of time has passed.
6017                  * In the block below, can store the current time (new Date().getTime()) alongside the
6018                  * callbacks in the new _pendingCallbacks entry. Then iterate through a copty of _pendingCallbacks,
6019                  * deleting all entries inside _pendingCallbacks that are older than a certain threshold (2 minutes for example.)
6020                  * This solves a potential memory leak issue if we never receive an event for a given stored requestId;
6021                  * we don't want to store unfired callbacks forever.
6022                  */
6023                 /** @private */
6024                 options.uuid = this._util.generateUUID();
6025                 params[gadgets.io.RequestParameters.HEADERS].requestId = options.uuid;
6026                 //By default, Shindig strips nearly all of the response headers, but this parameter tells Shindig
6027                 //to send the headers through unmodified; we need to be able to read the 'requestId' header if we
6028                 //get a synchronous error as a result of a non-GET request. (See the bottom of _createAjaxHandler().)
6029                 params[gadgets.io.RequestParameters.GET_FULL_HEADERS] = "true";
6030                 this._pendingCallbacks[options.uuid] = {};
6031                 this._pendingCallbacks[options.uuid].success = options.success;
6032                 this._pendingCallbacks[options.uuid].error = options.error;
6033             }
6034 
6035             //debugger;
6036             // NAT: IGNORE this until you hit save after changing assignments, then
6037             // pause here and set window.errorOnRequest to true, step past the next line,
6038             // and then set it to false. True value will throw an error when saving assignments.
6039             encodedUrl = encodeURI(url) + (window.errorOnRestRequest ? "ERROR" : "");
6040 
6041             if (!this.doNotLog) {
6042                 this._logger.log(this.getRestType() + ": requestId='" + options.uuid + "', Making REST request: method=" + (options.method || "GET") + ", url='" + encodedUrl + "'");
6043             }
6044 
6045             // Content Body
6046             if (typeof options.content === "object") {
6047                 // Content Type
6048                 params[gadgets.io.RequestParameters.HEADERS]["Content-Type"] = "application/xml";
6049                 // Content
6050                 params[gadgets.io.RequestParameters.POST_DATA] = this._util.js2xml(options.content);
6051                 
6052                 if (!this.doNotLog) {
6053                     this._logger.log(this.getRestType() + ": requestId='" + options.uuid + "', POST_DATA='" + params[gadgets.io.RequestParameters.POST_DATA] + "'");
6054                 }
6055             }
6056 
6057             ClientServices.makeRequest(encodedUrl, this._createAjaxHandler(options), params);
6058         },
6059 
6060         /**
6061          * Retrieves a reference to a particular notifierType.
6062          * @param notifierType is a string which indicates the notifier to retrieve
6063          * ('load', 'change', 'add', 'delete', 'error')
6064          * @return {Notifier}
6065          * @private
6066          */
6067         _getNotifierReference: function (notifierType) {
6068             var notifierReference = null;
6069             if (notifierType === 'load') {
6070                 notifierReference = this._loadNotifier;
6071             } else if (notifierType === 'change') {
6072                 notifierReference = this._changeNotifier;
6073             } else if (notifierType === 'add') {
6074                 notifierReference = this._addNotifier;
6075             } else if (notifierType === 'delete') {
6076                 notifierReference = this._deleteNotifier;
6077             } else if (notifierType === 'error') {
6078                 notifierReference = this._errorNotifier;
6079             } else {
6080                 throw new Error("_getNotifierReference(): Trying to get unknown notifier(notifierType=" + notifierType + ")");
6081             }
6082 
6083             return notifierReference;
6084         }
6085     });
6086 
6087     window.finesse = window.finesse || {};
6088     window.finesse.restservices = window.finesse.restservices || {};
6089     window.finesse.restservices.RestBase = RestBase;
6090     
6091     return RestBase;
6092 }));
6093 
6094 /** The following comment is to prevent jslint errors about 
6095  * using variables before they are defined.
6096  */
6097 /*global finesse*/
6098 
6099 /**
6100  * JavaScript base object that all REST collection objects should
6101  * inherit from because it encapsulates and provides the common functionality
6102  * that all REST objects need.
6103  *
6104  * @requires finesse.clientservices.ClientServices
6105  * @requires Class
6106  * @requires finesse.FinesseBase
6107  * @requires finesse.restservices.RestBase
6108  */
6109 
6110 /**
6111  * @class
6112  * JavaScript representation of a REST collection object.
6113  *
6114  * @constructor
6115  * @param {Function} callbacks.onCollectionAdd(this)
6116  *     Callback to invoke upon successful item addition to the collection.
6117  * @param {Function} callbacks.onCollectionDelete(this)
6118  *     Callback to invoke upon successful item deletion from the collection.
6119  * @borrows finesse.restservices.RestBase as finesse.restservices.RestCollectionBase
6120  */
6121 /** @private */
6122 (function (factory) {
6123     
6124 
6125     // Define as an AMD module if possible
6126     if ( typeof define === 'function' && define.amd )
6127     {
6128         define('restservices/RestCollectionBase', ['restservices/RestBase',
6129                  'utilities/Utilities',
6130                  'restservices/Notifier'], factory );
6131     }
6132     /* Define using browser globals otherwise
6133      * Prevent multiple instantiations if the script is loaded twice
6134      */
6135     else
6136     {
6137         factory(finesse.restservices.RestBase, finesse.utilities.Utilities, finesse.restservices.Notifier);
6138     } 
6139 }(function (RestBase, Utilities, Notifier) {
6140     var RestCollectionBase = RestBase.extend(/** @lends finesse.restservices.RestCollectionBase.prototype */{
6141 
6142         /**
6143          * Boolean function that specifies whether the collection handles subscribing
6144          * and propagation of events for the individual REST object items the
6145          * collection holds. False by default. Subclasses should override if true.
6146          * @private
6147          */
6148         supportsRestItemSubscriptions: false,
6149 
6150         /**
6151          * Gets the constructor the individual items that make of the collection.
6152          * For example, a Dialogs collection object will hold a list of Dialog items.
6153          * @throws Error because subtype must implement.
6154          * @private
6155          */
6156         getRestItemClass: function () {
6157             throw new Error("getRestItemClass(): Not implemented in subtype.");
6158         },
6159 
6160         /**
6161          * Gets the REST type of the individual items that make of the collection.
6162          * For example, a Dialogs collection object will hold a list of Dialog items.
6163          * @throws Error because subtype must implement.
6164          * @private
6165          */
6166         getRestItemType: function () {
6167             throw new Error("getRestItemType(): Not implemented in subtype.");
6168         },
6169 
6170         /**
6171          * The base REST URL in which items this object contains can be referenced.
6172          * @return {String}
6173          *     The REST URI for items this object contains.
6174          * @private
6175          */
6176         getRestItemBaseUrl: function () {
6177             var
6178             restUrl = "/finesse/api";
6179 
6180             //Append the REST type.
6181             restUrl += "/" + this.getRestItemType();
6182 
6183             return restUrl;
6184         },
6185 
6186          /*
6187          * Creates a new object from the given data
6188          * @param data - data object
6189          * @private
6190          */
6191         _objectCreator: function (data) {
6192             var objectId = this._extractId(data),
6193             newRestObj = this._collection[objectId],
6194             _this = this;
6195 
6196             //Prevent duplicate entries into collection.
6197             if (!newRestObj) {
6198                 //Create a new REST object using the subtype defined by the
6199                 //overridden method.
6200                 newRestObj = new (this.getRestItemClass())({
6201                     doNotSubscribe: this.handlesItemSubscription,
6202                     id: objectId,
6203                     data: data,
6204                     onLoad: function (newObj) {
6205                         //Normalize and add  REST object to collection datastore.
6206                         _this._collection[objectId] = newObj;
6207                         _this._collectionAddNotifier.notifyListeners(newObj);
6208                         _this.length += 1;
6209                     }
6210                 });
6211             }
6212             else {
6213                 //If entry already exist in collection, process the new event,
6214                 //and notify all change listeners since an existing object has
6215                 //change. This could happen in the case when the Finesse server
6216                 //cycles, and sends a snapshot of the user's calls.
6217                 newRestObj._processObject(data);
6218                 newRestObj._changeNotifier.notifyListeners(newRestObj);
6219             }
6220         },
6221 
6222         /*
6223          * Deletes and object and notifies its handlers
6224          * @param data - data object
6225          * @private
6226          */
6227         _objectDeleter: function (data) {
6228             var objectId = this._extractId(data),
6229             object = this._collection[objectId];
6230             if (object) {
6231                 //Even though this is a delete, let's make sure the object we are passing has got good data
6232                 object._processObject(data);
6233                 //Notify listeners and delete from internal datastore.
6234                 this._collectionDeleteNotifier.notifyListeners(object);
6235                 delete this._collection[objectId];
6236                 this.length -= 1;
6237             }
6238         },
6239 
6240          /**
6241           * Replaces the collection with a refreshed list using the passed in
6242           * data.
6243           * @param data - data object (usually this._data)
6244           * @private
6245           */
6246          _buildRefreshedCollection: function (data) {
6247             var i, dataObject, object, objectId, dataArray, newIds = [], foundFlag;
6248             if (data && this.getProperty(data, this.getRestItemType()) !== null) {
6249                 dataArray = Utilities.getArray(this.getProperty(data, this.getRestItemType()));
6250             } else {
6251                 dataArray = [];
6252             }
6253 
6254             // iterate through each item in the new data and add to or update collection
6255             for (i = 0; i < dataArray.length; i += 1) {
6256                 dataObject = {};
6257                 dataObject[this.getRestItemType()] = dataArray[i];
6258                 objectId = this._extractId(dataObject);
6259 
6260                 this._objectCreator(dataObject);
6261                 newIds.push(objectId);
6262 
6263                 // resubscribe if the object requires an explicit subscription
6264                 object = this._collection[objectId];
6265                 if (object.explicitSubscription) {
6266                     object._subscribeNode();
6267                 }
6268             }
6269 
6270             // now clean up items (if any) that were removed
6271             for (objectId in this._collection) {
6272                 if (this._collection.hasOwnProperty(objectId)) {
6273                     foundFlag = false;
6274                     for (i = newIds.length - 1; i >= 0; i -= 1) {
6275                         if (newIds[i] === objectId) {
6276                             foundFlag = true;
6277                             break;
6278                         }
6279                     }
6280                     // did not find in updated list, so delete it
6281                     if (!foundFlag) {
6282                         this._objectDeleter({'data': this._collection[objectId]._data});
6283                     }
6284                 }
6285             }
6286         },
6287 
6288         /**
6289          * Force an update on this object. Since an asynchronous GET is performed,
6290          * it is necessary to have an onChange handler registered in order to be
6291          * notified when the response of this returns.
6292          * @returns {finesse.restservices.RestBaseCollection}
6293          *     This RestBaseCollection object to allow cascading
6294          */
6295          refresh: function() {
6296             var _this = this, isLoaded = this._loaded;
6297 
6298             this._doGET({
6299                 success: function(rsp) {
6300                     if (_this._processResponse(rsp)) {
6301                         _this._buildRefreshedCollection(_this._data);
6302                     } else {
6303                         _this._errorNotifier.notifyListeners(_this);
6304                     }
6305 
6306                     // resubscribe if the collection requires an explicit subscription
6307                     if (_this.explicitSubscription) {
6308                         _this._subscribeNode();
6309                     }
6310                 },
6311                 error: function(rsp) {
6312                     _this._errorNotifier.notifyListeners(rsp);
6313                 }
6314             });
6315 
6316             return this;
6317          },
6318 
6319         /**
6320          * @private
6321          * The _addHandlerCb and _deleteHandlerCb require that data be passed in the
6322          * format of an array of {(Object Type): object} objects. For example, a
6323          * queues object would return [{Queue: queue1}, {Queue: queue2}, ...].
6324          * @param skipOuterObject If {true} is passed in for this param, then the "data"
6325          *                           property is returned instead of an object with the
6326          *                           data appended.
6327          * @return {Array}
6328          */
6329         extractCollectionData: function (skipOuterObject) {
6330             var restObjs,
6331             obj,
6332             result = [],
6333             _this = this;
6334             
6335             if (this._data)
6336             {
6337                 restObjs = this._data[this.getRestItemType()];
6338     
6339                 if (restObjs)
6340                 {
6341                     // check if there are multiple objects to pass
6342                     if (!$.isArray(restObjs))
6343                     {
6344                         restObjs = [restObjs];
6345                     }
6346     
6347                     // if so, create an object for each and add to result array
6348                     $.each(restObjs, function (id, object) {
6349                         if (skipOuterObject === true)
6350                         {
6351                             obj = object;
6352                         }
6353                         else
6354                         {
6355                             obj = {};
6356                             obj[_this.getRestItemType()] = object;
6357                         }
6358                         result.push(obj);
6359                     });
6360                 }
6361                 
6362             }
6363             
6364             return result;
6365         },
6366 
6367         /**
6368          * For Finesse, collections are handled uniquely on a POST and
6369          * doesn't necessary follow REST conventions. A POST on a collection
6370          * doesn't mean that the collection has been created, it means that an
6371          * item has been added to the collection. This function will generate
6372          * a closure which will handle this logic appropriately.
6373          * @param {Object} scope
6374          *     The scope of where the callback should be invoked.
6375          * @private
6376          */
6377         _addHandlerCb: function (scope) {
6378             return function (restItem) {
6379                 var data = restItem.extractCollectionData();               
6380 
6381                 $.each(data, function (id, object) {
6382                     scope._objectCreator(object);
6383                 });
6384             };
6385         },
6386 
6387         /**
6388          * For Finesse, collections are handled uniquely on a DELETE and
6389          * doesn't necessary follow REST conventions. A DELETE on a collection
6390          * doesn't mean that the collection has been deleted, it means that an
6391          * item has been deleted from the collection. This function will generate
6392          * a closure which will handle this logic appropriately.
6393          * @param {Object} scope
6394          *     The scope of where the callback should be invoked.
6395          * @private
6396          */
6397         _deleteHandlerCb: function (scope) {
6398             return function (restItem) {
6399                 var data = restItem.extractCollectionData();
6400 
6401                 $.each(data, function (id, obj) {
6402                     scope._objectDeleter(obj);
6403                 });
6404             };
6405         },
6406 
6407         /**
6408          * Utility method to process the update notification for Rest Items
6409          * that are children of the collection whose events are published to
6410          * the collection's node.
6411          * @param {Object} update
6412          *     The payload of an update notification.
6413          * @returns {Boolean}
6414          *     True if the update was successfully processed (the update object
6415          *     passed the schema validation) and updated the internal data cache,
6416          *     false otherwise.
6417          * @private
6418          */
6419         _processRestItemUpdate: function (update) {
6420             var object, objectId, updateObj = update.object.Update;
6421 
6422             //Extract the ID from the source if the Update was an error.
6423             if (updateObj.data.apiErrors) {
6424                 objectId = Utilities.getId(updateObj.source);
6425             }
6426             //Otherwise extract from the data object itself.
6427             else {
6428                 objectId = this._extractId(updateObj.data);
6429             }
6430 
6431             object = this._collection[objectId];
6432             if (object) {
6433                 if (object._processUpdate(update)) {
6434                     switch (updateObj.event) {
6435                     case "POST":
6436                         object._addNotifier.notifyListeners(object);
6437                         break;
6438                     case "PUT":
6439                         object._changeNotifier.notifyListeners(object);
6440                         break;
6441                     case "DELETE":
6442                         object._deleteNotifier.notifyListeners(object);
6443                         break;
6444                     }
6445                 }
6446             }
6447         },
6448 
6449         /**
6450          * SUBCLASS IMPLEMENTATION (override):
6451          * For collections, this callback has the additional responsibility of passing events
6452          * of collection item updates to the item objects themselves. The collection needs to
6453          * do this because item updates are published to the collection's node.
6454          * @returns {Function}
6455          *     The callback to be invoked when an update event is received
6456          * @private
6457          */
6458         _createPubsubCallback: function () {
6459             var _this = this;
6460             return function (update) {
6461                 //If the source of the update is our REST URL, this means the collection itself is modified
6462                 if (update.object.Update.source === _this.getRestUrl()) {
6463                     _this._updateEventHandler(_this, update);
6464                 } else {
6465                     //Otherwise, it is safe to assume that if we got an event on our topic, it must be a
6466                     //rest item update of one of our children that was published on our node (OpenAjax topic)
6467                     _this._processRestItemUpdate(update);
6468                 }
6469             };
6470         },
6471 
6472         /**
6473          * @class
6474          * This is the base collection object. 
6475          *
6476          * @constructs
6477          * @augments finesse.restservices.RestBase
6478          * @see finesse.restservices.Contacts
6479          * @see finesse.restservices.Dialogs
6480          * @see finesse.restservices.PhoneBooks
6481          * @see finesse.restservices.Queues
6482          * @see finesse.restservices.WorkflowActions
6483          * @see finesse.restservices.Workflows
6484          * @see finesse.restservices.WrapUpReasons
6485          */
6486         _fakeConstuctor: function () {
6487             /* This is here to hide the real init constructor from the public docs */
6488         },
6489         
6490        /**
6491          * @private
6492          * @param {Object} options
6493          *     An object with the following properties:<ul>
6494          *         <li><b>id:</b> The id of the object being constructed</li>
6495          *         <li><b>onCollectionAdd(this): (optional)</b> when an object is added to this collection</li>
6496          *         <li><b>onCollectionDelete(this): (optional)</b> when an object is removed from this collection</li>
6497          *         <li><b>onLoad(this): (optional)</b> when the collection is successfully loaded from the server</li>
6498          *         <li><b>onChange(this): (optional)</b> when an update notification of the collection is received. 
6499          *         This does not include adding and deleting members of the collection</li>
6500          *         <li><b>onAdd(this): (optional)</b> when a notification that the collection is created is received</li>
6501          *         <li><b>onDelete(this): (optional)</b> when a notification that the collection is deleted is received</li>
6502          *         <li><b>onError(rsp): (optional)</b> if loading of the collection fails, invoked with the error response object:<ul>
6503          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
6504          *             <li><b>content:</b> {String} Raw string of response</li>
6505          *             <li><b>object:</b> {Object} Parsed object of response</li>
6506          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
6507          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
6508          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
6509          *             </ul></li>
6510          *         </ul></li>
6511          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
6512          **/
6513         init: function (options) {
6514 
6515             options = options || {};
6516             options.id = "";
6517 
6518             //Make internal datastore collection to hold a list of objects.
6519             this._collection = {};
6520             this.length = 0;
6521 
6522             //Collections will have additional callbacks that will be invoked when
6523             //an item has been added/deleted.
6524             this._collectionAddNotifier = new Notifier();
6525             this._collectionDeleteNotifier = new Notifier();
6526 
6527             //Initialize the base class.
6528             this._super(options);
6529 
6530             this.addHandler('collectionAdd', options.onCollectionAdd);
6531             this.addHandler('collectionDelete', options.onCollectionDelete);
6532 
6533             //For Finesse, collections are handled uniquely on a POST/DELETE and
6534             //doesn't necessary follow REST conventions. A POST on a collection
6535             //doesn't mean that the collection has been created, it means that an
6536             //item has been added to the collection. A DELETE means that an item has
6537             //been removed from the collection. Due to this, we are attaching
6538             //special callbacks to the add/delete that will handle this logic.
6539             this.addHandler("add", this._addHandlerCb(this));
6540             this.addHandler("delete", this._deleteHandlerCb(this));
6541         },
6542 
6543         /**
6544          * Returns the collection.
6545          * @returns {Object}
6546          *     The collection as an object
6547          */
6548         getCollection: function () {
6549             //TODO: is this safe? or should we instead return protected functions such as .each(function)?
6550             return this._collection;
6551         },
6552 
6553         /**
6554          * Utility method to build the internal collection data structure (object) based on provided data
6555          * @param {Object} data
6556          *     The data to build the internal collection from
6557          * @private
6558          */
6559         _buildCollection: function (data) {
6560             var i, object, objectId, dataArray;
6561             if (data && this.getProperty(data, this.getRestItemType()) !== null) {
6562                 dataArray = Utilities.getArray(this.getProperty(data, this.getRestItemType()));
6563                 for (i = 0; i < dataArray.length; i += 1) {
6564 
6565                     object = {};
6566                     object[this.getRestItemType()] = dataArray[i];
6567                     objectId = this._extractId(object);
6568                     this._collection[objectId] = new (this.getRestItemClass())({
6569                         doNotSubscribe: this.handlesItemSubscription,
6570                         id: objectId,
6571                         data: object
6572                     });
6573                     this.length += 1;
6574                 }
6575             }
6576         },
6577 
6578         /**
6579          * Called to know whether to include an item in the _collection and _data. Return false to keep it, true to filter out (discard) it.
6580          * Override this in subclasses if you need only object with certain attribute values.
6581          * @param  {Object} item Item to test.
6582          * @return {Boolean} False to keep, true to filter out (discard);
6583          */
6584         _filterOutItem: function (item) {
6585             return false;
6586         },
6587     
6588         /**
6589          * Validate and store the object into the internal data store.
6590          * SUBCLASS IMPLEMENTATION (override):
6591          * Performs collection specific logic to _buildCollection internally based on provided data
6592          * @param {Object} object
6593          *     The JavaScript object that should match of schema of this REST object.
6594          * @returns {Boolean}
6595          *     True if the object was validated and stored successfully.
6596          * @private
6597          */
6598         _processObject: function (object) {
6599             var i,
6600                 restItemType = this.getRestItemType(),
6601                 items;
6602             if (this._validate(object)) {
6603                 this._data = this.getProperty(object, this.getRestType()); // Should clone the object here?
6604     
6605                 // If a subclass has overriden _filterOutItem then we'll need to run through the items and remove them
6606                 if (this._data)
6607                 {
6608                     items = this._data[restItemType];
6609     
6610                     if (typeof(items) !== "undefined")
6611                     {
6612                         if (typeof(items.length) === "undefined")
6613                         {
6614                             // Single object
6615                             if (this._filterOutItem(items))
6616                             {
6617                                 this._data[restItemType] = items = [];
6618                             }
6619                             
6620                         }
6621                         else
6622                         {
6623                             // filter out objects
6624                             for (i = items.length - 1; i !== -1; i = i - 1)
6625                             {
6626                                 if (this._filterOutItem(items[i]))
6627                                 {
6628                                     items.splice(i, 1);
6629                                 }
6630                             }
6631                         }
6632                     }
6633                 }
6634     
6635                 // If loaded for the first time, call the load notifiers.
6636                 if (!this._loaded) {
6637                     this._buildCollection(this._data);
6638                     this._loaded = true;
6639                     this._loadNotifier.notifyListeners(this);
6640                 }
6641                 
6642                 return true;
6643                 
6644             }
6645             return false;
6646         },
6647 
6648         /**
6649          * Retrieves a reference to a particular notifierType.
6650          * @param {String} notifierType
6651          *      Specifies the notifier to retrieve (load, change, error, add, delete)
6652          * @return {Notifier} The notifier object.
6653          */
6654         _getNotifierReference: function (notifierType) {
6655             var notifierReference;
6656 
6657             try {
6658                 //Use the base method to get references for load/change/error.
6659                 notifierReference = this._super(notifierType);
6660             } catch (err) {
6661                 //Check for add/delete
6662                 if (notifierType === "collectionAdd") {
6663                     notifierReference = this._collectionAddNotifier;
6664                 } else if (notifierType === "collectionDelete") {
6665                     notifierReference = this._collectionDeleteNotifier;
6666                 } else {
6667                     //Rethrow exception from base class.
6668                     throw err;
6669                 }
6670             }
6671             return notifierReference;
6672         }
6673     });
6674     
6675     window.finesse = window.finesse || {};
6676     window.finesse.restservices = window.finesse.restservices || {};
6677     window.finesse.restservices.RestCollectionBase = RestCollectionBase;
6678     
6679     return RestCollectionBase;
6680 }));
6681 
6682 /**
6683  * JavaScript representation of the Finesse Dialog object.
6684  *
6685  * @requires finesse.clientservices.ClientServices
6686  * @requires Class
6687  * @requires finesse.FinesseBase
6688  * @requires finesse.restservices.RestBase
6689  */
6690 
6691 /** @private */
6692 (function (factory) {
6693     
6694 
6695     // Define as an AMD module if possible
6696     if ( typeof define === 'function' && define.amd )
6697     {
6698         define('restservices/Dialog', ['restservices/RestBase',
6699                  'utilities/Utilities'], factory );
6700     }
6701     /* Define using browser globals otherwise
6702      * Prevent multiple instantiations if the script is loaded twice
6703      */
6704     else
6705     {
6706         factory(finesse.restservices.RestBase, finesse.utilities.Utilities);
6707     } 
6708 }(function (RestBase, Utilities) {
6709 	var Dialog = RestBase.extend(/** @lends finesse.restservices.Dialog.prototype */{
6710 
6711         /**
6712          * @class
6713          * A Dialog is an attempted connection between or among multiple participants,
6714          * for example, a regular phone call, a conference, or a silent monitor session.
6715          * 
6716          * @augments finesse.restservices.RestBase
6717          * @constructs
6718          */
6719         _fakeConstuctor: function () {
6720             /* This is here to hide the real init constructor from the public docs */
6721         },
6722         
6723         /**
6724          * @private
6725          *
6726          * @param {Object} options
6727          *     An object with the following properties:<ul>
6728          *         <li><b>id:</b> The id of the object being constructed</li>
6729          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
6730          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
6731          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
6732          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
6733          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
6734          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
6735          *             <li><b>content:</b> {String} Raw string of response</li>
6736          *             <li><b>object:</b> {Object} Parsed object of response</li>
6737          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
6738          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
6739          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
6740          *             </ul></li>
6741          *         </ul></li>
6742          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
6743          **/
6744         init: function (options) {
6745             this._super(options);
6746         },
6747 
6748         /**
6749          * @private
6750          * Gets the REST class for the current object - this is the Dialog class.
6751          * @returns {Object} The Dialog class.
6752          */
6753         getRestClass: function () {
6754             return Dialog;
6755         },
6756         
6757         /**
6758          * @private
6759          * The constant for agent device.
6760          */
6761         _agentDeviceType: "AGENT_DEVICE",
6762         
6763         /**
6764          * @private
6765          * Gets the REST type for the current object - this is a "Dialog".
6766          * @returns {String} The Dialog string.
6767          */
6768         getRestType: function () {
6769             return "Dialog";
6770         },
6771 
6772         /**
6773          * @private
6774          * Override default to indicate that this object doesn't support making
6775          * requests.
6776          */
6777         supportsRequests: false,
6778 
6779         /**
6780          * @private
6781          * Override default to indicate that this object doesn't support subscriptions.
6782          */
6783         supportsSubscriptions: false,
6784 
6785         /**
6786          * Getter for the from address.
6787          * @returns {String} The from address.
6788          */
6789         getFromAddress: function () {
6790             this.isLoaded();
6791             return this.getData().fromAddress;
6792         },
6793 
6794         /**
6795          * Getter for the to address.
6796          * @returns {String} The to address.
6797          */
6798         getToAddress: function () {
6799             this.isLoaded();
6800             return this.getData().toAddress;
6801         },
6802         /**
6803          * Getter for the media type.
6804          * @returns {String} The media type.
6805          */
6806         getMediaType: function () {
6807             this.isLoaded();
6808             return this.getData().mediaType;
6809         },
6810         /**
6811          * @private
6812          * Getter for the uri.
6813          * @returns {String} The uri.
6814          */
6815         getDialogUri: function () {
6816             this.isLoaded();
6817             return this.getData().uri;
6818         },
6819 
6820         /**
6821          * Getter for the callType.
6822          * @deprecated Use getMediaProperties().callType instead.
6823          * @returns {String} The callType.
6824          */
6825         getCallType: function () {
6826             this.isLoaded();
6827             return this.getData().mediaProperties.callType;
6828         },
6829 
6830         /**
6831          * Getter for the DNIS. This is usually the actual number dialed.
6832          * @deprecated Use getMediaProperties().DNIS instead.
6833          * @returns {String} The callType.
6834          */
6835         getDNIS: function () {
6836             this.isLoaded();
6837             return this.getData().mediaProperties.DNIS;
6838         },
6839         
6840         /**
6841          * Getter for the Dialog state.
6842          * @returns {String} The Dialog state.
6843          */
6844         getState: function () {
6845             this.isLoaded();
6846             return this.getData().state;
6847         },
6848 
6849         /**
6850          * Retrieves a list of participants within the Dialog object.
6851          * @returns {Object} Array list of participants.
6852          */
6853         getParticipants: function () {
6854             this.isLoaded();
6855             var participants = this.getData().participants.Participant;
6856             //Due to the nature of the XML->JSO converter library, a single
6857             //element in the XML array will be considered to an object instead of
6858             //a real array. This will handle those cases to ensure that an array is
6859             //always returned.
6860 
6861             return Utilities.getArray(participants);
6862         },
6863 
6864         /**
6865          * Determines the droppable participants.  A droppable participant is a participant that is an agent extension.   
6866          * (It is not a CTI Route Point, IVR Port, or the caller)
6867          * 
6868          * @param {String} filterExtension used to remove a single extension from the list
6869          * @returns {Array} Participants which is an array of all participants which can be dropped.
6870          */
6871         getDroppableParticipants: function (filterExtension) {
6872           this.isLoaded();
6873           var droppableParticipants = [], participants, index, idx, filterExtensionToRemove = "", callStateOk, part;
6874 
6875           participants = this.getParticipants();
6876 
6877           if (filterExtension)
6878           {
6879             filterExtensionToRemove = filterExtension;
6880           }
6881 
6882           //Loop through all the participants to remove non-agents & remove filterExtension
6883           //We could have removed filterExtension using splice, but we have to iterate through
6884           //the list anyway.
6885           for(idx=0;idx<participants.length;idx=idx+1)
6886           {
6887             part = participants[idx];
6888 
6889             //Skip the filterExtension
6890             if (part.mediaAddress !== filterExtensionToRemove)
6891             {
6892                 callStateOk = this._isParticipantStateDroppable(part);
6893 
6894                 //Remove non-agents & make sure callstate 
6895                 if (callStateOk === true && part.mediaAddressType === this._agentDeviceType)
6896                 {
6897                   droppableParticipants.push(part);
6898                 }
6899             }
6900         }
6901 
6902         return Utilities.getArray(droppableParticipants);
6903         },
6904 
6905         _isParticipantStateDroppable : function (part)
6906         {
6907           var isParticipantStateDroppable = false;
6908           if (part.state === Dialog.ParticipantStates.ACTIVE || part.state === Dialog.ParticipantStates.ACCEPTED || part.state === Dialog.ParticipantStates.HELD)
6909           {
6910             isParticipantStateDroppable = true;
6911           }
6912           
6913           return isParticipantStateDroppable;
6914         },
6915         
6916         /**
6917          * Is the participant droppable
6918          *
6919          * @param {String} participantExt Extension of participant.
6920          * @returns {Boolean} True is droppable.
6921          */
6922         isParticipantDroppable : function (participantExt) {
6923           var droppableParticipants = null, isDroppable = false, idx, part, callStateOk;
6924           
6925           droppableParticipants = this.getDroppableParticipants();
6926           
6927           if (droppableParticipants) 
6928           {
6929             for(idx=0;idx<droppableParticipants.length;idx=idx+1)
6930             {
6931               part = droppableParticipants[idx];
6932              
6933               if (part.mediaAddress === participantExt)
6934               {
6935                 callStateOk = this._isParticipantStateDroppable(part);
6936 
6937                 //Remove non-agents & make sure callstate 
6938                 if (callStateOk === true && part.mediaAddressType === this._agentDeviceType)
6939                 {
6940                   isDroppable = true;
6941                   break;
6942                 }
6943               }
6944             }
6945           }
6946           
6947           return isDroppable;
6948         },
6949         
6950         /**
6951          * Retrieves a list of media properties from the dialog object.
6952          * @returns {Object} Map of call variables; names mapped to values.
6953          * Variables may include the following:<ul>
6954          * <li>dialedNumber: The number dialed.
6955          * <li>callType: The type of call. Call types include:<ul>
6956          *     <li>ACD_IN
6957          *     <li>PREROUTE_ACD_IN
6958          *     <li>PREROUTE_DIRECT_AGENT
6959          *     <li>TRANSFER
6960          *     <li>OTHER_IN
6961          *     <li>OUT
6962          *     <li>AGENT_INSIDE
6963          *     <li>CONSULT
6964          *     <li>CONFERENCE
6965          *     <li>SUPERVISOR_MONITOR
6966          *     <li>OUTBOUND
6967          *     <li>OUTBOUND_PREVIEW</ul>
6968          * <li>DNIS: The DNIS provided. For routed calls, this is the route point.
6969          * <li>wrapUpReason: A description of the call.
6970          * <li>Call Variables, by name.  The name indicates whether it is a call variable or ECC variable.
6971          * Call variable names start with callVariable#, where # is 1-10. ECC variable names (both scalar and array) are prepended with "user".
6972          * ECC variable arrays include an index enclosed within square brackets located at the end of the ECC array name.
6973          * <li>The following call variables provide additional details about an Outbound Option call:<ul>
6974          *     <li>BACampaign
6975          *     <li>BAAccountNumber
6976          *     <li>BAResponse
6977          *     <li>BAStatus<ul>
6978          *         <li>PREDICTIVE_OUTBOUND: A predictive outbound call.
6979          *         <li>PROGRESSIVE_OUTBOUND: A progressive outbound call.
6980          *         <li>PREVIEW_OUTBOUND_RESERVATION: Agent is reserved for a preview outbound call.
6981          *         <li>PREVIEW_OUTBOUND: Agent is on a preview outbound call.</ul>
6982          *     <li>BADialedListID
6983          *     <li>BATimeZone
6984          *     <li>BABuddyName</ul></ul>
6985          *     
6986          */
6987         getMediaProperties: function () {
6988             var mpData, currentMediaPropertiesMap, thisMediaPropertiesJQuery;
6989 
6990             this.isLoaded();
6991             
6992             // We have to convert to jQuery object to do a proper compare
6993             thisMediaPropertiesJQuery = jQuery(this.getData().mediaProperties);
6994             
6995             if ((this._lastMediaPropertiesJQuery !== undefined) 
6996                     && (this._lastMediaPropertiesMap !== undefined) 
6997                     && (this._lastMediaPropertiesJQuery.is(thisMediaPropertiesJQuery))) {
6998 
6999                     return this._lastMediaPropertiesMap;
7000             }
7001             
7002             currentMediaPropertiesMap = {};
7003 
7004             mpData = this.getData().mediaProperties;
7005 
7006             if (mpData) {
7007                 if (mpData.callvariables && mpData.callvariables.CallVariable) {
7008                     jQuery.each(mpData.callvariables.CallVariable, function (i, callVariable) {
7009 			currentMediaPropertiesMap[callVariable.name] = callVariable.value;
7010                     });
7011                 }
7012 
7013                 jQuery.each(mpData, function (key, value) {
7014                     if (key !== 'callvariables') {
7015 			currentMediaPropertiesMap[key] = value;
7016                     }
7017                 });
7018             }
7019             
7020             this._lastMediaPropertiesMap = currentMediaPropertiesMap;
7021             this._lastMediaPropertiesJQuery = thisMediaPropertiesJQuery;
7022 
7023             return this._lastMediaPropertiesMap;
7024         },
7025 
7026         /**
7027          * @private
7028          * Invoke a request to the server given a content body and handlers.
7029          *
7030          * @param {Object} contentBody
7031          *     A JS object containing the body of the action request.
7032          * @param {finesse.interfaces.RequestHandlers} handlers
7033          *     An object containing the handlers for the request
7034          */
7035         _makeRequest: function (contentBody, handlers) {
7036             // Protect against null dereferencing of options allowing its
7037             // (nonexistent) keys to be read as undefined
7038             handlers = handlers || {};
7039 
7040             this.restRequest(this.getRestUrl(), {
7041                 method: 'PUT',
7042                 success: handlers.success,
7043                 error: handlers.error,
7044                 content: contentBody
7045             });
7046         },
7047 
7048         /**
7049          * Invoke a consult call out to a destination.
7050          *
7051          * @param {String} mediaAddress
7052          *     The media address of the user performing the consult call.
7053          * @param {String} toAddress
7054          *     The destination address of the consult call.
7055          * @param {finesse.interfaces.RequestHandlers} handlers
7056          *     An object containing the handlers for the request
7057          */
7058         makeConsultCall: function (mediaAddress, toAddress, handlers) {
7059             this.isLoaded();
7060             var contentBody = {};
7061             contentBody[this.getRestType()] = {
7062                 "targetMediaAddress": mediaAddress,
7063                 "toAddress": toAddress,
7064                 "requestedAction": Dialog.Actions.CONSULT_CALL
7065             };
7066             this._makeRequest(contentBody, handlers);
7067             return this; // Allow cascading
7068         },
7069         
7070         /**
7071          * Invoke a single step transfer request.
7072          *
7073          * @param {String} mediaAddress
7074          *     The media address of the user performing the single step transfer.
7075          * @param {String} toAddress
7076          *     The destination address of the single step transfer.
7077          * @param {finesse.interfaces.RequestHandlers} handlers
7078          *     An object containing the handlers for the request
7079          */
7080         initiateDirectTransfer: function (mediaAddress, toAddress, handlers) {
7081             this.isLoaded();
7082             var contentBody = {};
7083             contentBody[this.getRestType()] = {
7084                 "targetMediaAddress": mediaAddress,
7085                 "toAddress": toAddress,
7086                 "requestedAction": Dialog.Actions.TRANSFER_SST
7087             };
7088             this._makeRequest(contentBody, handlers);
7089             return this; // Allow cascading
7090         },
7091 
7092         /**
7093          * Update this dialog's wrap-up reason.
7094          *
7095          * @param {String} wrapUpReason
7096          *     The new wrap-up reason for this dialog
7097          * @param {finesse.interfaces.RequestHandlers} handlers
7098          *     An object containing the handlers for the request
7099          */
7100         updateWrapUpReason: function (wrapUpReason, options)
7101         {
7102             this.isLoaded();
7103             var mediaProperties =
7104             {
7105                 "wrapUpReason": wrapUpReason
7106             };
7107 
7108             options = options || {};
7109             options.content = {};
7110             options.content[this.getRestType()] =
7111             {
7112                 "mediaProperties": mediaProperties,
7113                 "requestedAction": Dialog.Actions.UPDATE_CALL_DATA
7114             };
7115             options.method = "PUT";
7116             this.restRequest(this.getRestUrl(), options);
7117 
7118             return this;
7119         },
7120 
7121         /**
7122          * Invoke a request to server based on the action given.
7123          * @param {String} mediaAddress
7124          *     The media address of the user performing the action.
7125          * @param {finesse.restservices.Dialog.Actions} action
7126          *     The action string indicating the action to invoke on dialog.
7127          * @param {finesse.interfaces.RequestHandlers} handlers
7128          *     An object containing the handlers for the request
7129          */
7130         requestAction: function (mediaAddress, action, handlers) {
7131             this.isLoaded();
7132             var contentBody = {};
7133             contentBody[this.getRestType()] = {
7134                 "targetMediaAddress": mediaAddress,
7135                 "requestedAction": action
7136             };
7137             this._makeRequest(contentBody, handlers);
7138             return this; // Allow cascading
7139         },
7140         
7141         /**
7142          * Wrapper around "requestAction" to request PARTICIPANT_DROP action.
7143          *
7144          * @param targetMediaAddress is the address to drop
7145          * @param {finesse.interfaces.RequestHandlers} handlers
7146          *     An object containing the handlers for the request
7147          */
7148         dropParticipant: function (targetMediaAddress, handlers) {
7149             this.requestAction(targetMediaAddress, Dialog.Actions.PARTICIPANT_DROP, handlers);
7150         },
7151         
7152         /**
7153          * Invoke a request to server to send DTMF digit tones.
7154          * @param {String} mediaAddress
7155          * @param {String} action
7156          *     The action string indicating the action to invoke on dialog.
7157          * @param {finesse.interfaces.RequestHandlers} handlers
7158          *     An object containing the handlers for the request
7159          */
7160         sendDTMFRequest: function (mediaAddress, handlers, digit) {
7161             this.isLoaded();
7162             var contentBody = {};
7163             contentBody[this.getRestType()] = {
7164                 "targetMediaAddress": mediaAddress,
7165                 "requestedAction": "SEND_DTMF",
7166                 "actionParams": {
7167                     "ActionParam": {
7168                         "name": "dtmfString",
7169                         "value": digit
7170                     }
7171                 }
7172             };
7173             this._makeRequest(contentBody, handlers);
7174             return this; // Allow cascading
7175         }        
7176     });
7177 
7178     Dialog.Actions = /** @lends finesse.restservices.Dialog.Actions.prototype */ {
7179             /**
7180              * Drops the Participant from the Dialog.
7181              */
7182             DROP: "DROP",
7183             /**
7184              * Answers a Dialog.
7185              */
7186             ANSWER: "ANSWER",
7187             /**
7188              * Holds the Dialog.
7189              */
7190             HOLD: "HOLD",
7191             /**
7192              * Barges into a Call Dialog.
7193              */
7194             BARGE_CALL: "BARGE_CALL",
7195             /**
7196              * Allow as Supervisor to Drop a Participant from the Dialog.
7197              */
7198             PARTICIPANT_DROP: "PARTICIPANT_DROP",
7199             /**
7200              * Makes a new Call Dialog.
7201              */
7202             MAKE_CALL: "MAKE_CALL",
7203             /**
7204              * Retrieves a Dialog that is on Hold.
7205              */
7206             RETRIEVE: "RETRIEVE",
7207             /**
7208              * Initiates a Consult Call.
7209              */
7210             CONSULT_CALL: "CONSULT_CALL",
7211             /**
7212              * Initiates a Transfer of a Dialog.
7213              */
7214             TRANSFER: "TRANSFER",
7215             /**
7216              * Initiates a Single-Step Transfer of a Dialog.
7217              */
7218             TRANSFER_SST: "TRANSFER_SST",
7219             /**
7220              * Initiates a Conference of a Dialog.
7221              */
7222             CONFERENCE: "CONFERENCE",
7223             /**
7224              * Updates data on a Call Dialog.
7225              */
7226             UPDATE_CALL_DATA: "UPDATE_CALL_DATA",
7227             /**
7228              * Initiates a Recording on a Call Dialog.
7229              */
7230             START_RECORDING : "START_RECORDING",
7231             /**
7232              * Sends DTMF (dialed digits) to a Call Dialog.
7233              */
7234             DTMF : "SEND_DTMF",            
7235             /**
7236              * Accepts a Dialog that is being Previewed.
7237              */
7238             ACCEPT: "ACCEPT",
7239             /**
7240              * Rejects a Dialog.
7241              */
7242             REJECT: "REJECT",
7243             /**
7244              * Closes a Dialog.
7245              */
7246             CLOSE : "CLOSE",
7247             /**
7248              * @class Set of action constants for a Dialog.  These should be used for
7249              * {@link finesse.restservices.Dialog#requestAction}.
7250              * @constructs
7251              */
7252             _fakeConstructor : function () {} // For JS Doc to work need a constructor so that the lends/constructs build the doc properly
7253         };  
7254 
7255     Dialog.States = /** @lends finesse.restservices.Dialog.States.prototype */ {
7256        /**
7257          * Indicates that the call is ringing at a device.
7258          */
7259         ALERTING: "ALERTING",
7260         /**
7261          * Indicates that the phone is off the hook at a device.
7262          */
7263         INITIATING: "INITIATING",
7264         /**
7265          * Indicates that the dialog has a least one active participant.
7266          */
7267         ACTIVE: "ACTIVE",
7268         /**
7269          * Indicates that the dialog has no active participants.
7270          */
7271         DROPPED: "DROPPED",
7272         /**
7273          * Indicates that the phone is dialing at the device.
7274          */
7275         INITIATED: "INITIATED",
7276         /**
7277          * Indicates that the dialog has failed.
7278          * @see Dialog.ReasonStates
7279          */
7280         FAILED: "FAILED",
7281         /**
7282          * Indicates that the user has accepted an OUTBOUND_PREVIEW dialog.
7283          */
7284         ACCEPTED: "ACCEPTED",
7285         /**
7286          * @class Possible Dialog State constants.
7287          * The State flow of a typical in-bound Dialog is as follows: INITIATING, INITIATED, ALERTING, ACTIVE, DROPPED.
7288          * @constructs
7289          */
7290         _fakeConstructor : function () {} // For JS Doc to work need a constructor so that the lends/constructs build the doc properly
7291     };
7292 
7293     Dialog.ParticipantStates = /** @lends finesse.restservices.Dialog.ParticipantStates.prototype */ {
7294         /**
7295           * Indicates that an incoming call is ringing on the device.
7296           */
7297          ALERTING: "ALERTING",
7298          /**
7299           * Indicates that an outgoing call, not yet active, exists on the device.
7300           */
7301          INITIATING: "INITIATING",
7302          /**
7303           * Indicates that the participant is active on the call.
7304           */
7305          ACTIVE: "ACTIVE",
7306          /**
7307           * Indicates that the participant has dropped from the call.
7308           */
7309          DROPPED: "DROPPED",
7310          /**
7311           * Indicates that the participant has held their connection to the call.
7312           */
7313          HELD: "HELD",
7314          /**
7315           * Indicates that the phone is dialing at a device.
7316           */
7317          INITIATED: "INITIATED",
7318          /**
7319           * Indicates that the call failed.
7320           * @see Dialog.ReasonStates
7321           */
7322          FAILED: "FAILED",
7323          /**
7324           * Indicates that the participant is not in active state on the call, but is wrapping up after the participant has dropped from the call.
7325           */
7326          WRAP_UP: "WRAP_UP",
7327          /**
7328           * Indicates that the participant has accepted the dialog.  This state is applicable to OUTBOUND_PREVIEW dialogs.
7329           */
7330          ACCEPTED: "ACCEPTED",
7331          /**
7332           * @class Possible Dialog Participant State constants.
7333           * @constructs
7334           */
7335          _fakeConstructor : function () {} // For JS Doc to work need a constructor so that the lends/constructs build the doc properly
7336      };
7337 
7338     Dialog.ReasonStates = /** @lends finesse.restservices.Dialog.ReasonStates.prototype */ {
7339        /**
7340         * Dialog was Busy.  This will typically be for a Failed Dialog.
7341         */
7342         BUSY: "BUSY",
7343         /**
7344          * Dialog reached a Bad Destination.  This will typically be for a Failed Dialog.
7345          */
7346         BAD_DESTINATION: "BAD_DESTINATION",
7347         /**
7348          * All Other Reasons.  This will typically be for a Failed Dialog.
7349          */
7350         OTHER: "OTHER",
7351         /**
7352          * The Device Resource for the Dialog was not available.
7353          */
7354         DEVICE_RESOURCE_NOT_AVAILABLE : "DEVICE_RESOURCE_NOT_AVAILABLE",
7355         /**
7356          * @class Possible dialog state reasons code constants.
7357          * @constructs
7358          */
7359         _fakeConstructor : function () {} // For JS Doc to work need a constructor so that the lends/constructs build the doc properly
7360     };
7361    
7362     window.finesse = window.finesse || {};
7363     window.finesse.restservices = window.finesse.restservices || {};
7364     window.finesse.restservices.Dialog = Dialog;
7365     
7366     
7367     return Dialog;
7368 }));
7369 
7370 /**
7371  * JavaScript representation of the Finesse Dialogs collection
7372  * object which contains a list of Dialog objects.
7373  *
7374  * @requires finesse.clientservices.ClientServices
7375  * @requires Class
7376  * @requires finesse.FinesseBase
7377  * @requires finesse.restservices.RestBase
7378  * @requires finesse.restservices.Dialog
7379  */
7380 /** @private */
7381 (function (factory) {
7382     
7383 
7384     // Define as an AMD module if possible
7385     if ( typeof define === 'function' && define.amd )
7386     {
7387         define('restservices/Dialogs', ['restservices/RestCollectionBase',
7388                  'restservices/Dialog'], factory );
7389     }
7390     /* Define using browser globals otherwise
7391      * Prevent multiple instantiations if the script is loaded twice
7392      */
7393     else
7394     {
7395         factory(finesse.restservices.RestCollectionBase, finesse.restservices.Dialog);
7396     } 
7397 }(function (RestCollectionBase, Dialog) {
7398     var Dialogs = RestCollectionBase.extend(/** @lends finesse.restservices.Dialogs.prototype */{
7399 
7400         /**
7401          * @class
7402          * JavaScript representation of a Dialogs collection object. Also exposes
7403          * methods to operate on the object against the server.
7404          * @augments finesse.restservices.RestCollectionBase
7405          * @constructs
7406          * @see finesse.restservices.Dialog
7407          * @example
7408          *  _dialogs = _user.getDialogs( {
7409          *      onCollectionAdd : _handleDialogAdd,
7410          *      onCollectionDelete : _handleDialogDelete,
7411          *      onLoad : _handleDialogsLoaded
7412          *  });
7413          *  
7414          * _dialogCollection = _dialogs.getCollection();
7415          * for (var dialogId in _dialogCollection) {
7416          *     if (_dialogCollection.hasOwnProperty(dialogId)) {
7417          *         _dialog = _dialogCollection[dialogId];
7418          *         etc...
7419          *     }
7420          * }
7421          */
7422         _fakeConstuctor: function () {
7423             /* This is here to hide the real init constructor from the public docs */
7424         },
7425         
7426         /**
7427          * @private
7428          * @param {Object} options
7429          *     An object with the following properties:<ul>
7430          *         <li><b>id:</b> The id of the object being constructed</li>
7431          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
7432          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
7433          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
7434          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
7435          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
7436          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
7437          *             <li><b>content:</b> {String} Raw string of response</li>
7438          *             <li><b>object:</b> {Object} Parsed object of response</li>
7439          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
7440          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
7441          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
7442          *             </ul></li>
7443          *         </ul></li>
7444          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
7445          **/
7446         init: function (options) {
7447             this._super(options);
7448         },
7449 
7450         /**
7451          * @private
7452          * Gets the REST class for the current object - this is the Dialogs class.
7453          */
7454         getRestClass: function () {
7455             return Dialogs;
7456         },
7457 
7458         /**
7459          * @private
7460          * Gets the REST class for the objects that make up the collection. - this
7461          * is the Dialog class.
7462          */
7463         getRestItemClass: function () {
7464             return Dialog;
7465         },
7466 
7467         /**
7468          * @private
7469          * Gets the REST type for the current object - this is a "Dialogs".
7470          */
7471         getRestType: function () {
7472             return "Dialogs";
7473         },
7474 
7475         /**
7476          * @private
7477          * Gets the REST type for the objects that make up the collection - this is "Dialogs".
7478          */
7479         getRestItemType: function () {
7480             return "Dialog";
7481         },
7482 
7483         /**
7484          * @private
7485          * Override default to indicates that the collection doesn't support making
7486          * requests.
7487          */
7488         supportsRequests: true,
7489 
7490         /**
7491          * @private
7492          * Override default to indicates that the collection subscribes to its objects.
7493          */
7494         supportsRestItemSubscriptions: true,
7495 
7496         /**
7497          * @private
7498          * Create a new Dialog in this collection
7499          *
7500          * @param {String} toAddress
7501          *     The to address of the new Dialog
7502          * @param {String} fromAddress
7503          *     The from address of the new Dialog
7504          * @param {finesse.interfaces.RequestHandlers} handlers
7505          *     An object containing the (optional) handlers for the request.
7506          * @return {finesse.restservices.Dialogs}
7507          *     This Dialogs object, to allow cascading.
7508          */
7509         createNewCallDialog: function (toAddress, fromAddress, handlers)
7510         {
7511             var contentBody = {};
7512             contentBody[this.getRestItemType()] = {
7513                 "requestedAction": "MAKE_CALL",
7514                 "toAddress": toAddress,
7515                 "fromAddress": fromAddress
7516             };
7517 
7518             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
7519             handlers = handlers || {};
7520 
7521             this.restRequest(this.getRestUrl(), {
7522                 method: 'POST',
7523                 success: handlers.success,
7524                 error: handlers.error,
7525                 content: contentBody
7526             });
7527             return this; // Allow cascading
7528         },
7529 
7530         /**
7531          * @private
7532          * Create a new Dialog in this collection as a result of a requested action
7533          *
7534          * @param {String} toAddress
7535          *     The to address of the new Dialog
7536          * @param {String} fromAddress
7537          *     The from address of the new Dialog
7538          * @param {finesse.restservices.Dialog.Actions} actionType
7539          *     The associated action to request for creating this new dialog
7540          * @param {finesse.interfaces.RequestHandlers} handlers
7541          *     An object containing the (optional) handlers for the request.
7542          * @return {finesse.restservices.Dialogs}
7543          *     This Dialogs object, to allow cascading.
7544          */
7545         createNewSuperviseCallDialog: function (toAddress, fromAddress, actionType, handlers)
7546         {
7547             var contentBody = {};
7548             this._isLoaded = true;
7549 
7550             contentBody[this.getRestItemType()] = {
7551                 "requestedAction": actionType,
7552                 "toAddress": toAddress,
7553                 "fromAddress": fromAddress
7554             };
7555 
7556             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
7557             handlers = handlers || {};
7558 
7559             this.restRequest(this.getRestUrl(), {
7560                 method: 'POST',
7561                 success: handlers.success,
7562                 error: handlers.error,
7563                 content: contentBody
7564             });
7565             return this; // Allow cascading
7566         },
7567         
7568         /**
7569          * @private
7570          * Create a new Dialog in this collection as a result of a requested action
7571          * @param {String} fromAddress
7572          *     The from address of the new Dialog
7573          * @param {String} toAddress
7574          *     The to address of the new Dialog
7575          * @param {finesse.restservices.Dialog.Actions} actionType
7576          *     The associated action to request for creating this new dialog
7577          * @param {String} dialogUri
7578          *     The associated uri of SUPERVISOR_MONITOR call
7579          * @param {finesse.interfaces.RequestHandlers} handlers
7580          *     An object containing the (optional) handlers for the request.
7581          * @return {finesse.restservices.Dialogs}
7582          *     This Dialogs object, to allow cascading.
7583          */
7584         createNewBargeCall: function (fromAddress, toAddress, actionType, dialogURI, handlers) {
7585             this.isLoaded();
7586          
7587             var contentBody = {};
7588             contentBody[this.getRestItemType()] = {
7589                 "fromAddress": fromAddress,
7590                 "toAddress": toAddress,
7591                 "requestedAction": actionType,
7592                 "associatedDialogUri": dialogURI
7593                 
7594             };
7595             // (nonexistent) keys to be read as undefined
7596             handlers = handlers || {};  
7597             this.restRequest(this.getRestUrl(), {
7598                 method: 'POST',
7599                 success: handlers.success,
7600                 error: handlers.error,
7601                 content: contentBody
7602             });
7603             return this; // Allow cascading
7604         },
7605 
7606         /**
7607          * Utility method to get the number of dialogs in this collection.
7608          * 'excludeSilentMonitor' flag is provided as an option to exclude calls with type
7609          * 'SUPERVISOR_MONITOR' from the count.
7610          * @param  {Boolean} excludeSilentMonitor If true, calls with type of 'SUPERVISOR_MONITOR' will be excluded from the count.
7611          * @return {Number} The number of dialogs in this collection.
7612          */
7613         getDialogCount: function (excludeSilentMonitor) {
7614             this.isLoaded();
7615 
7616             var dialogId, count = 0;
7617             if (excludeSilentMonitor) {
7618                 for (dialogId in this._collection) {
7619                     if (this._collection.hasOwnProperty(dialogId)) {
7620                         if (this._collection[dialogId].getCallType() !== 'SUPERVISOR_MONITOR') {
7621                             count += 1;
7622                         }
7623                     }
7624                 }
7625 
7626                 return count;
7627             } else {
7628                 return this.length;
7629             }        
7630         }
7631 
7632     });
7633     
7634     window.finesse = window.finesse || {};
7635     window.finesse.restservices = window.finesse.restservices || {};
7636     window.finesse.restservices.Dialogs = Dialogs;
7637     
7638     return Dialogs;
7639 }));
7640 
7641 /**
7642  * JavaScript representation of the Finesse ClientLog object
7643  *
7644  * @requires finesse.clientservices.ClientServices
7645  * @requires Class
7646  * @requires finesse.FinesseBase
7647  * @requires finesse.restservices.RestBase
7648  */
7649 
7650 /** The following comment is to prevent jslint errors about 
7651  * using variables before they are defined.
7652  */
7653 /** @private */
7654 /*global finesse*/
7655 
7656 (function (factory) {
7657     
7658 
7659     // Define as an AMD module if possible
7660     if ( typeof define === 'function' && define.amd )
7661     {
7662         define('restservices/ClientLog',["restservices/RestBase"], factory );
7663     }
7664     
7665     /* Define using browser globals otherwise
7666      * Prevent multiple instantiations if the script is loaded twice
7667      */
7668     else
7669     {
7670         factory(finesse.restservices.RestBase);
7671     }
7672     
7673 }(function (RestBase) {
7674     
7675     var ClientLog = RestBase.extend(/** @lends finesse.restservices.ClientLog.prototype */{    
7676         /**
7677          * @private
7678          * Returns whether this object supports transport logs
7679          */
7680         doNotLog : true,
7681 
7682         doNotRefresh: true,
7683         
7684         explicitSubscription : true,
7685         
7686         /**
7687          * @class
7688          * @private
7689          * JavaScript representation of a ClientLog object. Also exposes methods to operate
7690          * on the object against the server.
7691          *
7692          * @param {Object} options
7693          *     An object with the following properties:<ul>
7694          *         <li><b>id:</b> The id of the object being constructed</li>
7695          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
7696          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
7697          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
7698          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
7699          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
7700          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
7701          *             <li><b>content:</b> {String} Raw string of response</li>
7702          *             <li><b>object:</b> {Object} Parsed object of response</li>
7703          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
7704          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
7705          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
7706          *             </ul></li>
7707          *         </ul></li>
7708          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
7709          * @constructs
7710          * @augments finesse.restservices.RestBase
7711          **/
7712         init: function (options) {
7713             this._super({
7714                 id: "", 
7715                 data: {clientLog : null},
7716                 onAdd: options.onAdd,
7717                 onChange: options.onChange,
7718                 onLoad: options.onLoad,
7719                 onError: options.onError,
7720                 parentObj: options.parentObj
7721                 });
7722         },
7723 
7724         /**
7725          * @private
7726          * Gets the REST class for the current object - this is the ClientLog object.
7727          */
7728         getRestClass: function () {
7729             return ClientLog;
7730         },
7731 
7732         /**
7733          * @private
7734          * Gets the REST type for the current object - this is a "ClientLog".
7735          */
7736         getRestType: function ()
7737         {
7738             return "ClientLog";
7739         },
7740         
7741         /**
7742          * @private
7743          * Gets the node path for the current object
7744          * @returns {String} The node path
7745          */
7746         getXMPPNodePath: function () {
7747             return this.getRestUrl();
7748         },
7749            
7750         /**
7751          * @private
7752          * Invoke a request to the server given a content body and handlers.
7753          *
7754          * @param {Object} contentBody
7755          *     A JS object containing the body of the action request.
7756          * @param {Object} handlers
7757          *     An object containing the following (optional) handlers for the request:<ul>
7758          *         <li><b>success(rsp):</b> A callback function for a successful request to be invoked with the following
7759          *         response object as its only parameter:<ul>
7760          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
7761          *             <li><b>content:</b> {String} Raw string of response</li>
7762          *             <li><b>object:</b> {Object} Parsed object of response</li></ul>
7763          *         <li>A error callback function for an unsuccessful request to be invoked with the
7764          *         error response object as its only parameter:<ul>
7765          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
7766          *             <li><b>content:</b> {String} Raw string of response</li>
7767          *             <li><b>object:</b> {Object} Parsed object of response (HTTP errors)</li>
7768          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
7769          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
7770          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
7771          *             </ul></li>
7772          *         </ul>
7773          */
7774         sendLogs: function (contentBody, handlers) {
7775             // Protect against null dereferencing of options allowing its
7776             // (nonexistent) keys to be read as undefined
7777             handlers = handlers || {};
7778 
7779             this.restRequest(this.getRestUrl(), {
7780                 method: 'POST',
7781                 //success: handlers.success,
7782                 error: handlers.error,
7783                 content: contentBody
7784             });
7785         }
7786     });
7787     
7788     window.finesse = window.finesse || {};
7789     window.finesse.restservices = window.finesse.restservices || {};
7790     window.finesse.restservices.ClientLog = ClientLog;
7791     
7792     return ClientLog;
7793 }));
7794 
7795 /**
7796  * JavaScript representation of the Finesse Queue object
7797  * @requires finesse.clientservices.ClientServices
7798  * @requires Class
7799  * @requires finesse.FinesseBase
7800  * @requires finesse.restservices.RestBase
7801  */
7802 
7803 /** @private */
7804  (function (factory) {
7805     
7806 
7807     // Define as an AMD module if possible
7808     if ( typeof define === 'function' && define.amd )
7809     {
7810         define('restservices/Queue', ['restservices/RestBase',
7811                  'utilities/Utilities'], factory );
7812     }
7813     /* Define using browser globals otherwise
7814      * Prevent multiple instantiations if the script is loaded twice
7815      */
7816     else
7817     {
7818         factory(finesse.restservices.RestBase, finesse.utilities.Utilities);
7819     } 
7820 }(function (RestBase, Utilities) {
7821 	var Queue = RestBase.extend(/** @lends finesse.restservices.Queue.prototype */{
7822 
7823         /**
7824          * @class
7825          * A Queue is a list of Contacts available to a User for quick dial.
7826          * 
7827          * @augments finesse.restservices.RestBase
7828          * @constructs
7829          */
7830         _fakeConstuctor: function () {
7831             /* This is here to hide the real init constructor from the public docs */
7832         },
7833         
7834 		/**
7835 		 * @private
7836 		 * JavaScript representation of a Queue object. Also exposes methods to operate
7837 		 * on the object against the server.
7838 		 *
7839 		 * @constructor
7840 		 * @param {String} id
7841 		 *     Not required...
7842 		 * @param {Object} callbacks
7843 		 *     An object containing callbacks for instantiation and runtime
7844 		 * @param {Function} callbacks.onLoad(this)
7845 		 *     Callback to invoke upon successful instantiation
7846 		 * @param {Function} callbacks.onLoadError(rsp)
7847 		 *     Callback to invoke on instantiation REST request error
7848 		 *     as passed by finesse.clientservices.ClientServices.ajax()
7849 		 *     {
7850 		 *         status: {Number} The HTTP status code returned
7851 		 *         content: {String} Raw string of response
7852 		 *         object: {Object} Parsed object of response
7853 		 *         error: {Object} Wrapped exception that was caught
7854 		 *         error.errorType: {String} Type of error that was caught
7855 		 *         error.errorMessage: {String} Message associated with error
7856 		 *     }
7857 		 * @param {Function} callbacks.onChange(this)
7858 		 *     Callback to invoke upon successful update
7859 		 * @param {Function} callbacks.onError(rsp)
7860 		 *     Callback to invoke on update error (refresh or event)
7861 		 *     as passed by finesse.clientservices.ClientServices.ajax()
7862 		 *     {
7863 		 *         status: {Number} The HTTP status code returned
7864 		 *         content: {String} Raw string of response
7865 		 *         object: {Object} Parsed object of response
7866 		 *         error: {Object} Wrapped exception that was caught
7867 		 *         error.errorType: {String} Type of error that was caught
7868 		 *         error.errorMessage: {String} Message associated with error
7869 		 *     }
7870 		 *  
7871 		 */
7872         init: function (id, callbacks, restObj) {
7873             this._super(id, callbacks, restObj);
7874         },
7875 
7876         /**
7877          * @private
7878          * Gets the REST class for the current object - this is the Queue object.
7879          */
7880         getRestClass: function () {
7881             return Queue;
7882         },
7883 
7884         /**
7885          * @private
7886          * Gets the REST type for the current object - this is a "Queue".
7887          */
7888         getRestType: function () {
7889             return "Queue";
7890         },
7891 
7892         /**
7893          * @private
7894          * Returns whether this object supports subscriptions
7895          */
7896         supportsSubscriptions: function () {
7897             return true;
7898         },
7899         
7900         /**
7901          * @private
7902          * Specifies whether this object's subscriptions need to be explicitly requested
7903          */
7904         explicitSubscription: true,
7905 
7906         /**
7907          * @private
7908          * Specifies that this object should not be refreshed; possible reasons are that
7909          * it's encapsulating collection already does it
7910          */
7911         doNotRefresh: true,
7912         
7913         /**
7914          * @private
7915          * Gets the node path for the current object - this is the team Users node
7916          * @returns {String} The node path
7917          */
7918         getXMPPNodePath: function () {
7919             return this.getRestUrl();
7920         },
7921         
7922         /**
7923          * Getter for the queue id
7924          * @returns {String}
7925          *     The id of the Queue
7926          */
7927         getId: function () {
7928             this.isLoaded();
7929             return this._id;
7930         },
7931         
7932         /**
7933          * Getter for the queue name
7934          * @returns {String}
7935          *      The name of the Queue
7936          */
7937         getName: function () {
7938             this.isLoaded();
7939             return this.getData().name;
7940         },
7941         
7942         /**
7943          * Getter for the queue statistics.
7944          * Supported statistics include:<br>
7945          *  - callsInQueue<br>
7946          *  - startTimeOfLongestCallInQueue<br>
7947          *  <br>
7948          *  These statistics can be accessed via dot notation:<br>
7949          *  i.e.: getStatistics().callsInQueue
7950          * @returns {Object}
7951          *      The Object with different statistics as properties.
7952          */
7953         getStatistics: function () {
7954             this.isLoaded();
7955             return this.getData().statistics;       
7956         },
7957 
7958         /**
7959          * Parses a uriString to retrieve the id portion
7960          * @param {String} uriString
7961          * @return {String} id
7962          */
7963         _parseIdFromUriString : function (uriString) {
7964             return Utilities.getId(uriString);
7965         }
7966 
7967     });
7968 	
7969 	window.finesse = window.finesse || {};
7970     window.finesse.restservices = window.finesse.restservices || {};
7971     window.finesse.restservices.Queue = Queue;
7972     
7973     return Queue;
7974 }));
7975 
7976 /**
7977  * JavaScript representation of the Finesse Queues collection
7978  * object which contains a list of Queue objects.
7979  * @requires finesse.clientservices.ClientServices
7980  * @requires Class
7981  * @requires finesse.FinesseBase
7982  * @requires finesse.restservices.RestBase
7983  * @requires finesse.restservices.RestCollectionBase
7984  */
7985 
7986 /**
7987  * @class
7988  * JavaScript representation of a Queues collection object.
7989  *
7990  * @constructor
7991  * @borrows finesse.restservices.RestCollectionBase as finesse.restservices.Queues
7992  */
7993 
7994 /** @private */
7995  (function (factory) {
7996     
7997 
7998     // Define as an AMD module if possible
7999     if ( typeof define === 'function' && define.amd )
8000     {
8001         define('restservices/Queues', ['restservices/RestCollectionBase',
8002                  'restservices/Queue'], factory );
8003     }
8004     /* Define using browser globals otherwise
8005      * Prevent multiple instantiations if the script is loaded twice
8006      */
8007     else
8008     {
8009         factory(finesse.restservices.RestCollectionBase, finesse.restservices.Queue);
8010     } 
8011 }(function (RestCollectionBase, Queue) {
8012 	var Queues = RestCollectionBase.extend(/** @lends finesse.restservices.Queues.prototype */{
8013 
8014         /**
8015          * @class
8016          * JavaScript representation of a Queues collection object. 
8017          * @augments finesse.restservices.RestCollectionBase
8018          * @constructs
8019          * @see finesse.restservices.Queue
8020          * @example
8021          *  _queues = _user.getQueues( {
8022          *      onCollectionAdd : _handleQueueAdd,
8023          *      onCollectionDelete : _handleQueueDelete,
8024          *      onLoad : _handleQueuesLoaded
8025          *  });
8026          *  
8027          * _queueCollection = _queues.getCollection();
8028          * for (var queueId in _queueCollection) {
8029          *     if (_queueCollection.hasOwnProperty(queueId)) {
8030          *         _queue = _queueCollection[queueId];
8031          *         etc...
8032          *     }
8033          * }
8034          */
8035         _fakeConstuctor: function () {
8036             /* This is here to hide the real init constructor from the public docs */
8037         },
8038 	    
8039          /**
8040          * @private
8041          * JavaScript representation of a Queues object. Also exposes
8042          * methods to operate on the object against the server.
8043          *
8044          * @param {Object} options
8045          *     An object with the following properties:<ul>
8046          *         <li><b>id:</b> The id of the object being constructed</li>
8047          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
8048          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
8049          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
8050          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
8051          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
8052          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
8053          *             <li><b>content:</b> {String} Raw string of response</li>
8054          *             <li><b>object:</b> {Object} Parsed object of response</li>
8055          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
8056          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
8057          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
8058          *             </ul></li>
8059          *         </ul></li>
8060          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
8061          **/
8062         init: function (options) {
8063             this._super(options);           
8064         },
8065 
8066         /**
8067          * @private
8068          * Gets xmpp node path.
8069          */
8070         getXMPPNodePath: function () {
8071             return this.getRestUrl();
8072         },
8073 
8074         /**
8075          * @private
8076          * Gets the REST class for the current object - this is the Queues class.
8077          */
8078         getRestClass: function () {
8079             return Queues;
8080         },
8081 
8082         /**
8083          * @private
8084          * Gets the REST class for the objects that make up the collection. - this
8085          * is the Queue class.
8086          */
8087         getRestItemClass: function () {
8088             return Queue;
8089         },
8090 
8091         /**
8092          * @private
8093          * Gets the REST type for the current object - this is a "Queues".
8094          */
8095         getRestType: function () {
8096             return "Queues";
8097         },
8098         
8099         /**
8100          * @private
8101          * Gets the REST type for the objects that make up the collection - this is "Queue".
8102          */
8103         getRestItemType: function () {
8104             return "Queue";
8105         },
8106 
8107         explicitSubscription: true
8108     });
8109     
8110     window.finesse = window.finesse || {};
8111     window.finesse.restservices = window.finesse.restservices || {};
8112     window.finesse.restservices.Queues = Queues;
8113     
8114     return Queues;
8115 }));
8116 
8117 /**
8118  * JavaScript representation of the Finesse WrapUpReason object.
8119  *
8120  * @requires finesse.clientservices.ClientServices
8121  * @requires Class
8122  * @requires finesse.FinesseBase
8123  * @requires finesse.restservices.RestBase
8124  */
8125 
8126 /** @private */
8127 (function (factory) {
8128     
8129 
8130     // Define as an AMD module if possible
8131     if ( typeof define === 'function' && define.amd )
8132     {
8133         define('restservices/WrapUpReason',['restservices/RestBase'], factory);
8134     }
8135     /* Define using browser globals otherwise
8136      * Prevent multiple instantiations if the script is loaded twice
8137      */
8138     else
8139     {
8140         factory(finesse.restservices.RestBase);
8141     } 
8142 }(function (RestBase) {
8143 
8144     var WrapUpReason = RestBase.extend(/** @lends finesse.restservices.WrapUpReason.prototype */{
8145 
8146         /**
8147          * @class
8148          * A WrapUpReason is a code and description identifying a particular reason that a
8149          * User is in WORK (WrapUp) mode.
8150          * 
8151          * @augments finesse.restservices.RestBase
8152          * @see finesse.restservices.User
8153          * @see finesse.restservices.User.States#WORK
8154          * @constructs
8155          */
8156         _fakeConstuctor: function () {
8157             /* This is here to hide the real init constructor from the public docs */
8158         },
8159         
8160         /** 
8161          * @private
8162          * JavaScript representation of a WrapUpReason object. Also exposes
8163          * methods to operate on the object against the server.
8164          *
8165          * @param {Object} options
8166          *     An object with the following properties:<ul>
8167          *         <li><b>id:</b> The id of the object being constructed</li>
8168          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
8169          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
8170          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
8171          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
8172          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
8173          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
8174          *             <li><b>content:</b> {String} Raw string of response</li>
8175          *             <li><b>object:</b> {Object} Parsed object of response</li>
8176          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
8177          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
8178          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
8179          *             </ul></li>
8180          *         </ul></li>
8181          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
8182          **/
8183         init: function (options) {
8184             this._super(options);
8185         },
8186 
8187         /**
8188          * @private
8189          * Gets the REST class for the current object - this is the WrapUpReason class.
8190          * @returns {Object} The WrapUpReason class.
8191          */
8192         getRestClass: function () {
8193             return WrapUpReason;
8194         },
8195 
8196         /**
8197          * @private
8198          * Gets the REST type for the current object - this is a "WrapUpReason".
8199          * @returns {String} The WrapUpReason string.
8200          */
8201         getRestType: function () {
8202             return "WrapUpReason";
8203         },
8204 
8205         /**
8206          * @private
8207          * Gets the REST type for the current object - this is a "WrapUpReasons".
8208          * @returns {String} The WrapUpReasons string.
8209          */
8210         getParentRestType: function () {
8211             return "WrapUpReasons";
8212         },
8213 
8214         /**
8215          * @private
8216          * Override default to indicate that this object doesn't support making
8217          * requests.
8218          */
8219         supportsRequests: false,
8220 
8221         /**
8222          * @private
8223          * Override default to indicate that this object doesn't support subscriptions.
8224          */
8225         supportsSubscriptions: false,
8226 
8227         /**
8228          * Getter for the label.
8229          * @returns {String} The label.
8230          */
8231         getLabel: function () {
8232             this.isLoaded();
8233             return this.getData().label;
8234         },
8235 
8236         /**
8237          * @private
8238          * Getter for the forAll flag.
8239          * @returns {Boolean} True if global.
8240          */
8241         getForAll: function () {
8242             this.isLoaded();
8243             return this.getData().forAll;
8244         },
8245 
8246         /**
8247          * @private
8248          * Getter for the Uri value.
8249          * @returns {String} The Uri.
8250          */
8251         getUri: function () {
8252             this.isLoaded();
8253             return this.getData().uri;
8254         }
8255     });
8256 
8257     window.finesse = window.finesse || {};
8258     window.finesse.restservices = window.finesse.restservices || {};
8259     window.finesse.restservices.WrapUpReason = WrapUpReason;
8260         
8261     return WrapUpReason;
8262 }));
8263 
8264 /**
8265 * JavaScript representation of the Finesse WrapUpReasons collection
8266 * object which contains a list of WrapUpReason objects.
8267  *
8268  * @requires finesse.clientservices.ClientServices
8269  * @requires Class
8270  * @requires finesse.FinesseBase
8271  * @requires finesse.restservices.RestBase
8272  * @requires finesse.restservices.Dialog
8273  * @requires finesse.restservices.RestCollectionBase
8274  */
8275 
8276 /** @private */
8277 (function (factory) {
8278     
8279 
8280     // Define as an AMD module if possible
8281     if ( typeof define === 'function' && define.amd )
8282     {
8283         define('restservices/WrapUpReasons', ['restservices/RestCollectionBase',
8284                  'restservices/WrapUpReason'], factory );
8285     }
8286     /* Define using browser globals otherwise
8287      * Prevent multiple instantiations if the script is loaded twice
8288      */
8289     else
8290     {
8291         factory(finesse.restservices.RestCollectionBase, finesse.restservices.WrapUpReason);
8292     } 
8293 }(function (RestCollectionBase, WrapUpReason) {
8294 
8295     var WrapUpReasons = RestCollectionBase.extend(/** @lends finesse.restservices.WrapUpReasons.prototype */{
8296         
8297         /**
8298          * @class
8299          * JavaScript representation of a WrapUpReasons collection object. 
8300          * @augments finesse.restservices.RestCollectionBase
8301          * @constructs
8302          * @see finesse.restservices.WrapUpReason
8303          * @example
8304          *  _wrapUpReasons = _user.getWrapUpReasons ( {
8305          *      onCollectionAdd : _handleWrapUpReasonAdd,
8306          *      onCollectionDelete : _handleWrapUpReasonDelete,
8307          *      onLoad : _handleWrapUpReasonsLoaded
8308          *  });
8309          *  
8310          * _wrapUpReasonCollection = _wrapUpReasons.getCollection();
8311          * for (var wrapUpReasonId in _wrapUpReasonCollection) {
8312          *     if (_wrapUpReasonCollection.hasOwnProperty(wrapUpReasonId)) {
8313          *         _wrapUpReason = _wrapUpReasonCollection[wrapUpReasonId];
8314          *         etc...
8315          *     }
8316          * }
8317         */
8318         _fakeConstuctor: function () {
8319             /* This is here to hide the real init constructor from the public docs */
8320         },
8321         
8322         /** 
8323          * @private
8324          * JavaScript representation of a WrapUpReasons collection object. Also exposes
8325          * methods to operate on the object against the server.
8326          *
8327          * @param {Object} options
8328          *     An object with the following properties:<ul>
8329          *         <li><b>id:</b> The id of the object being constructed</li>
8330          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
8331          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
8332          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
8333          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
8334          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
8335          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
8336          *             <li><b>content:</b> {String} Raw string of response</li>
8337          *             <li><b>object:</b> {Object} Parsed object of response</li>
8338          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
8339          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
8340          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
8341          *             </ul></li>
8342          *         </ul></li>
8343          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
8344          **/
8345         init: function (options) {
8346             this._super(options);           
8347         },
8348 
8349         /**
8350          * @private
8351          * Gets the REST class for the current object - this is the WrapUpReasons class.
8352          */
8353         getRestClass: function () {
8354             return WrapUpReasons;
8355         },
8356 
8357         /**
8358          * @private
8359          * Gets the REST class for the objects that make up the collection. - this
8360          * is the WrapUpReason class.
8361          */
8362         getRestItemClass: function () {
8363             return WrapUpReason;
8364         },
8365 
8366         /**
8367          * @private
8368          * Gets the REST type for the current object - this is a "WrapUpReasons".
8369          */
8370         getRestType: function () {
8371             return "WrapUpReasons";
8372         },
8373         
8374         /**
8375          * @private
8376          * Gets the REST type for the objects that make up the collection - this is "WrapUpReason".
8377          */
8378         getRestItemType: function () {
8379             return "WrapUpReason";
8380         },
8381 
8382         /**
8383          * @private
8384          * Override default to indicates that the collection supports making
8385          * requests.
8386          */
8387         supportsRequests: true,
8388 
8389         /**
8390          * @private
8391          * Override default to indicate that this object doesn't support subscriptions.
8392          */
8393         supportsRestItemSubscriptions: false,
8394 
8395         /**
8396          * @private
8397          * Retrieve the Wrap-Up Reason Codes. This call will re-query the server and refresh the collection.
8398          *
8399          * @returns {finesse.restservices.WrapUpReasons}
8400          *     This ReadyReasonCodes object to allow cascading.
8401          */
8402         get: function () {
8403             // set loaded to false so it will rebuild the collection after the get
8404             this._loaded = false;
8405             // reset collection
8406             this._collection = {};
8407             // perform get
8408             this._synchronize();
8409             return this;
8410         }
8411         
8412     });
8413  
8414     window.finesse = window.finesse || {};
8415     window.finesse.restservices = window.finesse.restservices || {};
8416     window.finesse.restservices.WrapUpReasons = WrapUpReasons;
8417        
8418     return WrapUpReasons;
8419 }));
8420 
8421 /**
8422  * JavaScript representation of the Finesse Contact object.
8423  * @requires finesse.clientservices.ClientServices
8424  * @requires Class
8425  * @requires finesse.FinesseBase
8426  * @requires finesse.restservices.RestBase
8427  */
8428 /** @private */
8429 (function (factory) {
8430     
8431 
8432     // Define as an AMD module if possible
8433     if ( typeof define === 'function' && define.amd )
8434     {
8435         define('restservices/Contact',['restservices/RestBase'], factory);
8436     }
8437     /* Define using browser globals otherwise
8438      * Prevent multiple instantiations if the script is loaded twice
8439      */
8440     else
8441     {
8442         factory(finesse.restservices.RestBase);
8443     } 
8444 }(function (RestBase) {
8445     var Contact = RestBase.extend(/** @lends finesse.restservices.Contact.prototype */{
8446 
8447         /**
8448          * @class
8449          * A Contact is a single entry in a PhoneBook, consisting of a First and Last Name,
8450          * a Phone Number, and a Description.
8451          * 
8452          * @augments finesse.restservices.RestBase
8453          * @see finesse.restservices.PhoneBook
8454          * @constructs
8455          */
8456         _fakeConstuctor: function () {
8457             /* This is here to hide the real init constructor from the public docs */
8458         },
8459         
8460         /**
8461          * @private
8462          * @param {Object} options
8463          *     An object with the following properties:<ul>
8464          *         <li><b>id:</b> The id of the object being constructed</li>
8465          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
8466          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
8467          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
8468          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
8469          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
8470          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
8471          *             <li><b>content:</b> {String} Raw string of response</li>
8472          *             <li><b>object:</b> {Object} Parsed object of response</li>
8473          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
8474          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
8475          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
8476          *             </ul></li>
8477          *         </ul></li>
8478          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
8479          **/
8480         init: function (options) {
8481             this._super(options);
8482         },
8483 
8484         /**
8485          * @private
8486          * Gets the REST class for the current object - this is the Contact class.
8487          * @returns {Object} The Contact class.
8488          */
8489         getRestClass: function () {
8490             return Contact;
8491         },
8492 
8493         /**
8494          * @private
8495          * Gets the REST type for the current object - this is a "Contact".
8496          * @returns {String} The Contact string.
8497          */
8498         getRestType: function () {
8499             return "Contact";
8500         },
8501 
8502         /**
8503          * @private
8504          * Override default to indicate that this object doesn't support making
8505          * requests.
8506          */
8507         supportsRequests: false,
8508 
8509         /**
8510          * @private
8511          * Override default to indicate that this object doesn't support subscriptions.
8512          */
8513         supportsSubscriptions: false,
8514 
8515         /**
8516          * Getter for the firstName.
8517          * @returns {String} The firstName.
8518          */
8519         getFirstName: function () {
8520             this.isLoaded();
8521             return this.getData().firstName;
8522         },
8523 
8524         /**
8525          * Getter for the lastName.
8526          * @returns {String} The lastName.
8527          */
8528         getLastName: function () {
8529             this.isLoaded();
8530             return this.getData().lastName;
8531         },
8532 
8533         /**
8534          * Getter for the phoneNumber.
8535          * @returns {String} The phoneNumber.
8536          */
8537         getPhoneNumber: function () {
8538             this.isLoaded();
8539             return this.getData().phoneNumber;
8540         },
8541 
8542         /**
8543          * Getter for the description.
8544          * @returns {String} The description.
8545          */
8546         getDescription: function () {
8547             this.isLoaded();
8548             return this.getData().description;
8549         },
8550 
8551         /** @private */
8552         createPutSuccessHandler: function(contact, contentBody, successHandler){
8553             return function (rsp) {
8554                 // Update internal structure based on response. Here we
8555                 // inject the contentBody from the PUT request into the
8556                 // rsp.object element to mimic a GET as a way to take
8557                 // advantage of the existing _processResponse method.
8558                 rsp.object = contentBody;
8559                 contact._processResponse(rsp);
8560 
8561                 //Remove the injected Contact object before cascading response
8562                 rsp.object = {};
8563                 
8564                 //cascade response back to consumer's response handler
8565                 successHandler(rsp);
8566             };
8567         },
8568 
8569         /** @private */
8570         createPostSuccessHandler: function (contact, contentBody, successHandler) {
8571             return function (rsp) {
8572                 rsp.object = contentBody;
8573                 contact._processResponse(rsp);
8574 
8575                 //Remove the injected Contact object before cascading response
8576                 rsp.object = {};
8577 
8578                 //cascade response back to consumer's response handler
8579                 successHandler(rsp);
8580             };
8581         },
8582 
8583         /**
8584          * Add
8585          * @private
8586          */
8587         add: function (newValues, handlers) {
8588             // this.isLoaded();
8589             var contentBody = {};
8590 
8591             contentBody[this.getRestType()] = {
8592                 "firstName": newValues.firstName,
8593                 "lastName": newValues.lastName,
8594                 "phoneNumber": newValues.phoneNumber,
8595                 "description": newValues.description
8596             };
8597 
8598             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
8599             handlers = handlers || {};
8600 
8601             this.restRequest(this.getRestUrl(), {
8602                 method: 'POST',
8603                 success: this.createPostSuccessHandler(this, contentBody, handlers.success),
8604                 error: handlers.error,
8605                 content: contentBody
8606             });
8607 
8608             return this; // Allow cascading
8609         },
8610 
8611         /**
8612          * Update
8613          * @private
8614          */
8615         update: function (newValues, handlers) {
8616             this.isLoaded();
8617             var contentBody = {};
8618 
8619             contentBody[this.getRestType()] = {
8620                 "uri": this.getId(),
8621                 "firstName": newValues.firstName,
8622                 "lastName": newValues.lastName,
8623                 "phoneNumber": newValues.phoneNumber,
8624                 "description": newValues.description
8625             };
8626 
8627             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
8628             handlers = handlers || {};
8629 
8630             this.restRequest(this.getRestUrl(), {
8631                 method: 'PUT',
8632                 success: this.createPutSuccessHandler(this, contentBody, handlers.success),
8633                 error: handlers.error,
8634                 content: contentBody
8635             });
8636 
8637             return this; // Allow cascading
8638         },
8639 
8640 
8641         /**
8642          * Delete
8643          * @private
8644          */
8645         "delete": function ( handlers) {
8646             this.isLoaded();
8647 
8648             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
8649             handlers = handlers || {};
8650 
8651             this.restRequest(this.getRestUrl(), {
8652                 method: 'DELETE',
8653                 success: this.createPutSuccessHandler(this, {}, handlers.success),
8654                 error: handlers.error,
8655                 content: undefined
8656             });
8657 
8658             return this; // Allow cascading
8659         }
8660     });
8661 
8662     window.finesse = window.finesse || {};
8663     window.finesse.restservices = window.finesse.restservices || {};
8664     window.finesse.restservices.Contact = Contact;
8665     
8666     return Contact;
8667 }));
8668 
8669 /**
8670 * JavaScript representation of the Finesse Contacts collection
8671 * object which contains a list of Contact objects.
8672  *
8673  * @requires finesse.clientservices.ClientServices
8674  * @requires Class
8675  * @requires finesse.FinesseBase
8676  * @requires finesse.restservices.RestBase
8677  * @requires finesse.restservices.Dialog
8678  * @requires finesse.restservices.RestCollectionBase
8679  */
8680 /** @private */
8681 (function (factory) {
8682     
8683 
8684     // Define as an AMD module if possible
8685     if ( typeof define === 'function' && define.amd )
8686     {
8687         define('restservices/Contacts', ['restservices/RestCollectionBase',
8688                 'restservices/Contact'], factory );
8689     }
8690     /* Define using browser globals otherwise
8691      * Prevent multiple instantiations if the script is loaded twice
8692      */
8693     else
8694     {
8695         factory(finesse.restservices.RestCollectionBase, finesse.restservices.Contact);
8696     } 
8697 }(function (RestCollectionBase, Contact) {
8698     var Contacts = RestCollectionBase.extend(/** @lends finesse.restservices.Contacts.prototype */{
8699         
8700         /**
8701          * @class
8702          * JavaScript representation of a Contacts collection object. Also exposes
8703          * methods to operate on the object against the server.
8704          * @augments finesse.restservices.RestCollectionBase
8705          * @constructs
8706          * @see finesse.restservices.Contact
8707          * @see finesse.restservices.PhoneBook
8708          * @example
8709          *  _contacts = _phonebook.getContacts( {
8710          *      onCollectionAdd : _handleContactAdd,
8711          *      onCollectionDelete : _handleContactDelete,
8712          *      onLoad : _handleContactsLoaded
8713          *  });
8714          *  
8715          * _contactCollection = _contacts.getCollection();
8716          * for (var contactId in _contactCollection) {
8717          *     if (_contactCollection.hasOwnProperty(contactId)) {
8718          *         _contact = _contactCollection[contactId];
8719          *         etc...
8720          *     }
8721          * }
8722          */
8723         _fakeConstuctor: function () {
8724             /* This is here to hide the real init constructor from the public docs */
8725         },
8726         
8727         /** 
8728          * @private
8729          * JavaScript representation of a Contacts collection object. Also exposes
8730          * methods to operate on the object against the server.
8731          *
8732          * @param {Object} options
8733          *     An object with the following properties:<ul>
8734          *         <li><b>id:</b> The id of the object being constructed</li>
8735          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
8736          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
8737          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
8738          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
8739          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
8740          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
8741          *             <li><b>content:</b> {String} Raw string of response</li>
8742          *             <li><b>object:</b> {Object} Parsed object of response</li>
8743          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
8744          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
8745          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
8746          *             </ul></li>
8747          *         </ul></li>
8748          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
8749          **/
8750         init: function (options) {
8751             this._super(options);           
8752         },
8753 
8754         /**
8755          * @private
8756          * Gets the REST class for the current object - this is the Contacts class.
8757          */
8758         getRestClass: function () {
8759             return Contacts;
8760         },
8761 
8762         /**
8763          * @private
8764          * Gets the REST class for the objects that make up the collection. - this
8765          * is the Contact class.
8766          */
8767         getRestItemClass: function () {
8768             return Contact;
8769         },
8770 
8771         /**
8772          * @private
8773          * Gets the REST type for the current object - this is a "Contacts".
8774          */
8775         getRestType: function () {
8776             return "Contacts";
8777         },
8778         
8779         /**
8780          * @private
8781          * Gets the REST type for the objects that make up the collection - this is "Contacts".
8782          */
8783         getRestItemType: function () {
8784             return "Contact";
8785         },
8786 
8787         /**
8788          * @private
8789          * Override default to indicates that the collection supports making
8790          * requests.
8791          */
8792         supportsRequests: true,
8793 
8794         /**
8795          * @private
8796          * Override default to indicates that the collection subscribes to its objects.
8797          */
8798         supportsRestItemSubscriptions: false,
8799         
8800         /**
8801          * @private
8802          * Retrieve the Contacts.  This call will re-query the server and refresh the collection.
8803          *
8804          * @returns {finesse.restservices.Contacts}
8805          *     This Contacts object, to allow cascading.
8806          */
8807         get: function () {
8808             // set loaded to false so it will rebuild the collection after the get
8809             this._loaded = false;
8810             // reset collection
8811             this._collection = {};
8812             // perform get
8813             this._synchronize();
8814             return this;
8815         }
8816         
8817     });
8818     
8819     window.finesse = window.finesse || {};
8820     window.finesse.restservices = window.finesse.restservices || {};
8821     window.finesse.restservices.Contacts = Contacts;
8822     
8823     
8824     return Contacts;
8825 }));
8826 
8827 /**
8828  * JavaScript representation of the Finesse PhoneBook object.
8829  *
8830  * @requires finesse.clientservices.ClientServices
8831  * @requires Class
8832  * @requires finesse.FinesseBase
8833  * @requires finesse.restservices.RestBase
8834  */
8835 
8836 /** @private */
8837 (function (factory) {
8838     
8839 
8840     // Define as an AMD module if possible
8841     if ( typeof define === 'function' && define.amd )
8842     {
8843         define('restservices/PhoneBook',['restservices/RestBase',
8844 				'restservices/Contacts'], factory);
8845     }
8846     /* Define using browser globals otherwise
8847      * Prevent multiple instantiations if the script is loaded twice
8848      */
8849     else
8850     {
8851         factory(finesse.restservices.RestBase,
8852 				finesse.restservices.Contacts);
8853     } 
8854 }(function (RestBase, Contacts) {
8855     var PhoneBook = RestBase.extend(/** @lends finesse.restservices.PhoneBook.prototype */{
8856 
8857         _contacts: null,
8858 
8859         /**
8860          * @class
8861          * A PhoneBook is a list of Contacts available to a User for quick dial.
8862          * 
8863          * @augments finesse.restservices.RestBase
8864          * @see finesse.restservices.Contacts
8865          * @constructs
8866          */
8867         _fakeConstuctor: function () {
8868             /* This is here to hide the real init constructor from the public docs */
8869         },
8870         
8871         /** 
8872          * @private
8873          * JavaScript representation of a PhoneBook object. Also exposes
8874          * methods to operate on the object against the server.
8875          *
8876          * @param {Object} options
8877          *     An object with the following properties:<ul>
8878          *         <li><b>id:</b> The id of the object being constructed</li>
8879          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
8880          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
8881          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
8882          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
8883          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
8884          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
8885          *             <li><b>content:</b> {String} Raw string of response</li>
8886          *             <li><b>object:</b> {Object} Parsed object of response</li>
8887          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
8888          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
8889          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
8890          *             </ul></li>
8891          *         </ul></li>
8892          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
8893          **/
8894         init: function (options) {
8895             this._super(options);
8896         },
8897 
8898         /**
8899          * @private
8900          * Gets the REST class for the current object - this is the PhoneBook class.
8901          * @returns {Object} The PhoneBook class.
8902          */
8903         getRestClass: function () {
8904             return PhoneBook;
8905         },
8906 
8907         /**
8908          * @private
8909          * Gets the REST type for the current object - this is a "PhoneBook".
8910          * @returns {String} The PhoneBook string.
8911          */
8912         getRestType: function () {
8913             return "PhoneBook";
8914         },
8915 
8916         /**
8917          * @private
8918          * Override default to indicate that this object doesn't support making
8919          * requests.
8920          */
8921         supportsRequests: false,
8922 
8923         /**
8924          * @private
8925          * Override default to indicate that this object doesn't support subscriptions.
8926          */
8927         supportsSubscriptions: false,
8928 
8929         /**
8930          * Getter for the name of the Phone Book.
8931          * @returns {String} The name.
8932          */
8933         getName: function () {
8934             this.isLoaded();
8935             return this.getData().name;
8936         },
8937 
8938         /**
8939          * Getter for the type flag.
8940          * @returns {String} The type.
8941          */
8942         getType: function () {
8943             this.isLoaded();
8944             return this.getData().type;
8945         },
8946 
8947         /**
8948          * @private
8949          * Getter for the Uri value.
8950          * @returns {String} The Uri.
8951          */
8952         getUri: function () {
8953             this.isLoaded();
8954             return this.getData().uri;
8955         },
8956 
8957         /**
8958          * Getter for a Contacts collection object that is associated with PhoneBook.
8959          * @param {finesse.interfaces.RequestHandlers} handlers
8960          *     An object containing the handlers for the request
8961          * @returns {finesse.restservices.Contacts}
8962          *     A Contacts collection object.
8963          */
8964         getContacts: function (callbacks) {
8965             var options = callbacks || {};
8966             options.parentObj = this;
8967             this.isLoaded();
8968 
8969             if (this._contacts === null) {
8970                 this._contacts = new Contacts(options);
8971             }
8972 
8973             return this._contacts;
8974         },
8975 
8976         /**
8977          * Getter for <contacts> node within PhoneBook - sometimes it's just a URI, sometimes it is a Contacts collection
8978          * @returns {String} uri to contacts
8979          *          or {finesse.restservices.Contacts} collection
8980          */
8981         getEmbeddedContacts: function(){
8982             this.isLoaded();
8983             return this.getData().contacts;
8984         },
8985 
8986         /** @private */
8987         createPutSuccessHandler: function(phonebook, contentBody, successHandler){
8988             return function (rsp) {
8989                 // Update internal structure based on response. Here we
8990                 // inject the contentBody from the PUT request into the
8991                 // rsp.object element to mimic a GET as a way to take
8992                 // advantage of the existing _processResponse method.
8993                 rsp.object = contentBody;
8994                 phonebook._processResponse(rsp);
8995 
8996                 //Remove the injected PhoneBook object before cascading response
8997                 rsp.object = {};
8998                 
8999                 //cascade response back to consumer's response handler
9000                 successHandler(rsp);
9001             };
9002         },
9003 
9004         /** @private */
9005         createPostSuccessHandler: function (phonebook, contentBody, successHandler) {
9006             return function (rsp) {
9007                 rsp.object = contentBody;
9008                 phonebook._processResponse(rsp);
9009 
9010                 //Remove the injected PhoneBook object before cascading response
9011                 rsp.object = {};
9012 
9013                 //cascade response back to consumer's response handler
9014                 successHandler(rsp);
9015             };
9016         },
9017 
9018         /**
9019          * @private
9020          * Add a PhoneBook.
9021          * @param {Object} newValues
9022          * @param {String} newValues.name Name of PhoneBook
9023          * @param {String} newValues.type Type of PhoneBook
9024          * @param {finesse.interfaces.RequestHandlers} handlers
9025          *     An object containing the handlers for the request
9026          * @returns {finesse.restservices.PhoneBook}
9027          *     This PhoneBook object, to allow cascading
9028          */
9029         add: function (newValues, handlers) {
9030             // this.isLoaded();
9031             var contentBody = {};
9032 
9033             contentBody[this.getRestType()] = {
9034                 "name": newValues.name,
9035                 "type": newValues.type
9036             };
9037 
9038             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
9039             handlers = handlers || {};
9040 
9041             this.restRequest(this.getRestUrl(), {
9042                 method: 'POST',
9043                 success: this.createPostSuccessHandler(this, contentBody, handlers.success),
9044                 error: handlers.error,
9045                 content: contentBody
9046             });
9047 
9048             return this; // Allow cascading
9049         },
9050 
9051         /**
9052          * @private
9053          * Update a PhoneBook.
9054          * @param {Object} newValues
9055          * @param {String} newValues.name Name of PhoneBook
9056          * @param {String} newValues.type Type of PhoneBook
9057          * @param {finesse.interfaces.RequestHandlers} handlers
9058          *     An object containing the handlers for the request
9059          * @returns {finesse.restservices.PhoneBook}
9060          *     This PhoneBook object, to allow cascading
9061          */
9062         update: function (newValues, handlers) {
9063             this.isLoaded();
9064             var contentBody = {};
9065 
9066             contentBody[this.getRestType()] = {
9067                 "uri": this.getId(),
9068                 "name": newValues.name,
9069                 "type": newValues.type
9070             };
9071 
9072             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
9073             handlers = handlers || {};
9074 
9075             this.restRequest(this.getRestUrl(), {
9076                 method: 'PUT',
9077                 success: this.createPutSuccessHandler(this, contentBody, handlers.success),
9078                 error: handlers.error,
9079                 content: contentBody
9080             });
9081 
9082             return this; // Allow cascading
9083         },
9084 
9085 
9086         /**
9087          * Delete a PhoneBook.
9088          * @param {finesse.interfaces.RequestHandlers} handlers
9089          *     An object containing the handlers for the request
9090          * @returns {finesse.restservices.PhoneBook}
9091          *     This PhoneBook object, to allow cascading
9092          */
9093         "delete": function ( handlers) {
9094             this.isLoaded();
9095 
9096             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
9097             handlers = handlers || {};
9098 
9099             this.restRequest(this.getRestUrl(), {
9100                 method: 'DELETE',
9101                 success: this.createPutSuccessHandler(this, {}, handlers.success),
9102                 error: handlers.error,
9103                 content: undefined
9104             });
9105 
9106             return this; // Allow cascading
9107         }
9108 
9109 
9110 
9111     });
9112     
9113     window.finesse = window.finesse || {};
9114     window.finesse.restservices = window.finesse.restservices || {};
9115     window.finesse.restservices.PhoneBook = PhoneBook;
9116     
9117     return PhoneBook;
9118 }));
9119 
9120 /**
9121 * JavaScript representation of the Finesse PhoneBooks collection
9122 * object which contains a list of PhoneBook objects.
9123  *
9124  * @requires finesse.clientservices.ClientServices
9125  * @requires Class
9126  * @requires finesse.FinesseBase
9127  * @requires finesse.restservices.RestBase
9128  * @requires finesse.restservices.Dialog
9129  * @requires finesse.restservices.RestCollectionBase
9130  */
9131 /** @private */
9132 (function (factory) {
9133     
9134 
9135     // Define as an AMD module if possible
9136     if ( typeof define === 'function' && define.amd )
9137     {
9138         define('restservices/PhoneBooks', ['restservices/RestCollectionBase',
9139                  'restservices/PhoneBook'], factory );
9140     }
9141     /* Define using browser globals otherwise
9142      * Prevent multiple instantiations if the script is loaded twice
9143      */
9144     else
9145     {
9146         factory(finesse.restservices.RestCollectionBase, finesse.restservices.PhoneBook);
9147     } 
9148 }(function (RestCollectionBase, PhoneBook) {
9149     var PhoneBooks = RestCollectionBase.extend(/** @lends finesse.restservices.PhoneBooks.prototype */{
9150         
9151         /**
9152          * @class
9153          * JavaScript representation of a PhoneBooks collection object. 
9154          * @augments finesse.restservices.RestCollectionBase
9155          * @constructs
9156          * @see finesse.restservices.PhoneBook
9157          * @see finesse.restservices.Contacts
9158          * @see finesse.restservices.Contact
9159          * @example
9160          *  _phoneBooks = _user.getPhoneBooks( {
9161          *      onCollectionAdd : _handlePhoneBookAdd,
9162          *      onCollectionDelete : _handlePhoneBookDelete,
9163          *      onLoad : _handlePhoneBooksLoaded
9164          *  });
9165          *  
9166          * _phoneBookCollection = _phoneBooks.getCollection();
9167          * for (var phoneBookId in _phoneBookCollection) {
9168          *     if (_phoneBookCollection.hasOwnProperty(phoneBookId)) {
9169          *         _phoneBook = _phoneBookCollection[phoneBookId];
9170          *         etc...
9171          *     }
9172          * }
9173         */
9174         _fakeConstuctor: function () {
9175             /* This is here to hide the real init constructor from the public docs */
9176         },
9177         
9178        /**
9179          * @private
9180          *
9181          * @param {Object} options
9182          *     An object with the following properties:<ul>
9183          *         <li><b>id:</b> The id of the object being constructed</li>
9184          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
9185          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
9186          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
9187          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
9188          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
9189          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
9190          *             <li><b>content:</b> {String} Raw string of response</li>
9191          *             <li><b>object:</b> {Object} Parsed object of response</li>
9192          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
9193          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
9194          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
9195          *             </ul></li>
9196          *         </ul></li>
9197          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
9198          **/
9199         init: function (options) {
9200             this._super(options);           
9201         },
9202 
9203         /**
9204          * @private
9205          * Gets the REST class for the current object - this is the PhoneBooks class.
9206          */
9207         getRestClass: function () {
9208             return PhoneBooks;
9209         },
9210 
9211         /**
9212          * @private
9213          * Gets the REST class for the objects that make up the collection. - this
9214          * is the PhoneBook class.
9215          */
9216         getRestItemClass: function () {
9217             return PhoneBook;
9218         },
9219 
9220         /**
9221          * @private
9222          * Gets the REST type for the current object - this is a "PhoneBooks".
9223          */
9224         getRestType: function () {
9225             return "PhoneBooks";
9226         },
9227         
9228         /**
9229          * @private
9230          * Gets the REST type for the objects that make up the collection - this is "PhoneBooks".
9231          */
9232         getRestItemType: function () {
9233             return "PhoneBook";
9234         },
9235 
9236         /**
9237          * @private
9238          * Override default to indicates that the collection supports making
9239          * requests.
9240          */
9241         supportsRequests: true,
9242 
9243         /**
9244          * @private
9245          * Override default to indicates that the collection subscribes to its objects.
9246          */
9247         supportsRestItemSubscriptions: false,
9248         
9249         /**
9250          * @private
9251          * Retrieve the PhoneBooks.  This call will re-query the server and refresh the collection.
9252          *
9253          * @returns {finesse.restservices.PhoneBooks}
9254          *     This PhoneBooks object, to allow cascading.
9255          */
9256         get: function () {
9257             // set loaded to false so it will rebuild the collection after the get
9258             this._loaded = false;
9259             // reset collection
9260             this._collection = {};
9261             // perform get
9262             this._synchronize();
9263             return this;
9264         }
9265         
9266     });
9267     
9268     window.finesse = window.finesse || {};
9269     window.finesse.restservices = window.finesse.restservices || {};
9270     window.finesse.restservices.PhoneBooks = PhoneBooks;
9271     
9272     return PhoneBooks;
9273 }));
9274 
9275 /**
9276  * JavaScript representation of the Finesse WorkflowAction object.
9277  *
9278  * @requires finesse.clientservices.ClientServices
9279  * @requires Class
9280  * @requires finesse.FinesseBase
9281  * @requires finesse.restservices.RestBase
9282  */
9283 
9284 /*jslint browser: true, nomen: true, sloppy: true, forin: true */
9285 /*global define,finesse */
9286 
9287 /** @private */
9288 (function (factory) {
9289     
9290 
9291     // Define as an AMD module if possible
9292     if ( typeof define === 'function' && define.amd )
9293     {
9294         define('restservices/WorkflowAction', ['restservices/RestBase'], factory );
9295     }
9296     /* Define using browser globals otherwise
9297      * Prevent multiple instantiations if the script is loaded twice
9298      */
9299     else
9300     {
9301         factory(finesse.restservices.RestBase);
9302     } 
9303 }(function (RestBase) {
9304 
9305     var WorkflowAction = RestBase.extend({
9306 
9307         _contacts: null,
9308 
9309         actionTypes: [
9310             {
9311                 name: 'BROWSER_POP',
9312                 params: [
9313                     {
9314                         name: 'windowName',
9315                         type: 'text'
9316                     },
9317                     {
9318                         name: 'path',
9319                         type: 'systemVariableSingleLineEditor'
9320                     }
9321                 ]
9322             },
9323             {
9324                 name: 'HTTP_REQUEST',
9325                 params: [
9326                     {
9327                         name: 'method',
9328                         type: 'dropdown',
9329                         values: ['POST', 'PUT']
9330                     },
9331                     {
9332                         name: 'location',
9333                         type: 'dropdown',
9334                         values: ['FINESSE', 'OTHER']
9335                     },
9336                     {
9337                         name: 'contentType',
9338                         type: 'text'
9339                     },
9340                     {
9341                         name: 'path',
9342                         type: 'systemVariableSingleLineEditor'
9343                     },
9344                     {
9345                         name: 'body',
9346                         type: 'systemVariableMultiLineEditor'
9347                     }
9348                 ]
9349             }            
9350             // more action type definitions here
9351         ],
9352 
9353         /**
9354          * @class
9355          * A WorkflowAction is an action (e.g. Browser Pop, Rest Request) defined in a
9356          * Workflow and triggered by a system event (Call Received, Call Ended, etc.).
9357          * 
9358          * @augments finesse.restservices.RestBase
9359          * @see finesse.restservices.Workflow
9360          * @constructs
9361          */
9362         _fakeConstuctor: function () {
9363             /* This is here to hide the real init constructor from the public docs */
9364         },
9365         
9366         /**
9367          * @private
9368          * JavaScript representation of a WorkflowAction object. Also exposes
9369          * methods to operate on the object against the server.
9370          *
9371          * @param {Object} options
9372          *     An object with the following properties:<ul>
9373          *         <li><b>id:</b> The id of the object being constructed</li>
9374          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
9375          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
9376          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
9377          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
9378          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
9379          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
9380          *             <li><b>content:</b> {String} Raw string of response</li>
9381          *             <li><b>object:</b> {Object} Parsed object of response</li>
9382          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
9383          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
9384          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
9385          *             </ul></li>
9386          *         </ul></li>
9387          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
9388          **/
9389         init: function (options) {
9390             this._super(options);
9391         },
9392 
9393         /**
9394          * @private
9395          * Gets the REST class for the current object - this is the WorkflowAction class.
9396          * @returns {Object} The WorkflowAction class.
9397          */
9398         getRestClass: function () {
9399             return finesse.restservices.WorkflowAction;
9400         },
9401 
9402         /**
9403          * @private
9404          * Gets the REST type for the current object - this is a "WorkflowAction".
9405          * @returns {String} The WorkflowAction string.
9406          */
9407         getRestType: function () {
9408             return "WorkflowAction";
9409         },
9410 
9411         /**
9412          * @private
9413          * Override default to indicate that this object doesn't support making
9414          * requests.
9415          */
9416         supportsRequests: false,
9417 
9418         /**
9419          * @private
9420          * Override default to indicate that this object doesn't support subscriptions.
9421          */
9422         supportsSubscriptions: false,
9423 
9424         /**
9425          * Getter for the name.
9426          * @returns {String} The name.
9427          */
9428         getName: function () {
9429             this.isLoaded();
9430             return this.getData().name;
9431         },
9432 
9433         /**
9434          * Getter for the type flag.
9435          * @returns {String} The type.
9436          */
9437         getType: function () {
9438             this.isLoaded();
9439             return this.getData().type;
9440         },
9441 
9442         /**
9443          * @private
9444          * Getter for the Uri value.
9445          * @returns {String} The Uri.
9446          */
9447         getUri: function () {
9448             this.isLoaded();
9449             return this.getData().uri;
9450         },
9451 
9452         /**
9453          * @private
9454          * Getter for the handledBy value.
9455          * @returns {String} handledBy.
9456          */
9457         getHandledBy: function () {
9458             this.isLoaded();
9459             return this.getData().handledBy;
9460         },
9461 
9462         /**
9463          * Getter for the parameters.
9464          * @returns {Object} key = param name, value = param value
9465          */
9466         getParams: function () {
9467             var map = {},
9468                 params = this.getData().params.Param,
9469                 i,
9470                 param;
9471 
9472             for(i=0; i<params.length; i+=1){
9473                 param = params[i];
9474                 map[param.name] = param.value || "";
9475             }
9476 
9477             return map;
9478         },
9479 
9480         /**
9481          * Getter for the ActionVariables
9482          * @returns {Object} key = action variable name, value = Object{name, type, node, testValue}
9483          */
9484         getActionVariables: function() {
9485             var map = {},
9486                 actionVariablesParent = this.getData().actionVariables,
9487                 actionVariables,
9488                 i,
9489                 actionVariable;
9490 
9491             if(actionVariablesParent === null || actionVariablesParent.length === 0){
9492                 return map;
9493             }
9494             actionVariables = actionVariablesParent.ActionVariable;
9495 
9496             if(actionVariables.length > 0){
9497                 for(i=0; i<actionVariables.length; i+=1){
9498                     actionVariable = actionVariables[i];
9499                     // escape nulls to empty string
9500                     actionVariable.name = actionVariable.name || "";
9501                     actionVariable.type = actionVariable.type || "";
9502                     actionVariable.node = actionVariable.node || "";
9503                     actionVariable.testValue = actionVariable.testValue || "";
9504                     map[actionVariable.name] = actionVariable;
9505                 }
9506             } else {
9507                 map[actionVariables.name] = actionVariables;
9508             }
9509 
9510             return map;
9511         },
9512 
9513         /** @private */
9514         createPutSuccessHandler: function(action, contentBody, successHandler){
9515             return function (rsp) {
9516                 // Update internal structure based on response. Here we
9517                 // inject the contentBody from the PUT request into the
9518                 // rsp.object element to mimic a GET as a way to take
9519                 // advantage of the existing _processResponse method.
9520                 rsp.object = contentBody;
9521                 action._processResponse(rsp);
9522 
9523                 //Remove the injected WorkflowAction object before cascading response
9524                 rsp.object = {};
9525                 
9526                 //cascade response back to consumer's response handler
9527                 successHandler(rsp);
9528             };
9529         },
9530 
9531         /** @private */
9532         createPostSuccessHandler: function (action, contentBody, successHandler) {
9533             return function (rsp) {
9534                 rsp.object = contentBody;
9535                 action._processResponse(rsp);
9536 
9537                 //Remove the injected WorkflowAction object before cascading response
9538                 rsp.object = {};
9539 
9540                 //cascade response back to consumer's response handler
9541                 successHandler(rsp);
9542             };
9543         },
9544 
9545         /**
9546          * @private
9547          * Build params array out of all the values coming into add or update methods
9548          * paramMap is a map of params.. we need to translate it into an array of Param objects
9549          * where path and windowName are params for the BROWSER_POP type
9550          */
9551         buildParamsForRest: function(paramMap){
9552             var params = {"Param": []},
9553                 i;
9554             for(i in paramMap){
9555                 if(paramMap.hasOwnProperty(i)){
9556                     params.Param.push({name: i, value: paramMap[i]});
9557                 }
9558             }
9559             return params;
9560         },
9561 
9562         /**
9563          * @private
9564          * Build actionVariables array out of all the values coming into add or update methods
9565          * actionVariableMap is a map of actionVariables.. we need to translate it into an array of ActionVariable objects
9566          * where path and windowName are params for the BROWSER_POP type
9567          */
9568         buildActionVariablesForRest: function(actionVariableMap){
9569             var actionVariables = {"ActionVariable": []},
9570                 i,
9571                 actionVariable;
9572             for(i in actionVariableMap){
9573                 if(actionVariableMap.hasOwnProperty(i)){
9574                     // {name: "callVariable1", type: "SYSTEM", node: "", testValue: "<blink>"}
9575                     actionVariable = {
9576                         "name": actionVariableMap[i].name,
9577                         "type": actionVariableMap[i].type,
9578                         "node": actionVariableMap[i].node,
9579                         "testValue": actionVariableMap[i].testValue
9580                     };
9581                     actionVariables.ActionVariable.push(actionVariable);
9582                 }
9583             }
9584             return actionVariables;
9585         },
9586 
9587         /**
9588          * Add
9589          */
9590         add: function (newValues, handlers) {
9591             var contentBody = {};
9592 
9593             contentBody[this.getRestType()] = {
9594                 "name": newValues.name,
9595                 "type": newValues.type,
9596                 "handledBy": newValues.handledBy,
9597                 "params": this.buildParamsForRest(newValues.params),
9598                 "actionVariables": this.buildActionVariablesForRest(newValues.actionVariables)
9599             };
9600 
9601             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
9602             handlers = handlers || {};
9603 
9604             this.restRequest(this.getRestUrl(), {
9605                 method: 'POST',
9606                 success: this.createPostSuccessHandler(this, contentBody, handlers.success),
9607                 error: handlers.error,
9608                 content: contentBody
9609             });
9610 
9611             return this; // Allow cascading
9612         },
9613 
9614         /**
9615          * @private
9616          * Update
9617          */
9618         update: function (newValues, handlers) {
9619             this.isLoaded();
9620             var contentBody = {};
9621             
9622             contentBody[this.getRestType()] = {
9623                 "uri": this.getId(),
9624                 "name": newValues.name,
9625                 "type": newValues.type,
9626                 "handledBy": newValues.handledBy,
9627                 "params": this.buildParamsForRest(newValues.params),
9628                 "actionVariables": this.buildActionVariablesForRest(newValues.actionVariables)
9629             };
9630 
9631             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
9632             handlers = handlers || {};
9633 
9634             this.restRequest(this.getRestUrl(), {
9635                 method: 'PUT',
9636                 success: this.createPutSuccessHandler(this, contentBody, handlers.success),
9637                 error: handlers.error,
9638                 content: contentBody
9639             });
9640 
9641             return this; // Allow cascading
9642         },
9643 
9644 
9645         /**
9646          * @private
9647          * Delete
9648          */
9649         "delete": function ( handlers) {
9650             this.isLoaded();
9651 
9652             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
9653             handlers = handlers || {};
9654 
9655             this.restRequest(this.getRestUrl(), {
9656                 method: 'DELETE',
9657                 success: this.createPutSuccessHandler(this, {}, handlers.success),
9658                 error: handlers.error,
9659                 content: undefined
9660             });
9661 
9662             return this; // Allow cascading
9663         }
9664 
9665 
9666 
9667     });
9668 
9669     window.finesse = window.finesse || {};
9670     window.finesse.restservices = window.finesse.restservices || {};
9671     window.finesse.restservices.WorkflowAction = WorkflowAction;
9672     
9673     return WorkflowAction;
9674 }));
9675 
9676 /**
9677 * JavaScript representation of the Finesse WorkflowActions collection
9678 * object which contains a list of WorkflowAction objects.
9679  *
9680  * @requires finesse.clientservices.ClientServices
9681  * @requires Class
9682  * @requires finesse.FinesseBase
9683  * @requires finesse.restservices.RestBase
9684  * @requires finesse.restservices.Dialog
9685  * @requires finesse.restservices.RestCollectionBase
9686  */
9687 
9688 /** @private */
9689 (function (factory) {
9690     
9691 
9692     // Define as an AMD module if possible
9693     if ( typeof define === 'function' && define.amd )
9694     {
9695         define('restservices/WorkflowActions', ['restservices/RestCollectionBase',
9696                  'restservices/RestBase',
9697                  'restservices/WorkflowAction'], factory );
9698     }
9699     /* Define using browser globals otherwise
9700      * Prevent multiple instantiations if the script is loaded twice
9701      */
9702     else
9703     {
9704         factory(finesse.restservices.RestCollectionBase, finesse.restservices.RestBase, finesse.restservices.WorkflowAction);
9705     } 
9706 }(function (RestCollectionBase, RestBase, WorkflowAction) {
9707 
9708     var WorkflowActions = RestCollectionBase.extend({
9709         
9710         /**
9711          * @class
9712          * JavaScript representation of a WorkflowActions collection object. 
9713          * @augments finesse.restservices.RestCollectionBase
9714          * @constructs
9715          * @see finesse.restservices.WorkflowAction
9716          * @see finesse.restservices.Workflow
9717          * @see finesse.restservices.Workflows
9718          * @example
9719          *  _workflowActions = _user.getWorkflowActions( {
9720          *      onCollectionAdd : _handleWorkflowActionAdd,
9721          *      onCollectionDelete : _handleWorkflowActionDelete,
9722          *      onLoad : _handleWorkflowActionsLoaded
9723          *  });
9724         */
9725         _fakeConstuctor: function () {
9726             /* This is here to hide the real init constructor from the public docs */
9727         },
9728         
9729         /**
9730          * @private
9731          * JavaScript representation of a WorkflowActions collection object. Also exposes
9732          * methods to operate on the object against the server.
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 WorkflowActions class.
9759          */
9760         getRestClass: function () {
9761             return WorkflowActions;
9762         },
9763 
9764         /**
9765          * @private
9766          * Gets the REST class for the objects that make up the collection. - this
9767          * is the WorkflowAction class.
9768          */
9769         getRestItemClass: function () {
9770             return WorkflowAction;
9771         },
9772 
9773         /**
9774          * @private
9775          * Gets the REST type for the current object - this is a "WorkflowActions".
9776          */
9777         getRestType: function () {
9778             return "WorkflowActions";
9779         },
9780         
9781         /**
9782          * @private
9783          * Gets the REST type for the objects that make up the collection - this is "WorkflowActions".
9784          */
9785         getRestItemType: function () {
9786             return "WorkflowAction";
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 WorkflowActions.
9805          *
9806          * @returns {finesse.restservices.WorkflowActions}
9807          *     This WorkflowActions 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     window.finesse = window.finesse || {};
9821     window.finesse.restservices = window.finesse.restservices || {};
9822     window.finesse.restservices.WorkflowActions = WorkflowActions;
9823         
9824     return WorkflowActions;
9825 }));
9826 
9827 /**
9828  * JavaScript representation of the Finesse Workflow object.
9829  *
9830  * @requires finesse.clientservices.ClientServices
9831  * @requires Class
9832  * @requires finesse.FinesseBase
9833  * @requires finesse.restservices.RestBase
9834  */
9835 
9836 /*jslint browser: true, nomen: true, sloppy: true, forin: true */
9837 /*global define,finesse */
9838 
9839 /** @private */
9840 (function (factory) {
9841     
9842 
9843     if (typeof define === 'function' && define.amd) {
9844         // Define as an AMD module if possible
9845         define('restservices/Workflow',['restservices/RestBase',
9846 				'restservices/WorkflowActions'], factory);
9847     } else {
9848         /* Define using browser globals otherwise
9849          * Prevent multiple instantiations if the script is loaded twice
9850          */
9851         factory(finesse.restservices.RestBase,
9852 				finesse.restservices.WorkflowActions);
9853     }
9854 }(function (RestBase, WorkflowActions) {
9855 
9856     var Workflow = RestBase.extend({
9857 
9858         /**
9859          * @class
9860          * JavaScript representation of a Workflow object. Also exposes
9861          * methods to operate on the object against the server.
9862          *
9863          * @param {Object} options
9864          *     An object with the following properties:<ul>
9865          *         <li><b>id:</b> The id of the object being constructed</li>
9866          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
9867          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
9868          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
9869          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
9870          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
9871          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
9872          *             <li><b>content:</b> {String} Raw string of response</li>
9873          *             <li><b>object:</b> {Object} Parsed object of response</li>
9874          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
9875          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
9876          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
9877          *             </ul></li>
9878          *         </ul></li>
9879          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
9880          * @constructs
9881          **/
9882         init: function (options) {
9883             this._super(options);
9884         },
9885 
9886         /**
9887          * @private
9888          * Gets the REST class for the current object - this is the Workflow class.
9889          * @returns {Object} The Workflow class.
9890          */
9891         getRestClass: function () {
9892             return Workflow;
9893         },
9894 
9895         /**
9896          * @private
9897          * Gets the REST type for the current object - this is a "Workflow".
9898          * @returns {String} The Workflow string.
9899          */
9900         getRestType: function () {
9901             return "Workflow";
9902         },
9903 
9904         /**
9905          * @private
9906          * Override default to indicate that this object doesn't support making
9907          * requests.
9908          */
9909         supportsRequests: false,
9910 
9911         /**
9912          * @private
9913          * Override default to indicate that this object doesn't support subscriptions.
9914          */
9915         supportsSubscriptions: false,
9916 
9917         /**
9918          * @private
9919          * Getter for the Uri value.
9920          * @returns {String} The Uri.
9921          */
9922         getUri: function () {
9923             this.isLoaded();
9924             return this.getData().uri;
9925         },
9926 
9927         /**
9928          * Getter for the name.
9929          * @returns {String} The name.
9930          */
9931         getName: function () {
9932             this.isLoaded();
9933             return this.getData().name;
9934         },
9935 
9936         /**
9937          * Getter for the description.
9938          * @returns {String} The description.
9939          */
9940         getDescription: function () {
9941             this.isLoaded();
9942             return this.getData().description;
9943         },
9944 
9945         /**
9946          * Getter for the trigger set.
9947          * @returns {String} The trigger set.
9948          */
9949         getTriggerSet: function () {
9950             this.isLoaded();
9951             return this.getData().TriggerSet;
9952         },
9953 
9954         /**
9955          * Getter for the condition set.
9956          * @returns {String} The condition set.
9957          */
9958         getConditionSet: function () {
9959             this.isLoaded();
9960             return this.getData().ConditionSet;
9961         },
9962         
9963         /**
9964          * Getter for the assigned workflowActions.
9965          * @returns {String} The workflowActions object.
9966          */
9967         getWorkflowActions: function () {
9968             this.isLoaded();
9969             var workflowActions = this.getData().workflowActions;
9970             if (workflowActions === null) {
9971                 workflowActions = "";
9972             }
9973             return workflowActions;
9974         },
9975 
9976         createPutSuccessHandler: function (workflow, contentBody, successHandler) {
9977             return function (rsp) {
9978                 // Update internal structure based on response. Here we
9979                 // inject the contentBody from the PUT request into the
9980                 // rsp.object element to mimic a GET as a way to take
9981                 // advantage of the existing _processResponse method.
9982                 rsp.object = contentBody;
9983                 workflow._processResponse(rsp);
9984 
9985                 //Remove the injected Workflow object before cascading response
9986                 rsp.object = {};
9987 
9988                 //cascade response back to consumer's response handler
9989                 successHandler(rsp);
9990             };
9991         },
9992 
9993         createPostSuccessHandler: function (workflow, contentBody, successHandler) {
9994             return function (rsp) {
9995                 rsp.object = contentBody;
9996                 workflow._processResponse(rsp);
9997 
9998                 //Remove the injected Workflow object before cascading response
9999                 rsp.object = {};
10000 
10001                 //cascade response back to consumer's response handler
10002                 successHandler(rsp);
10003             };
10004         },
10005 
10006         /**
10007          * @private
10008          * Add
10009          */
10010         add: function (newValues, handlers) {
10011             // this.isLoaded();
10012             var contentBody = {};
10013 
10014             contentBody[this.getRestType()] = {
10015                 "name": newValues.name,
10016                 "description": newValues.description,
10017                 "TriggerSet" : newValues.TriggerSet,
10018                 "ConditionSet" : newValues.ConditionSet,
10019                 "workflowActions" : newValues.workflowActions
10020             };
10021 
10022             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
10023             handlers = handlers || {};
10024 
10025             this.restRequest(this.getRestUrl(), {
10026                 method: 'POST',
10027                 success: this.createPostSuccessHandler(this, contentBody, handlers.success),
10028                 error: handlers.error,
10029                 content: contentBody
10030             });
10031 
10032             return this; // Allow cascading
10033         },
10034 
10035         /**
10036          * @private
10037          * Update
10038          */
10039         update: function (newValues, handlers) {
10040             this.isLoaded();
10041             var contentBody = {};
10042 
10043             contentBody[this.getRestType()] = {
10044                 "uri": this.getId(),
10045                 "name": newValues.name,
10046                 "description": newValues.description,
10047                 "TriggerSet" : newValues.TriggerSet,
10048                 "ConditionSet" : newValues.ConditionSet,
10049                 "workflowActions" : newValues.workflowActions
10050             };
10051 
10052             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
10053             handlers = handlers || {};
10054 
10055             this.restRequest(this.getRestUrl(), {
10056                 method: 'PUT',
10057                 success: this.createPutSuccessHandler(this, contentBody, handlers.success),
10058                 error: handlers.error,
10059                 content: contentBody
10060             });
10061 
10062             return this; // Allow cascading
10063         },
10064 
10065 
10066         /**
10067          * @private
10068          * Delete
10069          */
10070         "delete": function (handlers) {
10071             this.isLoaded();
10072 
10073             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
10074             handlers = handlers || {};
10075 
10076             this.restRequest(this.getRestUrl(), {
10077                 method: 'DELETE',
10078                 success: this.createPutSuccessHandler(this, {}, handlers.success),
10079                 error: handlers.error,
10080                 content: undefined
10081             });
10082 
10083             return this; // Allow cascading
10084         }
10085 
10086 
10087 
10088     });
10089 
10090     window.finesse = window.finesse || {};
10091     window.finesse.restservices = window.finesse.restservices || {};
10092     window.finesse.restservices.Workflow = Workflow;
10093 
10094     return Workflow;
10095 }));
10096 
10097 /**
10098 * JavaScript representation of the Finesse workflows collection
10099 * object which contains a list of workflow objects.
10100  *
10101  * @requires finesse.clientservices.ClientServices
10102  * @requires Class
10103  * @requires finesse.FinesseBase
10104  * @requires finesse.restservices.RestBase
10105  * @requires finesse.restservices.Dialog
10106  * @requires finesse.restservices.RestCollectionBase
10107  */
10108 
10109 /** @private */
10110 (function (factory) {
10111     
10112 
10113     // Define as an AMD module if possible
10114     if ( typeof define === 'function' && define.amd )
10115     {
10116         define('restservices/Workflows', ['restservices/RestCollectionBase',
10117                  'restservices/RestBase',
10118                  'restservices/Workflow'], factory );
10119     }
10120     /* Define using browser globals otherwise
10121      * Prevent multiple instantiations if the script is loaded twice
10122      */
10123     else
10124     {
10125         factory(finesse.restservices.RestCollectionBase, finesse.restservices.RestBase, finesse.restservices.Workflow);
10126     } 
10127 }(function (RestCollectionBase, RestBase, Workflow) {
10128 
10129     var Workflows = RestCollectionBase.extend({
10130 
10131         /**
10132          * @class
10133          * JavaScript representation of a workflows collection object. Also exposes
10134          * methods to operate on the object against the server.
10135          *
10136          * @param {Object} options
10137          *     An object with the following properties:<ul>
10138          *         <li><b>id:</b> The id of the object being constructed</li>
10139          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
10140          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
10141          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
10142          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
10143          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
10144          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
10145          *             <li><b>content:</b> {String} Raw string of response</li>
10146          *             <li><b>object:</b> {Object} Parsed object of response</li>
10147          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
10148          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
10149          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
10150          *             </ul></li>
10151          *         </ul></li>
10152          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
10153          *  @constructs
10154          **/
10155         init: function (options) {
10156             this._super(options);
10157         },
10158 
10159         /**
10160          * @private
10161          * Gets the REST class for the current object - this is the workflows class.
10162          */
10163         getRestClass: function () {
10164             return Workflows;
10165         },
10166 
10167         /**
10168          * @private
10169          * Gets the REST class for the objects that make up the collection. - this
10170          * is the workflow class.
10171          */
10172         getRestItemClass: function () {
10173             return Workflow;
10174         },
10175 
10176         /**
10177          * @private
10178          * Gets the REST type for the current object - this is a "workflows".
10179          */
10180         getRestType: function () {
10181             return "Workflows";
10182         },
10183 
10184         /**
10185          * @private
10186          * Gets the REST type for the objects that make up the collection - this is "workflows".
10187          */
10188         getRestItemType: function () {
10189             return "Workflow";
10190         },
10191 
10192         /**
10193          * @private
10194          * Override default to indicates that the collection supports making requests.
10195          */
10196         supportsRequests: true,
10197 
10198         /**
10199          * @private
10200          * Override default to indicates that the collection does not subscribe to its objects.
10201          */
10202         supportsRestItemSubscriptions: false,
10203 
10204         /**
10205          * @private
10206          * Retrieve the workflows. This call will re-query the server and refresh the collection.
10207          *
10208          * @returns {finesse.restservices.workflows}
10209          *     This workflows object to allow cascading.
10210          */
10211         get: function () {
10212             // set loaded to false so it will rebuild the collection after the get
10213             this._loaded = false;
10214             // reset collection
10215             this._collection = {};
10216             // perform get
10217             this._synchronize();
10218             return this;
10219         }
10220     });
10221 
10222     window.finesse = window.finesse || {};
10223     window.finesse.restservices = window.finesse.restservices || {};
10224     window.finesse.restservices.Workflows = Workflows;
10225         
10226     return Workflows;
10227 }));
10228 
10229 /**
10230  * JavaScript representation of the Finesse MediaPropertiesLayout object
10231  *
10232  * @requires finesse.clientservices.ClientServices
10233  * @requires Class
10234  * @requires finesse.FinesseBase
10235  * @requires finesse.restservices.RestBase
10236  */
10237 
10238 /** The following comment is to prevent jslint errors about 
10239  * using variables before they are defined.
10240  */
10241 /*global finesse*/
10242 
10243 /** @private */
10244 (function (factory) {
10245     
10246 
10247     // Define as an AMD module if possible
10248     if ( typeof define === 'function' && define.amd )
10249     {
10250         define('restservices/MediaPropertiesLayout', ['restservices/RestBase'], 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.RestBase);
10258     } 
10259 }(function (RestBase) {
10260     var MediaPropertiesLayout = RestBase.extend(/** @lends finesse.restservices.MediaPropertiesLayout.prototype */{
10261 
10262         /**
10263          * @class
10264          * The MediaPropertiesLayout handles which call variables are associated with Dialogs.
10265          * 
10266          * @augments finesse.restservices.RestBase
10267          * @see finesse.restservices.Dialog#getMediaProperties
10268          * @see finesse.restservices.User#getMediaPropertiesLayout
10269          * @constructs
10270          */
10271         _fakeConstuctor: function () {
10272             /* This is here to hide the real init constructor from the public docs */
10273         },
10274         
10275         /**
10276          * @private
10277          * JavaScript representation of a MediaPropertiesLayout object. Also exposes
10278          * methods to operate on the object against the server.
10279          *
10280          * @param {Object} options
10281          *     An object with the following properties:<ul>
10282          *         <li><b>id:</b> The id of the object being constructed</li>
10283          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
10284          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
10285          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
10286          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
10287          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
10288          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
10289          *             <li><b>content:</b> {String} Raw string of response</li>
10290          *             <li><b>object:</b> {Object} Parsed object of response</li>
10291          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
10292          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
10293          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
10294          *             </ul></li>
10295          *         </ul></li>
10296          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
10297          **/
10298         init: function (options) {
10299             this._super(options);
10300         },
10301 
10302         /**
10303          * @private
10304          * Gets the REST class for the current object - this is the MediaPropertiesLayout object.
10305          */
10306         getRestClass: function () {
10307             return MediaPropertiesLayout;
10308         },
10309 
10310         /**
10311          * @private
10312          * Gets the REST type for the current object - this is a "MediaPropertiesLayout".
10313          */
10314         getRestType: function () {
10315             return "MediaPropertiesLayout";
10316         },
10317 
10318         /**
10319          * @private
10320          * Overrides the parent class.  Returns the url for the MediaPropertiesLayout resource
10321          */
10322         getRestUrl: function () {
10323             return ("/finesse/api/User/" + this.getId() + "/" + this.getRestType());
10324         },
10325 
10326         /**
10327          * @private
10328          * Returns whether this object supports subscriptions
10329          */
10330         supportsSubscriptions: false,
10331 
10332         /**
10333          * Retrieve the media properties layout. This call will re-query the server and refresh the layout object.
10334          * @returns {finesse.restservices.MediaPropertiesLayout}
10335          *     This MediaPropertiesLayout object to allow cascading
10336          */
10337         get: function () {
10338             this._synchronize();
10339 
10340             return this; //Allow cascading
10341         },
10342 
10343         /**
10344          * Gets the data for this object.
10345          * 
10346          * Performs safe conversion from raw API data to ensure that the returned layout object
10347          * always has a header with correct entry fields, and exactly two columns with lists of entries.
10348          *
10349          * @returns {finesse.restservices.MediaPropertiesLayout.Object} Data in columns (unless only one defined).
10350          */
10351         getData: function () {
10352 
10353             var layout = this._data, result, _addColumnData;
10354 
10355             result = this.getEmptyData();
10356 
10357             /**
10358              * @private
10359              */
10360             _addColumnData = function (entryData, colIndex) {
10361 
10362                 if (!entryData) {
10363                     //If there's no entry data at all, rewrite entryData to be an empty collection of entries
10364                     entryData = {};
10365                 } else if (entryData.mediaProperty) {
10366                     //If entryData contains the keys for a single entry rather than being a collection of entries,
10367                     //rewrite it to be a collection containing a single entry
10368                     entryData = { "": entryData };
10369                 }
10370 
10371                 //Add each of the entries in the list to the column
10372                 jQuery.each(entryData, function (i, entryData) {
10373 
10374                     //If the entry has no displayName specified, explicitly set it to the empty string
10375                     if (!entryData.displayName) {
10376                         entryData.displayName = "";
10377                     }
10378 
10379                     result.columns[colIndex].push(entryData);
10380 
10381                 });
10382 
10383             };
10384 
10385             //The header should only contain a single entry
10386             if (layout.header && layout.header.entry) {
10387 
10388                 //If the entry has no displayName specified, explicitly set it to the empty string
10389                 if (!layout.header.entry.displayName) {
10390                     layout.header.entry.displayName = "";
10391                 }
10392 
10393                 result.header = layout.header.entry;
10394 
10395             } else {
10396 
10397                 throw "MediaPropertiesLayout.getData() - Header does not contain an entry";
10398 
10399             }
10400 
10401             //If the column object contains an entry object that wasn't part of a list of entries,
10402             //it must be a single right-hand entry object (left-hand entry object would be part of a list.)
10403             //Force the entry object to be the 2nd element in an otherwise-empty list.
10404             if (layout.column && layout.column.entry) {
10405                 layout.column = [
10406                     null,
10407                     { "entry": layout.column.entry }
10408                 ];
10409             }
10410 
10411             if (layout.column && layout.column.length > 0 && layout.column.length <= 2) {
10412 
10413                 //Render left column entries
10414                 if (layout.column[0] && layout.column[0].entry) {
10415                     _addColumnData(layout.column[0].entry, 0);
10416                 }
10417 
10418                 //Render right column entries
10419                 if (layout.column[1] && layout.column[1].entry) {
10420                     _addColumnData(layout.column[1].entry, 1);
10421                 }
10422 
10423             }
10424 
10425             return result;
10426 
10427         },
10428 
10429         /**
10430          * @private
10431          * Empty/template version of getData().
10432          *
10433          * Used by getData(), and by callers of getData() in error cases.
10434          */
10435         getEmptyData: function () {
10436 
10437             return {
10438                 header : {
10439                     displayName: null,
10440                     mediaProperty: null
10441                 },
10442                 columns : [[], []]
10443             };
10444 
10445         },
10446 
10447         /**
10448          * @private
10449          * Set the layout of this MediaPropertiesLayout.
10450          * @param {String} layout
10451          *     The layout you are setting
10452          * @param {finesse.interfaces.RequestHandlers} handlers
10453          *     An object containing the handlers for the request
10454          * @returns {finesse.restservices.MediaPropertiesLayout}
10455          *     This MediaPropertiesLayout object to allow cascading
10456          */
10457         setLayout: function (layout, handlers) {
10458 
10459             var contentBody = {};
10460 
10461             contentBody[this.getRestType()] = layout;
10462 
10463             //Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
10464             handlers = handlers || {};
10465 
10466             this.restRequest(this.getRestUrl(), {
10467                 method: 'PUT',
10468                 success: handlers.success,
10469                 error: handlers.error,
10470                 content: contentBody
10471             });
10472 
10473             return this; // Allow cascading
10474         }
10475 
10476     });
10477     
10478     MediaPropertiesLayout.Object = /** @lends finesse.restservices.MediaPropertiesLayout.Object.prototype */ {
10479         /**
10480          * @class Format of MediaPropertiesLayout Object.<br>
10481          * Object { <ul>
10482          *      <li>header : { <ul>
10483          *          <li>dispayName {String} 
10484          *          <li>mediaProperty {String}</ul>}
10485          *      <li>columns : { <ul>
10486          *          <li>[ [] , [] ]
10487          *          </ul>
10488          *      where column arrays consists of the same Object format as header.<br>
10489          *          }</ul>
10490          *      }<br>         
10491          * @constructs
10492          */
10493         _fakeConstructor : function () {} // For JS Doc to work need a constructor so that the lends/constructs build the doc properly
10494         
10495     };
10496 
10497 	window.finesse = window.finesse || {};
10498     window.finesse.restservices = window.finesse.restservices || {};
10499     window.finesse.restservices.MediaPropertiesLayout = MediaPropertiesLayout;
10500     
10501     return MediaPropertiesLayout;
10502 }));
10503 
10504 /**
10505  * JavaScript representation of the Finesse User object
10506  *
10507  * @requires finesse.clientservices.ClientServices
10508  * @requires Class
10509  * @requires finesse.FinesseBase
10510  * @requires finesse.restservices.RestBase
10511  */
10512 
10513 /** @private */
10514 (function (factory) {
10515     
10516 
10517     // Define as an AMD module if possible
10518     if ( typeof define === 'function' && define.amd )
10519     {
10520         define('restservices/User', ['restservices/RestBase',
10521                  'restservices/Dialogs',
10522                  'restservices/ClientLog',
10523                  'restservices/Queues',
10524                  'restservices/WrapUpReasons',
10525                  'restservices/PhoneBooks',
10526                  'restservices/Workflows',
10527                  'restservices/MediaPropertiesLayout',
10528                  'utilities/Utilities'], factory );
10529     }
10530     /* Define using browser globals otherwise
10531      * Prevent multiple instantiations if the script is loaded twice
10532      */
10533     else
10534     {
10535         factory(finesse.restservices.RestBase, 
10536         finesse.restservices.Dialogs, 
10537         finesse.restservices.ClientLog,
10538         finesse.restservices.Queues,
10539         finesse.restservices.WrapUpReasons,
10540         finesse.restservices.PhoneBooks,
10541         finesse.restservices.Workflows,
10542         finesse.restservices.MediaPropertiesLayout,
10543         finesse.utilities.Utilities);
10544     } 
10545 }(function (RestBase, 
10546             Dialogs, 
10547             ClientLog,
10548             Queues,
10549             WrapUpReasons,
10550             PhoneBooks,
10551             Workflows,
10552             MediaPropertiesLayout,
10553             Utilities) {
10554     
10555     var User = RestBase.extend(/** @lends finesse.restservices.User.prototype */{
10556 
10557         _dialogs : null,
10558         _clientLogObj : null,
10559         _wrapUpReasons : null,
10560         _phoneBooks : null,
10561         _workflows : null,
10562         _mediaPropertiesLayout : null,
10563         _queues : null,
10564         
10565         /**
10566          * @class
10567          * The User represents a Finesse Agent or Supervisor.
10568          *
10569          * @param {Object} options
10570          *     An object with the following properties:<ul>
10571          *         <li><b>id:</b> The id of the object being constructed</li>
10572          *         <li><b>onLoad(this): (optional)</b> callback handler for when the object is successfully loaded from the server</li>
10573          *         <li><b>onChange(this): (optional)</b> callback handler for when an update notification of the object is received</li>
10574          *         <li><b>onAdd(this): (optional)</b> callback handler for when a notification that the object is created is received</li>
10575          *         <li><b>onDelete(this): (optional)</b> callback handler for when a notification that the object is deleted is received</li>
10576          *         <li><b>onError(rsp): (optional)</b> callback handler for if loading of the object fails, invoked with the error response object:<ul>
10577          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
10578          *             <li><b>content:</b> {String} Raw string of response</li>
10579          *             <li><b>object:</b> {Object} Parsed object of response</li>
10580          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
10581          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
10582          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
10583          *             </ul></li>
10584          *         </ul></li>
10585          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
10586          * @augments finesse.restservices.RestBase
10587          * @constructs
10588          * @example
10589          *      _user = new finesse.restservices.User({
10590          *                      id: _id, 
10591          *                      onLoad : _handleUserLoad,
10592          *                      onChange : _handleUserChange
10593          *      });
10594          **/
10595         init: function (options) {
10596             this._super(options);
10597         },
10598         
10599         Callbacks: {},
10600     
10601         /**
10602          * @private
10603          * Gets the REST class for the current object - this is the User object.
10604          */
10605         getRestClass: function () {
10606             return User;
10607         },
10608     
10609         /**
10610         * @private
10611          * Gets the REST type for the current object - this is a "User".
10612          */
10613         getRestType: function () {
10614             return "User";
10615         },
10616         /**
10617          * @private
10618          * overloading this to return URI
10619          */
10620         getXMPPNodePath: function () {
10621             return this.getRestUrl();
10622         },
10623         /**
10624         * @private
10625          * Returns whether this object supports subscriptions
10626          */
10627         supportsSubscriptions: function () {
10628             return true;
10629         },
10630     
10631         /**
10632          * Getter for the firstName of this User.
10633          * @returns {String}
10634          *     The firstName for this User
10635          */
10636         getFirstName: function () {
10637             this.isLoaded();
10638             return Utilities.convertNullToEmptyString(this.getData().firstName);
10639         },
10640     
10641         /**
10642          * Getter for the lastName of this User.
10643          * @returns {String}
10644          *     The lastName for this User
10645          */
10646         getLastName: function () {
10647             this.isLoaded();
10648             return Utilities.convertNullToEmptyString(this.getData().lastName);
10649         },
10650     
10651         /**
10652          * Getter for the extension of this User.
10653          * @returns {String}
10654          *     The extension, if any, of this User
10655          */
10656         getExtension: function () {
10657             this.isLoaded();
10658             return Utilities.convertNullToEmptyString(this.getData().extension);
10659         },
10660         
10661         /**
10662          * Getter for the id of the Team of this User
10663          * @returns {String}
10664          *     The current (or last fetched) id of the Team of this User
10665          */
10666         getTeamId: function () {
10667             this.isLoaded();
10668             return this.getData().teamId;
10669         },
10670         
10671         /**
10672          * Getter for the name of the Team of this User
10673          * @returns {String}
10674          *     The current (or last fetched) name of the Team of this User
10675          */
10676         getTeamName: function () {
10677             this.isLoaded();
10678             return this.getData().teamName;
10679         },
10680         
10681         /**
10682          * Is user an agent?
10683          * @returns {Boolean} True if user has role of agent, else false.
10684          */
10685         hasAgentRole: function () {
10686             this.isLoaded();
10687             return this.hasRole("Agent");
10688         },
10689     
10690         /**
10691          * Is user a supervisor?
10692          * @returns {Boolean} True if user has role of supervisor, else false.
10693          */
10694         hasSupervisorRole: function () {
10695             this.isLoaded();
10696             return this.hasRole("Supervisor");
10697         },
10698     
10699         /**
10700          * @private
10701          * Checks to see if user has "theRole"
10702          * @returns {Boolean}
10703          */
10704         hasRole: function (theRole) {
10705             this.isLoaded();
10706             var result = false, i, roles, len;
10707     
10708             roles = this.getData().roles.role;
10709             len = roles.length;
10710             if (typeof roles === 'string') {
10711                 if (roles === theRole) {
10712                     result = true;
10713                 }
10714             } else {
10715                 for (i = 0; i < len ; i = i + 1) {
10716                     if (roles[i] === theRole) {
10717                         result = true;
10718                         break;
10719                     }
10720                 }
10721             }
10722     
10723             return result;
10724         },
10725 
10726         /**
10727          * Getter for the pending state of this User.
10728          * @returns {String}
10729          *     The pending state of this User
10730          * @see finesse.restservices.User.States
10731          */
10732         getPendingState: function () {
10733             this.isLoaded();
10734             return Utilities.convertNullToEmptyString(this.getData().pendingState);
10735         },
10736     
10737         /**
10738          * Getter for the state of this User.
10739          * @returns {String}
10740          *     The current (or last fetched) state of this User
10741          * @see finesse.restservices.User.States
10742          */
10743         getState: function () {
10744             this.isLoaded();
10745             return this.getData().state;
10746         },
10747         
10748         /**
10749          * Getter for the state change time of this User.
10750          * @returns {String}
10751          *     The state change time of this User
10752          */
10753         getStateChangeTime: function () {
10754             this.isLoaded();
10755             return this.getData().stateChangeTime;
10756         },
10757     
10758         /**
10759          * Checks to see if the user is considered a mobile agent by checking for
10760          * the existence of the mobileAgent node.
10761          * @returns {Boolean}
10762          *      True if this agent is a mobile agent.
10763          */
10764         isMobileAgent: function () {
10765             this.isLoaded();
10766             var ma = this.getData().mobileAgent;
10767             return ma !== null && typeof ma === "object";
10768         },
10769     
10770         /**
10771          * Getter for the mobile agent work mode.
10772          * @returns {finesse.restservices.User.WorkMode}
10773          *      If available, return the mobile agent work mode, otherwise null.
10774          */
10775         getMobileAgentMode: function () {
10776             this.isLoaded();
10777             if (this.isMobileAgent()) {
10778                 return this.getData().mobileAgent.mode;
10779             }
10780             return null;
10781         },
10782     
10783         /**
10784          * Getter for the mobile agent dial number.
10785          * @returns {String}
10786          *      If available, return the mobile agent dial number, otherwise null.
10787          */
10788         getMobileAgentDialNumber: function () {
10789             this.isLoaded();
10790             if (this.isMobileAgent()) {
10791                 return this.getData().mobileAgent.dialNumber;
10792             }
10793             return null;
10794         },
10795     
10796         /**
10797          * Getter for a Dialogs collection object that is associated with User.
10798          * @param {finesse.interfaces.RestObjectHandlers} [handlers] Object that sets callback handlers (only 
10799          * applicable when Object has not been previously created).
10800          * @returns {finesse.restservices.Dialogs}
10801          *     A Dialogs collection object.
10802          */
10803         getDialogs: function (callbacks) {
10804             var options = callbacks || {};
10805             options.parentObj = this;
10806             this.isLoaded();
10807     
10808             if (this._dialogs === null) {
10809                 this._dialogs = new Dialogs(options);
10810             }
10811     
10812             return this._dialogs;
10813         },
10814         
10815         /**
10816          * @private
10817          * Getter for a ClientLog object that is associated with User.
10818          * @param {finesse.interfaces.RestObjectHandlers} [handlers] Object that sets callback handlers (only 
10819          * applicable when Object has not been previously created).
10820          * @returns {finesse.restservices.ClientLog}
10821          *     A ClientLog collection object.
10822          */
10823         getClientLog: function (callbacks) {
10824             var options = callbacks || {};
10825             options.parentObj = this;
10826             this.isLoaded();
10827            
10828             if (this._clientLogObj === null) {
10829                 this._clientLogObj = new ClientLog(options);
10830             }
10831             else {
10832                 if(options.onLoad && typeof options.onLoad === "function") {
10833                 options.onLoad(this._clientLogObj);
10834                 }
10835             }
10836             return this._clientLogObj;
10837         },
10838        
10839         /**
10840          * Getter for a Queues collection object that is associated with User.
10841          * @param {finesse.interfaces.RestObjectHandlers} [handlers] Object that sets callback handlers (only 
10842          * applicable when Object has not been previously created).
10843          * @returns {finesse.restservices.Queues}
10844          *     A Queues collection object.
10845          */
10846         getQueues: function (callbacks) {
10847             var options = callbacks || {};
10848             options.parentObj = this;
10849             this.isLoaded();
10850     
10851             if (this._queues === null) {
10852                 this._queues = new Queues(options);
10853             }
10854     
10855             return this._queues;
10856         },
10857 
10858         /**
10859          * Getter for a WrapUpReasons collection object that is associated with User.
10860          * @param {finesse.interfaces.RestObjectHandlers} [handlers] Object that sets callback handlers (only 
10861          * applicable when Object has not been previously created).
10862          * @returns {finesse.restservices.WrapUpReasons}
10863          *     A WrapUpReasons collection object.
10864          */
10865         getWrapUpReasons: function (callbacks) {
10866             var options = callbacks || {};
10867             options.parentObj = this;
10868             this.isLoaded();
10869     
10870             if (this._wrapUpReasons === null) {
10871                 this._wrapUpReasons = new WrapUpReasons(options);
10872             }
10873     
10874             return this._wrapUpReasons;
10875         },
10876 
10877         /**
10878          * Getter for a PhoneBooks collection object that is associated with User.
10879          * @param {finesse.interfaces.RestObjectHandlers} [handlers] Object that sets callback handlers (only 
10880          * applicable when Object has not been previously created).
10881          * @returns {finesse.restservices.PhoneBooks}
10882          *     A PhoneBooks collection object.
10883          */
10884         getPhoneBooks: function (callbacks) {
10885             var options = callbacks || {};
10886             options.parentObj = this;
10887             this.isLoaded();
10888     
10889             if (this._phoneBooks === null) {
10890                 this._phoneBooks = new PhoneBooks(options);
10891             }
10892     
10893             return this._phoneBooks;
10894         },
10895 
10896         /**
10897          * @private
10898          * Loads the Workflows collection object that is associated with User and
10899          * 'returns' them to the caller via the handlers.
10900          * @param {finesse.interfaces.RestObjectHandlers} [handlers] Object that sets callback handlers (only 
10901          * applicable when Object has not been previously created).
10902          * @see finesse.restservices.Workflow
10903          * @see finesse.restservices.Workflows
10904          * @see finesse.restservices.RestCollectionBase
10905          */
10906         loadWorkflows: function (callbacks) {
10907             var options = callbacks || {};
10908             options.parentObj = this;
10909             this.isLoaded();
10910 
10911             if (this._workflows === null) {
10912                 this._workflows = new Workflows(options);
10913             } else {
10914                 this._workflows.refresh();
10915             }
10916 
10917         },
10918 
10919         /**
10920          * Getter for a MediaPropertiesLayout object that is associated with User.
10921          * @param {finesse.interfaces.RestObjectHandlers} [handlers] Object that sets callback handlers (only 
10922          * applicable when Object has not been previously created).
10923          * @returns {finesse.restservices.MediaPropertiesLayout}
10924          *     The MediaPropertiesLayout object associated with this user
10925          */
10926         getMediaPropertiesLayout: function (callbacks) {
10927             var options = callbacks || {};
10928             options.parentObj = this;
10929             options.id = this._id;
10930     
10931             this.isLoaded();
10932             if (this._mediaPropertiesLayout === null) {
10933                 this._mediaPropertiesLayout = new MediaPropertiesLayout(options);
10934             }
10935             return this._mediaPropertiesLayout;
10936         },
10937     
10938         /**
10939          * Getter for the supervised Teams this User (Supervisor) supervises, if any.
10940          * @see finesse.restservices.Team
10941          * @returns {Array}
10942          *     An array of Teams supervised by this User (Supervisor)
10943          */
10944         getSupervisedTeams: function () {
10945             this.isLoaded();
10946     
10947             try {
10948                 return Utilities.getArray(this.getData().teams.Team);
10949             } catch (e) {
10950                 return [];
10951             }
10952     
10953         },
10954     
10955         /**
10956          * Perform an agent login for this user, associating him with the
10957          * specified extension.
10958          * @param {Object} params
10959          *     An object containing properties for agent login.
10960          * @param {String} params.extension
10961          *     The extension to associate with this user
10962          * @param {Object} [params.mobileAgent]
10963          *     A mobile agent object containing the mode and dial number properties.
10964          * @param {finesse.interfaces.RequestHandlers} params.handlers
10965          * @see finesse.interfaces.RequestHandlers
10966          * @returns {finesse.restservices.User}
10967          *     This User object, to allow cascading
10968          * @private
10969          */
10970         _login: function (params) {
10971             var handlers, contentBody = {},
10972             restType = this.getRestType();
10973             
10974             // Protect against null dereferencing.
10975             params = params || {};
10976     
10977             contentBody[restType] = {
10978                 "state": User.States.LOGIN,
10979                 "extension": params.extension
10980             };
10981     
10982             // Create mobile agent node if available.
10983             if (typeof params.mobileAgent === "object") {
10984                 contentBody[restType].mobileAgent = {
10985                     "mode": params.mobileAgent.mode,
10986                     "dialNumber": params.mobileAgent.dialNumber
10987                 };
10988             }
10989     
10990             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
10991             handlers = params.handlers || {};
10992     
10993             this.restRequest(this.getRestUrl(), {
10994                 method: 'PUT',
10995                 success: handlers.success,
10996                 error: handlers.error,
10997                 content: contentBody
10998             });
10999     
11000             return this; // Allow cascading
11001         },
11002     
11003         /**
11004          * Perform an agent login for this user, associating him with the
11005          * specified extension.
11006          * @param {String} extension
11007          *     The extension to associate with this user
11008          * @param {finesse.interfaces.RequestHandlers} handlers
11009          *     An object containing the handlers for the request
11010          * @returns {finesse.restservices.User}
11011          *     This User object, to allow cascading
11012          */
11013         login: function (extension, handlers) {
11014             this.isLoaded();
11015             var params = {
11016                 "extension": extension,
11017                 "handlers": handlers
11018             };
11019             return this._login(params);
11020         },
11021     
11022         /**
11023          * Perform an agent login for this user, associating him with the
11024          * specified extension.
11025          * @param {String} extension
11026          *     The extension to associate with this user
11027          * @param {String} mode
11028          *     The mobile agent work mode as defined in finesse.restservices.User.WorkMode.
11029          * @param {String} extension
11030          *     The external dial number desired to be used by the mobile agent.
11031          * @param {finesse.interfaces.RequestHandlers} handlers
11032          *     An object containing the handlers for the request
11033          * @returns {finesse.restservices.User}
11034          *     This User object, to allow cascading
11035          */
11036         loginMobileAgent: function (extension, mode, dialNumber, handlers) {
11037             this.isLoaded();
11038             var params = {
11039                 "extension": extension,
11040                 "mobileAgent": {
11041                     "mode": mode,
11042                     "dialNumber": dialNumber
11043                 },
11044                 "handlers": handlers
11045             };
11046             return this._login(params);
11047         },
11048     
11049         /**
11050          * Perform an agent logout for this user.
11051          * @param {String} reasonCode
11052          *     The reason this user is logging out.  Pass null for no reason.
11053          * @param {finesse.interfaces.RequestHandlers} handlers
11054          *     An object containing the handlers for the request
11055          * @returns {finesse.restservices.User}
11056          *     This User object, to allow cascading
11057          */
11058         logout: function (reasonCode, handlers) {
11059             return this.setState("LOGOUT", reasonCode, handlers);
11060         },
11061     
11062         /**
11063          * Set the state of the user.
11064          * @param {String} newState
11065          *     The state you are setting
11066          * @param {ReasonCode} reasonCode
11067          *     The reason this user is logging out.  Pass null for no reason.
11068          * @param {finesse.interfaces.RequestHandlers} handlers
11069          *     An object containing the handlers for the request
11070          * @see finesse.restservices.User.States
11071          * @returns {finesse.restservices.User}
11072          *     This User object, to allow cascading
11073          */
11074         setState: function (newState, reasonCode, handlers) {
11075             this.isLoaded();
11076     
11077             var options, contentBody = {};
11078     
11079             if (!reasonCode) {
11080                 contentBody[this.getRestType()] = {
11081                     "state": newState
11082                 };
11083             } else {
11084                 contentBody[this.getRestType()] = {
11085                     "state": newState,
11086                     "reasonCodeId": reasonCode.id
11087                 };
11088             }
11089     
11090             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
11091             handlers = handlers || {};
11092     
11093             options = {
11094                 method: 'PUT',
11095                 success: handlers.success,
11096                 error: handlers.error,
11097                 content: contentBody
11098             };
11099     
11100             // After removing the selective 202 handling, we should be able to just use restRequest
11101             this.restRequest(this.getRestUrl(), options);
11102     
11103             return this; // Allow cascading
11104         },
11105     
11106         /**
11107          * Make call to a particular phone number.
11108          *
11109          * @param {String} 
11110          *     The number to call
11111          * @param {finesse.interfaces.RequestHandlers} handlers
11112          *     An object containing the handlers for the request
11113          * @returns {finesse.restservices.User}
11114          *     This User object, to allow cascading
11115          */ 
11116         makeCall: function (number, handlers) {
11117             this.isLoaded();
11118     
11119             this.getDialogs().createNewCallDialog(number, this.getExtension(), handlers);
11120     
11121             return this; // Allow cascading
11122         },
11123     
11124         /**
11125          * Make a silent monitor call to a particular agent's phone number.
11126          *
11127          * @param {String} 
11128          *     The number to call
11129          * @param {finesse.interfaces.RequestHandlers} handlers
11130          *     An object containing the handlers for the request
11131          * @returns {finesse.restservices.User}
11132          *     This User object, to allow cascading
11133          */
11134         makeSMCall: function (number, handlers) {
11135             this.isLoaded();
11136     
11137             var actionType = "SILENT_MONITOR";
11138     
11139             this.getDialogs().createNewSuperviseCallDialog(number, this.getExtension(), actionType, handlers);
11140     
11141             return this; // Allow cascading
11142         },
11143         
11144     
11145         /**
11146          * Make a silent monitor call to a particular agent's phone number.
11147          *
11148          * @param {String}
11149          *     The number to call
11150          * @param {String} dialogUri
11151          *     The associated dialog uri of SUPERVISOR_MONITOR call
11152          * @param {finesse.interfaces.RequestHandlers} handlers
11153          *     An object containing the handlers for the request
11154          * @see finesse.restservices.dialog
11155          * @returns {finesse.restservices.User}
11156          *     This User object, to allow cascading
11157          */
11158         makeBargeCall:function (number, dialogURI, handlers) {
11159             this.isLoaded();
11160             var actionType = "BARGE_CALL";
11161             this.getDialogs().createNewBargeCall( this.getExtension(), number, actionType, dialogURI,handlers);
11162     
11163             return this; // Allow cascading
11164         },
11165         
11166         /**
11167          * Returns true if the user's current state will result in a pending state change. A pending state
11168          * change is a request to change state that does not result in an immediate state change. For
11169          * example if an agent attempts to change to the NOT_READY state while in the TALKING state, the
11170          * agent will not change state until the call ends.
11171          *
11172          * The current set of states that result in pending state changes is as follows:
11173          *     TALKING
11174          *     HOLD
11175          *     RESERVED_OUTBOUND_PREVIEW
11176          *  @returns {Boolean} True if there is a pending state change.
11177          *  @see finesse.restservices.User.States
11178          */
11179         isPendingStateChange: function () {
11180             var state = this.getState();
11181             return state && ((state === User.States.TALKING) || (state === User.States.HOLD) || (state === User.States.RESERVED_OUTBOUND_PREVIEW));
11182         },
11183         
11184         /**
11185          * Returns true if the user's current state is WORK or WORK_READY. This is used so
11186          * that a pending state is not cleared when moving into wrap up (work) mode. 
11187          * Note that we don't add this as a pending state, since changes while in wrap up
11188          * occur immediately (and we don't want any "pending state" to flash on screen.
11189          * 
11190          * @see finesse.restservices.User.States
11191          * @returns {Boolean} True if user is in wrap-up mode.
11192          */
11193         isWrapUp: function () {
11194             var state = this.getState();
11195             return state && ((state === User.States.WORK) || (state === User.States.WORK_READY));
11196         },
11197     
11198         /**
11199          * @private
11200          * Parses a uriString to retrieve the id portion
11201          * @param {String} uriString
11202          * @return {String} id
11203          */
11204         _parseIdFromUriString : function (uriString) {
11205             return Utilities.getId(uriString);
11206         },
11207     
11208         /**
11209          * Gets the user's Not Ready reason code.
11210          * @return {String} Reason Code Id, or undefined if not set or indeterminate
11211          */
11212         getNotReadyReasonCodeId : function () {
11213             this.isLoaded();
11214     
11215             var reasoncodeIdResult, finesseServerReasonCodeId;
11216             finesseServerReasonCodeId = this.getData().reasonCodeId;
11217     
11218             //FinesseServer will give "-l" => we will set to undefined (for convenience)
11219             if (finesseServerReasonCodeId !== "-1") {
11220                 reasoncodeIdResult = finesseServerReasonCodeId;
11221             }
11222     
11223             return reasoncodeIdResult;
11224         },
11225     
11226         /**
11227          * Performs a GET against the Finesse server looking up the reasonCodeId specified.
11228          * Note that there is no return value; use the success handler to process a
11229          * valid return.
11230          * @param {finesse.interfaces.RequestHandlers} handlers
11231          *     An object containing the handlers for the request
11232          * @param {String} reasonCodeId The id for the reason code to lookup
11233          * 
11234          */
11235         getReasonCodeById : function (handlers, reasonCodeId)
11236         {
11237             var self = this, contentBody, reasonCode, url;
11238             contentBody = {};
11239     
11240             url = this.getRestUrl() + "/ReasonCode/" + reasonCodeId;
11241             this.restRequest(url, {
11242                 method: 'GET',
11243                 success: function (rsp) {
11244                     reasonCode = {
11245                         uri: rsp.object.ReasonCode.uri,
11246                         label: rsp.object.ReasonCode.label,
11247                         id: self._parseIdFromUriString(rsp.object.ReasonCode.uri)
11248                     };
11249                     handlers.success(reasonCode);
11250                 },
11251                 error: function (rsp) {
11252                     handlers.error(rsp);
11253                 },
11254                 content: contentBody
11255             });
11256         },
11257     
11258         /**
11259          * Performs a GET against Finesse server retrieving all the specified type of reason codes.
11260          * @param {String} type (LOGOUT or NOT_READY)
11261          * @param {finesse.interfaces.RequestHandlers} handlers
11262          *     An object containing the handlers for the request
11263          */
11264         _getReasonCodesByType : function (type, handlers)
11265         {
11266             var self = this, contentBody = {}, url, reasonCodes, i, reasonCodeArray;
11267     
11268             url = this.getRestUrl() + "/ReasonCodes?category=" + type;
11269             this.restRequest(url, {
11270                 method: 'GET',
11271                 success: function (rsp) {
11272                     reasonCodes = [];
11273     
11274                     reasonCodeArray = rsp.object.ReasonCodes.ReasonCode;
11275                     if (reasonCodeArray === undefined) {
11276                         reasonCodes = undefined;
11277                     } else if (reasonCodeArray[0] !== undefined) {
11278                         for (i = 0; i < reasonCodeArray.length; i = i + 1) {
11279                             reasonCodes[i] = {
11280                                 label: rsp.object.ReasonCodes.ReasonCode[i].label,
11281                                 id: self._parseIdFromUriString(rsp.object.ReasonCodes.ReasonCode[i].uri)
11282                             };
11283                         }
11284                     } else {
11285                         reasonCodes[0] = {
11286                             label: rsp.object.ReasonCodes.ReasonCode.label,
11287                             id: self._parseIdFromUriString(rsp.object.ReasonCodes.ReasonCode.uri)
11288                         };
11289                     }
11290                     handlers.success(reasonCodes);
11291                 },
11292                 error: function (rsp) {
11293                     handlers.error(rsp);
11294                 },
11295                 content: contentBody
11296             });
11297         },
11298     
11299         /**
11300          * Performs a GET against Finesse server retrieving all the Signout reason codes.
11301          * Note that there is no return value; use the success handler to process a
11302          * valid return.
11303          * @param {finesse.interfaces.RequestHandlers} handlers
11304          *     An object containing the handlers for the request
11305          */
11306         getSignoutReasonCodes : function (handlers)
11307         {
11308             this._getReasonCodesByType("LOGOUT", handlers);
11309         },
11310     
11311         /**
11312          * Performs a GET against Finesse server retrieving all the Not Ready reason codes.
11313          * Note that there is no return value; use the success handler to process a
11314          * valid return.
11315          * @param {finesse.interfaces.RequestHandlers} handlers
11316          *     An object containing the handlers for the request
11317          */
11318         getNotReadyReasonCodes : function (handlers)
11319         {
11320             this._getReasonCodesByType("NOT_READY", handlers);
11321         }
11322     });
11323     
11324     User.States = /** @lends finesse.restservices.User.States.prototype */ {
11325             /**
11326              * User Login.  Note that while this is an action, is not technically a state, since a 
11327              * logged-in User will always be in a specific state (READY, NOT_READY, TALKING, etc.).
11328              */
11329             LOGIN: "LOGIN",
11330             /**
11331              * User is logged out.
11332              */
11333             LOGOUT: "LOGOUT",
11334             /**
11335              * User is not ready. Note that in UCCX implementations, the user is in this state while on a non-routed call.
11336              */
11337             NOT_READY: "NOT_READY",
11338             /**
11339              * User is ready for calls.
11340              */
11341             READY: "READY",
11342             /**
11343              * User has a call coming in, but has not answered it.
11344              */
11345             RESERVED: "RESERVED",
11346             /**
11347              * User has an outbound call being made, but has not been connected to it.
11348              */
11349             RESERVED_OUTBOUND: "RESERVED_OUTBOUND",
11350             /**
11351              * User has an outbound call's preview information being displayed, but has not acted on it.
11352              */
11353             RESERVED_OUTBOUND_PREVIEW: "RESERVED_OUTBOUND_PREVIEW",
11354             /**
11355              * User is on a call.  Note that in UCCX implementations, this is for routed calls only.
11356              */
11357             TALKING: "TALKING",
11358             /**
11359              * User is on hold.  Note that in UCCX implementations, the user remains in TALKING state while on hold.
11360              */
11361             HOLD: "HOLD",
11362             /**
11363              * User is wrap-up/work mode.  This mode is typically configured to time out, after which the user becomes NOT_READY.
11364              */
11365             WORK: "WORK",
11366             /**
11367              * This is the same as WORK, except that after time out user becomes READY.
11368              */
11369             WORK_READY: "WORK_READY",
11370             /**
11371              * @class Possible User state values.
11372              * @constructs
11373              */
11374             _fakeConstructor : function () {} // For JS Doc to work need a constructor so that the lends/constructs build the doc properly
11375           
11376         };
11377     
11378     User.WorkMode = { /** @lends finesse.restservices.User.WorkMode.prototype */
11379         /**
11380          * Mobile agent is connected (dialed) for each incoming call received.
11381          */
11382         CALL_BY_CALL: "CALL_BY_CALL",
11383         /**
11384          * Mobile agent is connected (dialed) at login.
11385          */
11386         NAILED_CONNECTION: "NAILED_CONNECTION",
11387         /**
11388          * @class Possible Mobile Agent Work Mode Types.
11389          * @constructs
11390          */
11391         _fakeConstructor : function () {} // For JS Doc to work need a constructor so that the lends/constructs build the doc properly
11392         
11393     };
11394 
11395     window.finesse = window.finesse || {};
11396     window.finesse.restservices = window.finesse.restservices || {};
11397     window.finesse.restservices.User = User;
11398         
11399     return User;
11400 }));
11401 
11402 /**
11403  * JavaScript representation of the Finesse Users collection
11404  * object which contains a list of Users objects.
11405  *
11406  * @requires finesse.clientservices.ClientServices
11407  * @requires Class
11408  * @requires finesse.FinesseBase
11409  * @requires finesse.restservices.RestBase
11410  * @requires finesse.restservices.RestCollectionBase
11411  * @requires finesse.restservices.User
11412  */
11413 
11414 /** @private */
11415 (function (factory) {
11416     
11417 
11418     // Define as an AMD module if possible
11419     if ( typeof define === 'function' && define.amd )
11420     {
11421         define('restservices/Users', ['restservices/RestCollectionBase',
11422                  'restservices/RestBase',
11423                  'restservices/User'], factory );
11424     }
11425     /* Define using browser globals otherwise
11426      * Prevent multiple instantiations if the script is loaded twice
11427      */
11428     else
11429     {
11430         factory(finesse.restservices.RestCollectionBase, finesse.restservices.RestBase, finesse.restservices.User);
11431     }
11432 }(function (RestCollectionBase, RestBase, User) {
11433 
11434 	var Users = RestCollectionBase.extend(/** @lends finesse.restservices.Users.prototype */{
11435 
11436     /**
11437      * @class
11438      * JavaScript representation of a Users collection object. 
11439      * While there is no method provided to retrieve all Users, this collection is
11440      * used to return the Users in a supervised Team.
11441      * @augments finesse.restservices.RestCollectionBase
11442      * @constructs
11443      * @see finesse.restservices.Team
11444      * @see finesse.restservices.User
11445      * @see finesse.restservices.User#getSupervisedTeams
11446      * @example
11447      *  // Note: The following method gets an Array of Teams, not a Collection.
11448      *  _teams = _user.getSupervisedTeams();
11449      *  if (_teams.length > 0) {
11450      *      _team0Users = _teams[0].getUsers();
11451      *  }
11452      */
11453     _fakeConstuctor: function () {
11454         /* This is here to hide the real init constructor from the public docs */
11455     },
11456         
11457     /**
11458      * @private
11459      * JavaScript representation of the Finesse Users collection
11460      * object which contains a list of Users objects.
11461      *
11462 	 * @param {Object} options
11463 	 *     An object with the following properties:<ul>
11464      *         <li><b>id:</b> The id of the object being constructed</li>
11465      *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
11466      *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
11467      *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
11468      *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
11469      *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
11470      *             <li><b>status:</b> {Number} The HTTP status code returned</li>
11471      *             <li><b>content:</b> {String} Raw string of response</li>
11472      *             <li><b>object:</b> {Object} Parsed object of response</li>
11473      *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
11474      *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
11475      *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
11476      *             </ul></li>
11477      *         </ul></li>
11478      *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
11479      **/
11480 	init: function (options) {
11481 		this._super(options);
11482 	},
11483 
11484 	/**
11485      * @private
11486 	 * Gets the REST class for the current object - this is the Users class.
11487 	 */
11488 	getRestClass: function () {
11489 	    return Users;
11490 	},
11491 
11492 	/**
11493      * @private
11494 	 * Gets the REST class for the objects that make up the collection. - this
11495 	 * is the User class.
11496 	 */
11497 	getRestItemClass: function () {
11498 		return User;
11499 	},
11500 
11501 	/**
11502      * @private
11503 	 * Gets the REST type for the current object - this is a "Users".
11504 	 */
11505 	getRestType: function () {
11506 	    return "Users";
11507 	},
11508 
11509 	/**
11510      * @private
11511 	 * Gets the REST type for the objects that make up the collection - this is "User".
11512 	 */
11513 	getRestItemType: function () {
11514 	    return "User";
11515 	},
11516 
11517 	/**
11518      * @private
11519      * Gets the node path for the current object - this is the team Users node
11520      * @returns {String} The node path
11521      */
11522     getXMPPNodePath: function () {
11523 		return this.getRestUrl();
11524     },
11525 
11526     /**
11527      * @private
11528      * Overloading _doGET to reroute the GET to /Team/id from /Team/id/Users
11529      * This needs to be done because the GET /Team/id/Users API is missing
11530      * @returns {Users} This Users (collection) object to allow cascading
11531      */
11532     _doGET: function (handlers) {
11533         var _this = this;
11534         handlers = handlers || {};
11535         // Only do this for /Team/id/Users
11536         if (this._restObj && this._restObj.getRestType() === "Team") {
11537             this._restObj._doGET({
11538                 success: function (rspObj) {
11539                     // Making sure the response was a valid Team
11540                     if (_this._restObj._validate(rspObj.object)) {
11541                         // Shimmying the response to look like a Users collection by extracting it from the Team response
11542                         rspObj.object[_this.getRestType()] = rspObj.object[_this._restObj.getRestType()][_this.getRestType().toLowerCase()];
11543                         handlers.success(rspObj);
11544                     } else {
11545                         handlers.error(rspObj);
11546                     }
11547                 },
11548                 error: handlers.error
11549             });
11550             return this; // Allow cascading
11551         } else {
11552             return this._super(handlers);
11553         }
11554     },
11555 
11556 	/**
11557      * @private
11558      * Override default to indicates that the collection doesn't support making
11559 	 * requests.
11560 	 */
11561 	supportsRequests: false,
11562 
11563     /**
11564      * @private
11565      * Indicates that this collection handles the subscription for its items
11566      */
11567     handlesItemSubscription: true,
11568 	
11569     /**
11570      * @private
11571      * Override default to indicate that we need to subscribe explicitly
11572      */
11573     explicitSubscription: true
11574     
11575 	});
11576 
11577     window.finesse = window.finesse || {};
11578     window.finesse.restservices = window.finesse.restservices || {};
11579     window.finesse.restservices.Users = Users;
11580 
11581 	return Users;
11582 }));
11583 
11584 /**
11585  * JavaScript representation of the Finesse Team Not Ready Reason Code Assignment object.
11586  *
11587  * @requires finesse.clientservices.ClientServices
11588  * @requires Class
11589  * @requires finesse.FinesseBase
11590  * @requires finesse.restservices.RestBase
11591  */
11592 
11593 /** @private */
11594 (function (factory) {
11595     
11596 
11597     // Define as an AMD module if possible
11598     if ( typeof define === 'function' && define.amd )
11599     {
11600         define('restservices/TeamNotReadyReasonCode', ['restservices/RestBase'], factory );
11601     }
11602     /* Define using browser globals otherwise
11603      * Prevent multiple instantiations if the script is loaded twice
11604      */
11605     else
11606     {
11607         factory(finesse.restservices.RestBase);
11608     } 
11609 }(function (RestBase) {
11610     
11611     var TeamNotReadyReasonCode = RestBase.extend( {
11612 
11613         /**
11614          * @class
11615          * JavaScript representation of a Team Not Ready ReasonCode object. Also exposes
11616          * methods to operate on the object against the server.
11617          *
11618          * @param {Object} options
11619          *     An object with the following properties:<ul>
11620          *         <li><b>id:</b> The id of the object being constructed</li>
11621          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
11622          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
11623          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
11624          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
11625          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
11626          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
11627          *             <li><b>content:</b> {String} Raw string of response</li>
11628          *             <li><b>object:</b> {Object} Parsed object of response</li>
11629          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
11630          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
11631          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
11632          *             </ul></li>
11633          *         </ul></li>
11634          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
11635          * @constructs
11636          **/
11637         init: function (options) {
11638             this._super(options);
11639         },
11640     
11641         /**
11642          * @private
11643          * Gets the REST class for the current object - this is the TeamNotReadyReasonCode class.
11644          * @returns {Object} The TeamNotReadyReasonCode class.
11645          */
11646         getRestClass: function () {
11647             return TeamNotReadyReasonCode;
11648         },
11649     
11650         /**
11651          * @private
11652          * Gets the REST type for the current object - this is a "ReasonCode".
11653          * @returns {String} The ReasonCode string.
11654          */
11655         getRestType: function () {
11656             return "ReasonCode";
11657         },
11658     
11659         /**
11660          * @private
11661          * Override default to indicate that this object doesn't support making
11662          * requests.
11663          */
11664         supportsRequests: false,
11665     
11666         /**
11667          * @private
11668          * Override default to indicate that this object doesn't support subscriptions.
11669          */
11670         supportsSubscriptions: false,
11671     
11672         /**
11673          * Getter for the category.
11674          * @returns {String} The category.
11675          */
11676         getCategory: function () {
11677             this.isLoaded();
11678             return this.getData().category;
11679         },
11680     
11681         /**
11682          * Getter for the code.
11683          * @returns {String} The code.
11684          */
11685         getCode: function () {
11686             this.isLoaded();
11687             return this.getData().code;
11688         },
11689     
11690         /**
11691          * Getter for the label.
11692          * @returns {String} The label.
11693          */
11694         getLabel: function () {
11695             this.isLoaded();
11696             return this.getData().label;
11697         },
11698     
11699         /**
11700          * Getter for the forAll value.
11701          * @returns {String} The forAll.
11702          */
11703         getForAll: function () {
11704             this.isLoaded();
11705             return this.getData().forAll;
11706         },
11707     
11708         /**
11709          * Getter for the Uri value.
11710          * @returns {String} The Uri.
11711          */
11712         getUri: function () {
11713             this.isLoaded();
11714             return this.getData().uri;
11715         }
11716 
11717     });
11718     
11719     window.finesse = window.finesse || {};
11720     window.finesse.restservices = window.finesse.restservices || {};
11721     window.finesse.restservices.TeamNotReadyReasonCode = TeamNotReadyReasonCode;
11722         
11723     return TeamNotReadyReasonCode;
11724 }));
11725 
11726 /**
11727 * JavaScript representation of the Finesse TeamNotReadyReasonCodes collection
11728 * object which contains a list of TeamNotReadyReasonCode objects.
11729  *
11730  * @requires finesse.clientservices.ClientServices
11731  * @requires Class
11732  * @requires finesse.FinesseBase
11733  * @requires finesse.restservices.RestBase
11734  * @requires finesse.restservices.Dialog
11735  * @requires finesse.restservices.RestCollectionBase
11736  */
11737 
11738 /** @private */
11739 (function (factory) {
11740     
11741 
11742     // Define as an AMD module if possible
11743     if ( typeof define === 'function' && define.amd )
11744     {
11745         define('restservices/TeamNotReadyReasonCodes', ['restservices/RestCollectionBase',
11746                  'restservices/RestBase',
11747                  'restservices/TeamNotReadyReasonCode'], factory );
11748     }
11749     /* Define using browser globals otherwise
11750      * Prevent multiple instantiations if the script is loaded twice
11751      */
11752     else
11753     {
11754         factory(finesse.restservices.RestCollectionBase, finesse.restservices.RestBase, finesse.restservices.TeamNotReadyReasonCode);
11755     }
11756 }(function (RestCollectionBase, RestBase, TeamNotReadyReasonCode) {
11757     
11758     var TeamNotReadyReasonCodes = RestCollectionBase.extend( {
11759 
11760       /**
11761        * @class
11762        * JavaScript representation of a TeamNotReadyReasonCodes collection object. Also exposes
11763        * methods to operate on the object against the server.
11764        *
11765        * @param {Object} options
11766        *     An object with the following properties:<ul>
11767        *         <li><b>id:</b> The id of the object being constructed</li>
11768        *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
11769        *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
11770        *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
11771        *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
11772        *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
11773        *             <li><b>status:</b> {Number} The HTTP status code returned</li>
11774        *             <li><b>content:</b> {String} Raw string of response</li>
11775        *             <li><b>object:</b> {Object} Parsed object of response</li>
11776        *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
11777        *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
11778        *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
11779        *             </ul></li>
11780        *         </ul></li>
11781        *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
11782        * @augments finesse.restservices.RestCollectionBase
11783        * @constructs
11784        **/
11785       init: function (options) {
11786           this._super(options);
11787       },
11788     
11789       /**
11790        * @private
11791        * Gets the REST class for the current object - this is the TeamNotReadyReasonCodes class.
11792        */
11793       getRestClass: function () {
11794           return TeamNotReadyReasonCodes;
11795       },
11796     
11797       /**
11798        * @private
11799        * Gets the REST class for the objects that make up the collection. - this
11800        * is the TeamNotReadyReasonCode class.
11801        */
11802       getRestItemClass: function () {
11803           return TeamNotReadyReasonCode;
11804       },
11805     
11806       /**
11807        * @private
11808        * Gets the REST type for the current object - this is a "ReasonCodes".
11809        */
11810       getRestType: function () {
11811           return "ReasonCodes";
11812       },
11813     
11814       /**
11815        * @private
11816        * Overrides the parent class.  Returns the url for the NotReadyReasonCodes resource
11817        */
11818       getRestUrl: function () {
11819           // return ("/finesse/api/" + this.getRestType() + "?category=NOT_READY");
11820           var restObj = this._restObj,
11821               restUrl = "";
11822           //Prepend the base REST object if one was provided.
11823           //Otherwise prepend with the default webapp name.
11824           if (restObj instanceof RestBase) {
11825               restUrl += restObj.getRestUrl();
11826           }
11827           else {
11828               restUrl += "/finesse/api";
11829           }
11830           //Append the REST type.
11831           restUrl += "/ReasonCodes?category=NOT_READY";
11832           //Append ID if it is not undefined, null, or empty.
11833           if (this._id) {
11834               restUrl += "/" + this._id;
11835           }
11836           return restUrl;
11837       },
11838     
11839       /**
11840        * @private
11841        * Gets the REST type for the objects that make up the collection - this is "ReasonCode".
11842        */
11843       getRestItemType: function () {
11844           return "ReasonCode";
11845       },
11846     
11847       /**
11848        * @private
11849        * Override default to indicates that the collection supports making
11850        * requests.
11851        */
11852       supportsRequests: true,
11853     
11854       /**
11855        * @private
11856        * Override default to indicate that this object doesn't support subscriptions.
11857        */
11858       supportsRestItemSubscriptions: false,
11859     
11860       /**
11861        * @private
11862        * Retrieve the Not Ready Reason Codes.
11863        *
11864        * @returns {TeamNotReadyReasonCodes}
11865        *     This TeamNotReadyReasonCodes object to allow cascading.
11866        */
11867       get: function () {
11868           // set loaded to false so it will rebuild the collection after the get
11869           this._loaded = false;
11870           // reset collection
11871           this._collection = {};
11872           // perform get
11873           this._synchronize();
11874           return this;
11875       },
11876     
11877       /**
11878        * @private
11879        * Set up the PutSuccessHandler for TeamNotReadyReasonCodes
11880        * @param {Object} reasonCodes
11881        * @param {String} contentBody
11882        * @param successHandler    
11883        * @return {function}
11884        */
11885       createPutSuccessHandler: function (reasonCodes, contentBody, successHandler) {
11886           return function (rsp) {
11887               // Update internal structure based on response. Here we
11888               // inject the contentBody from the PUT request into the
11889               // rsp.object element to mimic a GET as a way to take
11890               // advantage of the existing _processResponse method.
11891               rsp.object = contentBody;
11892               reasonCodes._processResponse(rsp);
11893     
11894               //Remove the injected contentBody object before cascading response
11895               rsp.object = {};
11896     
11897               //cascade response back to consumer's response handler
11898               successHandler(rsp);
11899           };
11900       },
11901     
11902       /**
11903        * @private
11904        * Perform the REST API PUT call to update the reason code assignments for the team
11905        * @param {string[]} newValues
11906        * @param handlers     
11907        */
11908       update: function (newValues, handlers) {
11909           this.isLoaded();
11910           var contentBody = {}, contentBodyInner = [], i, innerObject = {};
11911     
11912           contentBody[this.getRestType()] = {
11913           };
11914     
11915           for (i in newValues) {
11916               if (newValues.hasOwnProperty(i)) {
11917                   innerObject = {
11918                       "uri": newValues[i]
11919                   };
11920                   contentBodyInner.push(innerObject);
11921               }
11922           }
11923     
11924           contentBody[this.getRestType()] = {
11925               "ReasonCode" : contentBodyInner
11926           };
11927     
11928           // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
11929           handlers = handlers || {};
11930     
11931           this.restRequest(this.getRestUrl(), {
11932               method: 'PUT',
11933               success: this.createPutSuccessHandler(this, contentBody, handlers.success),
11934               error: handlers.error,
11935               content: contentBody
11936           });
11937     
11938           return this; // Allow cascading
11939       }
11940   });
11941   
11942     window.finesse = window.finesse || {};
11943     window.finesse.restservices = window.finesse.restservices || {};
11944     window.finesse.restservices.TeamNotReadyReasonCodes = TeamNotReadyReasonCodes;
11945     
11946   return TeamNotReadyReasonCodes;
11947 }));
11948 
11949 /**
11950  * JavaScript representation of the Finesse Team Wrap Up Reason object.
11951  *
11952  * @requires finesse.clientservices.ClientServices
11953  * @requires Class
11954  * @requires finesse.FinesseBase
11955  * @requires finesse.restservices.RestBase
11956  */
11957 /** @private */
11958 (function (factory) {
11959     
11960 
11961     // Define as an AMD module if possible
11962     if ( typeof define === 'function' && define.amd )
11963     {
11964         define('restservices/TeamWrapUpReason',['restservices/RestBase'], factory);
11965     }
11966     /* Define using browser globals otherwise
11967      * Prevent multiple instantiations if the script is loaded twice
11968      */
11969     else
11970     {
11971         factory(finesse.restservices.RestBase);
11972     } 
11973 }(function (RestBase) {
11974 
11975 	var TeamWrapUpReason = RestBase.extend({
11976 
11977     /**
11978      * @class
11979      * JavaScript representation of a TeamWrapUpReason object. Also exposes
11980      * methods to operate on the object against the server.
11981      *
11982      * @param {Object} options
11983      *     An object with the following properties:<ul>
11984      *         <li><b>id:</b> The id of the object being constructed</li>
11985      *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
11986      *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
11987      *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
11988      *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
11989      *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
11990      *             <li><b>status:</b> {Number} The HTTP status code returned</li>
11991      *             <li><b>content:</b> {String} Raw string of response</li>
11992      *             <li><b>object:</b> {Object} Parsed object of response</li>
11993      *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
11994      *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
11995      *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
11996      *             </ul></li>
11997      *         </ul></li>
11998      *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
11999      * @constructs
12000      **/
12001     init: function (options) {
12002         this._super(options);
12003     },
12004 
12005     /**
12006      * @private
12007      * Gets the REST class for the current object - this is the TeamWrapUpReason class.
12008      * @returns {Object} The TeamWrapUpReason class.
12009      */
12010     getRestClass: function () {
12011         return TeamWrapUpReason;
12012     },
12013 
12014     /**
12015      * @private
12016      * Gets the REST type for the current object - this is a "WrapUpReason".
12017      * @returns {String} The WrapUpReason string.
12018      */
12019     getRestType: function () {
12020         return "WrapUpReason";
12021     },
12022 
12023     /**
12024      * @private
12025      * Override default to indicate that this object doesn't support making
12026      * requests.
12027      */
12028     supportsRequests: false,
12029 
12030     /**
12031      * @private
12032      * Override default to indicate that this object doesn't support subscriptions.
12033      */
12034     supportsSubscriptions: false,
12035 
12036     /**
12037      * Getter for the label.
12038      * @returns {String} The label.
12039      */
12040     getLabel: function () {
12041         this.isLoaded();
12042         return this.getData().label;
12043     },
12044 
12045     /**
12046      * @private
12047      * Getter for the forAll value.
12048      * @returns {Boolean} True if global
12049      */
12050     getForAll: function () {
12051         this.isLoaded();
12052         return this.getData().forAll;
12053     },
12054 
12055     /**
12056      * @private
12057      * Getter for the Uri value.
12058      * @returns {String} The Uri.
12059      */
12060     getUri: function () {
12061         this.isLoaded();
12062         return this.getData().uri;
12063     }
12064 	});
12065 
12066     window.finesse = window.finesse || {};
12067     window.finesse.restservices = window.finesse.restservices || {};
12068     window.finesse.restservices.TeamWrapUpReason = TeamWrapUpReason;
12069 
12070 	return TeamWrapUpReason;
12071 }));
12072 
12073 /**
12074 * JavaScript representation of the Finesse Team Wrap-Up Reasons collection
12075 * object which contains a list of Wrap-Up Reasons objects.
12076  *
12077  * @requires finesse.clientservices.ClientServices
12078  * @requires Class
12079  * @requires finesse.FinesseBase
12080  * @requires finesse.restservices.RestBase
12081  * @requires finesse.restservices.Dialog
12082  * @requires finesse.restservices.RestCollectionBase
12083  */
12084 /** @private */
12085 (function (factory) {
12086     
12087 
12088     // Define as an AMD module if possible
12089     if ( typeof define === 'function' && define.amd )
12090     {
12091         define('restservices/TeamWrapUpReasons', ['restservices/RestCollectionBase',
12092                  'restservices/RestBase',
12093                  'restservices/TeamWrapUpReason'], factory );
12094     }
12095     /* Define using browser globals otherwise
12096      * Prevent multiple instantiations if the script is loaded twice
12097      */
12098     else
12099     {
12100         factory(finesse.restservices.RestCollectionBase, finesse.restservices.RestBase, finesse.restservices.TeamWrapUpReason);
12101     } 
12102 }(function (RestCollectionBase, RestBase, TeamWrapUpReason) {
12103 
12104 	var TeamWrapUpReasons = RestCollectionBase.extend({
12105 
12106     /**
12107      * @class
12108      * JavaScript representation of a TeamWrapUpReasons collection object. Also exposes
12109      * methods to operate on the object against the server.
12110      *
12111      * @param {Object} options
12112      *     An object with the following properties:<ul>
12113      *         <li><b>id:</b> The id of the object being constructed</li>
12114      *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
12115      *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
12116      *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
12117      *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
12118      *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
12119      *             <li><b>status:</b> {Number} The HTTP status code returned</li>
12120      *             <li><b>content:</b> {String} Raw string of response</li>
12121      *             <li><b>object:</b> {Object} Parsed object of response</li>
12122      *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
12123      *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
12124      *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
12125      *             </ul></li>
12126      *         </ul></li>
12127      *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
12128      * @constructs
12129      **/
12130     init: function (options) {
12131         this._super(options);
12132     },
12133 
12134     /**
12135      * @private
12136      * Gets the REST class for the current object - this is the TeamWrapUpReasons class.
12137      */
12138     getRestClass: function () {
12139         return TeamWrapUpReasons;
12140     },
12141 
12142     /**
12143      * @private
12144      * Gets the REST class for the objects that make up the collection. - this
12145      * is the TeamWrapUpReason class.
12146      */
12147     getRestItemClass: function () {
12148         return TeamWrapUpReason;
12149     },
12150 
12151     /**
12152      * @private
12153      * Gets the REST type for the current object - this is a "WrapUpReasons".
12154      */
12155     getRestType: function () {
12156         return "WrapUpReasons";
12157     },
12158 
12159     /**
12160      * @private
12161      * Gets the REST type for the objects that make up the collection - this is "WrapUpReason".
12162      */
12163     getRestItemType: function () {
12164         return "WrapUpReason";
12165     },
12166 
12167     /**
12168      * @private
12169      * Override default to indicates that the collection supports making
12170      * requests.
12171      */
12172     supportsRequests: true,
12173 
12174     /**
12175      * @private
12176      * Override default to indicate that this object doesn't support subscriptions.
12177      */
12178     supportsRestItemSubscriptions: false,
12179 
12180     /**
12181      * Retrieve the Team Wrap Up Reasons.
12182      *
12183      * @returns {finesse.restservices.TeamWrapUpReasons}
12184      *     This TeamWrapUpReasons object to allow cascading.
12185      */
12186     get: function () {
12187         // set loaded to false so it will rebuild the collection after the get
12188         this._loaded = false;
12189         // reset collection
12190         this._collection = {};
12191         // perform get
12192         this._synchronize();
12193         return this;
12194     },
12195 
12196     /**
12197      * Set up the PutSuccessHandler for TeamWrapUpReasons
12198      * @param {Object} wrapUpReasons
12199      * @param {Object} contentBody
12200      * @param successHandler
12201      * @returns response
12202      */
12203     createPutSuccessHandler: function (wrapUpReasons, contentBody, successHandler) {
12204         return function (rsp) {
12205             // Update internal structure based on response. Here we
12206             // inject the contentBody from the PUT request into the
12207             // rsp.object element to mimic a GET as a way to take
12208             // advantage of the existing _processResponse method.
12209             rsp.object = contentBody;
12210             
12211             wrapUpReasons._processResponse(rsp);
12212 
12213             //Remove the injected contentBody object before cascading response
12214             rsp.object = {};
12215 
12216             //cascade response back to consumer's response handler
12217             successHandler(rsp);
12218         };
12219     },
12220 
12221     /**    
12222      * Perform the REST API PUT call to update the reason code assignments for the team
12223      * @param {String Array} newValues
12224      * @param handlers
12225      * @returns {Object} this
12226      */
12227     update: function (newValues, handlers) {
12228         this.isLoaded();
12229         var contentBody = {}, contentBodyInner = [], i, innerObject = {};
12230 
12231         contentBody[this.getRestType()] = {
12232         };
12233 
12234         for (i in newValues) {
12235             if (newValues.hasOwnProperty(i)) {
12236                 innerObject = {
12237                     "uri": newValues[i]
12238                 };
12239                 contentBodyInner.push(innerObject);
12240             }
12241         }
12242 
12243         contentBody[this.getRestType()] = {
12244             "WrapUpReason" : contentBodyInner
12245         };
12246 
12247         // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
12248         handlers = handlers || {};
12249 
12250         this.restRequest(this.getRestUrl(), {
12251             method: 'PUT',
12252             success: this.createPutSuccessHandler(this, contentBody, handlers.success),
12253             error: handlers.error,
12254             content: contentBody
12255         });
12256 
12257         return this; // Allow cascading
12258     }
12259 	});
12260 
12261     window.finesse = window.finesse || {};
12262     window.finesse.restservices = window.finesse.restservices || {};
12263     window.finesse.restservices.TeamWrapUpReasons = TeamWrapUpReasons;
12264 
12265 	return TeamWrapUpReasons;
12266 }));
12267 
12268 /**
12269  * JavaScript representation of a TeamSignOutReasonCode.
12270  *
12271  * @requires finesse.clientservices.ClientServices
12272  * @requires Class
12273  * @requires finesse.FinesseBase
12274  * @requires finesse.restservices.RestBase
12275  */
12276 
12277 /** @private */
12278 (function (factory) {
12279     
12280 
12281     // Define as an AMD module if possible
12282     if ( typeof define === 'function' && define.amd )
12283     {
12284         define('restservices/TeamSignOutReasonCode', ['restservices/RestBase'], factory );
12285     }
12286     /* Define using browser globals otherwise
12287      * Prevent multiple instantiations if the script is loaded twice
12288      */
12289     else
12290     {
12291         factory(finesse.restservices.RestBase);
12292     }
12293 }(function (RestBase) {
12294     var TeamSignOutReasonCode = RestBase.extend({
12295 
12296         /**
12297          * @class
12298          * JavaScript representation of a TeamSignOutReasonCode object. Also exposes
12299          * methods to operate on the object against the server.
12300          *
12301          * @param {Object} options
12302          *     An object with the following properties:<ul>
12303          *         <li><b>id:</b> The id of the object being constructed</li>
12304          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
12305          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
12306          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
12307          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
12308          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
12309          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
12310          *             <li><b>content:</b> {String} Raw string of response</li>
12311          *             <li><b>object:</b> {Object} Parsed object of response</li>
12312          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
12313          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
12314          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
12315          *             </ul></li>
12316          *         </ul></li>
12317          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
12318          * @constructs
12319          * @ignore
12320          **/
12321         init: function (options) {
12322             this._super(options);
12323         },
12324 
12325         /**
12326          * @private
12327          * Gets the REST class for the current object - this is the TeamSignOutReasonCode class.
12328          * @returns {Object} The TeamSignOutReasonCode class.
12329          */
12330         getRestClass: function () {
12331             return TeamSignOutReasonCode;
12332         },
12333 
12334         /**
12335          * @private
12336          * Gets the REST type for the current object - this is a "ReasonCode".
12337          * @returns {String} The ReasonCode string.
12338          */
12339         getRestType: function () {
12340             return "ReasonCode";
12341         },
12342 
12343         /**
12344          * @private
12345          * Override default to indicate that this object doesn't support making
12346          * requests.
12347          */
12348         supportsRequests: false,
12349 
12350         /**
12351          * @private
12352          * Override default to indicate that this object doesn't support subscriptions.
12353          */
12354         supportsSubscriptions: false,
12355 
12356         /**
12357          * Getter for the category.
12358          * @returns {String} The category.
12359          */
12360         getCategory: function () {
12361             this.isLoaded();
12362             return this.getData().category;
12363         },
12364 
12365         /**
12366          * Getter for the code.
12367          * @returns {String} The code.
12368          */
12369         getCode: function () {
12370             this.isLoaded();
12371             return this.getData().code;
12372         },
12373 
12374         /**
12375          * Getter for the label.
12376          * @returns {String} The label.
12377          */
12378         getLabel: function () {
12379             this.isLoaded();
12380             return this.getData().label;
12381         },
12382 
12383         /**
12384          * Getter for the forAll value.
12385          * @returns {String} The forAll.
12386          */
12387         getForAll: function () {
12388             this.isLoaded();
12389             return this.getData().forAll;
12390         },
12391 
12392         /**
12393          * Getter for the Uri value.
12394          * @returns {String} The Uri.
12395          */
12396         getUri: function () {
12397             this.isLoaded();
12398             return this.getData().uri;
12399         }
12400 
12401     });
12402 
12403     window.finesse = window.finesse || {};
12404     window.finesse.restservices = window.finesse.restservices || {};
12405     window.finesse.restservices.TeamSignOutReasonCode = TeamSignOutReasonCode;
12406     
12407     return TeamSignOutReasonCode;
12408 }));
12409 
12410 /**
12411 * JavaScript representation of the TeamSignOutReasonCodes collection
12412 * object which contains a list of TeamSignOutReasonCode objects.
12413  *
12414  * @requires finesse.clientservices.ClientServices
12415  * @requires Class
12416  * @requires finesse.FinesseBase
12417  * @requires finesse.restservices.RestBase
12418  * @requires finesse.restservices.Dialog
12419  * @requires finesse.restservices.RestCollectionBase
12420  */
12421 
12422 /** @private */
12423 (function (factory) {
12424     
12425 
12426     // Define as an AMD module if possible
12427     if ( typeof define === 'function' && define.amd )
12428     {
12429         define('restservices/TeamSignOutReasonCodes', ['restservices/RestCollectionBase',
12430                  'restservices/RestBase',
12431                  'restservices/TeamSignOutReasonCode'], factory );
12432     }
12433     /* Define using browser globals otherwise
12434      * Prevent multiple instantiations if the script is loaded twice
12435      */
12436     else
12437     {
12438         factory(finesse.restservices.RestCollectionBase, finesse.restservices.RestBase, finesse.restservices.TeamSignOutReasonCode);
12439     } 
12440 }(function (RestCollectionBase, RestBase, TeamSignOutReasonCode) {
12441     
12442     var TeamSignOutReasonCodes = RestCollectionBase.extend({
12443         /**
12444          * @class
12445          * JavaScript representation of a TeamSignOutReasonCodes collection object. Also exposes
12446          * methods to operate on the object against the server.
12447          *
12448          * @param {Object} options
12449          *     An object with the following properties:<ul>
12450          *         <li><b>id:</b> The id of the object being constructed</li>
12451          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
12452          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
12453          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
12454          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
12455          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
12456          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
12457          *             <li><b>content:</b> {String} Raw string of response</li>
12458          *             <li><b>object:</b> {Object} Parsed object of response</li>
12459          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
12460          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
12461          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
12462          *             </ul></li>
12463          *         </ul></li>
12464          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
12465          * @constructs
12466          **/
12467         init: function (options) {
12468             this._super(options);
12469         },
12470 
12471         /**
12472          * @private
12473          * Gets the REST class for the current object - this is the TeamSignOutReasonCodes class.
12474          */
12475         getRestClass: function () {
12476             return TeamSignOutReasonCodes;
12477         },
12478 
12479         /**
12480          * @private
12481          * Gets the REST class for the objects that make up the collection. - this
12482          * is the TeamSignOutReasonCode class.
12483          */
12484         getRestItemClass: function () {
12485             return TeamSignOutReasonCode;
12486         },
12487 
12488         /**
12489          * @private
12490          * Gets the REST type for the current object - this is a "ReasonCodes".
12491          */
12492         getRestType: function () {
12493             return "ReasonCodes";
12494         },
12495 
12496         /**
12497          * Overrides the parent class.  Returns the url for the SignOutReasonCodes resource
12498          */
12499         getRestUrl: function () {
12500             var restObj = this._restObj, restUrl = "";
12501 
12502             //Prepend the base REST object if one was provided.
12503             //Otherwise prepend with the default webapp name.
12504             if (restObj instanceof RestBase) {
12505                 restUrl += restObj.getRestUrl();
12506             } else {
12507                 restUrl += "/finesse/api";
12508             }
12509             //Append the REST type.
12510             restUrl += "/ReasonCodes?category=LOGOUT";
12511             //Append ID if it is not undefined, null, or empty.
12512             if (this._id) {
12513                 restUrl += "/" + this._id;
12514             }
12515             return restUrl;
12516         },
12517 
12518         /**
12519          * @private
12520          * Gets the REST type for the objects that make up the collection - this is "ReasonCode".
12521          */
12522         getRestItemType: function () {
12523             return "ReasonCode";
12524         },
12525 
12526         /**
12527          * @private
12528          * Override default to indicates that the collection supports making requests.
12529          */
12530         supportsRequests: true,
12531 
12532         /**
12533          * @private
12534          * Override default to indicates that the collection does not subscribe to its objects.
12535          */
12536         supportsRestItemSubscriptions: false,
12537 
12538         /**
12539          * Retrieve the Sign Out Reason Codes.
12540          *
12541          * @returns {finesse.restservices.TeamSignOutReasonCodes}
12542          *     This TeamSignOutReasonCodes object to allow cascading.
12543          */
12544         get: function () {
12545             // set loaded to false so it will rebuild the collection after the get
12546             this._loaded = false;
12547             // reset collection
12548             this._collection = {};
12549             // perform get
12550             this._synchronize();
12551             return this;
12552         },
12553 
12554         /* We only use PUT and GET on Reason Code team assignments
12555          * @param {Object} contact
12556          * @param {Object} contentBody
12557          * @param {Function} successHandler
12558          */
12559         createPutSuccessHandler: function (contact, contentBody, successHandler) {
12560             return function (rsp) {
12561                 // Update internal structure based on response. Here we
12562                 // inject the contentBody from the PUT request into the
12563                 // rsp.object element to mimic a GET as a way to take
12564                 // advantage of the existing _processResponse method.
12565                 rsp.object = contentBody;
12566                 contact._processResponse(rsp);
12567 
12568                 //Remove the injected contentBody object before cascading response
12569                 rsp.object = {};
12570 
12571                 //cascade response back to consumer's response handler
12572                 successHandler(rsp);
12573             };
12574         },
12575 
12576         /**
12577          * Update - This should be all that is needed.
12578          * @param {Object} newValues
12579          * @param {Object} handlers
12580          * @returns {finesse.restservices.TeamSignOutReasonCodes}
12581          *     This TeamSignOutReasonCodes object to allow cascading.
12582          */
12583         update: function (newValues, handlers) {
12584             this.isLoaded();
12585             var contentBody = {}, contentBodyInner = [], i, innerObject = {};
12586 
12587             contentBody[this.getRestType()] = {
12588             };
12589 
12590             for (i in newValues) {
12591                 if (newValues.hasOwnProperty(i)) {
12592                     innerObject = {
12593                         "uri": newValues[i]
12594                     };
12595                     contentBodyInner.push(innerObject);
12596                 }
12597             }
12598 
12599             contentBody[this.getRestType()] = {
12600                 "ReasonCode" : contentBodyInner
12601             };
12602 
12603             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
12604             handlers = handlers || {};
12605 
12606             this.restRequest(this.getRestUrl(), {
12607                 method: 'PUT',
12608                 success: this.createPutSuccessHandler(this, contentBody, handlers.success),
12609                 error: handlers.error,
12610                 content: contentBody
12611             });
12612 
12613             return this; // Allow cascading
12614         }
12615 
12616     });
12617     
12618     window.finesse = window.finesse || {};
12619     window.finesse.restservices = window.finesse.restservices || {};
12620     window.finesse.restservices.TeamSignOutReasonCodes = TeamSignOutReasonCodes;
12621     
12622     return TeamSignOutReasonCodes;
12623 }));
12624 
12625 /**
12626  * JavaScript representation of the Finesse PhoneBook Assignment object.
12627  *
12628  * @requires finesse.clientservices.ClientServices
12629  * @requires Class
12630  * @requires finesse.FinesseBase
12631  * @requires finesse.restservices.RestBase
12632  */
12633 
12634 /**
12635  * The following comment prevents JSLint errors concerning undefined global variables.
12636  * It tells JSLint that these identifiers are defined elsewhere.
12637  */
12638 /*jslint bitwise:true, browser:true, nomen:true, regexp:true, sloppy:true, white:true */
12639 
12640 /** The following comment is to prevent jslint errors about 
12641  * using variables before they are defined.
12642  */
12643 /*global $, jQuery, Handlebars, dojox, dojo, finesse */
12644 
12645 /** @private */
12646 (function (factory) {
12647     
12648 
12649     // Define as an AMD module if possible
12650     if ( typeof define === 'function' && define.amd )
12651     {
12652         define('restservices/TeamPhoneBook', ['restservices/RestBase'], factory );
12653     }
12654     /* Define using browser globals otherwise
12655      * Prevent multiple instantiations if the script is loaded twice
12656      */
12657     else
12658     {
12659         factory(finesse.restservices.RestBase);
12660     }
12661 }(function (RestBase) {
12662     var TeamPhoneBook = RestBase.extend({
12663 
12664         /**
12665          * @class
12666          * JavaScript representation of a PhoneBook object. Also exposes
12667          * methods to operate on the object against the server.
12668          *
12669          * @param {Object} options
12670          *     An object with the following properties:<ul>
12671          *         <li><b>id:</b> The id of the object being constructed</li>
12672          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
12673          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
12674          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
12675          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
12676          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
12677          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
12678          *             <li><b>content:</b> {String} Raw string of response</li>
12679          *             <li><b>object:</b> {Object} Parsed object of response</li>
12680          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
12681          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
12682          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
12683          *             </ul></li>
12684          *         </ul></li>
12685          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
12686          * @constructs
12687          **/
12688         init: function (options) {
12689             this._super(options);
12690         },
12691 
12692         /**
12693          * @private
12694          * Gets the REST class for the current object - this is the PhoneBooks class.
12695          * @returns {Object} The PhoneBooks class.
12696          */
12697         getRestClass: function () {
12698             return TeamPhoneBook;
12699         },
12700 
12701         /**
12702          * @private
12703          * Gets the REST type for the current object - this is a "PhoneBook".
12704          * @returns {String} The PhoneBook string.
12705          */
12706         getRestType: function () {
12707             return "PhoneBook";
12708         },
12709 
12710         /**
12711          * @private
12712          * Override default to indicate that this object doesn't support making
12713          * requests.
12714          */
12715         supportsRequests: false,
12716 
12717         /**
12718          * @private
12719          * Override default to indicate that this object doesn't support subscriptions.
12720          */
12721         supportsSubscriptions: false,
12722 
12723         /**
12724          * Getter for the name.
12725          * @returns {String} The name.
12726          */
12727         getName: function () {
12728             this.isLoaded();
12729             return this.getData().name;
12730         },
12731 
12732         /**
12733          * Getter for the Uri value.
12734          * @returns {String} The Uri.
12735          */
12736         getUri: function () {
12737             this.isLoaded();
12738             return this.getData().uri;
12739         }
12740 
12741     });
12742 
12743     window.finesse = window.finesse || {};
12744     window.finesse.restservices = window.finesse.restservices || {};
12745     window.finesse.restservices.TeamPhoneBook = TeamPhoneBook;
12746     
12747     return TeamPhoneBook;
12748 }));
12749 
12750 /**
12751 * JavaScript representation of the Finesse PhoneBook Assignments collection
12752 * object which contains a list of Not Ready Reason Codes objects.
12753  *
12754  * @requires finesse.clientservices.ClientServices
12755  * @requires Class
12756  * @requires finesse.FinesseBase
12757  * @requires finesse.restservices.RestBase
12758  * @requires finesse.restservices.Dialog
12759  * @requires finesse.restservices.RestCollectionBase
12760  */
12761 
12762 /**
12763  * The following comment prevents JSLint errors concerning undefined global variables.
12764  * It tells JSLint that these identifiers are defined elsewhere.
12765  */
12766 /*jslint bitwise:true, browser:true, nomen:true, regexp:true, sloppy:true, white:true */
12767 
12768 /** The following comment is to prevent jslint errors about 
12769  * using variables before they are defined.
12770  */
12771 /*global $, jQuery, Handlebars, dojox, dojo, finesse */
12772 
12773 /** @private */
12774 (function (factory) {
12775     
12776 
12777     // Define as an AMD module if possible
12778     if ( typeof define === 'function' && define.amd )
12779     {
12780         define('restservices/TeamPhoneBooks', ['restservices/RestCollectionBase',
12781                  'restservices/RestBase',
12782                  'restservices/TeamPhoneBook'], factory );
12783     }
12784     /* Define using browser globals otherwise
12785      * Prevent multiple instantiations if the script is loaded twice
12786      */
12787     else
12788     {
12789         factory(finesse.restservices.RestCollectionBase, finesse.restservices.RestBase, finesse.restservices.TeamPhoneBook);
12790     } 
12791 }(function (RestCollectionBase, RestBase, TeamPhoneBook) {
12792     var TeamPhoneBooks = RestCollectionBase.extend({
12793         
12794         /**
12795          * @class
12796          * JavaScript representation of a TeamPhoneBooks collection object. Also exposes
12797          * methods to operate on the object against the server.
12798          *
12799          * @param {Object} options
12800          *     An object with the following properties:<ul>
12801          *         <li><b>id:</b> The id of the object being constructed</li>
12802          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
12803          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
12804          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
12805          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
12806          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
12807          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
12808          *             <li><b>content:</b> {String} Raw string of response</li>
12809          *             <li><b>object:</b> {Object} Parsed object of response</li>
12810          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
12811          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
12812          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
12813          *             </ul></li>
12814          *         </ul></li>
12815          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
12816          * @constructs
12817          **/
12818         init: function (options) {
12819             this._super(options);           
12820         },
12821 
12822         /**
12823          * @private
12824          * Gets the REST class for the current object - this is the TeamPhoneBooks class.
12825          */
12826         getRestClass: function () {
12827             return TeamPhoneBooks;
12828         },
12829 
12830         /**
12831          * @private
12832          * Gets the REST class for the objects that make up the collection. - this
12833          * is the TeamPhoneBooks class.
12834          */
12835         getRestItemClass: function () {
12836             return TeamPhoneBook;
12837         },
12838 
12839         /**
12840          * @private
12841          * Gets the REST type for the current object - this is a "ReasonCodes".
12842          */
12843         getRestType: function () {
12844             return "PhoneBooks";
12845         },
12846         
12847         /**
12848          * Overrides the parent class.  Returns the url for the PhoneBooks resource
12849          */
12850         getRestUrl: function () {
12851             // return ("/finesse/api/" + this.getRestType() + "?category=NOT_READY");
12852             var restObj = this._restObj,
12853             restUrl = "";
12854             //Prepend the base REST object if one was provided.
12855             if (restObj instanceof RestBase) {
12856                 restUrl += restObj.getRestUrl();
12857             }
12858             //Otherwise prepend with the default webapp name.
12859             else {
12860                 restUrl += "/finesse/api";
12861             }
12862             //Append the REST type.
12863             restUrl += "/PhoneBooks";
12864             //Append ID if it is not undefined, null, or empty.
12865             if (this._id) {
12866                 restUrl += "/" + this._id;
12867             }
12868             return restUrl;        
12869         },
12870         
12871         /**
12872          * @private
12873          * Gets the REST type for the objects that make up the collection - this is "ReasonCode".
12874          */
12875         getRestItemType: function () {
12876             return "PhoneBook";
12877         },
12878 
12879         /**
12880          * @private
12881          * Override default to indicates that the collection supports making
12882          * requests.
12883          */
12884         supportsRequests: true,
12885 
12886         /**
12887          * @private
12888          * Override default to indicates that the collection subscribes to its objects.
12889          */
12890         supportsRestItemSubscriptions: false,
12891         
12892         /**
12893          * Retrieve the Not Ready Reason Codes.
12894          *
12895          * @returns {finesse.restservices.TeamPhoneBooks}
12896          *     This TeamPhoneBooks object to allow cascading.
12897          */
12898         get: function () {
12899             // set loaded to false so it will rebuild the collection after the get
12900             /** @private */
12901             this._loaded = false;
12902             // reset collection
12903             /** @private */
12904             this._collection = {};
12905             // perform get
12906             this._synchronize();
12907             return this;
12908         },
12909 
12910         /* We only use PUT and GET on Reason Code team assignments 
12911          */
12912         createPutSuccessHandler: function(contact, contentBody, successHandler){
12913             return function (rsp) {
12914                 // Update internal structure based on response. Here we
12915                 // inject the contentBody from the PUT request into the
12916                 // rsp.object element to mimic a GET as a way to take
12917                 // advantage of the existing _processResponse method.
12918                 rsp.object = contentBody;
12919                 contact._processResponse(rsp);
12920 
12921                 //Remove the injected Contact object before cascading response
12922                 rsp.object = {};
12923                 
12924                 //cascade response back to consumer's response handler
12925                 successHandler(rsp);
12926             };
12927         },
12928 
12929         /**
12930          * Update - This should be all that is needed.
12931          */
12932         update: function (newValues, handlers) {
12933             this.isLoaded();
12934             var contentBody = {}, contentBodyInner = [], i, innerObject;
12935 
12936             contentBody[this.getRestType()] = {
12937             };
12938         
12939             for (i in newValues) {
12940                 if (newValues.hasOwnProperty(i)) {
12941                     innerObject = {};
12942                     innerObject = {
12943                         "uri": newValues[i]
12944                     };
12945                     contentBodyInner.push(innerObject);
12946                 }
12947             }
12948 
12949             contentBody[this.getRestType()] = {
12950                 "PhoneBook" : contentBodyInner
12951             };
12952 
12953             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
12954             handlers = handlers || {};
12955 
12956             this.restRequest(this.getRestUrl(), {
12957                 method: 'PUT',
12958                 success: this.createPutSuccessHandler(this, contentBody, handlers.success),
12959                 error: handlers.error,
12960                 content: contentBody
12961             });
12962 
12963             return this; // Allow cascading
12964         }       
12965         
12966     });
12967         
12968     window.finesse = window.finesse || {};
12969     window.finesse.restservices = window.finesse.restservices || {};
12970     window.finesse.restservices.TeamPhoneBooks = TeamPhoneBooks;
12971     
12972     return TeamPhoneBooks;
12973 }));
12974 
12975 /**
12976  * JavaScript representation of the Finesse LayoutConfig object
12977  * @requires ClientServices
12978  * @requires finesse.FinesseBase
12979  * @requires finesse.restservices.RestBase
12980  */
12981 
12982 /** @private */
12983 (function (factory) {
12984     
12985 
12986     // Define as an AMD module if possible
12987     if ( typeof define === 'function' && define.amd )
12988     {
12989         define('restservices/LayoutConfig', ['restservices/RestBase'], factory );
12990     }
12991     /* Define using browser globals otherwise
12992      * Prevent multiple instantiations if the script is loaded twice
12993      */
12994     else
12995     {
12996         factory(finesse.restservices.RestBase);
12997     } 
12998 }(function (RestBase) {
12999     /** @private */
13000 	var LayoutConfig = RestBase.extend({
13001 
13002 		/**
13003 		 * @class
13004 		 * JavaScript representation of a LayoutConfig object. Also exposes methods to operate
13005 		 * on the object against the server.
13006 		 *
13007 		 * @param {String} id
13008 		 *     Not required...
13009 		 * @param {Object} callbacks
13010 		 *     An object containing callbacks for instantiation and runtime
13011 		 * @param {Function} callbacks.onLoad(this)
13012 		 *     Callback to invoke upon successful instantiation
13013 		 * @param {Function} callbacks.onLoadError(rsp)
13014 		 *     Callback to invoke on instantiation REST request error
13015 		 *     as passed by finesse.clientservices.ClientServices.ajax()
13016 		 *     {
13017 		 *         status: {Number} The HTTP status code returned
13018 		 *         content: {String} Raw string of response
13019 		 *         object: {Object} Parsed object of response
13020 		 *         error: {Object} Wrapped exception that was caught
13021 		 *         error.errorType: {String} Type of error that was caught
13022 		 *         error.errorMessage: {String} Message associated with error
13023 		 *     }
13024 		 * @param {Function} callbacks.onChange(this)
13025 		 *     Callback to invoke upon successful update
13026 		 * @param {Function} callbacks.onError(rsp)
13027 		 *     Callback to invoke on update error (refresh or event)
13028 		 *     as passed by finesse.clientservices.ClientServices.ajax()
13029 		 *     {
13030 		 *         status: {Number} The HTTP status code returned
13031 		 *         content: {String} Raw string of response
13032 		 *         object: {Object} Parsed object of response
13033 		 *         error: {Object} Wrapped exception that was caught
13034 		 *         error.errorType: {String} Type of error that was caught
13035 		 *         error.errorMessage: {String} Message associated with error
13036 		 *     }
13037 		 *  
13038 	     * @constructs
13039 		 */
13040 		init: function (callbacks) {
13041 			this._super("", callbacks);
13042 			//when post is performed and id is empty
13043 			/*if (id === "") {
13044 				this._loaded = true;
13045 			}*/
13046 	        this._layoutxml = {};
13047 		},
13048 	
13049 		/**
13050 		 * Returns REST class of LayoutConfig object
13051 		 */
13052 		getRestClass: function () {
13053 			return LayoutConfig;
13054 		},
13055 	
13056 		/**
13057 		 * The type of this REST object is LayoutConfig
13058 		 */
13059 		getRestType: function () {
13060 			return "LayoutConfig";
13061 		},
13062 
13063 		/**
13064 		 * Gets the REST URL of this object.
13065 		 * 
13066 		 * If the parent has an id, the id is appended.
13067 		 * On occasions of POST, it will not have an id.
13068 		 */
13069 		getRestUrl: function () {
13070 			var layoutUri = "/finesse/api/" + this.getRestType() + "/default";
13071 			/*if (this._id) {
13072 				layoutUri = layoutUri + "/" + this._id;
13073 			}*/
13074 			return layoutUri;
13075 		},
13076 	
13077 		/**
13078 		 * This API does not support subscription
13079 		 */
13080 		supportsSubscriptions: false,
13081 		
13082 		keepRestResponse: true,
13083 
13084 
13085 		/**
13086 		 * Gets finesselayout.xml retrieved from the API call
13087 		 */
13088 		getLayoutxml: function () {
13089 			this.isLoaded();
13090 			var layoutxml = this.getData().layoutxml;
13091 
13092             // We need to unescape everything that is unallowed in xml so consumers don't have to deal with it (used in tandem with update())
13093             layoutxml = layoutxml.replace(/&/g,"&");
13094 
13095             return layoutxml;
13096 		},
13097 	
13098 		/**
13099 		 * Gets the type of this LayoutConfig object
13100 		 */
13101 		/*
13102 		getType: function () {
13103 			this.isLoaded();
13104 			return this.getData().type;
13105 		},*/
13106 	
13107 		/**
13108 		 * Retrieve the LayoutConfig settings.
13109 		 * If the id is not provided the API call will fail.
13110 		 * @returns {LayoutConfig}
13111 		 *     This LayoutConfig object to allow cascading.
13112 		 */
13113 		get: function () {      
13114 			this._synchronize();
13115 			return this;
13116 		},
13117 
13118 		/**
13119 		 * Closure handle updating of the internal data for the LayoutConfig object
13120 		 * upon a successful update (PUT) request before calling the intended
13121 		 * success handler provided by the consumer
13122 		 * 
13123 		 * @param {Object}
13124 		 *            layoutconfig Reference to this LayoutConfig object
13125 		 * @param {Object}
13126 		 *            LayoutConfig Object that contains the  settings to be
13127 		 *            submitted in the api request
13128 		 * @param {Function}
13129 		 *            successHandler The success handler specified by the consumer
13130 		 *            of this object
13131 		 * @returns {LayoutConfig} This LayoutConfig object to allow cascading
13132 		 */
13133 	
13134 		createPutSuccessHandler: function (layoutconfig, contentBody, successHandler) {
13135 			return function (rsp) {			
13136 				// Update internal structure based on response. Here we
13137 				// inject the contentBody from the PUT request into the
13138 				// rsp.object element to mimic a GET as a way to take
13139 				// advantage of the existing _processResponse method.
13140 				rsp.content = contentBody;
13141 				rsp.object.LayoutConfig = {};
13142 				rsp.object.LayoutConfig.finesseLayout = contentBody;
13143 				layoutconfig._processResponse(rsp);
13144 	
13145 				//Remove the injected layoutConfig object before cascading response
13146 				rsp.object.LayoutConfig = {};
13147 	
13148 				//cascade response back to consumer's response handler
13149 				successHandler(rsp);
13150 			};
13151 		},
13152 	
13153 		/**
13154 		 *  Update LayoutConfig
13155 		 * @param {Object} finesselayout
13156 		 *     The XML for FinesseLayout being stored
13157 		 * 
13158 		 * @param {Object} handlers
13159 		 *     An object containing callback handlers for the request. Optional.
13160 		 * @param {Function} options.success(rsp)
13161 		 *     A callback function to be invoked for a successful request.
13162 		 *     {
13163 		 *         status: {Number} The HTTP status code returned
13164 		 *         content: {String} Raw string of response
13165 		 *         object: {Object} Parsed object of response
13166 		 *     }
13167 		 * @param {Function} options.error(rsp)
13168 		 *     A callback function to be invoked for an unsuccessful request.
13169 		 *     {
13170 		 *         status: {Number} The HTTP status code returned
13171 		 *         content: {String} Raw string of response
13172 		 *         object: {Object} Parsed object of response (HTTP errors)
13173 		 *         error: {Object} Wrapped exception that was caught
13174 		 *         error.errorType: {String} Type of error that was caught
13175 		 *         error.errorMessage: {String} Message associated with error
13176 		 *     }
13177 		 * @returns {finesse.restservices.LayoutConfig}
13178 		 *     This LayoutConfig object to allow cascading
13179 		 */
13180 	
13181 		update: function (layoutxml, handlers) {
13182 			this.isLoaded();
13183 			var contentBody = {};
13184 
13185 			// We need to escape everything that is unallowed in xml so consumers don't have to deal with it (used in tandem with getLayoutxml())
13186 			layoutxml = layoutxml.replace(/&(?!amp;)/g, "&");
13187 
13188 			contentBody[this.getRestType()] = {
13189 				"layoutxml": finesse.utilities.Utilities.translateHTMLEntities(layoutxml, true)
13190 			};
13191 
13192 			// Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
13193 			handlers = handlers || {};
13194 
13195 			this.restRequest(this.getRestUrl(), {
13196 				method: 'PUT',
13197 				success: this.createPutSuccessHandler(this, layoutxml, handlers.success),
13198 				error: handlers.error,
13199 				content: contentBody
13200 			});
13201 
13202 			return this; // Allow cascading
13203 		}
13204 	
13205 		/**
13206 		 *TODO createPostSuccessHandler needs to be debugged to make it working
13207 		 * Closure handle creating new  LayoutConfig object
13208 		 * upon a successful create (POST) request before calling the intended
13209 		 * success handler provided by the consumer
13210 		 * 
13211 		 * @param {Object}
13212 		 *            layoutconfig Reference to this LayoutConfig object
13213 		 * @param {Object}
13214 		 *            LayoutConfig Object that contains the  settings to be
13215 		 *            submitted in the api request
13216 		 * @param {Function}
13217 		 *            successHandler The success handler specified by the consumer
13218 		 *            of this object
13219 		 * @returns {finesse.restservices.LayoutConfig} This LayoutConfig object to allow cascading
13220 		 */
13221 	/*
13222 		createPostSuccessHandler: function (layoutconfig, contentBody, successHandler) {
13223 			return function (rsp) {
13224 	
13225 				rsp.object = contentBody;
13226 				layoutconfig._processResponse(rsp);
13227 	
13228 				//Remove the injected layoutConfig object before cascading response
13229 				rsp.object = {};
13230 	
13231 				//cascade response back to consumer's response handler
13232 				successHandler(rsp);
13233 			};
13234 		}, */
13235 	
13236 		/**
13237 		 * TODO Method needs to be debugged to make POST working
13238 		 *  Add LayoutConfig
13239 		 * @param {Object} finesselayout
13240 		 *     The XML for FinesseLayout being stored
13241 		 * 
13242 		 * @param {Object} handlers
13243 		 *     An object containing callback handlers for the request. Optional.
13244 		 * @param {Function} options.success(rsp)
13245 		 *     A callback function to be invoked for a successful request.
13246 		 *     {
13247 		 *         status: {Number} The HTTP status code returned
13248 		 *         content: {String} Raw string of response
13249 		 *         object: {Object} Parsed object of response
13250 		 *     }
13251 		 * @param {Function} options.error(rsp)
13252 		 *     A callback function to be invoked for an unsuccessful request.
13253 		 *     {
13254 		 *         status: {Number} The HTTP status code returned
13255 		 *         content: {String} Raw string of response
13256 		 *         object: {Object} Parsed object of response (HTTP errors)
13257 		 *         error: {Object} Wrapped exception that was caught
13258 		 *         error.errorType: {String} Type of error that was caught
13259 		 *         error.errorMessage: {String} Message associated with error
13260 		 *     }
13261 		 * @returns {finesse.restservices.LayoutConfig}
13262 		 *     This LayoutConfig object to allow cascading
13263 		 */
13264 	/*
13265 		add: function (layoutxml, handlers) {
13266 			this.isLoaded();
13267 			var contentBody = {};
13268 	
13269 	
13270 			contentBody[this.getRestType()] = {
13271 					"layoutxml": layoutxml,
13272 					"type": "current"
13273 			    };
13274 	
13275 			// Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
13276 			handlers = handlers || {};
13277 	
13278 			this.restRequest(this.getRestUrl(), {
13279 				method: 'POST',
13280 				success: this.createPostSuccessHandler(this, contentBody, handlers.success),
13281 				error: handlers.error,
13282 				content: contentBody
13283 			});
13284 	
13285 			return this; // Allow cascading
13286 		} */
13287 	});
13288 	
13289 	window.finesse = window.finesse || {};
13290     window.finesse.restservices = window.finesse.restservices || {};
13291     window.finesse.restservices.LayoutConfig = LayoutConfig;
13292     
13293 	return LayoutConfig;
13294 	
13295 }));
13296 
13297 /**
13298  * JavaScript representation of the Finesse LayoutConfig object for a Team.
13299  *
13300  * @requires finesse.clientservices.ClientServices
13301  * @requires Class
13302  * @requires finesse.FinesseBase
13303  * @requires finesse.restservices.RestBase
13304  * @requires finesse.utilities.Utilities
13305  * @requires finesse.restservices.LayoutConfig
13306  */
13307 
13308 /** The following comment is to prevent jslint errors about 
13309  * using variables before they are defined.
13310  */
13311 /*global Exception */
13312 
13313 /** @private */
13314 (function (factory) {
13315     
13316 
13317     // Define as an AMD module if possible
13318     if ( typeof define === 'function' && define.amd )
13319     {
13320         define('restservices/TeamLayoutConfig', ['restservices/RestBase',
13321                  'utilities/Utilities',
13322                  'restservices/LayoutConfig'], factory );
13323     }
13324     /* Define using browser globals otherwise
13325      * Prevent multiple instantiations if the script is loaded twice
13326      */
13327     else
13328     {
13329         factory(finesse.restservices.RestBase, finesse.utilities.Utilities, finesse.restservices.LayoutConfig);
13330     }
13331 }(function (RestBase, Utilities, LayoutConfig) {
13332     
13333     var TeamLayoutConfig = RestBase.extend({
13334       // Keep the restresponse so we can parse the layoutxml out of it in getLayoutXML()
13335       keepRestResponse: true,
13336     
13337       /**
13338        * @class
13339        * JavaScript representation of a LayoutConfig object for a Team. Also exposes
13340        * methods to operate on the object against the server.
13341        *
13342        * @param {Object} options
13343        *     An object with the following properties:<ul>
13344        *         <li><b>id:</b> The id of the object being constructed</li>
13345        *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
13346        *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
13347        *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
13348        *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
13349        *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
13350        *             <li><b>status:</b> {Number} The HTTP status code returned</li>
13351        *             <li><b>content:</b> {String} Raw string of response</li>
13352        *             <li><b>object:</b> {Object} Parsed object of response</li>
13353        *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
13354        *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
13355        *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
13356        *             </ul></li>
13357        *         </ul></li>
13358        *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
13359        * @constructs
13360        **/
13361       init: function (options) {
13362           this._super(options);
13363       },
13364     
13365       /**
13366        * @private
13367        * Gets the REST class for the current object - this is the LayoutConfigs class.
13368        * @returns {Object} The LayoutConfigs class.
13369        */
13370       getRestClass: function () {
13371           return TeamLayoutConfig;
13372       },
13373     
13374       /**
13375        * @private
13376        * Gets the REST type for the current object - this is a "LayoutConfig".
13377        * @returns {String} The LayoutConfig string.
13378        */
13379       getRestType: function () {
13380           return "TeamLayoutConfig";
13381       },
13382     
13383       /**
13384        * @private
13385        * Override default to indicate that this object doesn't support making
13386        * requests.
13387        */
13388       supportsRequests: false,
13389     
13390       /**
13391        * @private
13392        * Override default to indicate that this object doesn't support subscriptions.
13393        */
13394       supportsSubscriptions: false,
13395     
13396       /**
13397        * Getter for the category.
13398        * @returns {String} The category.
13399        */
13400       getLayoutXML: function () {
13401           this.isLoaded();
13402           var layoutxml = this.getData().layoutxml;
13403 
13404           // We need to unescape everything that is unallowed in xml so consumers don't have to deal with it (used in tandem with put())
13405           layoutxml = layoutxml.replace(/&/g,"&");
13406 
13407           return layoutxml;
13408       },
13409     
13410       /**
13411        * Getter for the code.
13412        * @returns {String} The code.
13413        */
13414       getUseDefault: function () {
13415           this.isLoaded();
13416           return this.getData().useDefault;
13417       },
13418       
13419       /**
13420        * Retrieve the TeamLayoutConfig.
13421        *
13422        * @returns {finesse.restservices.TeamLayoutConfig}
13423        */
13424       get: function () {
13425           // this._id is needed, but is not used in this object.. we're overriding getRestUrl anyway
13426           this._id = "0";
13427           // set loaded to false so it will rebuild the collection after the get
13428           this._loaded = false;
13429           // reset collection
13430           this._collection = {};
13431           // perform get
13432           this._synchronize();
13433           return this;
13434       },
13435     
13436       createPutSuccessHandler: function(contact, contentBody, successHandler){
13437           return function (rsp) {
13438               // Update internal structure based on response. Here we
13439               // inject the contentBody from the PUT request into the
13440               // rsp.object element to mimic a GET as a way to take
13441               // advantage of the existing _processResponse method.
13442               rsp.object = contentBody;
13443               contact._processResponse(rsp);
13444     
13445               //Remove the injected Contact object before cascading response
13446               rsp.object = {};
13447               
13448               //cascade response back to consumer's response handler
13449               successHandler(rsp);
13450           };
13451       },
13452       
13453       put: function (newValues, handlers) {
13454           // this._id is needed, but is not used in this object.. we're overriding getRestUrl anyway
13455           this._id = "0";
13456           this.isLoaded();
13457 
13458           // We need to escape everything that is unallowed in xml so consumers don't have to deal with it (used in tandem with getLayoutxml())
13459           var layoutxml = newValues.layoutXML.replace(/&(?!amp;)/g, "&"),
13460               contentBody = {};
13461           
13462           contentBody[this.getRestType()] = {
13463               "useDefault": newValues.useDefault,
13464               // The LayoutConfig restservice javascript class only translates ampersands, so we'll do that also
13465               "layoutxml": finesse.utilities.Utilities.translateHTMLEntities(layoutxml, true)
13466           };
13467     
13468           // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
13469           handlers = handlers || {};
13470     
13471           this.restRequest(this.getRestUrl(), {
13472               method: 'PUT',
13473               success: this.createPutSuccessHandler(this, contentBody, handlers.success),
13474               error: handlers.error,
13475               content: contentBody
13476           });
13477     
13478           return this; // Allow cascading
13479       },
13480     
13481       getRestUrl: function(){
13482           // return team's url + /LayoutConfig
13483           // eg: /api/Team/1/LayoutConfig
13484           if(this._restObj === undefined){
13485               throw new Exception("TeamLayoutConfig instances must have a parent team object.");
13486           }
13487           return this._restObj.getRestUrl() + '/LayoutConfig';
13488       }
13489     
13490       });
13491         
13492     window.finesse = window.finesse || {};
13493     window.finesse.restservices = window.finesse.restservices || {};
13494     window.finesse.restservices.TeamLayoutConfig = TeamLayoutConfig;
13495       
13496       return TeamLayoutConfig;
13497 }));
13498 
13499 /**
13500  * JavaScript representation of a TeamWorkflow.
13501  *
13502  * @requires finesse.clientservices.ClientServices
13503  * @requires Class
13504  * @requires finesse.FinesseBase
13505  * @requires finesse.restservices.RestBase
13506  */
13507 /** @private */
13508 (function (factory) {
13509     
13510 
13511     // Define as an AMD module if possible
13512     if ( typeof define === 'function' && define.amd )
13513     {
13514         define('restservices/TeamWorkflow', ['restservices/RestBase'], factory );
13515     }
13516     /* Define using browser globals otherwise
13517      * Prevent multiple instantiations if the script is loaded twice
13518      */
13519     else
13520     {
13521         factory(finesse.restservices.RestBase);
13522     } 
13523 }(function (RestBase) {
13524 
13525     var TeamWorkflow = RestBase.extend({
13526 
13527         /**
13528          * @class
13529          * JavaScript representation of a TeamWorkflow object. Also exposes
13530          * methods to operate on the object against the server.
13531          *
13532          * @param {Object} options
13533          *     An object with the following properties:<ul>
13534          *         <li><b>id:</b> The id of the object being constructed</li>
13535          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
13536          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
13537          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
13538          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
13539          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
13540          *             <li><b>status:</b> {Number} The HTTP status description returned</li>
13541          *             <li><b>content:</b> {String} Raw string of response</li>
13542          *             <li><b>object:</b> {Object} Parsed object of response</li>
13543          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
13544          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
13545          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
13546          *             </ul></li>
13547          *         </ul></li>
13548          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
13549          * @constructs
13550          **/
13551         init: function (options) {
13552             this._super(options);
13553         },
13554 
13555         /**
13556          * @private
13557          * Gets the REST class for the current object - this is the TeamWorkflow class.
13558          * @returns {Object} The TeamWorkflow class.
13559          */
13560         getRestClass: function () {
13561             return TeamWorkflow;
13562         },
13563 
13564         /**
13565          * @private
13566          * Gets the REST type for the current object - this is a "Workflow".
13567          * @returns {String} The Workflow string.
13568          */
13569         getRestType: function () {
13570             return "Workflow";
13571         },
13572 
13573         /**
13574          * @private
13575          * Override default to indicate that this object doesn't support making
13576          * requests.
13577          */
13578         supportsRequests: false,
13579 
13580         /**
13581          * @private
13582          * Override default to indicate that this object doesn't support subscriptions.
13583          */
13584         supportsSubscriptions: false,
13585 
13586         /**
13587          * Getter for the name.
13588          * @returns {String} The name.
13589          */
13590         getName: function () {
13591             this.isLoaded();
13592             return this.getData().name;
13593         },
13594 
13595         /**
13596          * Getter for the description.
13597          * @returns {String} The description.
13598          */
13599         getDescription: function () {
13600             this.isLoaded();
13601             return this.getData().description;
13602         },
13603 
13604         /**
13605          * Getter for the Uri value.
13606          * @returns {String} The Uri.
13607          */
13608         getUri: function () {
13609             this.isLoaded();
13610             return this.getData().uri;
13611         }
13612 
13613     });
13614     
13615 	window.finesse = window.finesse || {};
13616     window.finesse.restservices = window.finesse.restservices || {};
13617     window.finesse.restservices.TeamWorkflow = TeamWorkflow;
13618 
13619     return TeamWorkflow;
13620 }));
13621 
13622 /**
13623 * JavaScript representation of the TeamWorkflows collection
13624 * object which contains a list of TeamWorkflow objects.
13625  *
13626  * @requires finesse.clientservices.ClientServices
13627  * @requires Class
13628  * @requires finesse.FinesseBase
13629  * @requires finesse.restservices.RestBase
13630  * @requires finesse.restservices.Dialog
13631  * @requires finesse.restservices.RestCollectionBase
13632  */
13633 /** @private */
13634 (function (factory) {
13635     
13636 
13637     // Define as an AMD module if possible
13638     if ( typeof define === 'function' && define.amd )
13639     {
13640         define('restservices/TeamWorkflows', ['restservices/RestCollectionBase',
13641                  'restservices/TeamWorkflow',
13642                  'restservices/RestBase'], factory );
13643     }
13644     /* Define using browser globals otherwise
13645      * Prevent multiple instantiations if the script is loaded twice
13646      */
13647     else
13648     {
13649         factory(finesse.restservices.RestCollectionBase, finesse.restservices.TeamWorkflow, finesse.restservices.RestBase);
13650     } 
13651 }(function (RestCollectionBase, TeamWorkflow, RestBase) {
13652 
13653     var TeamWorkflows = RestCollectionBase.extend({
13654     
13655         /**
13656          * @class
13657          * JavaScript representation of a TeamWorkflows collection object. Also exposes
13658          * methods to operate on the object against the server.
13659          *
13660          * @param {Object} options
13661          *     An object with the following properties:<ul>
13662          *         <li><b>id:</b> The id of the object being constructed</li>
13663          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
13664          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
13665          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
13666          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
13667          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
13668          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
13669          *             <li><b>content:</b> {String} Raw string of response</li>
13670          *             <li><b>object:</b> {Object} Parsed object of response</li>
13671          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
13672          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
13673          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
13674          *             </ul></li>
13675          *         </ul></li>
13676          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
13677          * @constructs
13678          **/
13679         init: function (options) {
13680             this._super(options);
13681         },
13682 
13683         /**
13684          * @private
13685          * Gets the REST class for the current object - this is the TeamWorkflows class.
13686          */
13687         getRestClass: function () {
13688             return TeamWorkflows;
13689         },
13690 
13691         /**
13692          * @private
13693          * Gets the REST class for the objects that make up the collection. - this
13694          * is the TeamWorkflow class.
13695          */
13696         getRestItemClass: function () {
13697             return TeamWorkflow;
13698         },
13699 
13700         /**
13701          * @private
13702          * Gets the REST type for the current object - this is a "Workflows".
13703          */
13704         getRestType: function () {
13705             return "Workflows";
13706         },
13707 
13708         /**
13709          * Overrides the parent class.  Returns the url for the Workflows resource
13710          */
13711         getRestUrl: function () {
13712             var restObj = this._restObj, restUrl = "";
13713 
13714             //Prepend the base REST object if one was provided.
13715             //Otherwise prepend with the default webapp name.
13716             if (restObj instanceof RestBase) {
13717                 restUrl += restObj.getRestUrl();
13718             } else {
13719                 restUrl += "/finesse/api/Team";
13720             }
13721             //Append ID if it is not undefined, null, or empty.
13722             if (this._id) {
13723                 restUrl += "/" + this._id;
13724             }
13725             //Append the REST type.
13726             restUrl += "/Workflows";
13727             
13728             return restUrl;
13729         },
13730 
13731         /**
13732          * @private
13733          * Gets the REST type for the objects that make up the collection - this is "Workflow".
13734          */
13735         getRestItemType: function () {
13736             return "Workflow";
13737         },
13738 
13739         /**
13740          * @private
13741          * Override default to indicates that the collection supports making requests.
13742          */
13743         supportsRequests: true,
13744 
13745         /**
13746          * @private
13747          * Override default to indicates that the collection does not subscribe to its objects.
13748          */
13749         supportsRestItemSubscriptions: false,
13750 
13751         /**
13752          * Retrieve the Sign Out Reason Codes.
13753          *
13754          * @returns {finesse.restservices.TeamWorkflows}
13755          *     This TeamWorkflows object to allow cascading.
13756          */
13757         get: function () {
13758             // set loaded to false so it will rebuild the collection after the get
13759             this._loaded = false;
13760             // reset collection
13761             this._collection = {};
13762             // perform get
13763             this._synchronize();
13764             return this;
13765         },
13766 
13767         /* We only use PUT and GET on Reason Code team assignments
13768          * @param {Object} contact
13769          * @param {Object} contentBody
13770          * @param {Function} successHandler
13771          */
13772         createPutSuccessHandler: function (contact, contentBody, successHandler) {
13773             return function (rsp) {
13774                 // Update internal structure based on response. Here we
13775                 // inject the contentBody from the PUT request into the
13776                 // rsp.object element to mimic a GET as a way to take
13777                 // advantage of the existing _processResponse method.
13778                 rsp.object = contentBody;
13779                 contact._processResponse(rsp);
13780 
13781                 //Remove the injected contentBody object before cascading response
13782                 rsp.object = {};
13783 
13784                 //cascade response back to consumer's response handler
13785                 successHandler(rsp);
13786             };
13787         },
13788 
13789         /**
13790          * Update - This should be all that is needed.
13791          * @param {Object} newValues
13792          * @param {Object} handlers
13793          * @returns {finesse.restservices.TeamWorkflows}
13794          *     This TeamWorkflows object to allow cascading.
13795          */
13796         update: function (newValues, handlers) {
13797             this.isLoaded();
13798             var contentBody = {}, contentBodyInner = [], i, innerObject = {};
13799 
13800             contentBody[this.getRestType()] = {
13801             };
13802 
13803             for (i in newValues) {
13804                 if (newValues.hasOwnProperty(i)) {
13805                     innerObject = {
13806                         "uri": newValues[i]
13807                     };
13808                     contentBodyInner.push(innerObject);
13809                 }
13810             }
13811 
13812             contentBody[this.getRestType()] = {
13813                 "Workflow" : contentBodyInner
13814             };
13815 
13816             // Protect against null dereferencing of options allowing its (nonexistent) keys to be read as undefined
13817             handlers = handlers || {};
13818 
13819             this.restRequest(this.getRestUrl(), {
13820                 method: 'PUT',
13821                 success: this.createPutSuccessHandler(this, contentBody, handlers.success),
13822                 error: handlers.error,
13823                 content: contentBody
13824             });
13825 
13826             return this; // Allow cascading
13827         }
13828 
13829     });
13830     
13831 	window.finesse = window.finesse || {};
13832     window.finesse.restservices = window.finesse.restservices || {};
13833     window.finesse.restservices.TeamWorkflows = TeamWorkflows;
13834     
13835     return TeamWorkflows;
13836 }));
13837 
13838 /**
13839  * JavaScript representation of the Finesse Team REST object.
13840  *
13841  * @requires finesse.clientservices.ClientServices
13842  * @requires Class
13843  * @requires finesse.FinesseBase
13844  * @requires finesse.restservices.RestBase
13845  * @requires finesse.restservices.RestCollectionBase
13846  * @requires finesse.restservices.User
13847  * @requires finesse.restservices.Users
13848  */
13849 
13850 /**
13851  * The following comment prevents JSLint errors concerning undefined global variables.
13852  * It tells JSLint that these identifiers are defined elsewhere.
13853  */
13854 /*jslint bitwise:true, browser:true, nomen:true, regexp:true, sloppy:true, white:true */
13855 
13856 /** The following comment is to prevent jslint errors about 
13857  * using variables before they are defined.
13858  */
13859 /*global $, jQuery, Handlebars, dojox, dojo, finesse */
13860 
13861 /** @private */
13862 (function (factory) {
13863     
13864 
13865     // Define as an AMD module if possible
13866     if ( typeof define === 'function' && define.amd )
13867     {
13868         define('restservices/Team', ['restservices/RestBase',
13869                  'utilities/Utilities',
13870                  'restservices/Users',
13871                  'restservices/TeamNotReadyReasonCodes',
13872                  'restservices/TeamWrapUpReasons',
13873                  'restservices/TeamSignOutReasonCodes',
13874                  'restservices/TeamPhoneBooks',
13875                  'restservices/TeamLayoutConfig',
13876                  'restservices/TeamWorkflows'], factory );
13877     }
13878     /* Define using browser globals otherwise
13879      * Prevent multiple instantiations if the script is loaded twice
13880      */
13881     else
13882     {
13883         factory(finesse.restservices.RestBase,
13884                 finesse.utilities.Utilities,
13885                 finesse.restservices.Users,
13886                 finesse.restservices.TeamNotReadyReasonCodes,
13887                 finesse.restservices.TeamWrapUpReasons,
13888                 finesse.restservices.TeamSignOutReasonCodes,
13889                 finesse.restservices.TeamPhoneBooks,
13890                 finesse.restservices.TeamLayoutConfig,
13891                 finesse.restservices.TeamWorkflows);
13892     }
13893 }(function (RestBase, Utilities, Users, TeamNotReadyReasonCodes, TeamWrapUpReasons, TeamSignOutReasonCodes, TeamPhoneBooks, TeamLayoutConfig, TeamWorkflows) {
13894     var Team = RestBase.extend(/** @lends finesse.restservices.Team.prototype */{
13895         
13896         _teamLayoutConfig: null,
13897 
13898         /**
13899          * @class
13900          * A Team is a set of Agent Users, typically supervised by one or more Supervisor Users.
13901          *
13902          * @augments finesse.restservices.RestBase
13903          * @see finesse.restservices.User#getSupervisedTeams
13904          * @see finesse.restservices.Users
13905          * @constructs
13906          */
13907         _fakeConstuctor: function () {
13908             /* This is here to hide the real init constructor from the public docs */
13909         },
13910         
13911         /**
13912          * @private
13913          * @class
13914          * JavaScript representation of a Team object. Also exposes methods to operate
13915          * on the object against the server.
13916          *
13917          * @param {Object} options
13918          *     An object with the following properties:<ul>
13919          *         <li><b>id:</b> The id of the object being constructed</li>
13920          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
13921          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
13922          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
13923          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
13924          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
13925          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
13926          *             <li><b>content:</b> {String} Raw string of response</li>
13927          *             <li><b>object:</b> {Object} Parsed object of response</li>
13928          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
13929          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
13930          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
13931          *             </ul></li>
13932          *         </ul></li>
13933          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
13934          **/
13935         init: function (options) {
13936             this._super(options);
13937         },
13938     
13939         /**
13940          * @private
13941          * Gets the REST class for the current object - this is the Team class.
13942          * @returns {Object} The Team constructor.
13943          */
13944         getRestClass: function () {
13945             return finesse.restesrvices.Team;
13946         },
13947     
13948         /**
13949          * @private
13950          * Gets the REST type for the current object - this is a "Team".
13951          * @returns {String} The Team string.
13952          */
13953         getRestType: function () {
13954             return "Team";
13955         },
13956     
13957         /**
13958          * @private
13959          * Override default to indicate that this object doesn't support making
13960          * requests.
13961          */
13962         supportsSubscriptions: false,
13963     
13964         /**
13965          * Getter for the team id.
13966          * @returns {String} The team id.
13967          */
13968         getId: function () {
13969             this.isLoaded();
13970             return this.getData().id;
13971         },
13972     
13973         /**
13974          * Getter for the team name.
13975          * @returns {String} The team name
13976          */
13977         getName: function () {
13978             this.isLoaded();
13979             return this.getData().name;
13980         },
13981     
13982         /**
13983          * @private
13984          * Getter for the team uri.
13985          * @returns {String} The team uri
13986          */
13987         getUri: function () {
13988             this.isLoaded();
13989             return this.getData().uri;        
13990         },
13991     
13992         /**
13993          * Constructs and returns a collection of Users.
13994          * @param {finesse.interfaces.RestObjectHandlers} [handlers] Object that sets callback handlers.
13995          * @returns {finesse.restservices.Users} Users collection of User objects.
13996          */
13997         getUsers: function (options) {
13998             this.isLoaded();
13999             options = options || {};
14000     
14001             options.parentObj = this;
14002             // We are using getData() instead of getData.Users because the superclass (RestCollectionBase)
14003             // for Users needs the "Users" key to validate the provided payload matches the class type.
14004             options.data = this.getData();
14005     
14006             return new Users(options);
14007         },
14008     
14009         /**
14010          * @private
14011          * Getter for a teamNotReadyReasonCodes collection object that is associated with Team.
14012          * @param callbacks
14013          * @returns {teamNotReadyReasonCodes}
14014          *     A teamNotReadyReasonCodes collection object.
14015          */
14016         getTeamNotReadyReasonCodes: function (callbacks) {
14017             var options = callbacks || {};
14018             options.parentObj = this;
14019             this.isLoaded();
14020     
14021             if (!this._teamNotReadyReasonCodes) {
14022                 this._teamNotReadyReasonCodes = new TeamNotReadyReasonCodes(options);
14023             }
14024     
14025             return this._teamNotReadyReasonCodes;
14026         },
14027     
14028         /**
14029          * @private
14030          * Getter for a teamWrapUpReasons collection object that is associated with Team.
14031          * @param callbacks
14032          * @returns {teamWrapUpReasons}
14033          *     A teamWrapUpReasons collection object.
14034          */
14035         getTeamWrapUpReasons: function (callbacks) {
14036             var options = callbacks || {};
14037             options.parentObj = this;
14038             this.isLoaded();
14039     
14040             if (!this._teamWrapUpReasons) {
14041                 this._teamWrapUpReasons = new TeamWrapUpReasons(options);
14042             }
14043     
14044             return this._teamWrapUpReasons;
14045         },
14046     
14047         /**
14048          * @private
14049          * Getter for a teamSignOutReasonCodes collection object that is associated with Team.
14050          * @param callbacks
14051          * @returns {teamSignOutReasonCodes}
14052          *     A teamSignOutReasonCodes collection object.
14053          */
14054     
14055         getTeamSignOutReasonCodes: function (callbacks) {
14056             var options = callbacks || {};
14057             options.parentObj = this;
14058             this.isLoaded();
14059     
14060             if (!this._teamSignOutReasonCodes) {
14061                 this._teamSignOutReasonCodes = new TeamSignOutReasonCodes(options);
14062             }
14063     
14064             return this._teamSignOutReasonCodes;
14065         },
14066     
14067         /**
14068          * @private
14069          * Getter for a teamPhoneBooks collection object that is associated with Team.
14070          * @param callbacks
14071          * @returns {teamPhoneBooks}
14072          *     A teamPhoneBooks collection object.
14073          */
14074         getTeamPhoneBooks: function (callbacks) {
14075             var options = callbacks || {};
14076             options.parentObj = this;
14077             this.isLoaded();
14078     
14079             if (!this._phonebooks) {
14080                 this._phonebooks = new TeamPhoneBooks(options);
14081             }
14082     
14083             return this._phonebooks;
14084         },
14085     
14086         /**
14087          * @private
14088          * Getter for a teamWorkflows collection object that is associated with Team.
14089          * @param callbacks
14090          * @returns {teamWorkflows}
14091          *     A teamWorkflows collection object.
14092          */
14093         getTeamWorkflows: function (callbacks) {
14094             var options = callbacks || {};
14095             options.parentObj = this;
14096             this.isLoaded();
14097     
14098             if (!this._workflows) {
14099                 this._workflows = new TeamWorkflows(options);
14100             }
14101     
14102             return this._workflows;
14103         },
14104     
14105         /**
14106          * @private
14107          * Getter for a teamLayoutConfig object that is associated with Team.
14108          * @param callbacks
14109          * @returns {teamLayoutConfig}
14110          */
14111         getTeamLayoutConfig: function (callbacks) {
14112             var options = callbacks || {};
14113             options.parentObj = this;
14114             this.isLoaded();
14115     
14116             if (this._teamLayoutConfig === null) {
14117                 this._teamLayoutConfig = new TeamLayoutConfig(options);
14118             }
14119     
14120             return this._teamLayoutConfig;
14121         }
14122     
14123     });
14124     
14125     window.finesse = window.finesse || {};
14126     window.finesse.restservices = window.finesse.restservices || {};
14127     window.finesse.restservices.Team = Team;
14128     
14129     return Team;    
14130 }));
14131 
14132 /**
14133  * JavaScript representation of the Finesse Teams collection.
14134  * object which contains a list of Team objects
14135  * @requires finesse.clientservices.ClientServices
14136  * @requires Class
14137  * @requires finesse.FinesseBase
14138  * @requires finesse.restservices.RestBase
14139  * @requires finesse.restservices.RestCollectionBase
14140  */
14141 
14142 /** @private */
14143 (function (factory) {
14144     
14145 
14146     // Define as an AMD module if possible
14147     if ( typeof define === 'function' && define.amd )
14148     {
14149         define('restservices/Teams', ['restservices/RestCollectionBase',
14150                  'restservices/Team'], factory );
14151     }
14152     /* Define using browser globals otherwise
14153      * Prevent multiple instantiations if the script is loaded twice
14154      */
14155     else
14156     {
14157         factory(finesse.restservices.RestCollectionBase, finesse.restservices.Team);
14158     } 
14159 }(function (RestCollectionBase, Team) {
14160     /** @private */
14161     var Teams = RestCollectionBase.extend({
14162 
14163         /**
14164          * @class
14165          * JavaScript representation of a Teams collection object. Also exposes methods to operate
14166          * on the object against the server.
14167          *
14168          * @param {Object} options
14169          *     An object with the following properties:<ul>
14170          *         <li><b>id:</b> The id of the object being constructed</li>
14171          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
14172          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
14173          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
14174          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
14175          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
14176          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
14177          *             <li><b>content:</b> {String} Raw string of response</li>
14178          *             <li><b>object:</b> {Object} Parsed object of response</li>
14179          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
14180          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
14181          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
14182          *             </ul></li>
14183          *         </ul></li>
14184          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
14185          * @constructs
14186          **/
14187         init: function (options) {
14188             this._super(options);
14189         },
14190 
14191         /**
14192          * @private
14193          * Gets the REST class for the current object - this is the Teams class.
14194          * @returns {Object} The Teams constructor.
14195          */
14196         getRestClass: function () {
14197             return Teams;
14198         },
14199 
14200         /**
14201          * @private
14202          * Gets the REST class for the objects that make up the collection. - this
14203          * is the Team class.
14204          */
14205         getRestItemClass: function () {
14206             return Team;
14207         },
14208 
14209         /**
14210          * @private
14211          * Gets the REST type for the current object - this is a "Teams".
14212          * @returns {String} The Teams string.
14213          */
14214         getRestType: function () {
14215             return "Teams";
14216         },
14217         
14218         /**
14219          * @private
14220          * Gets the REST type for the objects that make up the collection - this is "Team".
14221          */
14222         getRestItemType: function () {
14223             return "Team";
14224         },
14225 
14226         /**
14227          * @private
14228          * Override default to indicates that the collection supports making
14229          * requests.
14230          */
14231         supportsRequests: true,
14232 
14233         /**
14234          * @private
14235          * Override default to indicate that this object doesn't support subscriptions.
14236          */
14237         supportsRestItemSubscriptions: false,
14238         
14239         /**
14240          * @private
14241          * Retrieve the Teams.  This call will re-query the server and refresh the collection.
14242          *
14243          * @returns {finesse.restservices.Teams}
14244          *     This Teams object to allow cascading.
14245          */
14246         get: function () {
14247             // set loaded to false so it will rebuild the collection after the get
14248             this._loaded = false;
14249             // reset collection
14250             this._collection = {};
14251             // perform get
14252             this._synchronize();
14253             return this;
14254         }
14255 
14256     });
14257 
14258     window.finesse = window.finesse || {};
14259     window.finesse.restservices = window.finesse.restservices || {};
14260     window.finesse.restservices.Teams = Teams;
14261     
14262     return Teams;
14263 }));
14264 
14265 /**
14266  * JavaScript representation of the Finesse SystemInfo object
14267  *
14268  * @requires finesse.clientservices.ClientServices
14269  * @requires Class
14270  * @requires finesse.FinesseBase
14271  * @requires finesse.restservices.RestBase
14272  */
14273 
14274 /** @private */
14275 (function (factory) {
14276     
14277 
14278     // Define as an AMD module if possible
14279     if ( typeof define === 'function' && define.amd )
14280     {
14281         define('restservices/SystemInfo', ['restservices/RestBase'], factory );
14282     }
14283     /* Define using browser globals otherwise
14284      * Prevent multiple instantiations if the script is loaded twice
14285      */
14286     else
14287     {
14288         factory(finesse.restservices.RestBase);
14289     } 
14290 }(function (RestBase) {
14291     
14292     var SystemInfo = RestBase.extend(/** @lends finesse.restservices.SystemInfo.prototype */{
14293         /**
14294          * @private
14295          * Returns whether this object supports subscriptions
14296          */
14297         supportsSubscriptions: false,
14298 
14299         doNotRefresh: true,
14300       
14301         /**
14302          * @class
14303          * JavaScript representation of a SystemInfo object.
14304          * 
14305          * @augments finesse.restservices.RestBase
14306          * @see finesse.restservices.SystemInfo.Statuses
14307          * @constructs
14308          */
14309         _fakeConstuctor: function () {
14310             /* This is here to hide the real init constructor from the public docs */
14311         },
14312         
14313          /**
14314          * @private
14315          * JavaScript representation of a SystemInfo object. Also exposes methods to operate
14316          * on the object against the server.
14317          *
14318          * @param {Object} options
14319          *     An object with the following properties:<ul>
14320          *         <li><b>id:</b> The id of the object being constructed</li>
14321          *         <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li>
14322          *         <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li>
14323          *         <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li>
14324          *         <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li>
14325          *         <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul>
14326          *             <li><b>status:</b> {Number} The HTTP status code returned</li>
14327          *             <li><b>content:</b> {String} Raw string of response</li>
14328          *             <li><b>object:</b> {Object} Parsed object of response</li>
14329          *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
14330          *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
14331          *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
14332          *             </ul></li>
14333          *         </ul></li>
14334          *         <li><b>parentObj: (optional)</b> The parent object</li></ul>
14335          **/
14336         init: function (id, callbacks, restObj)
14337         {
14338             this._super(id, callbacks, restObj);
14339         },
14340 
14341         /**
14342          * @private
14343          * Gets the REST class for the current object - this is the SystemInfo object.
14344          */
14345         getRestClass: function () {
14346             return SystemInfo;
14347         },
14348 
14349         /**
14350          * @private
14351          * Gets the REST type for the current object - this is a "SystemInfo".
14352          */
14353         getRestType: function ()
14354         {
14355             return "SystemInfo";
14356         },
14357         
14358         _validate: function (obj)
14359         {
14360             return true;
14361         },
14362         
14363         /**
14364          * Returns the status of the Finesse system.
14365          *   IN_SERVICE if the Finesse API reports that it is in service,
14366          *   OUT_OF_SERVICE otherwise.
14367          * @returns {finesse.restservices.SystemInfo.Statuses} System Status
14368          */
14369         getStatus: function () {
14370             this.isLoaded();
14371             return this.getData().status;
14372         },
14373         
14374         /**
14375          * Returns the current timestamp from this SystemInfo object.
14376          *   This is used to calculate time drift delta between server and client.
14377          *  @returns {String} Time (GMT): yyyy-MM-dd'T'HH:mm:ss'Z'
14378          */
14379         getCurrentTimestamp: function () {
14380             this.isLoaded();
14381             return this.getData().currentTimestamp;
14382         },
14383         
14384         /**
14385          * Getter for the xmpp domain of the system.
14386          * @returns {String} The xmpp domain corresponding to this SystemInfo object.
14387          */
14388         getXmppDomain: function () {
14389             this.isLoaded();
14390             return this.getData().xmppDomain;
14391         },
14392         
14393         /**
14394          * Getter for the xmpp pubsub domain of the system.
14395          * @returns {String} The xmpp pubsub domain corresponding to this SystemInfo object.
14396          */
14397         getXmppPubSubDomain: function () {
14398             this.isLoaded();
14399             return this.getData().xmppPubSubDomain;
14400         },
14401 
14402         /**
14403          * Getter for the deployment type (UCCE or UCCX).
14404          * @returns {String} "UCCE" or "UCCX"
14405          */ 
14406         getDeploymentType: function () {
14407             this.isLoaded();
14408             return this.getData().deploymentType;
14409         },
14410 
14411         /**
14412          * Returns whether this is a single node deployment or not by checking for the existence of the secondary node in SystemInfo.
14413          * @returns {Boolean} True for single node deployments, false otherwise.
14414          */ 
14415         isSingleNode: function () {
14416             var secondary = this.getData().secondaryNode;
14417             if (secondary && secondary.host) {
14418                 return false;
14419             }
14420             return true;
14421         },
14422 
14423         /**
14424          * Checks all arguments against the primary and secondary hosts (FQDN) and returns the match.
14425          * This is useful for getting the FQDN of the current Finesse server.
14426          * @param {String} ...arguments[]... - any number of arguments to match against
14427          * @returns {String} FQDN (if properly configured) of the matched host of the primary or secondary node, or undefined if no match is found.
14428          */ 
14429         getThisHost: function () {
14430             var i,
14431             primary = this.getData().primaryNode,
14432             secondary = this.getData().secondaryNode;
14433 
14434             for (i = 0; (i < arguments.length); i = i + 1) {
14435                 if (primary && arguments[i] === primary.host) {
14436                     return primary.host;
14437                 } else if (secondary && arguments[i] === secondary.host) {
14438                     return secondary.host;
14439                 }
14440             }
14441         },
14442 
14443         /**
14444          * Checks all arguments against the primary and secondary hosts (FQDN) and returns the other node.
14445          * This is useful for getting the FQDN of the other Finesse server, i.e. for failover purposes.
14446          * @param {String} arguments - any number of arguments to match against
14447          * @returns {String} FQDN (if properly configured) of the alternate node, defaults to primary if no match is found, undefined for single node deployments.
14448          */ 
14449         getAlternateHost: function () {
14450             var i,
14451             isPrimary = false,
14452             primary = this.getData().primaryNode,
14453             secondary = this.getData().secondaryNode,
14454             alternateHost;
14455 
14456             if (primary && primary.host) {
14457                 for (i = 0; (i < arguments.length); i = i + 1) {
14458                     if (arguments[i] === primary.host) {
14459                         isPrimary = true;
14460                         break;
14461                     }
14462                 }
14463                 if (secondary && secondary.host) {
14464                     if (isPrimary) {
14465                         return secondary.host;
14466                     }
14467                     return primary.host;
14468                 }
14469             }
14470         }
14471     });
14472     
14473     SystemInfo.Statuses = /** @lends finesse.restservices.SystemInfo.Statuses.prototype */ { 
14474         /** 
14475          * Finesse is in service. 
14476          */
14477         IN_SERVICE: "IN_SERVICE",
14478         /** 
14479          * Finesse is not in service. 
14480          */
14481         OUT_OF_SERVICE: "OUT_OF_SERVICE",
14482         /**
14483          * @class SystemInfo status values.
14484          * @constructs
14485          */
14486         _fakeConstructor : function () {} // For JS Doc to work need a constructor so that the lends/constructs build the doc properly
14487 
14488     };
14489     
14490     window.finesse = window.finesse || {};
14491     window.finesse.restservices = window.finesse.restservices || {};
14492     window.finesse.restservices.SystemInfo = SystemInfo;
14493     
14494     return SystemInfo;
14495 }));
14496 
14497 /**
14498  * Provides standard way resolve message keys with substitution
14499  *
14500  * @requires finesse.container.I18n or gadgets.Prefs
14501  */
14502 
14503 // Add Utilities to the finesse.utilities namespace
14504 var finesse = finesse || {};
14505 finesse.utilities = finesse.utilities || {};
14506 
14507 (function (factory) {
14508     
14509 
14510     // Define as an AMD module if possible
14511     if ( typeof define === 'function' && define.amd )
14512     {
14513         define('utilities/I18n', [], factory );
14514     }
14515     /* Define using browser globals otherwise
14516      * Prevent multiple instantiations if the script is loaded twice
14517      */
14518     else
14519     {
14520         finesse.utilities.I18n = factory();
14521     }
14522 }(function () {
14523     var I18n = (function () {
14524 
14525         /**
14526          * Shortcut to finesse.container.I18n.getMsg or gadgets.Prefs.getMsg
14527          * @private
14528          */
14529         var _getMsg;
14530 
14531         return {
14532             /**
14533              * Provides a message resolver for this utility singleton.
14534              * @param {Function} getMsg
14535              *     A function that returns a string given a message key.
14536              *     If the key is not found, this function must return 
14537              *     something that tests false (i.e. undefined or "").
14538              */
14539             setGetter : function (getMsg) {
14540                 _getMsg = getMsg;
14541             },
14542 
14543             /**
14544              * Resolves the given message key, also performing substitution.
14545              * This generic utility will use a custom function to resolve the key
14546              * provided by finesse.utilities.I18n.setGetter. Otherwise, it will 
14547              * discover either finesse.container.I18n.getMsg or gadgets.Prefs.getMsg
14548              * upon the first invocation and store that reference for efficiency.
14549              * 
14550              * Since this will construct a new gadgets.Prefs object, it is recommended
14551              * for gadgets to explicitly provide the setter to prevent duplicate
14552              * gadgets.Prefs objects. This does not apply if your gadget does not need
14553              * access to gadgets.Prefs other than getMsg. 
14554              * 
14555              * @param {String} key
14556              *     The key to lookup
14557              * @param {String} arguments
14558              *     Arguments for substitution
14559              * @returns {String/Function}
14560              *     The resolved string if successful, otherwise a function that returns
14561              *     a '???' string that can also be casted into a string.
14562              */
14563             getString : function (key) {
14564                 var prefs, i, retStr, noMsg, getFailed = "";
14565                 if (!_getMsg) {
14566                     if (finesse.container && finesse.container.I18n) {
14567                         _getMsg = finesse.container.I18n.getMsg;
14568                     } else if (gadgets) {
14569                         prefs = new gadgets.Prefs();
14570                         _getMsg = prefs.getMsg;
14571                     }
14572                 }
14573                 
14574                 try {
14575                     retStr = _getMsg(key);
14576                 } catch (e) {
14577                     getFailed = "finesse.utilities.I18n.getString(): invalid _getMsg";
14578                 }
14579                 
14580                 if (retStr) { // Lookup was successful, perform substitution (if any)
14581                     for (i = 1; i < arguments.length; i += 1) {
14582                         retStr = retStr.replace(new RegExp("\\{" + (i - 1) + "\\}", "g"), arguments[i]);
14583                     }
14584                     //in order to fix French text with single quotes in it, we need to replace \' with '
14585                     return retStr.replace(/\\'/g, "'");
14586                 }
14587                 // We want a function because jQuery.html() and jQuery.text() is smart enough to invoke it.
14588                 /** @private */
14589                 noMsg = function () {
14590                     return "???" + key + "???" + getFailed;
14591                 };
14592                 // We overload the toString() of this "function" to allow JavaScript to cast it into a string
14593                 // For example, var myMsg = "something " + finesse.utilities.I18n.getMsg("unresolvable.key");
14594                 /** @private */
14595                 noMsg.toString = function () {
14596                     return "???" + key + "???" + getFailed;
14597                 };
14598                 return noMsg;
14599 
14600             }
14601         };
14602     }());
14603     
14604     return I18n;
14605 }));
14606 
14607 /**
14608  * Logging.js: provides simple logging for clients to use and overrides synchronous native methods: alert(), confirm(), and prompt().
14609  * 
14610  * On Firefox, it will hook into console for logging.  On IE, it will log to the status bar. 
14611  */
14612 // Add Utilities to the finesse.utilities namespace
14613 var finesse = finesse || {};
14614 finesse.utilities = finesse.utilities || {};
14615 
14616 (function (factory) {
14617     
14618 
14619     // Define as an AMD module if possible
14620     if ( typeof define === 'function' && define.amd )
14621     {
14622         define('utilities/Logger', [], factory );
14623     }
14624     /* Define using browser globals otherwise
14625      * Prevent multiple instantiations if the script is loaded twice
14626      */
14627     else
14628     {
14629         finesse.utilities.Logger = factory();
14630     }
14631 }(function () {
14632     var Logger = (function () {
14633         
14634         var
14635         
14636         /** @private **/
14637         debugOn,
14638         
14639         /**
14640          * Pads a single digit number for display purposes (e.g. '4' shows as '04')
14641          * @param num is the number to pad to 2 digits
14642          * @returns a two digit padded string
14643          * @private
14644          */
14645         padTwoDigits = function (num) {        
14646             return (num < 10) ? '0' + num : num;  
14647         },
14648         
14649         /**
14650          * Checks to see if we have a console - this allows us to support Firefox or IE.
14651          * @returns {Boolean} True for Firefox, False for IE
14652          * @private
14653          */
14654         hasConsole = function () {
14655             var retval = false;
14656             try
14657             {
14658                 if (window.console !== undefined) 
14659                 {
14660                     retval = true;
14661                 }
14662             } 
14663             catch (err)
14664             {
14665                 retval = false;
14666             }
14667               
14668             return retval;
14669         },
14670         
14671         /**
14672          * Gets a timestamp.
14673          * @returns {String} is a timestamp in the following format: HH:MM:SS
14674          * @private
14675          */
14676         getTimeStamp = function () {
14677             var date = new Date(), timeStr;
14678             timeStr = padTwoDigits(date.getHours()) + ":" + padTwoDigits(date.getMinutes()) + ":" + padTwoDigits(date.getSeconds());
14679 
14680             return timeStr;
14681         };
14682         
14683         return {
14684             /**
14685              * Enable debug mode. Debug mode may impact performance on the UI.
14686              *
14687              * @param {Boolean} enable
14688              *      True to enable debug logging.
14689              * @private
14690              */
14691             setDebug : function (enable) {
14692                 debugOn = enable;
14693             },
14694             
14695             /**
14696              * Logs a string as DEBUG.
14697              * 
14698              * @param str is the string to log. 
14699              * @private
14700              */
14701             log : function (str) {
14702                 var timeStr = getTimeStamp();
14703                 
14704                 if (debugOn) {
14705                     if (hasConsole())
14706                     {
14707                         window.console.log(timeStr + ": " + "DEBUG" + " - " + str);
14708                     }
14709                 }
14710             },
14711             
14712             /**
14713              * Logs a string as INFO.
14714              * 
14715              * @param str is the string to log. 
14716              * @private
14717              */
14718             info : function (str) {
14719                 var timeStr = getTimeStamp();
14720                 
14721                 if (hasConsole())
14722                 {
14723                     window.console.info(timeStr + ": " + "INFO" + " - " + str);
14724                 }
14725             },
14726             
14727             /**
14728              * Logs a string as WARN.
14729              * 
14730              * @param str is the string to log. 
14731              * @private
14732              */
14733             warn : function (str) {
14734                 var timeStr = getTimeStamp();
14735                 
14736                 if (hasConsole())
14737                 {
14738                     window.console.warn(timeStr + ": " + "WARN" + " - " + str);
14739                 }
14740             },
14741             /**
14742              * Logs a string as ERROR.
14743              * 
14744              * @param str is the string to log. 
14745              * @private
14746              */
14747             error : function (str) {
14748                 var timeStr = getTimeStamp();
14749                 
14750                 if (hasConsole())
14751                 {
14752                     window.console.error(timeStr + ": " + "ERROR" + " - " + str);
14753                 }
14754             }
14755         };
14756     }());
14757     
14758     return Logger;
14759 }));
14760 
14761 /**
14762  * Allows gadgets to call the log function to publish client logging messages over the hub.
14763  *
14764  * @requires OpenAjax
14765  */
14766 /** @private */
14767 (function (factory) {
14768     
14769 
14770     // Define as an AMD module if possible
14771     if ( typeof define === 'function' && define.amd )
14772     {
14773         define('cslogger/ClientLogger',[], factory );
14774     }
14775     
14776     /* Define using browser globals otherwise
14777      * Prevent multiple instantiations if the script is loaded twice
14778      */
14779     else
14780     {
14781         factory();
14782     }
14783     
14784 }(function () {
14785 
14786     var ClientLogger = ( function () { /** @lends finesse.cslogger.ClientLogger.prototype */
14787         var _hub, _logTopic, _originId, _sessId,
14788  
14789         /**
14790          * Get a short form (6 character) session ID from sessionStorage
14791          * @private
14792         */
14793         getSessId = function() {
14794             if (!_sessId) {
14795                //when _sessId not defined yet, initiate it
14796                if (window.sessionStorage.getItem('enableLocalLog') === 'true') {
14797                   _sessId= " "+window.sessionStorage.getItem('finSessKey')+" ";
14798                }
14799                else {
14800                   _sessId=" ";
14801                }
14802             }
14803             return _sessId;
14804          },
14805 
14806         /**
14807          * Pads a single digit number for display purposes (e.g. '4' shows as '04')
14808          * @param num is the number to pad to 2 digits
14809          * @returns a two digit padded string
14810          * @private
14811          */
14812         padTwoDigits = function (num)
14813         {
14814             return (num < 10) ? '0' + num : num;
14815         },
14816         
14817         /**
14818          * Pads a single digit number for display purposes (e.g. '4' shows as '004')
14819          * @param num is the number to pad to 3 digits
14820          * @returns a three digit padded string
14821          * @private
14822          */
14823         padThreeDigits = function (num)
14824         {
14825             if (num < 10)
14826             {
14827               return '00'+num;
14828             }
14829             else if (num < 100)
14830             {
14831               return '0'+num;
14832             }
14833             else  
14834             {
14835                return num;
14836             }
14837         },
14838     
14839          /**
14840           * Gets a timestamp.
14841           * @returns {String} is a timestamp in the following format: HH:MM:SS
14842           * @private
14843           */
14844         getDateTimeStamp = function ()
14845         {
14846             var date = new Date(), timeStr;
14847             timeStr = date.getFullYear().toString().substring(2) +
14848                       padTwoDigits(date.getMonth()+1) + 
14849                       padTwoDigits (date.getDate()) + " "+
14850                       padTwoDigits(date.getHours()) + ":" + 
14851                       padTwoDigits(date.getMinutes()) + ":" +
14852                       padTwoDigits(date.getSeconds()+"." + 
14853                       padThreeDigits(date.getMilliseconds()));
14854     
14855             return timeStr;
14856         },
14857     
14858         /**
14859          * Checks to see if we have a console.
14860          * @returns Whether the console object exists.
14861          * @private
14862          */
14863         hasConsole = function () {
14864             try {
14865                 if (window.console !== undefined) {
14866                     return true;
14867                 }
14868             } catch (err) {
14869               // ignore and return false
14870             }
14871     
14872             return false;
14873         },
14874     
14875         /**
14876         * Logs a message to a hidden textarea element on the page
14877         *
14878         * @param str is the string to log.
14879         * @param logType is the optional type which is prefixed (default is "LOG")
14880         * @private
14881         */
14882         writeToLogOutput = function (msg) {
14883             var logOutput = document.getElementById("finesseLogOutput");
14884     
14885             if (logOutput === null)
14886             {
14887                 logOutput = document.createElement("textarea");
14888                 logOutput.id = "finesseLogOutput";
14889                 logOutput.style.display = "none";
14890                 document.body.appendChild(logOutput);
14891             }
14892     
14893             if (logOutput.value === "")
14894             {
14895                 logOutput.value = msg;
14896             }
14897             else
14898             {
14899                 logOutput.value = logOutput.value + "\n" + msg;
14900             }
14901         },
14902 
14903         /**
14904          * @private
14905          */
14906         logToConsole = function (str)
14907         {
14908             var msg, timeStr = getDateTimeStamp(), sessKey=getSessId();
14909             msg = "\n" + timeStr + sessKey + ": " + ((finesse.container && finesse.container.Config && finesse.container.Config.host) ? finesse.container.Config.host + ": " : "") + str;
14910     
14911             // Log to console
14912             if (hasConsole()) {
14913                 window.console.log(msg);
14914             }
14915     
14916             //Uncomment to print logs to hidden textarea.
14917             //writeToLogOutput(msg);
14918     
14919             return msg;
14920         };
14921     
14922         return {
14923     
14924             /**
14925              * Publishes a Log Message over the hub.
14926              *
14927              * @param {String} message
14928              *     The string to log.
14929              * @example
14930              * _clientLogger.log("This is some important message for MyGadget");
14931              * 
14932              */
14933             log : function (message) {
14934                 if(_hub) {
14935                     _hub.publish(_logTopic, logToConsole(_originId + message));
14936                 }
14937             },
14938     
14939             /**
14940              * @class
14941              * Allows gadgets to call the log function to publish client logging messages over the hub.
14942              * 
14943              * @constructs
14944              */
14945             _fakeConstuctor: function () {
14946                 /* This is here so we can document init() as a method rather than as a constructor. */
14947             },
14948             
14949             /**
14950              * Initiates the client logger with a hub and a gadgetId.
14951              * @param {Object} hub
14952              *      The hub to communicate with.
14953              * @param {String} gadgetId
14954              *      A unique string to identify which gadget is doing the logging.
14955              * @example
14956              * var _clientLogger = finesse.cslogger.ClientLogger;
14957              * _clientLogger.init(gadgets.Hub, "MyGadgetId");
14958              * 
14959              */
14960             init: function (hub, gadgetId) {
14961                 _hub = hub;
14962                 _logTopic = "finesse.clientLogging." + gadgetId;
14963                 _originId = gadgetId + " : ";
14964             }
14965         };
14966     }());
14967     
14968     window.finesse = window.finesse || {};
14969     window.finesse.cslogger = window.finesse.cslogger || {};
14970     window.finesse.cslogger.ClientLogger = ClientLogger;
14971     
14972     finesse = finesse || {};
14973     /** @namespace Supports writing messages to a central log. */
14974     finesse.cslogger = finesse.cslogger || {};
14975 
14976     return ClientLogger;
14977  }));
14978 
14979 /* using variables before they are defined.
14980  */
14981 /*global navigator,unescape,sessionStorage,localStorage,_initSessionList,_initSessionListComplete */
14982 
14983 /**
14984  * Allows each gadget to communicate with the server to send logs.
14985  */
14986 
14987 /**
14988  * @class
14989  * @private
14990  * Allows each product to initialize its method of storage
14991  */
14992 (function (factory) {
14993     
14994 
14995     // Define as an AMD module if possible
14996     if ( typeof define === 'function' && define.amd )
14997     {
14998         define('cslogger/FinesseLogger',["clientservices/ClientServices"], factory );
14999     }
15000     
15001     /* Define using browser globals otherwise
15002      * Prevent multiple instantiations if the script is loaded twice
15003      */
15004     else
15005     {
15006         factory(finesse.clientservices.ClientServices);
15007     }
15008     
15009 }(function (ClientServices) {
15010     window.finesse = window.finesse || {};
15011     window.finesse.cslogger = window.finesse.cslogger || {};
15012     /** @private */
15013     window.finesse.cslogger.FinesseLogger = (function () { 
15014 
15015         var
15016 
15017         /**
15018          * Array use to collect ongoing logs in memory
15019          * @private
15020          */
15021         _logArray = [],
15022 
15023         /**
15024          * The final data string sent to the server, =_logArray.join
15025          * @private
15026          */
15027         _logStr = "",
15028 
15029         /**
15030          * Keep track of size of log
15031          * @private
15032          */
15033         _logSize = 0,
15034 
15035         /**
15036          * Flag to keep track show/hide of send log link
15037          * @private
15038          */
15039         _sendLogShown = false,
15040 
15041         /**
15042          * Flag to keep track if local log initialized
15043          * @private
15044          */
15045         _loggingInitialized = false,
15046         
15047 
15048         /**
15049          * local log size limit
15050          * @private
15051          */
15052         _maxLocalStorageSize = 5000000,
15053 
15054         /**
15055          * half local log size limit
15056          * @private
15057          */
15058         _halfMaxLocalStorageSize = 0.5*_maxLocalStorageSize,
15059 
15060         
15061         /**
15062          * threshold for purge 
15063          * @private
15064          */
15065         _purgeStartPercent = 0.75,
15066         
15067         /**
15068          * log item prefix 
15069          * @private
15070          */
15071         _linePrefix = null,
15072         
15073         /**
15074          * locallog session 
15075          * @private
15076          */
15077         _session = null,
15078         
15079         /**
15080          * Flag to keep track show/hide of send log link
15081          * @private
15082          */
15083         _sessionKey = null,
15084         /**
15085          * Log session metadata 
15086          * @private
15087          */
15088         _logInfo = {},
15089         
15090         /**
15091          * Flag to find sessions 
15092          * @private
15093          */
15094         _findSessionsObj = null,
15095 
15096         /**
15097          * Wrap up console.log esp. for IE9 
15098          * @private
15099          */
15100         _myConsoleLog = function (str) {
15101             if (window.console !== undefined) {
15102               window.console.log(str);
15103             }
15104         },
15105         /**
15106          * Initialize the Local Logging
15107          * @private
15108          */
15109         _initLogging = function () {
15110             if (_loggingInitialized) {
15111                 return;
15112             }
15113             //Build a new store
15114             _session = sessionStorage.getItem("finSessKey");
15115             //if the _session is null or empty, skip the init
15116             if (!_session) {
15117               return;
15118             }
15119             _sessionKey = "Fi"+_session;
15120             _linePrefix = _sessionKey + "_";
15121             _logInfo = {};
15122             _logInfo.name = _session;
15123             _logInfo.size = 0;
15124             _logInfo.head = 0;
15125             _logInfo.tail = 0;
15126             _logInfo.startTime = new Date().getTime();
15127             _loggingInitialized = true;
15128             _initSessionList();
15129         },
15130         
15131         /**
15132          * get total data size 
15133          *
15134          * @return {Integer} which is the amount of data stored in local storage.
15135          * @private
15136          */
15137         _getTotalData = function ()
15138         {
15139             var sessName, sessLogInfoStr,sessLogInfoObj, sessionsInfoObj, totalData = 0,
15140             sessionsInfoStr = localStorage.getItem("FinesseSessionsInfo");
15141             if (!sessionsInfoStr) {
15142                  return 0;
15143             }
15144             sessionsInfoObj = JSON.parse(sessionsInfoStr);
15145 
15146             for (sessName in sessionsInfoObj.sessions)
15147             {
15148                 if (sessionsInfoObj.sessions.hasOwnProperty(sessName)) {
15149                     sessLogInfoStr = localStorage.getItem("Fi" + sessName);
15150                     if (!sessLogInfoStr) {
15151                         _myConsoleLog("_getTotalData failed to get log info for "+sessName);
15152                     }
15153                     else {
15154                        sessLogInfoObj = JSON.parse(sessLogInfoStr);
15155                        totalData = totalData + sessLogInfoObj.size;
15156                     }
15157                 }
15158             }
15159 
15160               return totalData;
15161         },
15162         
15163         /**
15164          * Remove lines from tail up until store size decreases to half of max size limit.
15165          *
15166          * @private
15167          */
15168         _purgeCurrentSession = function() {
15169             var curStoreSize, purgedSize=0, line, tailKey, secLogInfoStr, logInfoStr, theLogInfo;
15170             curStoreSize = _getTotalData();
15171             if (curStoreSize < _halfMaxLocalStorageSize) {
15172                return;
15173             }
15174             logInfoStr = localStorage.getItem(_sessionKey);
15175             if (!logInfoStr) {
15176                return;
15177             }
15178             theLogInfo = JSON.parse(logInfoStr);
15179             //_myConsoleLog("Starting _purgeCurrentSession() - currentStoreSize=" + curStoreSize);
15180             while(curStoreSize > _halfMaxLocalStorageSize) {
15181                try {
15182                    tailKey = _sessionKey+"_"+theLogInfo.tail;
15183                    line = localStorage.getItem(tailKey);
15184                    if (line) {
15185                        purgedSize = purgedSize +line.length;
15186                        localStorage.removeItem(tailKey);
15187                        curStoreSize = curStoreSize - line.length;
15188                        theLogInfo.size = theLogInfo.size - line.length;
15189                    }
15190                }
15191                catch (err) {
15192                    _myConsoleLog("purgeCurrentSession encountered err="+err);
15193                }
15194                if (theLogInfo.tail < theLogInfo.head) {
15195                    theLogInfo.tail = theLogInfo.tail  + 1;
15196                }
15197                else {
15198                    break;
15199                }
15200             }
15201             //purge stops here, we need to update session's meta data in storage
15202             secLogInfoStr = localStorage.getItem(_sessionKey);
15203             if (!secLogInfoStr) {
15204                 //somebody cleared the localStorage
15205                 return;
15206             }
15207             
15208             //_myConsoleLog("In _purgeCurrentSession() - after purging current session, currentStoreSize=" + curStoreSize);
15209             //_myConsoleLog("In _purgeCurrentSession() - after purging purgedSize=" + purgedSize);
15210             //_myConsoleLog("In _purgeCurrentSession() - after purging logInfo.size=" + theLogInfo.size);
15211             //_myConsoleLog("In _purgeCurrentSession() - after purging logInfo.tail=" + theLogInfo.tail);
15212             localStorage.setItem(_sessionKey, JSON.stringify(theLogInfo));
15213             _myConsoleLog("Done _purgeCurrentSession() - currentStoreSize=" + curStoreSize);
15214         },
15215        
15216         /**
15217          * Purge a session 
15218          *
15219          * @param sessionName is the name of the session
15220          * @return {Integer} which is the current amount of data purged
15221          * @private
15222          */
15223         _purgeSession = function (sessionName) {
15224               var theLogInfo, logInfoStr, sessionsInfoStr, sessionsInfoObj;
15225               //Get the session logInfo
15226               logInfoStr = localStorage.getItem("Fi" + sessionName);
15227               if (!logInfoStr) {
15228                  _myConsoleLog("_purgeSession failed to get logInfo for "+sessionName);
15229                  return 0;
15230               }
15231               theLogInfo = JSON.parse(logInfoStr);
15232               
15233               //Note: This assumes that we don't crash in the middle of purging
15234               //=> if we do then it should get deleted next time
15235               //Purge tail->head
15236               while (theLogInfo.tail <= theLogInfo.head)
15237               {
15238                   try {
15239                       localStorage.removeItem("Fi" + sessionName + "_" + theLogInfo.tail);
15240                       theLogInfo.tail = theLogInfo.tail + 1;
15241                   }
15242                   catch (err) {
15243                       _myConsoleLog("In _purgeSession err="+err);
15244                       break;
15245                   }
15246               }
15247 
15248               //Remove the entire session
15249               localStorage.removeItem("Fi" + sessionName);
15250 
15251               //Update FinesseSessionsInfo
15252               sessionsInfoStr = localStorage.getItem("FinesseSessionsInfo");
15253               if (!sessionsInfoStr) {
15254                  _myConsoleLog("_purgeSession could not get sessions Info, it was cleared?");
15255                  return 0;
15256               }
15257               sessionsInfoObj = JSON.parse(sessionsInfoStr);
15258               if (sessionsInfoObj.sessions !== null)
15259               {
15260                  delete sessionsInfoObj.sessions[sessionName];
15261               
15262                  sessionsInfoObj.total = sessionsInfoObj.total - 1;
15263                  sessionsInfoObj.lastWrittenBy = _session;
15264                  localStorage.setItem("FinesseSessionsInfo", JSON.stringify(sessionsInfoObj));
15265               }
15266               
15267               return theLogInfo.size;
15268         },
15269         
15270          /**
15271           * purge old sessions
15272           * 
15273           * @param storeSize
15274 	  * @return {Boolean} whether purging reaches its target
15275           * @private
15276          */
15277          _purgeOldSessions = function (storeSize) {
15278              var sessionsInfoStr, purgedSize = 0, sessName, sessions, curStoreSize, activeSession, sessionsInfoObj;
15279              sessionsInfoStr = localStorage.getItem("FinesseSessionsInfo");
15280              if (!sessionsInfoStr) {
15281                 _myConsoleLog("Could not get FinesseSessionsInfo");
15282                 return true;
15283              }
15284              sessionsInfoObj = JSON.parse(sessionsInfoStr);
15285              curStoreSize = _getTotalData();
15286              
15287              activeSession = _session;
15288              sessions = sessionsInfoObj.sessions;
15289              for (sessName in sessions) {
15290                 if (sessions.hasOwnProperty(sessName)) {
15291                     if (sessName !== activeSession) {
15292                         purgedSize = purgedSize + _purgeSession(sessName);
15293                         if ((curStoreSize-purgedSize) < _halfMaxLocalStorageSize) {
15294                             return true;
15295                         }
15296                     }
15297                 }
15298              }
15299             //purge is not done, so return false
15300             return false;
15301          },
15302          
15303        /**
15304         * handle insert error
15305         *
15306         * @param error
15307         * @private
15308         */
15309         _insertLineHandleError = function (error) {
15310             _myConsoleLog(error);
15311         },
15312 
15313         /**
15314          * check storage data size and if need purge
15315          * @private
15316          */
15317         _checkSizeAndPurge = function () {
15318             var purgeIsDone=false, totalSize = _getTotalData();
15319             if (totalSize > 0.75*_maxLocalStorageSize) {
15320                _myConsoleLog("in _checkSizeAndPurge, totalSize ("+totalSize+") exceeds limit");
15321                purgeIsDone = _purgeOldSessions(totalSize);
15322                if (purgeIsDone) {
15323                   _myConsoleLog("in _checkSizeAndPurge after purging old session, purge is done");
15324                }
15325                else {
15326                   //after all old sessions purged, still need purge
15327                   totalSize = _getTotalData();
15328                   if (totalSize > 0.75*_maxLocalStorageSize) {
15329                       _myConsoleLog("in _checkSizeAndPurge after purging old session,still needs purging, now storeSize ("+totalSize+")");
15330                      _purgeCurrentSession();
15331                      _myConsoleLog("in _checkSizeAndPurge done purging current session.");
15332                   }
15333                }
15334             }
15335         },
15336         
15337         /**
15338          * check if the session is already in meta data  
15339          * 
15340          * @param metaData
15341          * @param sessionName
15342          * @return {Boolean} true if session has metaData (false otherwise)
15343          * @private
15344          */
15345         _sessionsInfoContains = function (metaData, sessionName) {
15346            if (metaData && metaData.sessions && metaData.sessions.hasOwnProperty(sessionName)) {
15347               return true;
15348            }
15349            return false;
15350         },
15351         
15352         
15353         /**
15354          * setup sessions in local storage 
15355          * 
15356          * @param logInfo
15357          * @private
15358          */
15359         _getAndSetNumberOfSessions = function (logInfo) {
15360             var numOfSessionsPass1, numOfSessionsPass2, l;
15361             numOfSessionsPass1 = localStorage.getItem("FinesseSessionsInfo");
15362             if (numOfSessionsPass1 === null) {
15363                 //Init first time
15364                 numOfSessionsPass1 = {};
15365                 numOfSessionsPass1.total = 1;
15366                 numOfSessionsPass1.sessions = {};
15367                 numOfSessionsPass1.sessions[logInfo.name] = logInfo.startTime;
15368                 numOfSessionsPass1.lastWrittenBy = logInfo.name;
15369                 localStorage.setItem("FinesseSessionsInfo", JSON.stringify(numOfSessionsPass1));
15370             }
15371             else {
15372                 numOfSessionsPass1 = JSON.parse(numOfSessionsPass1);
15373                 //check if the session is already in the FinesseSessionSInfo
15374                 if (_sessionsInfoContains(numOfSessionsPass1, logInfo.name)) {
15375                     return;
15376                 }             
15377                 //Save numOfSessionsPass1
15378                 numOfSessionsPass1.total = parseInt(numOfSessionsPass1.total, 10) + 1;
15379                 numOfSessionsPass1.sessions[logInfo.name] = logInfo.startTime;
15380                 numOfSessionsPass1.lastWrittenBy = logInfo.name;
15381                 localStorage.setItem("FinesseSessionsInfo", JSON.stringify(numOfSessionsPass1));
15382                 numOfSessionsPass2 = localStorage.getItem("FinesseSessionsInfo");
15383                 if (!numOfSessionsPass2) {
15384                    _myConsoleLog("Could not get FinesseSessionsInfo");
15385                    return;
15386                 }
15387                 numOfSessionsPass2 = JSON.parse(numOfSessionsPass2);
15388                 //in future we need to confirm the numOfSessionsPass2 is the same as numOfSessionsPass1
15389                 ////if (numOfSessionsPass1.lastWrittenBy !== numOfSessionsPass2.lastWrittenBy) {
15390                 ////    _myConsoleLog("Rebuild sessions");
15391                 ////    _sessionTimerId = setTimeout(_initSessionList, 10000);
15392                 ////}
15393                 ////else {
15394                 ////    _sessionTimerId = null;
15395                 ////callback(numOfSessionsPass2.sessions);
15396                 ////}
15397             }
15398             if (!localStorage.getItem(_sessionKey)) {
15399                 localStorage.setItem(_sessionKey, JSON.stringify(_logInfo));
15400             }
15401         },
15402         
15403         
15404         /**
15405          * init session list 
15406          * @private
15407          */
15408         _initSessionList = function () {
15409             _getAndSetNumberOfSessions(_logInfo);
15410         },
15411         
15412        /**
15413         * do the real store of log line
15414         * 
15415         * @param line
15416         * @private
15417         */
15418         _persistLine = function (line) {
15419             var key, logInfoStr;
15420             logInfoStr = localStorage.getItem(_sessionKey);
15421             if (logInfoStr === null) {
15422                return;
15423             }
15424             _logInfo = JSON.parse(logInfoStr);
15425             _logInfo.head = _logInfo.head + 1;
15426             key = _linePrefix + _logInfo.head;
15427             localStorage.setItem(key, line);
15428             //Save the size
15429             _logInfo.size = _logInfo.size + line.length;
15430             if (_logInfo.tail === 0) {
15431                 _logInfo.tail = _logInfo.head;
15432             }
15433         
15434             localStorage.setItem(_sessionKey, JSON.stringify(_logInfo));
15435             _checkSizeAndPurge();
15436         },
15437         
15438         /**
15439          * Insert a line into the localStorage.
15440          *
15441          * @param line line to be inserted 
15442          * @private
15443         */
15444         _insertLine = function (line) {
15445             //_myConsoleLog("_insertLine: [" + line + "]");
15446             //Write the next line to localStorage
15447             try {
15448                //Persist the line 
15449                _persistLine(line);
15450             }
15451             catch (err) {
15452                _myConsoleLog("error in _insertLine(), err="+err);
15453                //_insertLineHandleError(err);
15454             }
15455         },
15456          
15457         
15458         /**
15459          * Clear the local storage
15460          * @private
15461          */
15462         _clearLocalStorage = function() {
15463             localStorage.clear();
15464 
15465         },
15466 
15467         /**
15468          * Collect logs when onCollect called
15469          *
15470          * @param data
15471          * @private
15472          */
15473         _collectMethod = function(data) {
15474           //Size of log should not exceed 1.5MB
15475           var info, maxLength = 1572864;
15476           
15477           //add size buffer equal to the size of info to be added when publish
15478           info = navigator.userAgent + "
";
15479           info = escape(info);
15480 
15481             //If log was empty previously, fade in buttons
15482             if (!_sendLogShown) {
15483                 //call the fadeInSendLog() in Footer
15484                 finesse.modules.Footer.sendLogAppear();
15485                 _sendLogShown = true;
15486                 _logSize = info.length;
15487             }
15488             
15489             //if local storage logging is enabled, then insert the log into local storage
15490             if (window.sessionStorage.getItem('enableLocalLog')==='true') {
15491                 if (data) {
15492                    if (data.length>0 && data.substring(0,1) === '\n') {
15493                       _insertLine(data.substring(1));
15494                    }
15495                    else {
15496                       _insertLine(data);
15497                    }
15498                 }
15499             }
15500               
15501             //escape all data to get accurate size (shindig will escape when it builds request)
15502             //escape 6 special chars for XML: &<>"'\n
15503             data = data.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/>/g, ">").replace(/</g, "<").replace(/\n/g, "
");
15504             data = escape(data+"\n");
15505 
15506             if (data.length < maxLength){
15507                 //make room for new data if log is exceeding max length
15508                 while (_logSize + data.length > maxLength) {
15509                     _logSize -= (_logArray.shift()).length;
15510                 }
15511             }
15512 
15513             //Else push the log into memory, increment the log size
15514             _logArray.push(data);
15515 
15516             //inc the size accordingly
15517             _logSize+=data.length;
15518 
15519         };
15520 
15521         return {
15522 
15523             /**
15524              * @private
15525              * Initiate FinesseLogger.
15526              */
15527             init: function () {
15528                 ClientServices.subscribe("finesse.clientLogging.*", _collectMethod);
15529                 _initLogging();
15530             },
15531 
15532             /**
15533              * @private
15534              * Clear all items stored in localStorage.
15535             */
15536             clear : function () {
15537                _clearLocalStorage();
15538             },
15539 
15540             /**
15541              * @private
15542              * Initialize the local storage logging.
15543             */
15544             initLocalLog: function () {
15545                _initLogging();
15546             },
15547 
15548             /**
15549              * @private
15550              * Inserts a line into the localStorage.
15551              * @param line to insert
15552             */
15553             localLog : function (line) {
15554                _insertLine(line);
15555             },
15556 
15557            /**
15558             * @ignore
15559             * Publish logs to server and clear the memory
15560             *
15561             * @param userObj
15562             * @param options
15563             * @param callBack
15564             */
15565             publish: function(userObj, options, callBack) {
15566                 // Avoid null references.
15567                 options = options || {};
15568                 callBack = callBack || {};
15569 
15570                 if (callBack.sending === "function") {
15571                     callBack.sending();
15572                 }
15573 
15574                 //logs the basic version and machine info and escaped new line
15575                 _logStr = navigator.userAgent + "
";
15576                 
15577                 //join the logs to correct string format
15578                 _logStr += unescape(_logArray.join(""));
15579 
15580                 //turning log string to JSON obj
15581                 var logObj = {
15582                         ClientLog: {
15583                         logData : _logStr //_logStr
15584                     }
15585                 },
15586                 tmpOnAdd = (options.onAdd && typeof options.onAdd === "function")? options.onAdd : function(){};
15587                 /** @private */
15588                 options.onAdd = function(){
15589                     tmpOnAdd();
15590                     _logArray.length = 0; _logSize =0;
15591                     _sendLogShown = false;
15592                     };
15593                 //adding onLoad to the callbacks, this is the subscribe success case for the first time user subscribe to the client log node
15594                 /** @private */
15595                 options.onLoad = function (clientLogObj) {
15596                     clientLogObj.sendLogs(logObj,{
15597                             error: callBack.error
15598                         });
15599                     };
15600 
15601                 userObj.getClientLog(options);
15602             }
15603         };
15604     }());
15605 }));
15606 
15607 /**
15608  *  Contains a list of topics used for containerservices pubsub.
15609  *
15610  */
15611 
15612 /**
15613  * @class
15614  * Contains a list of topics with some utility functions.
15615  */
15616 /** @private */
15617 (function (factory) {
15618     
15619 
15620     // Define as an AMD module if possible
15621     if ( typeof define === 'function' && define.amd )
15622     {
15623         define('containerservices/Topics',[], factory );
15624     }
15625     
15626     /* Define using browser globals otherwise
15627      * Prevent multiple instantiations if the script is loaded twice
15628      */
15629     else
15630     {
15631         factory();
15632     }
15633     
15634 }(function () {
15635 
15636     var Topics = (function () {
15637 
15638     /**
15639      * The namespace prepended to all Finesse topics.
15640      */
15641     this.namespace = "finesse.containerservices";
15642 
15643     /**
15644      * @private
15645      * Gets the full topic name with the ContainerServices namespace prepended.
15646      * @param {String} topic
15647      *     The topic category.
15648      * @returns {String}
15649      *     The full topic name with prepended namespace.
15650      */
15651     var _getNSTopic = function (topic) {
15652         return this.namespace + "." + topic;
15653     };
15654 
15655 
15656 
15657     /** @scope finesse.containerservices.Topics */
15658     return {
15659         /** 
15660          * @private
15661          * request channel. */
15662         REQUESTS: _getNSTopic("requests"),
15663 
15664         /**
15665          * @private
15666          * Convert a Finesse REST URI to a OpenAjax compatible topic name.
15667          */
15668         getTopic: function (restUri) {
15669             //The topic should not start with '/' else it will get replaced with
15670             //'.' which is invalid.
15671             //Thus, remove '/' if it is at the beginning of the string
15672             if (restUri.indexOf('/') === 0) {
15673                 restUri = restUri.substr(1);
15674             }
15675 
15676             //Replace every instance of "/" with ".". This is done to follow the
15677             //OpenAjaxHub topic name convention.
15678             return restUri.replace(/\//g, ".");
15679         }
15680     };
15681 	}());
15682 	
15683 	window.finesse = window.finesse || {};
15684     window.finesse.containerservices = window.finesse.containerservices || {};
15685     window.finesse.containerservices.Topics = Topics;
15686     
15687     /** @namespace JavaScript class objects and methods to handle gadget container services.*/
15688     finesse.containerservices = finesse.containerservices || {};
15689 
15690 	return Topics;
15691 
15692  }));
15693 
15694 /** The following comment is to prevent jslint errors about 
15695  * using variables before they are defined.
15696  */
15697 /*global finesse*/
15698 
15699 /**
15700  * Per containerservices request, publish to the OpenAjax gadget pubsub infrastructure.
15701  *
15702  * @requires OpenAjax, finesse.containerservices.Topics
15703  */
15704 
15705 /** @private */
15706 (function (factory) {
15707     
15708 
15709     // Define as an AMD module if possible
15710     if ( typeof define === 'function' && define.amd )
15711     {
15712         define('containerservices/MasterPublisher',["utilities/Utilities",
15713                 "containerservices/Topics"], factory );
15714     }
15715     
15716     /* Define using browser globals otherwise
15717      * Prevent multiple instantiations if the script is loaded twice
15718      */
15719     else
15720     {
15721         factory(finesse.utilities.Utilities, finesse.containerservices.Topics);
15722     }
15723     
15724 }(function (Utilities, Topics) {
15725 
15726     var MasterPublisher = function () {
15727 
15728     var
15729 
15730     /**
15731      * Reference to the gadget pubsub Hub instance.
15732      * @private
15733      */
15734     _hub = gadgets.Hub,
15735 
15736     /**
15737      * Reference to the Topics class.
15738      * @private
15739      */
15740     _topics = Topics,
15741     
15742     /**
15743      * Reference to conversion utilities class.
15744      * @private
15745      */
15746     _utils = Utilities,
15747     
15748 
15749     /**
15750      * The types of possible request types supported when listening to the
15751      * requests channel. Each request type could result in different operations.
15752      * @private
15753      */
15754     _REQTYPES = {
15755 		ACTIVETAB: "ActiveTabReq"
15756     },
15757 
15758     /**
15759      * Handles client requests made to the request topic. The type of the
15760      * request is described in the "type" property within the data payload. Each
15761      * type can result in a different operation.
15762      * @param {String} topic
15763      *     The topic which data was published to.
15764      * @param {Object} data
15765      *     The data containing requests information published by clients.
15766      * @param {String} data.type
15767      *     The type of the request. Supported: "ActiveTabReq"
15768      * @param {Object} data.data
15769      *     May contain data relevant for the particular requests.
15770      * @param {String} [data.invokeID]
15771      *     The ID used to identify the request with the response. The invoke ID
15772      *     will be included in the data in the publish to the topic. It is the
15773      *     responsibility of the client to correlate the published data to the
15774      *     request made by using the invoke ID.
15775      * @private
15776      */
15777     _clientRequestHandler = function (topic, data) {
15778     
15779         //Ensure a valid data object with "type" and "data" properties.
15780         if (typeof data === "object" &&
15781                 typeof data.type === "string" &&
15782                 typeof data.data === "object") {
15783 			switch (data.type) {
15784 			case _REQTYPES.ACTIVETAB:
15785                 _hub.publish("finesse.containerservices.activeTab", finesse.container.Tabs.getActiveTab());
15786                 break;
15787 			default:
15788 				break;
15789 			}
15790         }
15791     };
15792 
15793     (function () {
15794 
15795         //Listen to a request channel to respond to any requests made by other
15796         //clients because the Master may have access to useful information.
15797         _hub.subscribe(_topics.REQUESTS, _clientRequestHandler);
15798     }());
15799 
15800     //BEGIN TEST CODE//
15801     /**
15802      * Test code added to expose private functions that are used by unit test
15803      * framework. This section of code is removed during the build process
15804      * before packaging production code. The [begin|end]TestSection are used
15805      * by the build to identify the section to strip.
15806      * @ignore
15807      */
15808     this.beginTestSection = 0;
15809 
15810     /**
15811      * @ignore
15812      */
15813     this.getTestObject = function () {
15814         //Load mock dependencies.
15815         var _mock = new MockControl();
15816         _hub = _mock.createMock(gadgets.Hub);
15817 
15818         return {
15819             //Expose mock dependencies
15820             mock: _mock,
15821             hub: _hub,
15822 			
15823             //Expose internal private functions
15824             reqtypes: _REQTYPES,
15825             
15826             clientRequestHandler: _clientRequestHandler
15827 
15828         };
15829     };
15830 
15831 
15832     /**
15833      * @ignore
15834      */
15835     this.endTestSection = 0;
15836     //END TEST CODE//
15837 	};
15838 	
15839 	window.finesse = window.finesse || {};
15840     window.finesse.containerservices = window.finesse.containerservices || {};
15841     window.finesse.containerservices.MasterPublisher = MasterPublisher;
15842 	
15843 	return MasterPublisher;
15844  }));
15845 
15846 /**
15847  * JavaScript representation of the Finesse WorkflowActionEvent object.
15848  *
15849  * @requires finesse.FinesseBase
15850  */
15851 
15852 /** The following comment is to prevent jslint errors about 
15853  * using variables before they are defined.
15854  */
15855 /*global FinesseBase: true, publisher:true, define:true, finesse:true, window:true */
15856 /** @private */
15857 (function (factory) {
15858     
15859 
15860     // Define as an AMD module if possible
15861     if ( typeof define === 'function' && define.amd )
15862     {
15863         define('containerservices/WorkflowActionEvent', ["FinesseBase"], factory );
15864     }
15865     /* Define using browser globals otherwise
15866      * Prevent multiple instantiations if the script is loaded twice
15867      */
15868     else
15869     {
15870         factory(finesse.FinesseBase);
15871     }
15872 }(function (FinesseBase) {
15873     var WorkflowActionEvent = FinesseBase.extend(/** @lends finesse.containerservices.WorkflowActionEvent.prototype */{
15874         /**
15875          * Reference to the WorkflowActionEvent name
15876          * This will be set by setWorkflowActionEvent
15877          * @private
15878          */
15879         _name: null,
15880 
15881         /**
15882          * Reference to the WorkflowActionEvent type
15883          * This will be set by setWorkflowActionEvent
15884          * @private
15885          */
15886         _type: null,
15887 
15888         /**
15889          * Reference to the WorkflowActionEvent handledBy value
15890          * This will be set by setWorkflowActionEvent
15891          * @private
15892          */
15893         _handledBy: null,
15894 
15895         /**
15896          * Reference to the WorkflowActionEvent params array
15897          * This will be set by setWorkflowActionEvent
15898          * @private
15899          */
15900         _params: [],
15901 
15902         /**
15903          * Reference to the WorkflowActionEvent actionVariables array
15904          * This will be set by setWorkflowActionEvent
15905          * @private
15906          */            
15907         _actionVariables: [], 
15908         
15909         /**
15910          * @class
15911          * JavaScript representation of a WorkflowActionEvent object.
15912          * The WorkflowActionEvent object is delivered as the payload of
15913          * a WorkflowAction callback.  This can be subscribed to by using
15914          * {@link finesse.containerservices.ContainerServices#addHandler} with a 
15915          * topic of {@link finesse.containerservices.ContainerServices.Topics#WORKFLOW_ACTION_EVENT}. 
15916          * Gadgets should key on events with a handleBy value of "OTHER".
15917          * 
15918          * @constructs
15919          **/
15920         init: function () {
15921             this._super();
15922         },        
15923 
15924         /**
15925 	     * Validate that the passed in object is a WorkflowActionEvent object
15926 	     * and sets the variables if it is
15927 	     * @param maybeWorkflowActionEvent A possible WorkflowActionEvent object to be evaluated and set if 
15928 	     *                                 it validates successfully.
15929 	     * @returns {Boolean} Whether it is valid or not.
15930          * @private
15931 	     */
15932 	    setWorkflowActionEvent: function(maybeWorkflowActionEvent) {
15933 	        var returnValue;
15934 	
15935 	        if (maybeWorkflowActionEvent.hasOwnProperty("name") === true &&
15936 	                maybeWorkflowActionEvent.hasOwnProperty("type") === true &&
15937                     maybeWorkflowActionEvent.hasOwnProperty("handledBy") === true &&
15938 	                maybeWorkflowActionEvent.hasOwnProperty("params") === true &&
15939 	                maybeWorkflowActionEvent.hasOwnProperty("actionVariables") === true) {
15940 	            this._name = maybeWorkflowActionEvent.name;
15941 	            this._type = maybeWorkflowActionEvent.type;
15942                 this._handledBy = maybeWorkflowActionEvent.handledBy;
15943 	            this._params = maybeWorkflowActionEvent.params;
15944 	            this._actionVariables = maybeWorkflowActionEvent.actionVariables;
15945 	            returnValue = true;
15946 	        } else {
15947 	            returnValue = false;
15948 	        }
15949 	
15950 	        return returnValue;
15951 	    },
15952 	
15953 	    /**
15954 	     * Getter for the WorkflowActionEvent name.
15955 	     * @returns {String} The name of the WorkflowAction.
15956 	     */
15957 	    getName: function () {
15958 	        // escape nulls to empty string
15959 	        return this._name || "";
15960 	    },
15961 	
15962 	    /**
15963 	     * Getter for the WorkflowActionEvent type.
15964 	     * @returns {String} The type of the WorkflowAction (BROWSER_POP, HTTP_REQUEST).
15965 	     */
15966 	    getType: function () {
15967 	        // escape nulls to empty string
15968 	        return this._type || "";
15969 	    },
15970 	
15971         /**
15972          * Getter for the WorkflowActionEvent handledBy value. Gadgets should look for
15973          * events with a handleBy of "OTHER".
15974          * @see finesse.containerservices.WorkflowActionEvent.HandledBy
15975          * @returns {String} The handledBy value of the WorkflowAction that is a value of {@link finesse.containerservices.WorkflowActionEvent.HandledBy}.
15976          */
15977         getHandledBy: function () {
15978             // escape nulls to empty string
15979             return this._handledBy || "";
15980         },
15981 
15982 
15983 	    /**
15984 	     * Getter for the WorkflowActionEvent Params map.
15985 	     * @returns {Object} key = param name, value = Object{name, value, expandedValue}
15986 	     * BROWSER_POP<ul>
15987 	     * <li>windowName : Name of window to pop into, or blank to always open new window.
15988 	     * <li>path : URL to open.</ul>
15989 	     * HTTP_REQUEST<ul>
15990 	     * <li>method : "PUT" or "POST".
15991 	     * <li>location : "FINESSE" or "OTHER".
15992 	     * <li>contentType : MIME type of request body, if applicable, e.g. "text/plain".
15993 	     * <li>path : Request URL.
15994 	     * <li>body : Request content for POST requests.</ul>
15995 	     */
15996 	    getParams: function () {
15997 	        var map = {},
15998 	            params = this._params,
15999 	            i,
16000 	            param;
16001 	
16002 	        if (params === null || params.length === 0) {
16003 	            return map;
16004 	        }
16005 	
16006 	        for (i = 0; i < params.length; i += 1) {
16007 	            param = params[i];
16008 	            // escape nulls to empty string
16009 	            param.name = param.name || "";
16010 	            param.value = param.value || "";
16011 	            param.expandedValue = param.expandedValue || "";
16012 	            map[param.name] = param;
16013 	        }
16014 	
16015 	        return map;
16016 	    },
16017 	    
16018 	    /**
16019 	     * Getter for the WorkflowActionEvent ActionVariables map
16020 	     * @returns {Object} key = action variable name, value = Object{name, type, node, testValue, actualValue}
16021 	     */
16022 	    getActionVariables: function() {
16023 	        var map = {},
16024 	            actionVariables = this._actionVariables,
16025 	            i,
16026 	            actionVariable;
16027 	
16028 	        if (actionVariables === null || actionVariables.length === 0) {
16029 	            return map;
16030 	        }
16031 	
16032 	        for (i = 0; i < actionVariables.length; i += 1) {
16033 	            actionVariable = actionVariables[i];
16034 	            // escape nulls to empty string
16035 	            actionVariable.name = actionVariable.name || "";
16036 	            actionVariable.type = actionVariable.type || "";
16037 	            actionVariable.node = actionVariable.node || "";
16038 	            actionVariable.testValue = actionVariable.testValue || "";
16039 	            actionVariable.actualValue = actionVariable.actualValue || "";
16040 	            map[actionVariable.name] = actionVariable;
16041 	        }
16042 	
16043 	        return map;
16044 	    }
16045     }); 
16046     
16047     
16048     WorkflowActionEvent.HandledBy = /** @lends finesse.containerservices.WorkflowActionEvent.HandledBy.prototype */ {
16049         /**
16050          * This specifies that Finesse will handle this WorkflowActionEvent.  A 3rd Party can do additional processing
16051          * with the action, but first and foremost Finesse will handle this WorkflowAction.
16052          */
16053         FINESSE: "FINESSE",
16054 
16055         /**
16056          * This specifies that a 3rd Party will handle this WorkflowActionEvent.  Finesse's Workflow Engine Executor will 
16057          * ignore this action and expects Gadget Developers to take action.
16058          */
16059         OTHER: "OTHER",
16060         
16061         /**
16062          * @class This is the set of possible HandledBy values used for WorkflowActionEvent from ContainerServices.  This
16063          * is provided from the {@link finesse.containerservices.WorkflowActionEvent#getHandledBy} method.
16064          * @constructs
16065          */
16066         _fakeConstructor : function () {} // For JS Doc to work need a constructor so that the lends/constructs build the doc properly
16067     };    
16068     
16069     window.finesse = window.finesse || {};
16070     window.finesse.containerservices = window.finesse.containerservices || {};
16071     window.finesse.containerservices.WorkflowActionEvent = WorkflowActionEvent;
16072     
16073     return WorkflowActionEvent;
16074 }));
16075 
16076 /**
16077  * Exposes a set of API wrappers that will hide the dirty work of
16078  *     constructing Finesse API requests and consuming Finesse events.
16079  *
16080  * @requires OpenAjax, jQuery 1.5, finesse.utilities.Utilities
16081  */
16082 
16083 /** The following comment is to prevent jslint errors about using variables before they are defined. */
16084 /*global window:true, gadgets:true, publisher:true, define:true, finesse:true, _tabTracker:true, _workflowActionEventTracker:true, frameElement:true, $:true, parent:true, MockControl:true */
16085 /*jslint nomen: true, unparam: true, sloppy: true, white: true */
16086 /** @private */
16087 (function (factory) {
16088     
16089 
16090     // Define as an AMD module if possible
16091     if ( typeof define === 'function' && define.amd )
16092     {
16093         define('containerservices/ContainerServices',["utilities/Utilities",
16094                 "restservices/Notifier",
16095                 "containerservices/Topics",
16096                 "containerservices/MasterPublisher",
16097                 "containerservices/WorkflowActionEvent"], factory );
16098     }
16099     
16100     /* Define using browser globals otherwise
16101      * Prevent multiple instantiations if the script is loaded twice
16102      */
16103     else
16104     {
16105         factory(finesse.utilities.Utilities, finesse.restservices.Notifier, finesse.containerservices.Topics, finesse.containerservices.MasterPublisher, finesse.containerservices.WorkflowActionEvent);
16106     }
16107     
16108 }(function (Utilities, Notifier, Topics, MasterPublisher, WorkflowActionEvent) {
16109 
16110     var ContainerServices = ( function () { /** @lends finesse.containerservices.ContainerServices.prototype */
16111 
16112     var
16113 
16114     /**
16115      * Shortcut reference to the Utilities singleton
16116      * This will be set by init()
16117      * @private
16118      */
16119     _util,
16120 
16121     /**
16122      * Shortcut reference to the gadget pubsub Hub instance.
16123      * This will be set by init()
16124      * @private
16125      */
16126     _hub,
16127 
16128     /**
16129      * Boolean whether this instance is master or not
16130      * @private
16131      */
16132     _master = false,
16133 
16134     /**
16135      * Whether the Client Services have been initiated yet.
16136      * @private
16137      */
16138     _inited = false,
16139     
16140      /**
16141      * Stores the list of subscription IDs for all subscriptions so that it
16142      * could be retrieve for unsubscriptions.
16143      * @private
16144      */
16145     _subscriptionID = {},
16146     
16147     /**
16148      * Reference to the gadget's parent container
16149      * @private
16150      */
16151     _container,
16152 
16153     /**
16154      * Reference to the MasterPublisher
16155      * @private
16156      */
16157     _publisher,
16158     
16159     /**
16160      * Object that will contain the Notifiers
16161      * @private
16162      */
16163     _notifiers = {},
16164 
16165     /**
16166      * Reference to the tabId that is associated with the gadget
16167      * @private
16168      */
16169     _myTab = null,
16170     
16171     /**
16172      * Reference to the visibility of current gadget
16173      * @private
16174      */
16175     _visible = false,
16176     
16177     /**
16178      * Shortcut reference to the Topics class.
16179      * This will be set by init()
16180      * @private
16181      */
16182     _topics,
16183 
16184     /**
16185      * Associates a topic name with the private handler function.
16186      * Adding a new topic requires that you add this association here 
16187      *  in to keep addHandler generic.
16188      * @param {String} topic : Specifices the callback to retrieve
16189      * @return {Function} The callback function associated with the topic param.
16190      * @private
16191      */
16192     _topicCallback = function (topic) {
16193         var callback;
16194         switch (topic)
16195         {
16196             case finesse.containerservices.ContainerServices.Topics.ACTIVE_TAB:
16197                 callback = _tabTracker;
16198                 break;
16199             case finesse.containerservices.ContainerServices.Topics.WORKFLOW_ACTION_EVENT:
16200                 callback = _workflowActionEventTracker;
16201                 break;
16202             default:
16203                 throw new Error("ContainerServices : _topicCallback(topic) - Topic not recognized.");
16204         }
16205         return callback;
16206     },
16207 
16208     /**
16209      * Ensure that ClientServices have been inited.
16210      * @private
16211      */
16212     _isInited = function () {
16213         if (!_inited) {
16214             throw new Error("ContainerServices needs to be inited.");
16215         }
16216     },
16217 
16218     /**
16219      * Retrieves a Notifier reference to a particular topic, and creates one if it doesn't exist.
16220      * @param {String} topic : Specifies the notifier to retrieve
16221      * @return {Notifier} The notifier object.
16222      * @private
16223      */
16224     _getNotifierReference = function (topic) {
16225         if (!_notifiers.hasOwnProperty(topic))
16226         {
16227             _notifiers[topic] = new Notifier();
16228         }
16229 
16230         return _notifiers[topic];
16231     },
16232 
16233     /**
16234      * Utility function to make a subscription to a particular topic. Only one
16235      * callback function is registered to a particular topic at any time.
16236      * @param {String} topic
16237      *     The full topic name. The topic name should follow the OpenAjax
16238      *     convention using dot notation (ex: finesse.api.User.1000).
16239      * @param {Function} callback
16240      *     The function that should be invoked with the data when an event
16241      *     is delivered to the specific topic.
16242      * @returns {Boolean}
16243      *     True if the subscription was made successfully and the callback was
16244      *     been registered. False if the subscription already exist, the
16245      *     callback was not overwritten.
16246      * @private
16247      */
16248     _subscribe = function (topic, callback) {
16249         _isInited();
16250 
16251         //Ensure that the same subscription isn't made twice.
16252         if (!_subscriptionID[topic]) {
16253             //Store the subscription ID using the topic name as the key.
16254             _subscriptionID[topic] = _hub.subscribe(topic,
16255                 //Invoke the callback just with the data object.
16256                 function (topic, data) {
16257                     callback(data);
16258                 });
16259             return true;
16260         }
16261         return false;
16262     },
16263 
16264     /**
16265      * Unsubscribe from a particular topic.
16266      * @param {String} topic : The full topic name.
16267      * @private
16268      */
16269     _unsubscribe = function (topic) {
16270         _isInited();
16271 
16272         //Unsubscribe from the topic using the subscription ID recorded when
16273         //the subscription was made, then delete the ID from data structure.
16274         _hub.unsubscribe(_subscriptionID[topic]);
16275         delete _subscriptionID[topic];
16276     },
16277     
16278     /**
16279      * Callback function that is called when an activeTab message is posted to the Hub.
16280      * Notifies listener functions if this tab is the one that was just made active.
16281      * @param {String} tabId : The tabId which was just made visible.
16282      * @private
16283      */
16284     _tabTracker = function(tabId) {
16285         if (_myTab === null)
16286         {
16287             _myTab = $(frameElement).closest("div.tab-panel").attr("id").replace("panel_", "");
16288         }
16289 
16290         if (tabId === _myTab) {
16291             if(!_visible) {
16292                 _visible = true;
16293                 _notifiers[finesse.containerservices.ContainerServices.Topics.ACTIVE_TAB].notifyListeners(this);
16294             }
16295         } else {
16296             _visible = false;
16297         }
16298     },
16299 
16300     /**
16301      * Callback function that is called when a workflowActionEvent message is posted to the Hub.
16302      * Notifies listener functions if the posted object can be converted to a proper WorkflowActionEvent object.
16303      * @param {String} workflowActionEvent : The workflowActionEvent that was posted to the Hub
16304      * @private
16305      */
16306     _workflowActionEventTracker = function(workflowActionEvent) {
16307         var vWorkflowActionEvent = new finesse.containerservices.WorkflowActionEvent();
16308                 
16309         if (vWorkflowActionEvent.setWorkflowActionEvent(workflowActionEvent)) {
16310             _notifiers[finesse.containerservices.ContainerServices.Topics.WORKFLOW_ACTION_EVENT].notifyListeners(vWorkflowActionEvent);
16311         }
16312         // else
16313         // {
16314             //?console.log("Error in ContainerServices : _workflowActionEventTracker - could not map published HUB object to WorkflowActionEvent");
16315         // }
16316 
16317     },
16318 
16319     /**
16320      * Utility to be called within a gadget to determine the iframe of the parent container
16321      * corresponds to this gadget so that the gadget id can be parsed from the iframe id.
16322      * @return {String} id of the gadget
16323      * @private
16324      */
16325     _findMyGadgetId = function () {
16326         var pWindow = parent, myIframe, i, id, iframeId, gadgetFrames;
16327 
16328         // First, get the parent window
16329         while (pWindow && pWindow.parent !== pWindow) {
16330             pWindow = pWindow.parent;
16331         }
16332 
16333         // Then, get the list of all gadget iframes
16334         gadgetFrames = pWindow.document.getElementsByClassName('gadgets-gadget');
16335 
16336         // Then check to see which iframe matches this window
16337         for (i = 0; i < gadgetFrames.length; i += 1) {
16338             if (gadgetFrames[i].contentWindow === self) {
16339                 myIframe = gadgetFrames[i];
16340                 break;
16341             }
16342         }
16343 
16344         // Parse the iframe id to get the gadget id
16345         if (myIframe) {
16346             iframeId = myIframe.id;
16347             if (iframeId.indexOf('finesse_gadget_') !== -1) {
16348                 id = iframeId.substr(iframeId.indexOf('finesse_gadget_') + 15);
16349             }            
16350         }
16351 
16352         return id;
16353     };
16354 
16355     return {
16356         /**
16357          * @class
16358          * This class provides container-level services for gadget developers, exposing container events by
16359          * calling a set of exposed functions. Gadgets can utilize the container dialogs and 
16360          * event handling (add/remove).
16361          * @example
16362          *    containerServices = finesse.containerservices.ContainerServices.init();
16363          *    containerServices.addHandler(
16364          *      finesse.containerservices.ContainerServices.Topics.ACTIVE_TAB, 
16365          *      function() {
16366          *          clientLogs.log("Gadget is now visible");  // log to Finesse logger
16367          *          // automatically adjust the height of the gadget to show the html
16368          *          gadgets.window.adjustHeight();
16369          *      });
16370          *    containerServices.makeActiveTabReq();
16371          *    
16372          * @constructs
16373          */
16374         _fakeConstuctor: function () {
16375             /* This is here so we can document init() as a method rather than as a constructor. */
16376         },
16377 
16378         /**
16379          * Initialize ContainerServices for use in gadget.
16380          * @param {Boolean} [master=false] Do not use this parameter from your gadget.
16381          * @returns ContainerServices instance.
16382          */
16383         init: function (master) {
16384             if (!_inited) {
16385                 _inited = true;
16386                 // Set shortcuts
16387                 _util = Utilities;                
16388 
16389                 if (master){
16390                     _master = true;
16391                     _container = finesse.container.Container;
16392                     _publisher = new MasterPublisher();
16393                 } else {
16394                     _container = parent.finesse.container.Container;
16395                 }
16396 
16397                 //init the hub only when it's available
16398                 if(gadgets.Hub) {
16399                     _hub = gadgets.Hub;
16400                 }
16401 
16402                 if(Topics) {
16403                     _topics = Topics;
16404                 }
16405             }
16406             
16407             this.makeActiveTabReq();
16408 
16409             //Return the CS object for object chaining.
16410             return this;
16411         },
16412 
16413         /**
16414          * Shows the jQuery UI Dialog with the specified parameters. The following are the
16415          * default parameters: <ul>
16416          *     <li> Title of "Cisco Finesse".</li>
16417          *     <li>Message of "A generic error has occured".</li>
16418          *     <li>The only button, "Ok", closes the dialog.</li>
16419          *     <li>Modal (blocks other dialogs).</li>
16420          *     <li>Not draggable.</li>
16421          *     <li>Fixed size.</li></ul>
16422          * @param {Object} options
16423          *  An object containing additional options for the dialog.
16424          * @param {String/Boolean} options.title
16425          *  Title to use. undefined defaults to "Cisco Finesse". false to hide
16426          * @param {Function} options.close
16427          *  A function to invoke when the dialog is closed.
16428          * @param {String} options.message
16429          *  The message to display in the dialog.
16430          *  Defaults to "A generic error has occurred."
16431          * @param {Boolean} options.isBlocking
16432          *  Flag indicating whether this dialog will block other dialogs from being shown (Modal).
16433          * @returns {jQuery} JQuery wrapped object of the dialog DOM element.
16434          * @see finesse.containerservices.ContainerServices#hideDialog
16435          */
16436         showDialog: function(options) {
16437             if ((_container.showDialog !== undefined) && (_container.showDialog !== this.showDialog)) {
16438                 return _container.showDialog(options);
16439             }
16440         },
16441         
16442         /**
16443          * Hides the jQuery UI Dialog.
16444          * @returns {jQuery} jQuery wrapped object of the dialog DOM element
16445          * @see finesse.containerservices.ContainerServices#showDialog
16446          */
16447         hideDialog: function() {
16448             if ((_container.hideDialog !== undefined) && (_container.hideDialog !== this.hideDialog)) {
16449                 return _container.hideDialog();
16450             }
16451         },
16452 
16453         /**
16454          *  Reloads the current gadget. 
16455          *  For use from within a gadget only.
16456          */
16457         reloadMyGadget: function () {
16458             if (!_master) {
16459                 var gadgetId = _findMyGadgetId();
16460 
16461                 if (_container.reloadGadget) {
16462                     _container.reloadGadget(gadgetId);
16463                 }
16464             }            
16465         },
16466         
16467         /**
16468          * Adds a handler for one of the supported topics provided by ContainerServices.  The callbacks provided
16469          * will be invoked when that topic is notified.  
16470          * @param {String} topic
16471          *  The Hub topic to which we are listening.
16472          * @param {Function} callback
16473          *  The callback function to invoke.
16474          * @see finesse.containerservices.ContainerServices.Topics
16475          * @see finesse.containerservices.ContainerServices#removeHandler
16476          */
16477         addHandler: function (topic, callback) {
16478             _isInited();
16479             var notifier = null;
16480             
16481             try {    
16482                 // For backwards compatibility...
16483                 if (topic === "tabVisible") {
16484                     if (window.console && typeof window.console.log === "function") {
16485                         window.console.log("WARNING - Using tabVisible as topic.  This is deprecated.  Use finesse.containerservices.ContainerServices.Topics.ACTIVE_TAB now!");
16486                     }
16487                     
16488                     topic = finesse.containerservices.ContainerServices.Topics.ACTIVE_TAB;
16489                 }
16490                 
16491                 // Add the callback to the notifier.
16492                 _util.validateHandler(callback);
16493             
16494                 notifier = _getNotifierReference(topic);
16495             
16496                 notifier.addListener(callback);
16497             
16498                 // Subscribe to the topic. _subscribe ensures that a topic is only subscribed to once,
16499                 // so attempt to subscribe each time a handler is added. This ensures that a topic is subscribed
16500                 // to only when necessary.
16501                 _subscribe(topic, _topicCallback(topic));
16502             
16503             } catch (err) {
16504                 throw new Error("addHandler(): " + err);
16505             }
16506         }, 
16507         
16508         /**
16509          * Removes a previously-added handler for one of the supported topics.
16510          * @param {String} topic
16511          *  The Hub topic from which we are removing the callback.
16512          * @param {Function} callback
16513          *  The name of the callback function to remove.
16514          * @see finesse.containerservices.ContainerServices.Topics
16515          * @see finesse.containerservices.ContainerServices#addHandler
16516          */
16517         removeHandler: function(topic, callback) {
16518             var notifier = null;
16519             
16520             try {
16521                 _util.validateHandler(callback);
16522     
16523                 notifier = _getNotifierReference(topic);
16524     
16525                 notifier.removeListener(callback);
16526             } catch (err) {
16527                 throw new Error("removeHandler(): " + err);
16528             }
16529         },
16530 
16531         /**
16532          * Returns the visibility of current gadget.  Note that this 
16533          * will not be set until after the initialization of the gadget.
16534          * @return {Boolean} The visibility of current gadget.
16535          */
16536         tabVisible: function(){
16537             return _visible;
16538         },
16539         
16540         /**
16541          * Make a request to check the current tab.  The 
16542          * activeTab event will be invoked if on the active tab.  This
16543          * method should be called after {@link finesse.containerservices.ContainerServices#addHandler}
16544          * to ensure the gadget gets properly initialized.
16545          */
16546         makeActiveTabReq : function () {
16547             if(_hub){
16548                 var data = {
16549                     type: "ActiveTabReq",
16550                     data: {},
16551                     invokeID: (new Date()).getTime()          
16552                 };
16553                 _hub.publish(_topics.REQUESTS, data);
16554             } else {
16555                 throw new Error("Hub is not defined.");
16556             }
16557             
16558         },
16559 
16560         //BEGIN TEST CODE//
16561         /**
16562          * Test code added to expose private functions that are used by unit test
16563          * framework. This section of code is removed during the build process
16564          * before packaging production code. The [begin|end]TestSection are used
16565          * by the build to identify the section to strip.
16566          * @ignore
16567          */
16568         beginTestSection : 0,
16569 
16570         /**
16571          * @ignore
16572          */
16573         getTestObject: function () {
16574             //Load mock dependencies.
16575             var _mock = new MockControl();
16576             _util = _mock.createMock(Utilities);
16577             _hub = _mock.createMock(gadgets.Hub);
16578             _inited = true;
16579             return {
16580                 //Expose mock dependencies
16581                 mock: _mock,
16582                 hub: _hub,
16583                 util: _util,
16584                 addHandler: this.addHandler,
16585                 removeHandler: this.removeHandler
16586             };
16587         },
16588 
16589         /**
16590          * @ignore
16591          */
16592        endTestSection: 0
16593         //END TEST CODE//
16594     };
16595     }());
16596     
16597     ContainerServices.Topics = /** @lends finesse.containerservices.ContainerServices.Topics.prototype */ {
16598         /**
16599          * Topic for subscribing to be notified when the active tab changes.
16600          * The provided callback will be invoked when the tab that the gadget 
16601          * that subscribes with this becomes active.  To ensure code is called
16602          * when the gadget is already on the active tab use the 
16603          * {@link finesse.containerservices.ContainerServices#makeActiveTabReq}
16604          * method.
16605          */
16606         ACTIVE_TAB: "finesse.containerservices.activeTab",
16607 
16608         /**
16609          * Topic for WorkflowAction events traffic.
16610          * The provided callback will be invoked when a WorkflowAction needs
16611          * to be handled.  The callback will be passed a {@link finesse.containerservices.WorkflowActionEvent}
16612          * that can be used to interrogate the WorkflowAction and determine to use or not.
16613          */
16614         WORKFLOW_ACTION_EVENT: "finesse.containerservices.workflowActionEvent",
16615         
16616         /**
16617          * @class This is the set of Topics used for subscribing for events from ContainerServices.
16618          * Use {@link finesse.containerservices.ContainerServices#addHandler} to subscribe to the topic.
16619          * 
16620          * @constructs
16621          */
16622         _fakeConstructor : function () {} // For JS Doc to work need a constructor so that the lends/constructs build the doc properly
16623     };
16624     
16625     window.finesse = window.finesse || {};
16626     window.finesse.containerservices = window.finesse.containerservices || {};
16627     window.finesse.containerservices.ContainerServices = ContainerServices;
16628 
16629     return ContainerServices;
16630  }));
16631 
16632 /**
16633  * This "interface" is just a way to easily jsdoc the Object callback handlers.
16634  *
16635  * @requires finesse.clientservices.ClientServices
16636  * @requires Class
16637  */
16638 /** @private */
16639 (function (factory) {
16640     
16641 
16642     // Define as an AMD module if possible
16643     if ( typeof define === 'function' && define.amd )
16644     {
16645         define('interfaces/RestObjectHandlers', ["FinesseBase",
16646                  "utilities/Utilities",
16647                  "restservices/Notifier",
16648                  "clientservices/ClientServices",
16649                  "clientservices/Topics"], factory );
16650     }
16651     /* Define using browser globals otherwise
16652      * Prevent multiple instantiations if the script is loaded twice
16653      */
16654     else
16655     {
16656         factory(finesse.FinesseBase, finesse.utilities.Utilities,
16657                 finesse.restservices.Notifier,
16658                 finesse.clientservices.ClientServices,
16659                 finesse.clientservices.Topics);
16660     } 
16661 }(function () {
16662 
16663     var RestObjectHandlers = ( function () { /** @lends finesse.interfaces.RestObjectHandlers.prototype */
16664         
16665         return {
16666 
16667             /**
16668              * @class
16669              * This "interface" defines REST Object callback handlers, passed as an argument to
16670              * Object getter methods in cases where the Object is going to be created.
16671              * 
16672              * @param {Object} [handlers]
16673              *     An object containing callback handlers for instantiation and runtime
16674              *     Callback to invoke upon successful instantiation, passes in REST object.
16675              * @param {Function} [handlers.onLoad(this)]
16676              *     Callback to invoke upon loading the data for the first time.
16677              * @param {Function} [handlers.onChange(this)]
16678              *     Callback to invoke upon successful update object (PUT)
16679              * @param {Function} [handlers.onAdd(this)]
16680              *     Callback to invoke upon successful update to add object (POST)
16681              * @param {Function} [handlers.onDelete(this)]
16682              *     Callback to invoke upon successful update to delete object (DELETE)
16683              * @param {Function} [handlers.onError(rsp)]
16684              *     Callback to invoke on update error (refresh or event)
16685              *     as passed by finesse.restservices.RestBase.restRequest()<br>
16686              *     {<br>
16687              *         status: {Number} The HTTP status code returned<br>
16688              *         content: {String} Raw string of response<br>
16689              *         object: {Object} Parsed object of response<br>
16690              *         error: {Object} Wrapped exception that was caught<br>
16691              *         error.errorType: {String} Type of error that was caught<br>
16692              *         error.errorMessage: {String} Message associated with error<br>
16693              *     }<br>
16694              *     <br>
16695              * Note that RestCollections have two additional callback handlers:<br>
16696              * <br>
16697              * @param {Function} [handlers.onCollectionAdd(this)]: when an object is added to this collection
16698              * @param {Function} [handlers.onCollectionDelete(this)]: when an object is removed from this collection
16699 
16700              * @constructs
16701              */
16702             _fakeConstuctor: function () {
16703                 /* This is here to enable jsdoc to document this as a class. */
16704             }
16705         };
16706     }());
16707 
16708 window.finesse = window.finesse || {};
16709 window.finesse.interfaces = window.finesse.interfaces || {};
16710 window.finesse.interfaces.RestObjectHandlers = RestObjectHandlers;
16711 
16712 return RestObjectHandlers;
16713 
16714 }));
16715 
16716 
16717 /**
16718  * This "interface" is just a way to easily jsdoc the REST request handlers.
16719  *
16720  * @requires finesse.clientservices.ClientServices
16721  * @requires Class
16722  */
16723 /** @private */
16724 (function (factory) {
16725     
16726 
16727     // Define as an AMD module if possible
16728     if ( typeof define === 'function' && define.amd )
16729     {
16730         define('interfaces/RequestHandlers', ["FinesseBase",
16731                  "utilities/Utilities",
16732                  "restservices/Notifier",
16733                  "clientservices/ClientServices",
16734                  "clientservices/Topics"], factory );
16735     }
16736     /* Define using browser globals otherwise
16737      * Prevent multiple instantiations if the script is loaded twice
16738      */
16739     else
16740     {
16741         factory(finesse.FinesseBase, finesse.utilities.Utilities,
16742                 finesse.restservices.Notifier,
16743                 finesse.clientservices.ClientServices,
16744                 finesse.clientservices.Topics);
16745     } 
16746 }(function () {
16747 
16748     var RequestHandlers = ( function () { /** @lends finesse.interfaces.RequestHandlers.prototype */
16749         
16750         return {
16751 
16752             /**
16753              * @class
16754              * This "interface" defines REST Object callback handlers, passed as an argument to
16755              * Object getter methods in cases where the Object is going to be created.
16756              * 
16757              * @param {Object} handlers
16758              *     An object containing the following (optional) handlers for the request:<ul>
16759              *         <li><b>success(rsp):</b> A callback function for a successful request to be invoked with the following
16760              *         response object as its only parameter:<ul>
16761              *             <li><b>status:</b> {Number} The HTTP status code returned</li>
16762              *             <li><b>content:</b> {String} Raw string of response</li>
16763              *             <li><b>object:</b> {Object} Parsed object of response</li></ul>
16764              *         <li><b>error(rsp):</b> An error callback function for an unsuccessful request to be invoked with the
16765              *         error response object as its only parameter:<ul>
16766              *             <li><b>status:</b> {Number} The HTTP status code returned</li>
16767              *             <li><b>content:</b> {String} Raw string of response</li>
16768              *             <li><b>object:</b> {Object} Parsed object of response (HTTP errors)</li>
16769              *             <li><b>error:</b> {Object} Wrapped exception that was caught:<ul>
16770              *                 <li><b>errorType:</b> {String} Type of error that was caught</li>
16771              *                 <li><b>errorMessage:</b> {String} Message associated with error</li>
16772              *             </ul></li>
16773              *         </ul>
16774 
16775              * @constructs 
16776              */
16777             _fakeConstuctor: function () {
16778                 /* This is here to enable jsdoc to document this as a class. */
16779             }
16780         };
16781     }());
16782 
16783 window.finesse = window.finesse || {};
16784 window.finesse.interfaces = window.finesse.interfaces || {};
16785 window.finesse.interfaces.RequestHandlers = RequestHandlers;
16786 
16787 finesse = finesse || {};
16788 /** @namespace These interfaces are just a convenience for documenting common parameter structures. */
16789 finesse.interfaces = finesse.interfaces || {};
16790 
16791 return RequestHandlers;
16792 
16793 }));
16794 
16795 
16796 (function (factory) {
16797     
16798 
16799     // Define as an AMD module if possible
16800     if ( typeof define === 'function' && define.amd )
16801     {
16802         define('finesse-desktop', [], factory );
16803     }
16804     /* Define using browser globals otherwise
16805      * Prevent multiple instantiations if the script is loaded twice
16806      */
16807     else
16808     {
16809         factory();
16810     }
16811 }(function () {
16812     if (typeof require === 'function') {
16813         (function () {
16814             /*
16815               The 'paths' section lets you define keys to refer to libraries
16816               so you don't have to to refer to them by their full paths everywhere.
16817 
16818               This removes the need to refer to 3rd-party libraries using the '3rdparty' path,
16819               and the need to refer to patched libaries using the '.patched' suffix.
16820 
16821               These keys are usable inside all require() calls inside each gadget module.
16822             */
16823             require.config({
16824                 paths : {
16825                     'Math.uuid' : '../thirdparty/util/Math.uuid',
16826                     'iso8601' : '../thirdparty/util/iso8601'
16827                 },
16828 
16829                 /*
16830                   This 'shim' section lets you specify a dependency tree for all libaries that are NOT AMD modules.
16831                   (AMD modules always contain a 'define()' call. For more information about AMD: https://github.com/amdjs/amdjs-api/wiki/AMD)
16832 
16833                   ** DO NOT list any AMD modules in this 'shim' section. **
16834 
16835                   The format is 'libraryKey': ['dependencyKey1', 'dependencyKey2' ...]. Both keys can refer to any JS module
16836                   or one of the 'path' keys listed above.
16837 
16838                   FOR EXAMPLE:
16839                     dataTables depends on jQuery, but all of the dataTables plugins depend on dataTables.
16840                     We can refer to 'dataTables' and 'dataTables.scroller' as keys on the left side
16841                     since those are aliases defined in the 'paths' section above.
16842 
16843                   NOTE: Most jQuery plugins ARE NOT AMD modules, so when adding a new jQuery plugin that is not an AMD module,
16844                   make sure it has jquery listed as a dependency here (similar to all of the boostrap-* plugins, jquery.cookie, etc.)
16845 
16846                   Official documentation on RequireJS shim configuration: http://requirejs.org/docs/api.html#config-shim
16847                 */
16848                 shim : {
16849                     'Math.uuid' : {
16850                         exports : 'Math'
16851                     }
16852                 }
16853             });
16854             
16855             //All modules in this list (and their dependencies) will be concatenated into one file to be used in the container and gadgets
16856             require(['restservices/Users',
16857                      'restservices/Teams',
16858                      'restservices/SystemInfo',
16859                      'utilities/I18n',
16860                      'utilities/Logger',
16861                      'utilities/SaxParser',
16862                      'cslogger/ClientLogger',
16863                      'cslogger/FinesseLogger',
16864                      'containerservices/ContainerServices',
16865                      'interfaces/RestObjectHandlers',
16866                      'interfaces/RequestHandlers'], function() {
16867                 // Do nothing                
16868             });
16869         }.bind(this)());
16870     }
16871 
16872     // If being used in a gadget, stuff the auth string into the gadget prefs
16873     if (gadgets.Prefs) {
16874         var _prefs = new gadgets.Prefs(),
16875         authString = finesse.utilities.Utilities.getCookie("finesse_authorization");
16876         _prefs.set("authorization", authString);
16877     }
16878 }));
16879