/* Minification failed. Returning unminified contents.
(26806,213-221): run-time error JS1300: Strict-mode does not allow assignment to undefined variables: Sortable
 */
/*! jQuery v2.1.0 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k="".trim,l={},m=a.document,n="2.1.0",o=function(a,b){return new o.fn.init(a,b)},p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};o.fn=o.prototype={jquery:n,constructor:o,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=o.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return o.each(this,a,b)},map:function(a){return this.pushStack(o.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},o.extend=o.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||o.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(o.isPlainObject(d)||(e=o.isArray(d)))?(e?(e=!1,f=c&&o.isArray(c)?c:[]):f=c&&o.isPlainObject(c)?c:{},g[b]=o.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},o.extend({expando:"jQuery"+(n+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===o.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return a-parseFloat(a)>=0},isPlainObject:function(a){if("object"!==o.type(a)||a.nodeType||o.isWindow(a))return!1;try{if(a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(b){return!1}return!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=o.trim(a),a&&(1===a.indexOf("use strict")?(b=m.createElement("script"),b.text=a,m.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":k.call(a)},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?o.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),o.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||o.guid++,f):void 0},now:Date.now,support:l}),o.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=o.type(a);return"function"===c||o.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s="sizzle"+-new Date,t=a.document,u=0,v=0,w=eb(),x=eb(),y=eb(),z=function(a,b){return a===b&&(j=!0),0},A="undefined",B=1<<31,C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=D.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",M=L.replace("w","w#"),N="\\["+K+"*("+L+")"+K+"*(?:([*^$|!~]?=)"+K+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+M+")|)|)"+K+"*\\]",O=":("+L+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+N.replace(3,8)+")*)|.*)\\)|)",P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(O),U=new RegExp("^"+M+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L.replace("w","w*")+")"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=/'|\\/g,ab=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),bb=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{G.apply(D=H.call(t.childNodes),t.childNodes),D[t.childNodes.length].nodeType}catch(cb){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function db(a,b,d,e){var f,g,h,i,j,m,p,q,u,v;if((b?b.ownerDocument||b:t)!==l&&k(b),b=b||l,d=d||[],!a||"string"!=typeof a)return d;if(1!==(i=b.nodeType)&&9!==i)return[];if(n&&!e){if(f=Z.exec(a))if(h=f[1]){if(9===i){if(g=b.getElementById(h),!g||!g.parentNode)return d;if(g.id===h)return d.push(g),d}else if(b.ownerDocument&&(g=b.ownerDocument.getElementById(h))&&r(b,g)&&g.id===h)return d.push(g),d}else{if(f[2])return G.apply(d,b.getElementsByTagName(a)),d;if((h=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(h)),d}if(c.qsa&&(!o||!o.test(a))){if(q=p=s,u=b,v=9===i&&a,1===i&&"object"!==b.nodeName.toLowerCase()){m=ob(a),(p=b.getAttribute("id"))?q=p.replace(_,"\\$&"):b.setAttribute("id",q),q="[id='"+q+"'] ",j=m.length;while(j--)m[j]=q+pb(m[j]);u=$.test(a)&&mb(b.parentNode)||b,v=m.join(",")}if(v)try{return G.apply(d,u.querySelectorAll(v)),d}catch(w){}finally{p||b.removeAttribute("id")}}}return xb(a.replace(P,"$1"),b,d,e)}function eb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function fb(a){return a[s]=!0,a}function gb(a){var b=l.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function hb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function ib(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||B)-(~a.sourceIndex||B);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function jb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function kb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function lb(a){return fb(function(b){return b=+b,fb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function mb(a){return a&&typeof a.getElementsByTagName!==A&&a}c=db.support={},f=db.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},k=db.setDocument=function(a){var b,e=a?a.ownerDocument||a:t,g=e.defaultView;return e!==l&&9===e.nodeType&&e.documentElement?(l=e,m=e.documentElement,n=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){k()},!1):g.attachEvent&&g.attachEvent("onunload",function(){k()})),c.attributes=gb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=gb(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(e.getElementsByClassName)&&gb(function(a){return a.innerHTML="<div class='a'></div><div class='a i'></div>",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=gb(function(a){return m.appendChild(a).id=s,!e.getElementsByName||!e.getElementsByName(s).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==A&&n){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){var c=typeof a.getAttributeNode!==A&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==A?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==A&&n?b.getElementsByClassName(a):void 0},p=[],o=[],(c.qsa=Y.test(e.querySelectorAll))&&(gb(function(a){a.innerHTML="<select t=''><option selected=''></option></select>",a.querySelectorAll("[t^='']").length&&o.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||o.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll(":checked").length||o.push(":checked")}),gb(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&o.push("name"+K+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||o.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),o.push(",.*:")})),(c.matchesSelector=Y.test(q=m.webkitMatchesSelector||m.mozMatchesSelector||m.oMatchesSelector||m.msMatchesSelector))&&gb(function(a){c.disconnectedMatch=q.call(a,"div"),q.call(a,"[s!='']:x"),p.push("!=",O)}),o=o.length&&new RegExp(o.join("|")),p=p.length&&new RegExp(p.join("|")),b=Y.test(m.compareDocumentPosition),r=b||Y.test(m.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},z=b?function(a,b){if(a===b)return j=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===t&&r(t,a)?-1:b===e||b.ownerDocument===t&&r(t,b)?1:i?I.call(i,a)-I.call(i,b):0:4&d?-1:1)}:function(a,b){if(a===b)return j=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],k=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:i?I.call(i,a)-I.call(i,b):0;if(f===g)return ib(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)k.unshift(c);while(h[d]===k[d])d++;return d?ib(h[d],k[d]):h[d]===t?-1:k[d]===t?1:0},e):l},db.matches=function(a,b){return db(a,null,null,b)},db.matchesSelector=function(a,b){if((a.ownerDocument||a)!==l&&k(a),b=b.replace(S,"='$1']"),!(!c.matchesSelector||!n||p&&p.test(b)||o&&o.test(b)))try{var d=q.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return db(b,l,null,[a]).length>0},db.contains=function(a,b){return(a.ownerDocument||a)!==l&&k(a),r(a,b)},db.attr=function(a,b){(a.ownerDocument||a)!==l&&k(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!n):void 0;return void 0!==f?f:c.attributes||!n?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},db.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},db.uniqueSort=function(a){var b,d=[],e=0,f=0;if(j=!c.detectDuplicates,i=!c.sortStable&&a.slice(0),a.sort(z),j){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return i=null,a},e=db.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=db.selectors={cacheLength:50,createPseudo:fb,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ab,bb),a[3]=(a[4]||a[5]||"").replace(ab,bb),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||db.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&db.error(a[0]),a},PSEUDO:function(a){var b,c=!a[5]&&a[2];return V.CHILD.test(a[0])?null:(a[3]&&void 0!==a[4]?a[2]=a[4]:c&&T.test(c)&&(b=ob(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ab,bb).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=w[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&w(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==A&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=db.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),t=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&t){k=q[s]||(q[s]={}),j=k[a]||[],n=j[0]===u&&j[1],m=j[0]===u&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[u,n,m];break}}else if(t&&(j=(b[s]||(b[s]={}))[a])&&j[0]===u)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(t&&((l[s]||(l[s]={}))[a]=[u,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||db.error("unsupported pseudo: "+a);return e[s]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?fb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:fb(function(a){var b=[],c=[],d=g(a.replace(P,"$1"));return d[s]?fb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:fb(function(a){return function(b){return db(a,b).length>0}}),contains:fb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:fb(function(a){return U.test(a||"")||db.error("unsupported lang: "+a),a=a.replace(ab,bb).toLowerCase(),function(b){var c;do if(c=n?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===m},focus:function(a){return a===l.activeElement&&(!l.hasFocus||l.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:lb(function(){return[0]}),last:lb(function(a,b){return[b-1]}),eq:lb(function(a,b,c){return[0>c?c+b:c]}),even:lb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:lb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:lb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:lb(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=jb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=kb(b);function nb(){}nb.prototype=d.filters=d.pseudos,d.setFilters=new nb;function ob(a,b){var c,e,f,g,h,i,j,k=x[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=Q.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=R.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(P," ")}),h=h.slice(c.length));for(g in d.filter)!(e=V[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?db.error(a):x(a,i).slice(0)}function pb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function qb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=v++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[u,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[s]||(b[s]={}),(h=i[d])&&h[0]===u&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function rb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function sb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function tb(a,b,c,d,e,f){return d&&!d[s]&&(d=tb(d)),e&&!e[s]&&(e=tb(e,f)),fb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||wb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:sb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=sb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=sb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ub(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],i=g||d.relative[" "],j=g?1:0,k=qb(function(a){return a===b},i,!0),l=qb(function(a){return I.call(b,a)>-1},i,!0),m=[function(a,c,d){return!g&&(d||c!==h)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>j;j++)if(c=d.relative[a[j].type])m=[qb(rb(m),c)];else{if(c=d.filter[a[j].type].apply(null,a[j].matches),c[s]){for(e=++j;f>e;e++)if(d.relative[a[e].type])break;return tb(j>1&&rb(m),j>1&&pb(a.slice(0,j-1).concat({value:" "===a[j-2].type?"*":""})).replace(P,"$1"),c,e>j&&ub(a.slice(j,e)),f>e&&ub(a=a.slice(e)),f>e&&pb(a))}m.push(c)}return rb(m)}function vb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,i,j,k){var m,n,o,p=0,q="0",r=f&&[],s=[],t=h,v=f||e&&d.find.TAG("*",k),w=u+=null==t?1:Math.random()||.1,x=v.length;for(k&&(h=g!==l&&g);q!==x&&null!=(m=v[q]);q++){if(e&&m){n=0;while(o=a[n++])if(o(m,g,i)){j.push(m);break}k&&(u=w)}c&&((m=!o&&m)&&p--,f&&r.push(m))}if(p+=q,c&&q!==p){n=0;while(o=b[n++])o(r,s,g,i);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=E.call(j));s=sb(s)}G.apply(j,s),k&&!f&&s.length>0&&p+b.length>1&&db.uniqueSort(j)}return k&&(u=w,h=t),r};return c?fb(f):f}g=db.compile=function(a,b){var c,d=[],e=[],f=y[a+" "];if(!f){b||(b=ob(a)),c=b.length;while(c--)f=ub(b[c]),f[s]?d.push(f):e.push(f);f=y(a,vb(e,d))}return f};function wb(a,b,c){for(var d=0,e=b.length;e>d;d++)db(a,b[d],c);return c}function xb(a,b,e,f){var h,i,j,k,l,m=ob(a);if(!f&&1===m.length){if(i=m[0]=m[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&c.getById&&9===b.nodeType&&n&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(ab,bb),b)||[])[0],!b)return e;a=a.slice(i.shift().value.length)}h=V.needsContext.test(a)?0:i.length;while(h--){if(j=i[h],d.relative[k=j.type])break;if((l=d.find[k])&&(f=l(j.matches[0].replace(ab,bb),$.test(i[0].type)&&mb(b.parentNode)||b))){if(i.splice(h,1),a=f.length&&pb(i),!a)return G.apply(e,f),e;break}}}return g(a,m)(f,b,!n,e,$.test(a)&&mb(b.parentNode)||b),e}return c.sortStable=s.split("").sort(z).join("")===s,c.detectDuplicates=!!j,k(),c.sortDetached=gb(function(a){return 1&a.compareDocumentPosition(l.createElement("div"))}),gb(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||hb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&gb(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||hb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),gb(function(a){return null==a.getAttribute("disabled")})||hb(J,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),db}(a);o.find=t,o.expr=t.selectors,o.expr[":"]=o.expr.pseudos,o.unique=t.uniqueSort,o.text=t.getText,o.isXMLDoc=t.isXML,o.contains=t.contains;var u=o.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(o.isFunction(b))return o.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return o.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return o.filter(b,a,c);b=o.filter(b,a)}return o.grep(a,function(a){return g.call(b,a)>=0!==c})}o.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?o.find.matchesSelector(d,a)?[d]:[]:o.find.matches(a,o.grep(b,function(a){return 1===a.nodeType}))},o.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(o(a).filter(function(){for(b=0;c>b;b++)if(o.contains(e[b],this))return!0}));for(b=0;c>b;b++)o.find(a,e[b],d);return d=this.pushStack(c>1?o.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?o(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=o.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof o?b[0]:b,o.merge(this,o.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:m,!0)),v.test(c[1])&&o.isPlainObject(b))for(c in b)o.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=m.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=m,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):o.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(o):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),o.makeArray(a,this))};A.prototype=o.fn,y=o(m);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};o.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&o(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),o.fn.extend({has:function(a){var b=o(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(o.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?o(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&o.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?o.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(o(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(o.unique(o.merge(this.get(),o(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}o.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return o.dir(a,"parentNode")},parentsUntil:function(a,b,c){return o.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return o.dir(a,"nextSibling")},prevAll:function(a){return o.dir(a,"previousSibling")},nextUntil:function(a,b,c){return o.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return o.dir(a,"previousSibling",c)},siblings:function(a){return o.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return o.sibling(a.firstChild)},contents:function(a){return a.contentDocument||o.merge([],a.childNodes)}},function(a,b){o.fn[a]=function(c,d){var e=o.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=o.filter(d,e)),this.length>1&&(C[a]||o.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return o.each(a.match(E)||[],function(a,c){b[c]=!0}),b}o.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):o.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){o.each(b,function(b,c){var d=o.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&o.each(arguments,function(a,b){var c;while((c=o.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?o.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},o.extend({Deferred:function(a){var b=[["resolve","done",o.Callbacks("once memory"),"resolved"],["reject","fail",o.Callbacks("once memory"),"rejected"],["notify","progress",o.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return o.Deferred(function(c){o.each(b,function(b,f){var g=o.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&o.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?o.extend(a,d):d}},e={};return d.pipe=d.then,o.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&o.isFunction(a.promise)?e:0,g=1===f?a:o.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&o.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;o.fn.ready=function(a){return o.ready.promise().done(a),this},o.extend({isReady:!1,readyWait:1,holdReady:function(a){a?o.readyWait++:o.ready(!0)},ready:function(a){(a===!0?--o.readyWait:o.isReady)||(o.isReady=!0,a!==!0&&--o.readyWait>0||(H.resolveWith(m,[o]),o.fn.trigger&&o(m).trigger("ready").off("ready")))}});function I(){m.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),o.ready()}o.ready.promise=function(b){return H||(H=o.Deferred(),"complete"===m.readyState?setTimeout(o.ready):(m.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},o.ready.promise();var J=o.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===o.type(c)){e=!0;for(h in c)o.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,o.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(o(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};o.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=o.expando+Math.random()}K.uid=1,K.accepts=o.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,o.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(o.isEmptyObject(f))o.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,o.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{o.isArray(b)?d=b.concat(b.map(o.camelCase)):(e=o.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!o.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?o.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}o.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),o.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;
while(c--)d=g[c].name,0===d.indexOf("data-")&&(d=o.camelCase(d.slice(5)),P(f,d,e[d]));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=o.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),o.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||o.isArray(c)?d=L.access(a,b,o.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=o.queue(a,b),d=c.length,e=c.shift(),f=o._queueHooks(a,b),g=function(){o.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:o.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),o.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?o.queue(this[0],a):void 0===b?this:this.each(function(){var c=o.queue(this,a,b);o._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&o.dequeue(this,a)})},dequeue:function(a){return this.each(function(){o.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=o.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=L.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var Q=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,R=["Top","Right","Bottom","Left"],S=function(a,b){return a=b||a,"none"===o.css(a,"display")||!o.contains(a.ownerDocument,a)},T=/^(?:checkbox|radio)$/i;!function(){var a=m.createDocumentFragment(),b=a.appendChild(m.createElement("div"));b.innerHTML="<input type='radio' checked='checked' name='t'/>",l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";l.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return m.activeElement}catch(a){}}o.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=o.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof o!==U&&o.event.triggered!==b.type?o.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],n=q=h[1],p=(h[2]||"").split(".").sort(),n&&(l=o.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=o.event.special[n]||{},k=o.extend({type:n,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&o.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(n,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),o.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],n=q=h[1],p=(h[2]||"").split(".").sort(),n){l=o.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||o.removeEvent(a,n,r.handle),delete i[n])}else for(n in i)o.event.remove(a,n+b[j],c,d,!0);o.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,p=[d||m],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||m,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+o.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[o.expando]?b:new o.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:o.makeArray(c,[b]),n=o.event.special[q]||{},e||!n.trigger||n.trigger.apply(d,c)!==!1)){if(!e&&!n.noBubble&&!o.isWindow(d)){for(i=n.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||m)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:n.bindType||q,l=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),l&&l.apply(g,c),l=k&&g[k],l&&l.apply&&o.acceptData(g)&&(b.result=l.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||n._default&&n._default.apply(p.pop(),c)!==!1||!o.acceptData(d)||k&&o.isFunction(d[q])&&!o.isWindow(d)&&(h=d[k],h&&(d[k]=null),o.event.triggered=q,d[q](),o.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=o.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=o.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=o.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((o.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?o(e,this).index(i)>=0:o.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button;return null==a.pageX&&null!=b.clientX&&(c=a.target.ownerDocument||m,d=c.documentElement,e=c.body,a.pageX=b.clientX+(d&&d.scrollLeft||e&&e.scrollLeft||0)-(d&&d.clientLeft||e&&e.clientLeft||0),a.pageY=b.clientY+(d&&d.scrollTop||e&&e.scrollTop||0)-(d&&d.clientTop||e&&e.clientTop||0)),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},fix:function(a){if(a[o.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=W.test(e)?this.mouseHooks:V.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new o.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=m),3===a.target.nodeType&&(a.target=a.target.parentNode),g.filter?g.filter(a,f):a},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==_()&&this.focus?(this.focus(),!1):void 0},delegateType:"focusin"},blur:{trigger:function(){return this===_()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&o.nodeName(this,"input")?(this.click(),!1):void 0},_default:function(a){return o.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=o.extend(new o.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?o.event.trigger(e,null,b):o.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},o.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)},o.Event=function(a,b){return this instanceof o.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.getPreventDefault&&a.getPreventDefault()?Z:$):this.type=a,b&&o.extend(this,b),this.timeStamp=a&&a.timeStamp||o.now(),void(this[o.expando]=!0)):new o.Event(a,b)},o.Event.prototype={isDefaultPrevented:$,isPropagationStopped:$,isImmediatePropagationStopped:$,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=Z,a&&a.preventDefault&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=Z,a&&a.stopPropagation&&a.stopPropagation()},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z,this.stopPropagation()}},o.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){o.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!o.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),l.focusinBubbles||o.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){o.event.simulate(b,a.target,o.event.fix(a),!0)};o.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=L.access(d,b);e||d.addEventListener(a,c,!0),L.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=L.access(d,b)-1;e?L.access(d,b,e):(d.removeEventListener(a,c,!0),L.remove(d,b))}}}),o.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(g in a)this.on(g,b,c,a[g],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=$;else if(!d)return this;return 1===e&&(f=d,d=function(a){return o().off(a),f.apply(this,arguments)},d.guid=f.guid||(f.guid=o.guid++)),this.each(function(){o.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,o(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=$),this.each(function(){o.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){o.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?o.event.trigger(a,b,c,!0):void 0}});var ab=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ib={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return o.nodeName(a,"table")&&o.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)o.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=o.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&o.nodeName(a,b)?o.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}o.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=o.contains(a.ownerDocument,a);if(!(l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||o.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,n=a.length;n>m;m++)if(e=a[m],e||0===e)if("object"===o.type(e))o.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1></$2>")+h[2],j=h[0];while(j--)f=f.lastChild;o.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===o.inArray(e,d))&&(i=o.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f,g,h=o.event.special,i=0;void 0!==(c=a[i]);i++){if(o.acceptData(c)&&(f=c[L.expando],f&&(b=L.cache[f]))){if(d=Object.keys(b.events||{}),d.length)for(g=0;void 0!==(e=d[g]);g++)h[e]?o.event.remove(c,e):o.removeEvent(c,e,b.handle);L.cache[f]&&delete L.cache[f]}delete M.cache[c[M.expando]]}}}),o.fn.extend({text:function(a){return J(this,function(a){return void 0===a?o.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?o.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||o.cleanData(ob(c)),c.parentNode&&(b&&o.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(o.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return o.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(o.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,o.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,k=this.length,m=this,n=k-1,p=a[0],q=o.isFunction(p);if(q||k>1&&"string"==typeof p&&!l.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(k&&(c=o.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=o.map(ob(c,"script"),kb),g=f.length;k>j;j++)h=c,j!==n&&(h=o.clone(h,!0,!0),g&&o.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,o.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&o.contains(i,h)&&(h.src?o._evalUrl&&o._evalUrl(h.src):o.globalEval(h.textContent.replace(hb,"")))}return this}}),o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){o.fn[a]=function(a){for(var c,d=[],e=o(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),o(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d=o(c.createElement(b)).appendTo(c.body),e=a.getDefaultComputedStyle?a.getDefaultComputedStyle(d[0]).display:o.css(d[0],"display");return d.detach(),e}function tb(a){var b=m,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||o("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=qb[0].contentDocument,b.write(),b.close(),c=sb(a,b),qb.detach()),rb[a]=c),c}var ub=/^margin/,vb=new RegExp("^("+Q+")(?!px)[a-z%]+$","i"),wb=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)};function xb(a,b,c){var d,e,f,g,h=a.style;return c=c||wb(a),c&&(g=c.getPropertyValue(b)||c[b]),c&&(""!==g||o.contains(a.ownerDocument,a)||(g=o.style(a,b)),vb.test(g)&&ub.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function yb(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d="padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",e=m.documentElement,f=m.createElement("div"),g=m.createElement("div");g.style.backgroundClip="content-box",g.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===g.style.backgroundClip,f.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",f.appendChild(g);function h(){g.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%",e.appendChild(f);var d=a.getComputedStyle(g,null);b="1%"!==d.top,c="4px"===d.width,e.removeChild(f)}a.getComputedStyle&&o.extend(l,{pixelPosition:function(){return h(),b},boxSizingReliable:function(){return null==c&&h(),c},reliableMarginRight:function(){var b,c=g.appendChild(m.createElement("div"));return c.style.cssText=g.style.cssText=d,c.style.marginRight=c.style.width="0",g.style.width="1px",e.appendChild(f),b=!parseFloat(a.getComputedStyle(c,null).marginRight),e.removeChild(f),g.innerHTML="",b}})}(),o.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var zb=/^(none|table(?!-c[ea]).+)/,Ab=new RegExp("^("+Q+")(.*)$","i"),Bb=new RegExp("^([+-])=("+Q+")","i"),Cb={position:"absolute",visibility:"hidden",display:"block"},Db={letterSpacing:0,fontWeight:400},Eb=["Webkit","O","Moz","ms"];function Fb(a,b){if(b in a)return b;var c=b[0].toUpperCase()+b.slice(1),d=b,e=Eb.length;while(e--)if(b=Eb[e]+c,b in a)return b;return d}function Gb(a,b,c){var d=Ab.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Hb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=o.css(a,c+R[f],!0,e)),d?("content"===c&&(g-=o.css(a,"padding"+R[f],!0,e)),"margin"!==c&&(g-=o.css(a,"border"+R[f]+"Width",!0,e))):(g+=o.css(a,"padding"+R[f],!0,e),"padding"!==c&&(g+=o.css(a,"border"+R[f]+"Width",!0,e)));return g}function Ib(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=wb(a),g="border-box"===o.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=xb(a,b,f),(0>e||null==e)&&(e=a.style[b]),vb.test(e))return e;d=g&&(l.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Hb(a,b,c||(g?"border":"content"),d,f)+"px"}function Jb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=L.get(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&S(d)&&(f[g]=L.access(d,"olddisplay",tb(d.nodeName)))):f[g]||(e=S(d),(c&&"none"!==c||!e)&&L.set(d,"olddisplay",e?c:o.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}o.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=xb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=o.camelCase(b),i=a.style;return b=o.cssProps[h]||(o.cssProps[h]=Fb(i,h)),g=o.cssHooks[b]||o.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=Bb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(o.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||o.cssNumber[h]||(c+="px"),l.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]="",i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=o.camelCase(b);return b=o.cssProps[h]||(o.cssProps[h]=Fb(a.style,h)),g=o.cssHooks[b]||o.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=xb(a,b,d)),"normal"===e&&b in Db&&(e=Db[b]),""===c||c?(f=parseFloat(e),c===!0||o.isNumeric(f)?f||0:e):e}}),o.each(["height","width"],function(a,b){o.cssHooks[b]={get:function(a,c,d){return c?0===a.offsetWidth&&zb.test(o.css(a,"display"))?o.swap(a,Cb,function(){return Ib(a,b,d)}):Ib(a,b,d):void 0},set:function(a,c,d){var e=d&&wb(a);return Gb(a,c,d?Hb(a,b,d,"border-box"===o.css(a,"boxSizing",!1,e),e):0)}}}),o.cssHooks.marginRight=yb(l.reliableMarginRight,function(a,b){return b?o.swap(a,{display:"inline-block"},xb,[a,"marginRight"]):void 0}),o.each({margin:"",padding:"",border:"Width"},function(a,b){o.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+R[d]+b]=f[d]||f[d-2]||f[0];return e}},ub.test(a)||(o.cssHooks[a+b].set=Gb)}),o.fn.extend({css:function(a,b){return J(this,function(a,b,c){var d,e,f={},g=0;if(o.isArray(b)){for(d=wb(a),e=b.length;e>g;g++)f[b[g]]=o.css(a,b[g],!1,d);return f}return void 0!==c?o.style(a,b,c):o.css(a,b)},a,b,arguments.length>1)},show:function(){return Jb(this,!0)},hide:function(){return Jb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){S(this)?o(this).show():o(this).hide()})}});function Kb(a,b,c,d,e){return new Kb.prototype.init(a,b,c,d,e)}o.Tween=Kb,Kb.prototype={constructor:Kb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(o.cssNumber[c]?"":"px")},cur:function(){var a=Kb.propHooks[this.prop];return a&&a.get?a.get(this):Kb.propHooks._default.get(this)},run:function(a){var b,c=Kb.propHooks[this.prop];return this.pos=b=this.options.duration?o.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Kb.propHooks._default.set(this),this}},Kb.prototype.init.prototype=Kb.prototype,Kb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=o.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){o.fx.step[a.prop]?o.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[o.cssProps[a.prop]]||o.cssHooks[a.prop])?o.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Kb.propHooks.scrollTop=Kb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},o.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},o.fx=Kb.prototype.init,o.fx.step={};var Lb,Mb,Nb=/^(?:toggle|show|hide)$/,Ob=new RegExp("^(?:([+-])=|)("+Q+")([a-z%]*)$","i"),Pb=/queueHooks$/,Qb=[Vb],Rb={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=Ob.exec(b),f=e&&e[3]||(o.cssNumber[a]?"":"px"),g=(o.cssNumber[a]||"px"!==f&&+d)&&Ob.exec(o.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,o.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function Sb(){return setTimeout(function(){Lb=void 0}),Lb=o.now()}function Tb(a,b){var c,d=0,e={height:a};for(b=b?1:0;4>d;d+=2-b)c=R[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function Ub(a,b,c){for(var d,e=(Rb[b]||[]).concat(Rb["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function Vb(a,b,c){var d,e,f,g,h,i,j,k=this,l={},m=a.style,n=a.nodeType&&S(a),p=L.get(a,"fxshow");c.queue||(h=o._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,k.always(function(){k.always(function(){h.unqueued--,o.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[m.overflow,m.overflowX,m.overflowY],j=o.css(a,"display"),"none"===j&&(j=tb(a.nodeName)),"inline"===j&&"none"===o.css(a,"float")&&(m.display="inline-block")),c.overflow&&(m.overflow="hidden",k.always(function(){m.overflow=c.overflow[0],m.overflowX=c.overflow[1],m.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],Nb.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(n?"hide":"show")){if("show"!==e||!p||void 0===p[d])continue;n=!0}l[d]=p&&p[d]||o.style(a,d)}if(!o.isEmptyObject(l)){p?"hidden"in p&&(n=p.hidden):p=L.access(a,"fxshow",{}),f&&(p.hidden=!n),n?o(a).show():k.done(function(){o(a).hide()}),k.done(function(){var b;L.remove(a,"fxshow");for(b in l)o.style(a,b,l[b])});for(d in l)g=Ub(n?p[d]:0,d,k),d in p||(p[d]=g.start,n&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function Wb(a,b){var c,d,e,f,g;for(c in a)if(d=o.camelCase(c),e=b[d],f=a[c],o.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=o.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function Xb(a,b,c){var d,e,f=0,g=Qb.length,h=o.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=Lb||Sb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:o.extend({},b),opts:o.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:Lb||Sb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=o.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(Wb(k,j.opts.specialEasing);g>f;f++)if(d=Qb[f].call(j,a,k,j.opts))return d;return o.map(k,Ub,j),o.isFunction(j.opts.start)&&j.opts.start.call(a,j),o.fx.timer(o.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}o.Animation=o.extend(Xb,{tweener:function(a,b){o.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],Rb[c]=Rb[c]||[],Rb[c].unshift(b)},prefilter:function(a,b){b?Qb.unshift(a):Qb.push(a)}}),o.speed=function(a,b,c){var d=a&&"object"==typeof a?o.extend({},a):{complete:c||!c&&b||o.isFunction(a)&&a,duration:a,easing:c&&b||b&&!o.isFunction(b)&&b};return d.duration=o.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in o.fx.speeds?o.fx.speeds[d.duration]:o.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){o.isFunction(d.old)&&d.old.call(this),d.queue&&o.dequeue(this,d.queue)},d},o.fn.extend({fadeTo:function(a,b,c,d){return this.filter(S).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=o.isEmptyObject(a),f=o.speed(b,c,d),g=function(){var b=Xb(this,o.extend({},a),f);(e||L.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=o.timers,g=L.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&Pb.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&o.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=L.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=o.timers,g=d?d.length:0;for(c.finish=!0,o.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),o.each(["toggle","show","hide"],function(a,b){var c=o.fn[b];o.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(Tb(b,!0),a,d,e)}}),o.each({slideDown:Tb("show"),slideUp:Tb("hide"),slideToggle:Tb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){o.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),o.timers=[],o.fx.tick=function(){var a,b=0,c=o.timers;for(Lb=o.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||o.fx.stop(),Lb=void 0},o.fx.timer=function(a){o.timers.push(a),a()?o.fx.start():o.timers.pop()},o.fx.interval=13,o.fx.start=function(){Mb||(Mb=setInterval(o.fx.tick,o.fx.interval))},o.fx.stop=function(){clearInterval(Mb),Mb=null},o.fx.speeds={slow:600,fast:200,_default:400},o.fn.delay=function(a,b){return a=o.fx?o.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a=m.createElement("input"),b=m.createElement("select"),c=b.appendChild(m.createElement("option"));a.type="checkbox",l.checkOn=""!==a.value,l.optSelected=c.selected,b.disabled=!0,l.optDisabled=!c.disabled,a=m.createElement("input"),a.value="t",a.type="radio",l.radioValue="t"===a.value}();var Yb,Zb,$b=o.expr.attrHandle;o.fn.extend({attr:function(a,b){return J(this,o.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){o.removeAttr(this,a)})}}),o.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===U?o.prop(a,b,c):(1===f&&o.isXMLDoc(a)||(b=b.toLowerCase(),d=o.attrHooks[b]||(o.expr.match.bool.test(b)?Zb:Yb)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=o.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void o.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=o.propFix[c]||c,o.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)},attrHooks:{type:{set:function(a,b){if(!l.radioValue&&"radio"===b&&o.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),Zb={set:function(a,b,c){return b===!1?o.removeAttr(a,c):a.setAttribute(c,c),c}},o.each(o.expr.match.bool.source.match(/\w+/g),function(a,b){var c=$b[b]||o.find.attr;$b[b]=function(a,b,d){var e,f;
return d||(f=$b[b],$b[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,$b[b]=f),e}});var _b=/^(?:input|select|textarea|button)$/i;o.fn.extend({prop:function(a,b){return J(this,o.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[o.propFix[a]||a]})}}),o.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!o.isXMLDoc(a),f&&(b=o.propFix[b]||b,e=o.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){return a.hasAttribute("tabindex")||_b.test(a.nodeName)||a.href?a.tabIndex:-1}}}}),l.optSelected||(o.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null}}),o.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){o.propFix[this.toLowerCase()]=this});var ac=/[\t\r\n\f]/g;o.fn.extend({addClass:function(a){var b,c,d,e,f,g,h="string"==typeof a&&a,i=0,j=this.length;if(o.isFunction(a))return this.each(function(b){o(this).addClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=o.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0===arguments.length||"string"==typeof a&&a,i=0,j=this.length;if(o.isFunction(a))return this.each(function(b){o(this).removeClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?o.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(o.isFunction(a)?function(c){o(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=o(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===U||"boolean"===c)&&(this.className&&L.set(this,"__className__",this.className),this.className=this.className||a===!1?"":L.get(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ac," ").indexOf(b)>=0)return!0;return!1}});var bc=/\r/g;o.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=o.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,o(this).val()):a,null==e?e="":"number"==typeof e?e+="":o.isArray(e)&&(e=o.map(e,function(a){return null==a?"":a+""})),b=o.valHooks[this.type]||o.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=o.valHooks[e.type]||o.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(bc,""):null==c?"":c)}}}),o.extend({valHooks:{select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(l.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&o.nodeName(c.parentNode,"optgroup"))){if(b=o(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=o.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=o.inArray(o(d).val(),f)>=0)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),o.each(["radio","checkbox"],function(){o.valHooks[this]={set:function(a,b){return o.isArray(b)?a.checked=o.inArray(o(a).val(),b)>=0:void 0}},l.checkOn||(o.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})}),o.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){o.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),o.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var cc=o.now(),dc=/\?/;o.parseJSON=function(a){return JSON.parse(a+"")},o.parseXML=function(a){var b,c;if(!a||"string"!=typeof a)return null;try{c=new DOMParser,b=c.parseFromString(a,"text/xml")}catch(d){b=void 0}return(!b||b.getElementsByTagName("parsererror").length)&&o.error("Invalid XML: "+a),b};var ec,fc,gc=/#.*$/,hc=/([?&])_=[^&]*/,ic=/^(.*?):[ \t]*([^\r\n]*)$/gm,jc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,kc=/^(?:GET|HEAD)$/,lc=/^\/\//,mc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,nc={},oc={},pc="*/".concat("*");try{fc=location.href}catch(qc){fc=m.createElement("a"),fc.href="",fc=fc.href}ec=mc.exec(fc.toLowerCase())||[];function rc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(o.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function sc(a,b,c,d){var e={},f=a===oc;function g(h){var i;return e[h]=!0,o.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function tc(a,b){var c,d,e=o.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&o.extend(!0,a,d),a}function uc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function vc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}o.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:fc,type:"GET",isLocal:jc.test(ec[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":pc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":o.parseJSON,"text xml":o.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?tc(tc(a,o.ajaxSettings),b):tc(o.ajaxSettings,a)},ajaxPrefilter:rc(nc),ajaxTransport:rc(oc),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=o.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?o(l):o.event,n=o.Deferred(),p=o.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!f){f={};while(b=ic.exec(e))f[b[1].toLowerCase()]=b[2]}b=f[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?e:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return c&&c.abort(b),x(0,b),this}};if(n.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||fc)+"").replace(gc,"").replace(lc,ec[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=o.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(h=mc.exec(k.url.toLowerCase()),k.crossDomain=!(!h||h[1]===ec[1]&&h[2]===ec[2]&&(h[3]||("http:"===h[1]?"80":"443"))===(ec[3]||("http:"===ec[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=o.param(k.data,k.traditional)),sc(nc,k,b,v),2===t)return v;i=k.global,i&&0===o.active++&&o.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!kc.test(k.type),d=k.url,k.hasContent||(k.data&&(d=k.url+=(dc.test(d)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=hc.test(d)?d.replace(hc,"$1_="+cc++):d+(dc.test(d)?"&":"?")+"_="+cc++)),k.ifModified&&(o.lastModified[d]&&v.setRequestHeader("If-Modified-Since",o.lastModified[d]),o.etag[d]&&v.setRequestHeader("If-None-Match",o.etag[d])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+pc+"; q=0.01":""):k.accepts["*"]);for(j in k.headers)v.setRequestHeader(j,k.headers[j]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(j in{success:1,error:1,complete:1})v[j](k[j]);if(c=sc(oc,k,b,v)){v.readyState=1,i&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,c.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,f,h){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),c=void 0,e=h||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,f&&(u=uc(k,v,f)),u=vc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(o.lastModified[d]=w),w=v.getResponseHeader("etag"),w&&(o.etag[d]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?n.resolveWith(l,[r,x,v]):n.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,i&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),i&&(m.trigger("ajaxComplete",[v,k]),--o.active||o.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return o.get(a,b,c,"json")},getScript:function(a,b){return o.get(a,void 0,b,"script")}}),o.each(["get","post"],function(a,b){o[b]=function(a,c,d,e){return o.isFunction(c)&&(e=e||d,d=c,c=void 0),o.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),o.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){o.fn[b]=function(a){return this.on(b,a)}}),o._evalUrl=function(a){return o.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},o.fn.extend({wrapAll:function(a){var b;return o.isFunction(a)?this.each(function(b){o(this).wrapAll(a.call(this,b))}):(this[0]&&(b=o(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this)},wrapInner:function(a){return this.each(o.isFunction(a)?function(b){o(this).wrapInner(a.call(this,b))}:function(){var b=o(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=o.isFunction(a);return this.each(function(c){o(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){o.nodeName(this,"body")||o(this).replaceWith(this.childNodes)}).end()}}),o.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0},o.expr.filters.visible=function(a){return!o.expr.filters.hidden(a)};var wc=/%20/g,xc=/\[\]$/,yc=/\r?\n/g,zc=/^(?:submit|button|image|reset|file)$/i,Ac=/^(?:input|select|textarea|keygen)/i;function Bc(a,b,c,d){var e;if(o.isArray(b))o.each(b,function(b,e){c||xc.test(a)?d(a,e):Bc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==o.type(b))d(a,b);else for(e in b)Bc(a+"["+e+"]",b[e],c,d)}o.param=function(a,b){var c,d=[],e=function(a,b){b=o.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=o.ajaxSettings&&o.ajaxSettings.traditional),o.isArray(a)||a.jquery&&!o.isPlainObject(a))o.each(a,function(){e(this.name,this.value)});else for(c in a)Bc(c,a[c],b,e);return d.join("&").replace(wc,"+")},o.fn.extend({serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=o.prop(this,"elements");return a?o.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!o(this).is(":disabled")&&Ac.test(this.nodeName)&&!zc.test(a)&&(this.checked||!T.test(a))}).map(function(a,b){var c=o(this).val();return null==c?null:o.isArray(c)?o.map(c,function(a){return{name:b.name,value:a.replace(yc,"\r\n")}}):{name:b.name,value:c.replace(yc,"\r\n")}}).get()}}),o.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(a){}};var Cc=0,Dc={},Ec={0:200,1223:204},Fc=o.ajaxSettings.xhr();a.ActiveXObject&&o(a).on("unload",function(){for(var a in Dc)Dc[a]()}),l.cors=!!Fc&&"withCredentials"in Fc,l.ajax=Fc=!!Fc,o.ajaxTransport(function(a){var b;return l.cors||Fc&&!a.crossDomain?{send:function(c,d){var e,f=a.xhr(),g=++Cc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)f.setRequestHeader(e,c[e]);b=function(a){return function(){b&&(delete Dc[g],b=f.onload=f.onerror=null,"abort"===a?f.abort():"error"===a?d(f.status,f.statusText):d(Ec[f.status]||f.status,f.statusText,"string"==typeof f.responseText?{text:f.responseText}:void 0,f.getAllResponseHeaders()))}},f.onload=b(),f.onerror=b("error"),b=Dc[g]=b("abort"),f.send(a.hasContent&&a.data||null)},abort:function(){b&&b()}}:void 0}),o.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return o.globalEval(a),a}}}),o.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),o.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(d,e){b=o("<script>").prop({async:!0,charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&e("error"===a.type?404:200,a.type)}),m.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Gc=[],Hc=/(=)\?(?=&|$)|\?\?/;o.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Gc.pop()||o.expando+"_"+cc++;return this[a]=!0,a}}),o.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Hc.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Hc.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=o.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Hc,"$1"+e):b.jsonp!==!1&&(b.url+=(dc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||o.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Gc.push(e)),g&&o.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),o.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||m;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=o.buildFragment([a],b,e),e&&e.length&&o(e).remove(),o.merge([],d.childNodes))};var Ic=o.fn.load;o.fn.load=function(a,b,c){if("string"!=typeof a&&Ic)return Ic.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=a.slice(h),a=a.slice(0,h)),o.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&o.ajax({url:a,type:e,dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?o("<div>").append(o.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,f||[a.responseText,b,a])}),this},o.expr.filters.animated=function(a){return o.grep(o.timers,function(b){return a===b.elem}).length};var Jc=a.document.documentElement;function Kc(a){return o.isWindow(a)?a:9===a.nodeType&&a.defaultView}o.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=o.css(a,"position"),l=o(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=o.css(a,"top"),i=o.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),o.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},o.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){o.offset.setOffset(this,a,b)});var b,c,d=this[0],e={top:0,left:0},f=d&&d.ownerDocument;if(f)return b=f.documentElement,o.contains(b,d)?(typeof d.getBoundingClientRect!==U&&(e=d.getBoundingClientRect()),c=Kc(f),{top:e.top+c.pageYOffset-b.clientTop,left:e.left+c.pageXOffset-b.clientLeft}):e},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===o.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),o.nodeName(a[0],"html")||(d=a.offset()),d.top+=o.css(a[0],"borderTopWidth",!0),d.left+=o.css(a[0],"borderLeftWidth",!0)),{top:b.top-d.top-o.css(c,"marginTop",!0),left:b.left-d.left-o.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||Jc;while(a&&!o.nodeName(a,"html")&&"static"===o.css(a,"position"))a=a.offsetParent;return a||Jc})}}),o.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(b,c){var d="pageYOffset"===c;o.fn[b]=function(e){return J(this,function(b,e,f){var g=Kc(b);return void 0===f?g?g[c]:b[e]:void(g?g.scrollTo(d?a.pageXOffset:f,d?f:a.pageYOffset):b[e]=f)},b,e,arguments.length,null)}}),o.each(["top","left"],function(a,b){o.cssHooks[b]=yb(l.pixelPosition,function(a,c){return c?(c=xb(a,b),vb.test(c)?o(a).position()[b]+"px":c):void 0})}),o.each({Height:"height",Width:"width"},function(a,b){o.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){o.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return J(this,function(b,c,d){var e;return o.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?o.css(b,c,g):o.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),o.fn.size=function(){return this.length},o.fn.andSelf=o.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return o});var Lc=a.jQuery,Mc=a.$;return o.noConflict=function(b){return a.$===o&&(a.$=Mc),b&&a.jQuery===o&&(a.jQuery=Lc),o},typeof b===U&&(a.jQuery=a.$=o),o});
;
/*
 * jQuery JSONP Core Plugin 2.4.0 (2012-08-21)
 *
 * https://github.com/jaubourg/jquery-jsonp
 *
 * Copyright (c) 2012 Julian Aubourg
 *
 * This document is licensed as free software under the terms of the
 * MIT License: http://www.opensource.org/licenses/mit-license.php
 */
(function ($) {

    // ###################### UTILITIES ##

    // Noop
    function noop() {
    }

    // Generic callback
    function genericCallback(data) {
        lastValue = [data];
    }

    // Call if defined
    function callIfDefined(method, object, parameters) {
        return method && method.apply(object.context || object, parameters);
    }

    // Give joining character given url
    function qMarkOrAmp(url) {
        return /\?/.test(url) ? "&" : "?";
    }

    var // String constants (for better minification)
		STR_ASYNC = "async",
		STR_CHARSET = "charset",
		STR_EMPTY = "",
		STR_ERROR = "error",
		STR_INSERT_BEFORE = "insertBefore",
		STR_JQUERY_JSONP = "_jqjsp",
		STR_ON = "on",
		STR_ON_CLICK = STR_ON + "click",
		STR_ON_ERROR = STR_ON + STR_ERROR,
		STR_ON_LOAD = STR_ON + "load",
		STR_ON_READY_STATE_CHANGE = STR_ON + "readystatechange",
		STR_READY_STATE = "readyState",
		STR_REMOVE_CHILD = "removeChild",
		STR_SCRIPT_TAG = "<script>",
		STR_SUCCESS = "success",
		STR_TIMEOUT = "timeout",

		// Window
		win = window,
		// Deferred
		Deferred = $.Deferred,
		// Head element
		head = $("head")[0] || document.documentElement,
		// Page cache
		pageCache = {},
		// Counter
		count = 0,
		// Last returned value
		lastValue,

		// ###################### DEFAULT OPTIONS ##
		xOptionsDefaults = {
		    //beforeSend: undefined,
		    //cache: false,
		    callback: STR_JQUERY_JSONP,
		    //callbackParameter: undefined,
		    //charset: undefined,
		    //complete: undefined,
		    //context: undefined,
		    //data: "",
		    //dataFilter: undefined,
		    //error: undefined,
		    //pageCache: false,
		    //success: undefined,
		    //timeout: 0,
		    //traditional: false,
		    url: location.href
		},

		// opera demands sniffing :/
		opera = win.opera,

		// IE < 10
		oldIE = !!$("<div>").html("<!--[if IE]><i><![endif]-->").find("i").length;

    // ###################### MAIN FUNCTION ##
    function jsonp(xOptions) {

        // Build data with default
        xOptions = $.extend({}, xOptionsDefaults, xOptions);

        // References to xOptions members (for better minification)
        var successCallback = xOptions.success,
			errorCallback = xOptions.error,
			completeCallback = xOptions.complete,
			dataFilter = xOptions.dataFilter,
			callbackParameter = xOptions.callbackParameter,
			successCallbackName = xOptions.callback,
			cacheFlag = xOptions.cache,
			pageCacheFlag = xOptions.pageCache,
			charset = xOptions.charset,
			url = xOptions.url,
			data = xOptions.data,
			timeout = xOptions.timeout,
			pageCached,

			// Abort/done flag
			done = 0,

			// Life-cycle functions
			cleanUp = noop,

			// Support vars
			supportOnload,
			supportOnreadystatechange,

			// Request execution vars
			firstChild,
			script,
			scriptAfter,
			timeoutTimer;

        // If we have Deferreds:
        // - substitute callbacks
        // - promote xOptions to a promise
        Deferred && Deferred(function (defer) {
            defer.done(successCallback).fail(errorCallback);
            successCallback = defer.resolve;
            errorCallback = defer.reject;
        }).promise(xOptions);

        // Create the abort method
        xOptions.abort = function () {
            !(done++) && cleanUp();
        };

        // Call beforeSend if provided (early abort if false returned)
        if (callIfDefined(xOptions.beforeSend, xOptions, [xOptions]) === !1 || done) {
            return xOptions;
        }

        // Control entries
        url = url || STR_EMPTY;
        data = data ? ((typeof data) == "string" ? data : $.param(data, xOptions.traditional)) : STR_EMPTY;

        // Build final url
        url += data ? (qMarkOrAmp(url) + data) : STR_EMPTY;

        // Add callback parameter if provided as option
        callbackParameter && (url += qMarkOrAmp(url) + encodeURIComponent(callbackParameter) + "=?");

        // Add anticache parameter if needed
        !cacheFlag && !pageCacheFlag && (url += qMarkOrAmp(url) + "_" + (new Date()).getTime() + "=");

        // Replace last ? by callback parameter
        url = url.replace(/=\?(&|$)/, "=" + successCallbackName + "$1");

        // Success notifier
        function notifySuccess(json) {

            if (!(done++)) {

                cleanUp();
                // Pagecache if needed
                pageCacheFlag && (pageCache[url] = { s: [json] });
                // Apply the data filter if provided
                dataFilter && (json = dataFilter.apply(xOptions, [json]));
                // Call success then complete
                callIfDefined(successCallback, xOptions, [json, STR_SUCCESS, xOptions]);
                callIfDefined(completeCallback, xOptions, [xOptions, STR_SUCCESS]);

            }
        }

        // Error notifier
        function notifyError(type) {

            if (!(done++)) {

                // Clean up
                cleanUp();
                // If pure error (not timeout), cache if needed
                pageCacheFlag && type != STR_TIMEOUT && (pageCache[url] = type);
                // Call error then complete
                callIfDefined(errorCallback, xOptions, [xOptions, type]);
                callIfDefined(completeCallback, xOptions, [xOptions, type]);

            }
        }

        // Check page cache
        if (pageCacheFlag && (pageCached = pageCache[url])) {

            pageCached.s ? notifySuccess(pageCached.s[0]) : notifyError(pageCached);

        } else {

            // Install the generic callback
            // (BEWARE: global namespace pollution ahoy)
            win[successCallbackName] = genericCallback;

            // Create the script tag
            script = $(STR_SCRIPT_TAG)[0];
            script.id = STR_JQUERY_JSONP + count++;

            // Set charset if provided
            if (charset) {
                script[STR_CHARSET] = charset;
            }

            opera && opera.version() < 11.60 ?
            // onerror is not supported: do not set as async and assume in-order execution.
            // Add a trailing script to emulate the event
				((scriptAfter = $(STR_SCRIPT_TAG)[0]).text = "document.getElementById('" + script.id + "')." + STR_ON_ERROR + "()")
			:
            // onerror is supported: set the script as async to avoid requests blocking each others
				(script[STR_ASYNC] = STR_ASYNC)

            ;

            // Internet Explorer: event/htmlFor trick
            if (oldIE) {
                script.htmlFor = script.id;
                script.event = STR_ON_CLICK;
            }

            // Attached event handlers
            script[STR_ON_LOAD] = script[STR_ON_ERROR] = script[STR_ON_READY_STATE_CHANGE] = function (result) {

                // Test readyState if it exists
                if (!script[STR_READY_STATE] || !/i/.test(script[STR_READY_STATE])) {

                    try {

                        script[STR_ON_CLICK] && script[STR_ON_CLICK]();

                    } catch (_) { }

                    result = lastValue;
                    lastValue = 0;
                    result ? notifySuccess(result[0]) : notifyError(STR_ERROR);

                }
            };

            // Set source
            script.src = url;

            // Re-declare cleanUp function
            cleanUp = function (i) {
                timeoutTimer && clearTimeout(timeoutTimer);
                script[STR_ON_READY_STATE_CHANGE] = script[STR_ON_LOAD] = script[STR_ON_ERROR] = null;
                head[STR_REMOVE_CHILD](script);
                scriptAfter && head[STR_REMOVE_CHILD](scriptAfter);
            };

            // Append main script
            head[STR_INSERT_BEFORE](script, (firstChild = head.firstChild));

            // Append trailing script if needed
            scriptAfter && head[STR_INSERT_BEFORE](scriptAfter, firstChild);

            // If a timeout is needed, install it
            timeoutTimer = timeout > 0 && setTimeout(function () {
                notifyError(STR_TIMEOUT);
            }, timeout);

        }

        return xOptions;
    }

    // ###################### SETUP FUNCTION ##
    jsonp.setup = function (xOptions) {
        $.extend(xOptionsDefaults, xOptions);
    };

    // ###################### INSTALL in jQuery ##
    $.jsonp = jsonp;

})(jQuery);;
/*!
 * Modernizr v2.8.3
 * www.modernizr.com
 *
 * Copyright (c) Faruk Ates, Paul Irish, Alex Sexton
 * Available under the BSD and MIT licenses: www.modernizr.com/license/
 */

/*
 * Modernizr tests which native CSS3 and HTML5 features are available in
 * the current UA and makes the results available to you in two ways:
 * as properties on a global Modernizr object, and as classes on the
 * <html> element. This information allows you to progressively enhance
 * your pages with a granular level of control over the experience.
 *
 * Modernizr has an optional (not included) conditional resource loader
 * called Modernizr.load(), based on Yepnope.js (yepnopejs.com).
 * To get a build that includes Modernizr.load(), as well as choosing
 * which tests to include, go to www.modernizr.com/download/
 *
 * Authors        Faruk Ates, Paul Irish, Alex Sexton
 * Contributors   Ryan Seddon, Ben Alman
 */

window.Modernizr = (function( window, document, undefined ) {

    var version = '2.8.3',

    Modernizr = {},

    /*>>cssclasses*/
    // option for enabling the HTML classes to be added
    enableClasses = true,
    /*>>cssclasses*/

    docElement = document.documentElement,

    /**
     * Create our "modernizr" element that we do most feature tests on.
     */
    mod = 'modernizr',
    modElem = document.createElement(mod),
    mStyle = modElem.style,

    /**
     * Create the input element for various Web Forms feature tests.
     */
    inputElem /*>>inputelem*/ = document.createElement('input') /*>>inputelem*/ ,

    /*>>smile*/
    smile = ':)',
    /*>>smile*/

    toString = {}.toString,

    // TODO :: make the prefixes more granular
    /*>>prefixes*/
    // List of property values to set for css tests. See ticket #21
    prefixes = ' -webkit- -moz- -o- -ms- '.split(' '),
    /*>>prefixes*/

    /*>>domprefixes*/
    // Following spec is to expose vendor-specific style properties as:
    //   elem.style.WebkitBorderRadius
    // and the following would be incorrect:
    //   elem.style.webkitBorderRadius

    // Webkit ghosts their properties in lowercase but Opera & Moz do not.
    // Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+
    //   erik.eae.net/archives/2008/03/10/21.48.10/

    // More here: github.com/Modernizr/Modernizr/issues/issue/21
    omPrefixes = 'Webkit Moz O ms',

    cssomPrefixes = omPrefixes.split(' '),

    domPrefixes = omPrefixes.toLowerCase().split(' '),
    /*>>domprefixes*/

    /*>>ns*/
    ns = {'svg': 'http://www.w3.org/2000/svg'},
    /*>>ns*/

    tests = {},
    inputs = {},
    attrs = {},

    classes = [],

    slice = classes.slice,

    featureName, // used in testing loop


    /*>>teststyles*/
    // Inject element with style element and some CSS rules
    injectElementWithStyles = function( rule, callback, nodes, testnames ) {

      var style, ret, node, docOverflow,
          div = document.createElement('div'),
          // After page load injecting a fake body doesn't work so check if body exists
          body = document.body,
          // IE6 and 7 won't return offsetWidth or offsetHeight unless it's in the body element, so we fake it.
          fakeBody = body || document.createElement('body');

      if ( parseInt(nodes, 10) ) {
          // In order not to give false positives we create a node for each test
          // This also allows the method to scale for unspecified uses
          while ( nodes-- ) {
              node = document.createElement('div');
              node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
              div.appendChild(node);
          }
      }

      // <style> elements in IE6-9 are considered 'NoScope' elements and therefore will be removed
      // when injected with innerHTML. To get around this you need to prepend the 'NoScope' element
      // with a 'scoped' element, in our case the soft-hyphen entity as it won't mess with our measurements.
      // msdn.microsoft.com/en-us/library/ms533897%28VS.85%29.aspx
      // Documents served as xml will throw if using &shy; so use xml friendly encoded version. See issue #277
      style = ['&#173;','<style id="s', mod, '">', rule, '</style>'].join('');
      div.id = mod;
      // IE6 will false positive on some tests due to the style element inside the test div somehow interfering offsetHeight, so insert it into body or fakebody.
      // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
      (body ? div : fakeBody).innerHTML += style;
      fakeBody.appendChild(div);
      if ( !body ) {
          //avoid crashing IE8, if background image is used
          fakeBody.style.background = '';
          //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
          fakeBody.style.overflow = 'hidden';
          docOverflow = docElement.style.overflow;
          docElement.style.overflow = 'hidden';
          docElement.appendChild(fakeBody);
      }

      ret = callback(div, rule);
      // If this is done after page load we don't want to remove the body so check if body exists
      if ( !body ) {
          fakeBody.parentNode.removeChild(fakeBody);
          docElement.style.overflow = docOverflow;
      } else {
          div.parentNode.removeChild(div);
      }

      return !!ret;

    },
    /*>>teststyles*/

    /*>>mq*/
    // adapted from matchMedia polyfill
    // by Scott Jehl and Paul Irish
    // gist.github.com/786768
    testMediaQuery = function( mq ) {

      var matchMedia = window.matchMedia || window.msMatchMedia;
      if ( matchMedia ) {
        return matchMedia(mq) && matchMedia(mq).matches || false;
      }

      var bool;

      injectElementWithStyles('@media ' + mq + ' { #' + mod + ' { position: absolute; } }', function( node ) {
        bool = (window.getComputedStyle ?
                  getComputedStyle(node, null) :
                  node.currentStyle)['position'] == 'absolute';
      });

      return bool;

     },
     /*>>mq*/


    /*>>hasevent*/
    //
    // isEventSupported determines if a given element supports the given event
    // kangax.github.com/iseventsupported/
    //
    // The following results are known incorrects:
    //   Modernizr.hasEvent("webkitTransitionEnd", elem) // false negative
    //   Modernizr.hasEvent("textInput") // in Webkit. github.com/Modernizr/Modernizr/issues/333
    //   ...
    isEventSupported = (function() {

      var TAGNAMES = {
        'select': 'input', 'change': 'input',
        'submit': 'form', 'reset': 'form',
        'error': 'img', 'load': 'img', 'abort': 'img'
      };

      function isEventSupported( eventName, element ) {

        element = element || document.createElement(TAGNAMES[eventName] || 'div');
        eventName = 'on' + eventName;

        // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and "resize", whereas `in` "catches" those
        var isSupported = eventName in element;

        if ( !isSupported ) {
          // If it has no `setAttribute` (i.e. doesn't implement Node interface), try generic element
          if ( !element.setAttribute ) {
            element = document.createElement('div');
          }
          if ( element.setAttribute && element.removeAttribute ) {
            element.setAttribute(eventName, '');
            isSupported = is(element[eventName], 'function');

            // If property was created, "remove it" (by setting value to `undefined`)
            if ( !is(element[eventName], 'undefined') ) {
              element[eventName] = undefined;
            }
            element.removeAttribute(eventName);
          }
        }

        element = null;
        return isSupported;
      }
      return isEventSupported;
    })(),
    /*>>hasevent*/

    // TODO :: Add flag for hasownprop ? didn't last time

    // hasOwnProperty shim by kangax needed for Safari 2.0 support
    _hasOwnProperty = ({}).hasOwnProperty, hasOwnProp;

    if ( !is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined') ) {
      hasOwnProp = function (object, property) {
        return _hasOwnProperty.call(object, property);
      };
    }
    else {
      hasOwnProp = function (object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */
        return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
      };
    }

    // Adapted from ES5-shim https://github.com/kriskowal/es5-shim/blob/master/es5-shim.js
    // es5.github.com/#x15.3.4.5

    if (!Function.prototype.bind) {
      Function.prototype.bind = function bind(that) {

        var target = this;

        if (typeof target != "function") {
            throw new TypeError();
        }

        var args = slice.call(arguments, 1),
            bound = function () {

            if (this instanceof bound) {

              var F = function(){};
              F.prototype = target.prototype;
              var self = new F();

              var result = target.apply(
                  self,
                  args.concat(slice.call(arguments))
              );
              if (Object(result) === result) {
                  return result;
              }
              return self;

            } else {

              return target.apply(
                  that,
                  args.concat(slice.call(arguments))
              );

            }

        };

        return bound;
      };
    }

    /**
     * setCss applies given styles to the Modernizr DOM node.
     */
    function setCss( str ) {
        mStyle.cssText = str;
    }

    /**
     * setCssAll extrapolates all vendor-specific css strings.
     */
    function setCssAll( str1, str2 ) {
        return setCss(prefixes.join(str1 + ';') + ( str2 || '' ));
    }

    /**
     * is returns a boolean for if typeof obj is exactly type.
     */
    function is( obj, type ) {
        return typeof obj === type;
    }

    /**
     * contains returns a boolean for if substr is found within str.
     */
    function contains( str, substr ) {
        return !!~('' + str).indexOf(substr);
    }

    /*>>testprop*/

    // testProps is a generic CSS / DOM property test.

    // In testing support for a given CSS property, it's legit to test:
    //    `elem.style[styleName] !== undefined`
    // If the property is supported it will return an empty string,
    // if unsupported it will return undefined.

    // We'll take advantage of this quick test and skip setting a style
    // on our modernizr element, but instead just testing undefined vs
    // empty string.

    // Because the testing of the CSS property names (with "-", as
    // opposed to the camelCase DOM properties) is non-portable and
    // non-standard but works in WebKit and IE (but not Gecko or Opera),
    // we explicitly reject properties with dashes so that authors
    // developing in WebKit or IE first don't end up with
    // browser-specific content by accident.

    function testProps( props, prefixed ) {
        for ( var i in props ) {
            var prop = props[i];
            if ( !contains(prop, "-") && mStyle[prop] !== undefined ) {
                return prefixed == 'pfx' ? prop : true;
            }
        }
        return false;
    }
    /*>>testprop*/

    // TODO :: add testDOMProps
    /**
     * testDOMProps is a generic DOM property test; if a browser supports
     *   a certain property, it won't return undefined for it.
     */
    function testDOMProps( props, obj, elem ) {
        for ( var i in props ) {
            var item = obj[props[i]];
            if ( item !== undefined) {

                // return the property name as a string
                if (elem === false) return props[i];

                // let's bind a function
                if (is(item, 'function')){
                  // default to autobind unless override
                  return item.bind(elem || obj);
                }

                // return the unbound function or obj or value
                return item;
            }
        }
        return false;
    }

    /*>>testallprops*/
    /**
     * testPropsAll tests a list of DOM properties we want to check against.
     *   We specify literally ALL possible (known and/or likely) properties on
     *   the element including the non-vendor prefixed one, for forward-
     *   compatibility.
     */
    function testPropsAll( prop, prefixed, elem ) {

        var ucProp  = prop.charAt(0).toUpperCase() + prop.slice(1),
            props   = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');

        // did they call .prefixed('boxSizing') or are we just testing a prop?
        if(is(prefixed, "string") || is(prefixed, "undefined")) {
          return testProps(props, prefixed);

        // otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
        } else {
          props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
          return testDOMProps(props, prefixed, elem);
        }
    }
    /*>>testallprops*/


    /**
     * Tests
     * -----
     */

    // The *new* flexbox
    // dev.w3.org/csswg/css3-flexbox

    tests['flexbox'] = function() {
      return testPropsAll('flexWrap');
    };

    // The *old* flexbox
    // www.w3.org/TR/2009/WD-css3-flexbox-20090723/

    tests['flexboxlegacy'] = function() {
        return testPropsAll('boxDirection');
    };

    // On the S60 and BB Storm, getContext exists, but always returns undefined
    // so we actually have to call getContext() to verify
    // github.com/Modernizr/Modernizr/issues/issue/97/

    tests['canvas'] = function() {
        var elem = document.createElement('canvas');
        return !!(elem.getContext && elem.getContext('2d'));
    };

    tests['canvastext'] = function() {
        return !!(Modernizr['canvas'] && is(document.createElement('canvas').getContext('2d').fillText, 'function'));
    };

    // webk.it/70117 is tracking a legit WebGL feature detect proposal

    // We do a soft detect which may false positive in order to avoid
    // an expensive context creation: bugzil.la/732441

    tests['webgl'] = function() {
        return !!window.WebGLRenderingContext;
    };

    /*
     * The Modernizr.touch test only indicates if the browser supports
     *    touch events, which does not necessarily reflect a touchscreen
     *    device, as evidenced by tablets running Windows 7 or, alas,
     *    the Palm Pre / WebOS (touch) phones.
     *
     * Additionally, Chrome (desktop) used to lie about its support on this,
     *    but that has since been rectified: crbug.com/36415
     *
     * We also test for Firefox 4 Multitouch Support.
     *
     * For more info, see: modernizr.github.com/Modernizr/touch.html
     */

    tests['touch'] = function() {
        var bool;

        if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
          bool = true;
        } else {
          injectElementWithStyles(['@media (',prefixes.join('touch-enabled),('),mod,')','{#modernizr{top:9px;position:absolute}}'].join(''), function( node ) {
            bool = node.offsetTop === 9;
          });
        }

        return bool;
    };


    // geolocation is often considered a trivial feature detect...
    // Turns out, it's quite tricky to get right:
    //
    // Using !!navigator.geolocation does two things we don't want. It:
    //   1. Leaks memory in IE9: github.com/Modernizr/Modernizr/issues/513
    //   2. Disables page caching in WebKit: webk.it/43956
    //
    // Meanwhile, in Firefox < 8, an about:config setting could expose
    // a false positive that would throw an exception: bugzil.la/688158

    tests['geolocation'] = function() {
        return 'geolocation' in navigator;
    };


    tests['postmessage'] = function() {
      return !!window.postMessage;
    };


    // Chrome incognito mode used to throw an exception when using openDatabase
    // It doesn't anymore.
    tests['websqldatabase'] = function() {
      return !!window.openDatabase;
    };

    // Vendors had inconsistent prefixing with the experimental Indexed DB:
    // - Webkit's implementation is accessible through webkitIndexedDB
    // - Firefox shipped moz_indexedDB before FF4b9, but since then has been mozIndexedDB
    // For speed, we don't test the legacy (and beta-only) indexedDB
    tests['indexedDB'] = function() {
      return !!testPropsAll("indexedDB", window);
    };

    // documentMode logic from YUI to filter out IE8 Compat Mode
    //   which false positives.
    tests['hashchange'] = function() {
      return isEventSupported('hashchange', window) && (document.documentMode === undefined || document.documentMode > 7);
    };

    // Per 1.6:
    // This used to be Modernizr.historymanagement but the longer
    // name has been deprecated in favor of a shorter and property-matching one.
    // The old API is still available in 1.6, but as of 2.0 will throw a warning,
    // and in the first release thereafter disappear entirely.
    tests['history'] = function() {
      return !!(window.history && history.pushState);
    };

    tests['draganddrop'] = function() {
        var div = document.createElement('div');
        return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div);
    };

    // FF3.6 was EOL'ed on 4/24/12, but the ESR version of FF10
    // will be supported until FF19 (2/12/13), at which time, ESR becomes FF17.
    // FF10 still uses prefixes, so check for it until then.
    // for more ESR info, see: mozilla.org/en-US/firefox/organizations/faq/
    tests['websockets'] = function() {
        return 'WebSocket' in window || 'MozWebSocket' in window;
    };


    // css-tricks.com/rgba-browser-support/
    tests['rgba'] = function() {
        // Set an rgba() color and check the returned value

        setCss('background-color:rgba(150,255,150,.5)');

        return contains(mStyle.backgroundColor, 'rgba');
    };

    tests['hsla'] = function() {
        // Same as rgba(), in fact, browsers re-map hsla() to rgba() internally,
        //   except IE9 who retains it as hsla

        setCss('background-color:hsla(120,40%,100%,.5)');

        return contains(mStyle.backgroundColor, 'rgba') || contains(mStyle.backgroundColor, 'hsla');
    };

    tests['multiplebgs'] = function() {
        // Setting multiple images AND a color on the background shorthand property
        //  and then querying the style.background property value for the number of
        //  occurrences of "url(" is a reliable method for detecting ACTUAL support for this!

        setCss('background:url(https://),url(https://),red url(https://)');

        // If the UA supports multiple backgrounds, there should be three occurrences
        //   of the string "url(" in the return value for elemStyle.background

        return (/(url\s*\(.*?){3}/).test(mStyle.background);
    };



    // this will false positive in Opera Mini
    //   github.com/Modernizr/Modernizr/issues/396

    tests['backgroundsize'] = function() {
        return testPropsAll('backgroundSize');
    };

    tests['borderimage'] = function() {
        return testPropsAll('borderImage');
    };


    // Super comprehensive table about all the unique implementations of
    // border-radius: muddledramblings.com/table-of-css3-border-radius-compliance

    tests['borderradius'] = function() {
        return testPropsAll('borderRadius');
    };

    // WebOS unfortunately false positives on this test.
    tests['boxshadow'] = function() {
        return testPropsAll('boxShadow');
    };

    // FF3.0 will false positive on this test
    tests['textshadow'] = function() {
        return document.createElement('div').style.textShadow === '';
    };


    tests['opacity'] = function() {
        // Browsers that actually have CSS Opacity implemented have done so
        //  according to spec, which means their return values are within the
        //  range of [0.0,1.0] - including the leading zero.

        setCssAll('opacity:.55');

        // The non-literal . in this regex is intentional:
        //   German Chrome returns this value as 0,55
        // github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632
        return (/^0.55$/).test(mStyle.opacity);
    };


    // Note, Android < 4 will pass this test, but can only animate
    //   a single property at a time
    //   goo.gl/v3V4Gp
    tests['cssanimations'] = function() {
        return testPropsAll('animationName');
    };


    tests['csscolumns'] = function() {
        return testPropsAll('columnCount');
    };


    tests['cssgradients'] = function() {
        /**
         * For CSS Gradients syntax, please see:
         * webkit.org/blog/175/introducing-css-gradients/
         * developer.mozilla.org/en/CSS/-moz-linear-gradient
         * developer.mozilla.org/en/CSS/-moz-radial-gradient
         * dev.w3.org/csswg/css3-images/#gradients-
         */

        var str1 = 'background-image:',
            str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));',
            str3 = 'linear-gradient(left top,#9f9, white);';

        setCss(
             // legacy webkit syntax (FIXME: remove when syntax not in use anymore)
              (str1 + '-webkit- '.split(' ').join(str2 + str1) +
             // standard syntax             // trailing 'background-image:'
              prefixes.join(str3 + str1)).slice(0, -str1.length)
        );

        return contains(mStyle.backgroundImage, 'gradient');
    };


    tests['cssreflections'] = function() {
        return testPropsAll('boxReflect');
    };


    tests['csstransforms'] = function() {
        return !!testPropsAll('transform');
    };


    tests['csstransforms3d'] = function() {

        var ret = !!testPropsAll('perspective');

        // Webkit's 3D transforms are passed off to the browser's own graphics renderer.
        //   It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in
        //   some conditions. As a result, Webkit typically recognizes the syntax but
        //   will sometimes throw a false positive, thus we must do a more thorough check:
        if ( ret && 'webkitPerspective' in docElement.style ) {

          // Webkit allows this media query to succeed only if the feature is enabled.
          // `@media (transform-3d),(-webkit-transform-3d){ ... }`
          injectElementWithStyles('@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}', function( node, rule ) {
            ret = node.offsetLeft === 9 && node.offsetHeight === 3;
          });
        }
        return ret;
    };


    tests['csstransitions'] = function() {
        return testPropsAll('transition');
    };


    /*>>fontface*/
    // @font-face detection routine by Diego Perini
    // javascript.nwbox.com/CSSSupport/

    // false positives:
    //   WebOS github.com/Modernizr/Modernizr/issues/342
    //   WP7   github.com/Modernizr/Modernizr/issues/538
    tests['fontface'] = function() {
        var bool;

        injectElementWithStyles('@font-face {font-family:"font";src:url("https://")}', function( node, rule ) {
          var style = document.getElementById('smodernizr'),
              sheet = style.sheet || style.styleSheet,
              cssText = sheet ? (sheet.cssRules && sheet.cssRules[0] ? sheet.cssRules[0].cssText : sheet.cssText || '') : '';

          bool = /src/i.test(cssText) && cssText.indexOf(rule.split(' ')[0]) === 0;
        });

        return bool;
    };
    /*>>fontface*/

    // CSS generated content detection
    tests['generatedcontent'] = function() {
        var bool;

        injectElementWithStyles(['#',mod,'{font:0/0 a}#',mod,':after{content:"',smile,'";visibility:hidden;font:3px/1 a}'].join(''), function( node ) {
          bool = node.offsetHeight >= 3;
        });

        return bool;
    };



    // These tests evaluate support of the video/audio elements, as well as
    // testing what types of content they support.
    //
    // We're using the Boolean constructor here, so that we can extend the value
    // e.g.  Modernizr.video     // true
    //       Modernizr.video.ogg // 'probably'
    //
    // Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
    //                     thx to NielsLeenheer and zcorpan

    // Note: in some older browsers, "no" was a return value instead of empty string.
    //   It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2
    //   It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5

    tests['video'] = function() {
        var elem = document.createElement('video'),
            bool = false;

        // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224
        try {
            if ( bool = !!elem.canPlayType ) {
                bool      = new Boolean(bool);
                bool.ogg  = elem.canPlayType('video/ogg; codecs="theora"')      .replace(/^no$/,'');

                // Without QuickTime, this value will be `undefined`. github.com/Modernizr/Modernizr/issues/546
                bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"') .replace(/^no$/,'');

                bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,'');
            }

        } catch(e) { }

        return bool;
    };

    tests['audio'] = function() {
        var elem = document.createElement('audio'),
            bool = false;

        try {
            if ( bool = !!elem.canPlayType ) {
                bool      = new Boolean(bool);
                bool.ogg  = elem.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,'');
                bool.mp3  = elem.canPlayType('audio/mpeg;')               .replace(/^no$/,'');

                // Mimetypes accepted:
                //   developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements
                //   bit.ly/iphoneoscodecs
                bool.wav  = elem.canPlayType('audio/wav; codecs="1"')     .replace(/^no$/,'');
                bool.m4a  = ( elem.canPlayType('audio/x-m4a;')            ||
                              elem.canPlayType('audio/aac;'))             .replace(/^no$/,'');
            }
        } catch(e) { }

        return bool;
    };


    // In FF4, if disabled, window.localStorage should === null.

    // Normally, we could not test that directly and need to do a
    //   `('localStorage' in window) && ` test first because otherwise Firefox will
    //   throw bugzil.la/365772 if cookies are disabled

    // Also in iOS5 Private Browsing mode, attempting to use localStorage.setItem
    // will throw the exception:
    //   QUOTA_EXCEEDED_ERRROR DOM Exception 22.
    // Peculiarly, getItem and removeItem calls do not throw.

    // Because we are forced to try/catch this, we'll go aggressive.

    // Just FWIW: IE8 Compat mode supports these features completely:
    //   www.quirksmode.org/dom/html5.html
    // But IE8 doesn't support either with local files

    tests['localstorage'] = function() {
        try {
            localStorage.setItem(mod, mod);
            localStorage.removeItem(mod);
            return true;
        } catch(e) {
            return false;
        }
    };

    tests['sessionstorage'] = function() {
        try {
            sessionStorage.setItem(mod, mod);
            sessionStorage.removeItem(mod);
            return true;
        } catch(e) {
            return false;
        }
    };


    tests['webworkers'] = function() {
        return !!window.Worker;
    };


    tests['applicationcache'] = function() {
        return !!window.applicationCache;
    };


    // Thanks to Erik Dahlstrom
    tests['svg'] = function() {
        return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect;
    };

    // specifically for SVG inline in HTML, not within XHTML
    // test page: paulirish.com/demo/inline-svg
    tests['inlinesvg'] = function() {
      var div = document.createElement('div');
      div.innerHTML = '<svg/>';
      return (div.firstChild && div.firstChild.namespaceURI) == ns.svg;
    };

    // SVG SMIL animation
    tests['smil'] = function() {
        return !!document.createElementNS && /SVGAnimate/.test(toString.call(document.createElementNS(ns.svg, 'animate')));
    };

    // This test is only for clip paths in SVG proper, not clip paths on HTML content
    // demo: srufaculty.sru.edu/david.dailey/svg/newstuff/clipPath4.svg

    // However read the comments to dig into applying SVG clippaths to HTML content here:
    //   github.com/Modernizr/Modernizr/issues/213#issuecomment-1149491
    tests['svgclippaths'] = function() {
        return !!document.createElementNS && /SVGClipPath/.test(toString.call(document.createElementNS(ns.svg, 'clipPath')));
    };

    /*>>webforms*/
    // input features and input types go directly onto the ret object, bypassing the tests loop.
    // Hold this guy to execute in a moment.
    function webforms() {
        /*>>input*/
        // Run through HTML5's new input attributes to see if the UA understands any.
        // We're using f which is the <input> element created early on
        // Mike Taylr has created a comprehensive resource for testing these attributes
        //   when applied to all input types:
        //   miketaylr.com/code/input-type-attr.html
        // spec: www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary

        // Only input placeholder is tested while textarea's placeholder is not.
        // Currently Safari 4 and Opera 11 have support only for the input placeholder
        // Both tests are available in feature-detects/forms-placeholder.js
        Modernizr['input'] = (function( props ) {
            for ( var i = 0, len = props.length; i < len; i++ ) {
                attrs[ props[i] ] = !!(props[i] in inputElem);
            }
            if (attrs.list){
              // safari false positive's on datalist: webk.it/74252
              // see also github.com/Modernizr/Modernizr/issues/146
              attrs.list = !!(document.createElement('datalist') && window.HTMLDataListElement);
            }
            return attrs;
        })('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' '));
        /*>>input*/

        /*>>inputtypes*/
        // Run through HTML5's new input types to see if the UA understands any.
        //   This is put behind the tests runloop because it doesn't return a
        //   true/false like all the other tests; instead, it returns an object
        //   containing each input type with its corresponding true/false value

        // Big thanks to @miketaylr for the html5 forms expertise. miketaylr.com/
        Modernizr['inputtypes'] = (function(props) {

            for ( var i = 0, bool, inputElemType, defaultView, len = props.length; i < len; i++ ) {

                inputElem.setAttribute('type', inputElemType = props[i]);
                bool = inputElem.type !== 'text';

                // We first check to see if the type we give it sticks..
                // If the type does, we feed it a textual value, which shouldn't be valid.
                // If the value doesn't stick, we know there's input sanitization which infers a custom UI
                if ( bool ) {

                    inputElem.value         = smile;
                    inputElem.style.cssText = 'position:absolute;visibility:hidden;';

                    if ( /^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined ) {

                      docElement.appendChild(inputElem);
                      defaultView = document.defaultView;

                      // Safari 2-4 allows the smiley as a value, despite making a slider
                      bool =  defaultView.getComputedStyle &&
                              defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' &&
                              // Mobile android web browser has false positive, so must
                              // check the height to see if the widget is actually there.
                              (inputElem.offsetHeight !== 0);

                      docElement.removeChild(inputElem);

                    } else if ( /^(search|tel)$/.test(inputElemType) ){
                      // Spec doesn't define any special parsing or detectable UI
                      //   behaviors so we pass these through as true

                      // Interestingly, opera fails the earlier test, so it doesn't
                      //  even make it here.

                    } else if ( /^(url|email)$/.test(inputElemType) ) {
                      // Real url and email support comes with prebaked validation.
                      bool = inputElem.checkValidity && inputElem.checkValidity() === false;

                    } else {
                      // If the upgraded input compontent rejects the :) text, we got a winner
                      bool = inputElem.value != smile;
                    }
                }

                inputs[ props[i] ] = !!bool;
            }
            return inputs;
        })('search tel url email datetime date month week time datetime-local number range color'.split(' '));
        /*>>inputtypes*/
    }
    /*>>webforms*/


    // End of test definitions
    // -----------------------



    // Run through all tests and detect their support in the current UA.
    // todo: hypothetically we could be doing an array of tests and use a basic loop here.
    for ( var feature in tests ) {
        if ( hasOwnProp(tests, feature) ) {
            // run the test, throw the return value into the Modernizr,
            //   then based on that boolean, define an appropriate className
            //   and push it into an array of classes we'll join later.
            featureName  = feature.toLowerCase();
            Modernizr[featureName] = tests[feature]();

            classes.push((Modernizr[featureName] ? '' : 'no-') + featureName);
        }
    }

    /*>>webforms*/
    // input tests need to run.
    Modernizr.input || webforms();
    /*>>webforms*/


    /**
     * addTest allows the user to define their own feature tests
     * the result will be added onto the Modernizr object,
     * as well as an appropriate className set on the html element
     *
     * @param feature - String naming the feature
     * @param test - Function returning true if feature is supported, false if not
     */
     Modernizr.addTest = function ( feature, test ) {
       if ( typeof feature == 'object' ) {
         for ( var key in feature ) {
           if ( hasOwnProp( feature, key ) ) {
             Modernizr.addTest( key, feature[ key ] );
           }
         }
       } else {

         feature = feature.toLowerCase();

         if ( Modernizr[feature] !== undefined ) {
           // we're going to quit if you're trying to overwrite an existing test
           // if we were to allow it, we'd do this:
           //   var re = new RegExp("\\b(no-)?" + feature + "\\b");
           //   docElement.className = docElement.className.replace( re, '' );
           // but, no rly, stuff 'em.
           return Modernizr;
         }

         test = typeof test == 'function' ? test() : test;

         if (typeof enableClasses !== "undefined" && enableClasses) {
           docElement.className += ' ' + (test ? '' : 'no-') + feature;
         }
         Modernizr[feature] = test;

       }

       return Modernizr; // allow chaining.
     };


    // Reset modElem.cssText to nothing to reduce memory footprint.
    setCss('');
    modElem = inputElem = null;

    /*>>shiv*/
    /**
     * @preserve HTML5 Shiv prev3.7.1 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
     */
    ;(function(window, document) {
        /*jshint evil:true */
        /** version */
        var version = '3.7.0';

        /** Preset options */
        var options = window.html5 || {};

        /** Used to skip problem elements */
        var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i;

        /** Not all elements can be cloned in IE **/
        var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i;

        /** Detect whether the browser supports default html5 styles */
        var supportsHtml5Styles;

        /** Name of the expando, to work with multiple documents or to re-shiv one document */
        var expando = '_html5shiv';

        /** The id for the the documents expando */
        var expanID = 0;

        /** Cached data for each document */
        var expandoData = {};

        /** Detect whether the browser supports unknown elements */
        var supportsUnknownElements;

        (function() {
          try {
            var a = document.createElement('a');
            a.innerHTML = '<xyz></xyz>';
            //if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles
            supportsHtml5Styles = ('hidden' in a);

            supportsUnknownElements = a.childNodes.length == 1 || (function() {
              // assign a false positive if unable to shiv
              (document.createElement)('a');
              var frag = document.createDocumentFragment();
              return (
                typeof frag.cloneNode == 'undefined' ||
                typeof frag.createDocumentFragment == 'undefined' ||
                typeof frag.createElement == 'undefined'
              );
            }());
          } catch(e) {
            // assign a false positive if detection fails => unable to shiv
            supportsHtml5Styles = true;
            supportsUnknownElements = true;
          }

        }());

        /*--------------------------------------------------------------------------*/

        /**
         * Creates a style sheet with the given CSS text and adds it to the document.
         * @private
         * @param {Document} ownerDocument The document.
         * @param {String} cssText The CSS text.
         * @returns {StyleSheet} The style element.
         */
        function addStyleSheet(ownerDocument, cssText) {
          var p = ownerDocument.createElement('p'),
          parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;

          p.innerHTML = 'x<style>' + cssText + '</style>';
          return parent.insertBefore(p.lastChild, parent.firstChild);
        }

        /**
         * Returns the value of `html5.elements` as an array.
         * @private
         * @returns {Array} An array of shived element node names.
         */
        function getElements() {
          var elements = html5.elements;
          return typeof elements == 'string' ? elements.split(' ') : elements;
        }

        /**
         * Returns the data associated to the given document
         * @private
         * @param {Document} ownerDocument The document.
         * @returns {Object} An object of data.
         */
        function getExpandoData(ownerDocument) {
          var data = expandoData[ownerDocument[expando]];
          if (!data) {
            data = {};
            expanID++;
            ownerDocument[expando] = expanID;
            expandoData[expanID] = data;
          }
          return data;
        }

        /**
         * returns a shived element for the given nodeName and document
         * @memberOf html5
         * @param {String} nodeName name of the element
         * @param {Document} ownerDocument The context document.
         * @returns {Object} The shived element.
         */
        function createElement(nodeName, ownerDocument, data){
          if (!ownerDocument) {
            ownerDocument = document;
          }
          if(supportsUnknownElements){
            return ownerDocument.createElement(nodeName);
          }
          if (!data) {
            data = getExpandoData(ownerDocument);
          }
          var node;

          if (data.cache[nodeName]) {
            node = data.cache[nodeName].cloneNode();
          } else if (saveClones.test(nodeName)) {
            node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
          } else {
            node = data.createElem(nodeName);
          }

          // Avoid adding some elements to fragments in IE < 9 because
          // * Attributes like `name` or `type` cannot be set/changed once an element
          //   is inserted into a document/fragment
          // * Link elements with `src` attributes that are inaccessible, as with
          //   a 403 response, will cause the tab/window to crash
          // * Script elements appended to fragments will execute when their `src`
          //   or `text` property is set
          return node.canHaveChildren && !reSkip.test(nodeName) && !node.tagUrn ? data.frag.appendChild(node) : node;
        }

        /**
         * returns a shived DocumentFragment for the given document
         * @memberOf html5
         * @param {Document} ownerDocument The context document.
         * @returns {Object} The shived DocumentFragment.
         */
        function createDocumentFragment(ownerDocument, data){
          if (!ownerDocument) {
            ownerDocument = document;
          }
          if(supportsUnknownElements){
            return ownerDocument.createDocumentFragment();
          }
          data = data || getExpandoData(ownerDocument);
          var clone = data.frag.cloneNode(),
          i = 0,
          elems = getElements(),
          l = elems.length;
          for(;i<l;i++){
            clone.createElement(elems[i]);
          }
          return clone;
        }

        /**
         * Shivs the `createElement` and `createDocumentFragment` methods of the document.
         * @private
         * @param {Document|DocumentFragment} ownerDocument The document.
         * @param {Object} data of the document.
         */
        function shivMethods(ownerDocument, data) {
          if (!data.cache) {
            data.cache = {};
            data.createElem = ownerDocument.createElement;
            data.createFrag = ownerDocument.createDocumentFragment;
            data.frag = data.createFrag();
          }


          ownerDocument.createElement = function(nodeName) {
            //abort shiv
            if (!html5.shivMethods) {
              return data.createElem(nodeName);
            }
            return createElement(nodeName, ownerDocument, data);
          };

          ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' +
                                                          'var n=f.cloneNode(),c=n.createElement;' +
                                                          'h.shivMethods&&(' +
                                                          // unroll the `createElement` calls
                                                          getElements().join().replace(/[\w\-]+/g, function(nodeName) {
            data.createElem(nodeName);
            data.frag.createElement(nodeName);
            return 'c("' + nodeName + '")';
          }) +
            ');return n}'
                                                         )(html5, data.frag);
        }

        /*--------------------------------------------------------------------------*/

        /**
         * Shivs the given document.
         * @memberOf html5
         * @param {Document} ownerDocument The document to shiv.
         * @returns {Document} The shived document.
         */
        function shivDocument(ownerDocument) {
          if (!ownerDocument) {
            ownerDocument = document;
          }
          var data = getExpandoData(ownerDocument);

          if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) {
            data.hasCSS = !!addStyleSheet(ownerDocument,
                                          // corrects block display not defined in IE6/7/8/9
                                          'article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}' +
                                            // adds styling not present in IE6/7/8/9
                                            'mark{background:#FF0;color:#000}' +
                                            // hides non-rendered elements
                                            'template{display:none}'
                                         );
          }
          if (!supportsUnknownElements) {
            shivMethods(ownerDocument, data);
          }
          return ownerDocument;
        }

        /*--------------------------------------------------------------------------*/

        /**
         * The `html5` object is exposed so that more elements can be shived and
         * existing shiving can be detected on iframes.
         * @type Object
         * @example
         *
         * // options can be changed before the script is included
         * html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false };
         */
        var html5 = {

          /**
           * An array or space separated string of node names of the elements to shiv.
           * @memberOf html5
           * @type Array|String
           */
          'elements': options.elements || 'abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video',

          /**
           * current version of html5shiv
           */
          'version': version,

          /**
           * A flag to indicate that the HTML5 style sheet should be inserted.
           * @memberOf html5
           * @type Boolean
           */
          'shivCSS': (options.shivCSS !== false),

          /**
           * Is equal to true if a browser supports creating unknown/HTML5 elements
           * @memberOf html5
           * @type boolean
           */
          'supportsUnknownElements': supportsUnknownElements,

          /**
           * A flag to indicate that the document's `createElement` and `createDocumentFragment`
           * methods should be overwritten.
           * @memberOf html5
           * @type Boolean
           */
          'shivMethods': (options.shivMethods !== false),

          /**
           * A string to describe the type of `html5` object ("default" or "default print").
           * @memberOf html5
           * @type String
           */
          'type': 'default',

          // shivs the document according to the specified `html5` object options
          'shivDocument': shivDocument,

          //creates a shived element
          createElement: createElement,

          //creates a shived documentFragment
          createDocumentFragment: createDocumentFragment
        };

        /*--------------------------------------------------------------------------*/

        // expose html5
        window.html5 = html5;

        // shiv the document
        shivDocument(document);

    }(this, document));
    /*>>shiv*/

    // Assign private properties to the return object with prefix
    Modernizr._version      = version;

    // expose these for the plugin API. Look in the source for how to join() them against your input
    /*>>prefixes*/
    Modernizr._prefixes     = prefixes;
    /*>>prefixes*/
    /*>>domprefixes*/
    Modernizr._domPrefixes  = domPrefixes;
    Modernizr._cssomPrefixes  = cssomPrefixes;
    /*>>domprefixes*/

    /*>>mq*/
    // Modernizr.mq tests a given media query, live against the current state of the window
    // A few important notes:
    //   * If a browser does not support media queries at all (eg. oldIE) the mq() will always return false
    //   * A max-width or orientation query will be evaluated against the current state, which may change later.
    //   * You must specify values. Eg. If you are testing support for the min-width media query use:
    //       Modernizr.mq('(min-width:0)')
    // usage:
    // Modernizr.mq('only screen and (max-width:768)')
    Modernizr.mq            = testMediaQuery;
    /*>>mq*/

    /*>>hasevent*/
    // Modernizr.hasEvent() detects support for a given event, with an optional element to test on
    // Modernizr.hasEvent('gesturestart', elem)
    Modernizr.hasEvent      = isEventSupported;
    /*>>hasevent*/

    /*>>testprop*/
    // Modernizr.testProp() investigates whether a given style property is recognized
    // Note that the property names must be provided in the camelCase variant.
    // Modernizr.testProp('pointerEvents')
    Modernizr.testProp      = function(prop){
        return testProps([prop]);
    };
    /*>>testprop*/

    /*>>testallprops*/
    // Modernizr.testAllProps() investigates whether a given style property,
    //   or any of its vendor-prefixed variants, is recognized
    // Note that the property names must be provided in the camelCase variant.
    // Modernizr.testAllProps('boxSizing')
    Modernizr.testAllProps  = testPropsAll;
    /*>>testallprops*/


    /*>>teststyles*/
    // Modernizr.testStyles() allows you to add custom styles to the document and test an element afterwards
    // Modernizr.testStyles('#modernizr { position:absolute }', function(elem, rule){ ... })
    Modernizr.testStyles    = injectElementWithStyles;
    /*>>teststyles*/


    /*>>prefixed*/
    // Modernizr.prefixed() returns the prefixed or nonprefixed property name variant of your input
    // Modernizr.prefixed('boxSizing') // 'MozBoxSizing'

    // Properties must be passed as dom-style camelcase, rather than `box-sizing` hypentated style.
    // Return values will also be the camelCase variant, if you need to translate that to hypenated style use:
    //
    //     str.replace(/([A-Z])/g, function(str,m1){ return '-' + m1.toLowerCase(); }).replace(/^ms-/,'-ms-');

    // If you're trying to ascertain which transition end event to bind to, you might do something like...
    //
    //     var transEndEventNames = {
    //       'WebkitTransition' : 'webkitTransitionEnd',
    //       'MozTransition'    : 'transitionend',
    //       'OTransition'      : 'oTransitionEnd',
    //       'msTransition'     : 'MSTransitionEnd',
    //       'transition'       : 'transitionend'
    //     },
    //     transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];

    Modernizr.prefixed      = function(prop, obj, elem){
      if(!obj) {
        return testPropsAll(prop, 'pfx');
      } else {
        // Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame'
        return testPropsAll(prop, obj, elem);
      }
    };
    /*>>prefixed*/


    /*>>cssclasses*/
    // Remove "no-js" class from <html> element, if it exists:
    docElement.className = docElement.className.replace(/(^|\s)no-js(\s|$)/, '$1$2') +

                            // Add the new classes to the <html> element.
                            (enableClasses ? ' js ' + classes.join(' ') : '');
    /*>>cssclasses*/

    return Modernizr;

})(this, this.document);
;
/*!
 * ASP.NET SignalR JavaScript Library v2.2.1
 * http://signalr.net/
 *
 * Copyright (c) .NET Foundation. All rights reserved.
 * Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
 *
 */
(function(n,t,i){function w(t,i){var u,f;if(n.isArray(t)){for(u=t.length-1;u>=0;u--)f=t[u],n.type(f)==="string"&&r.transports[f]||(i.log("Invalid transport: "+f+", removing it from the transports list."),t.splice(u,1));t.length===0&&(i.log("No transports remain within the specified transport array."),t=null)}else if(r.transports[t]||t==="auto"){if(t==="auto"&&r._.ieVersion<=8)return["longPolling"]}else i.log("Invalid transport: "+t.toString()+"."),t=null;return t}function b(n){return n==="http:"?80:n==="https:"?443:void 0}function a(n,t){return t.match(/:\d+$/)?t:t+":"+b(n)}function k(t,i){var u=this,r=[];u.tryBuffer=function(i){return t.state===n.signalR.connectionState.connecting?(r.push(i),!0):!1};u.drain=function(){if(t.state===n.signalR.connectionState.connected)while(r.length>0)i(r.shift())};u.clear=function(){r=[]}}var f={nojQuery:"jQuery was not found. Please ensure jQuery is referenced before the SignalR client JavaScript file.",noTransportOnInit:"No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization.",errorOnNegotiate:"Error during negotiation request.",stoppedWhileLoading:"The connection was stopped during page load.",stoppedWhileNegotiating:"The connection was stopped during the negotiate request.",errorParsingNegotiateResponse:"Error parsing negotiate response.",errorDuringStartRequest:"Error during start request. Stopping the connection.",stoppedDuringStartRequest:"The connection was stopped during the start request.",errorParsingStartResponse:"Error parsing start response: '{0}'. Stopping the connection.",invalidStartResponse:"Invalid start response: '{0}'. Stopping the connection.",protocolIncompatible:"You are using a version of the client that isn't compatible with the server. Client version {0}, server version {1}.",sendFailed:"Send failed.",parseFailed:"Failed at parsing response: {0}",longPollFailed:"Long polling request failed.",eventSourceFailedToConnect:"EventSource failed to connect.",eventSourceError:"Error raised by EventSource",webSocketClosed:"WebSocket closed.",pingServerFailedInvalidResponse:"Invalid ping response when pinging server: '{0}'.",pingServerFailed:"Failed to ping server.",pingServerFailedStatusCode:"Failed to ping server.  Server responded with status code {0}, stopping the connection.",pingServerFailedParse:"Failed to parse ping server response, stopping the connection.",noConnectionTransport:"Connection is in an invalid state, there is no transport active.",webSocketsInvalidState:"The Web Socket transport is in an invalid state, transitioning into reconnecting.",reconnectTimeout:"Couldn't reconnect within the configured timeout of {0} ms, disconnecting.",reconnectWindowTimeout:"The client has been inactive since {0} and it has exceeded the inactivity timeout of {1} ms. Stopping the connection."};if(typeof n!="function")throw new Error(f.nojQuery);var r,h,o=t.document.readyState==="complete",e=n(t),c="__Negotiate Aborted__",u={onStart:"onStart",onStarting:"onStarting",onReceived:"onReceived",onError:"onError",onConnectionSlow:"onConnectionSlow",onReconnecting:"onReconnecting",onReconnect:"onReconnect",onStateChanged:"onStateChanged",onDisconnect:"onDisconnect"},v=function(n,i){if(i!==!1){var r;typeof t.console!="undefined"&&(r="["+(new Date).toTimeString()+"] SignalR: "+n,t.console.debug?t.console.debug(r):t.console.log&&t.console.log(r))}},s=function(t,i,r){return i===t.state?(t.state=r,n(t).triggerHandler(u.onStateChanged,[{oldState:i,newState:r}]),!0):!1},y=function(n){return n.state===r.connectionState.disconnected},l=function(n){return n._.keepAliveData.activated&&n.transport.supportsKeepAlive(n)},p=function(i){var f,e;i._.configuredStopReconnectingTimeout||(e=function(t){var i=r._.format(r.resources.reconnectTimeout,t.disconnectTimeout);t.log(i);n(t).triggerHandler(u.onError,[r._.error(i,"TimeoutException")]);t.stop(!1,!1)},i.reconnecting(function(){var n=this;n.state===r.connectionState.reconnecting&&(f=t.setTimeout(function(){e(n)},n.disconnectTimeout))}),i.stateChanged(function(n){n.oldState===r.connectionState.reconnecting&&t.clearTimeout(f)}),i._.configuredStopReconnectingTimeout=!0)};if(r=function(n,t,i){return new r.fn.init(n,t,i)},r._={defaultContentType:"application/x-www-form-urlencoded; charset=UTF-8",ieVersion:function(){var i,n;return t.navigator.appName==="Microsoft Internet Explorer"&&(n=/MSIE ([0-9]+\.[0-9]+)/.exec(t.navigator.userAgent),n&&(i=t.parseFloat(n[1]))),i}(),error:function(n,t,i){var r=new Error(n);return r.source=t,typeof i!="undefined"&&(r.context=i),r},transportError:function(n,t,r,u){var f=this.error(n,r,u);return f.transport=t?t.name:i,f},format:function(){for(var t=arguments[0],n=0;n<arguments.length-1;n++)t=t.replace("{"+n+"}",arguments[n+1]);return t},firefoxMajorVersion:function(n){var t=n.match(/Firefox\/(\d+)/);return!t||!t.length||t.length<2?0:parseInt(t[1],10)},configurePingInterval:function(i){var f=i._.config,e=function(t){n(i).triggerHandler(u.onError,[t])};f&&!i._.pingIntervalId&&f.pingInterval&&(i._.pingIntervalId=t.setInterval(function(){r.transports._logic.pingServer(i).fail(e)},f.pingInterval))}},r.events=u,r.resources=f,r.ajaxDefaults={processData:!0,timeout:null,async:!0,global:!1,cache:!1},r.changeState=s,r.isDisconnecting=y,r.connectionState={connecting:0,connected:1,reconnecting:2,disconnected:4},r.hub={start:function(){throw new Error("SignalR: Error loading hubs. Ensure your hubs reference is correct, e.g. <script src='/signalr/js'><\/script>.");}},typeof e.on=="function")e.on("load",function(){o=!0});else e.load(function(){o=!0});r.fn=r.prototype={init:function(t,i,r){var f=n(this);this.url=t;this.qs=i;this.lastError=null;this._={keepAliveData:{},connectingMessageBuffer:new k(this,function(n){f.triggerHandler(u.onReceived,[n])}),lastMessageAt:(new Date).getTime(),lastActiveAt:(new Date).getTime(),beatInterval:5e3,beatHandle:null,totalTransportConnectTimeout:0};typeof r=="boolean"&&(this.logging=r)},_parseResponse:function(n){var t=this;return n?typeof n=="string"?t.json.parse(n):n:n},_originalJson:t.JSON,json:t.JSON,isCrossDomain:function(i,r){var u;return(i=n.trim(i),r=r||t.location,i.indexOf("http")!==0)?!1:(u=t.document.createElement("a"),u.href=i,u.protocol+a(u.protocol,u.host)!==r.protocol+a(r.protocol,r.host))},ajaxDataType:"text",contentType:"application/json; charset=UTF-8",logging:!1,state:r.connectionState.disconnected,clientProtocol:"1.5",reconnectDelay:2e3,transportConnectTimeout:0,disconnectTimeout:3e4,reconnectWindow:3e4,keepAliveWarnAt:2/3,start:function(i,h){var a=this,v={pingInterval:3e5,waitForPageLoad:!0,transport:"auto",jsonp:!1},d,y=a._deferral||n.Deferred(),b=t.document.createElement("a"),k,g;if(a.lastError=null,a._deferral=y,!a.json)throw new Error("SignalR: No JSON parser found. Please ensure json2.js is referenced before the SignalR.js file if you need to support clients without native JSON parsing support, e.g. IE<8.");if(n.type(i)==="function"?h=i:n.type(i)==="object"&&(n.extend(v,i),n.type(v.callback)==="function"&&(h=v.callback)),v.transport=w(v.transport,a),!v.transport)throw new Error("SignalR: Invalid transport(s) specified, aborting start.");return(a._.config=v,!o&&v.waitForPageLoad===!0)?(a._.deferredStartHandler=function(){a.start(i,h)},e.bind("load",a._.deferredStartHandler),y.promise()):a.state===r.connectionState.connecting?y.promise():s(a,r.connectionState.disconnected,r.connectionState.connecting)===!1?(y.resolve(a),y.promise()):(p(a),b.href=a.url,b.protocol&&b.protocol!==":"?(a.protocol=b.protocol,a.host=b.host):(a.protocol=t.document.location.protocol,a.host=b.host||t.document.location.host),a.baseUrl=a.protocol+"//"+a.host,a.wsProtocol=a.protocol==="https:"?"wss://":"ws://",v.transport==="auto"&&v.jsonp===!0&&(v.transport="longPolling"),a.url.indexOf("//")===0&&(a.url=t.location.protocol+a.url,a.log("Protocol relative URL detected, normalizing it to '"+a.url+"'.")),this.isCrossDomain(a.url)&&(a.log("Auto detected cross domain url."),v.transport==="auto"&&(v.transport=["webSockets","serverSentEvents","longPolling"]),typeof v.withCredentials=="undefined"&&(v.withCredentials=!0),v.jsonp||(v.jsonp=!n.support.cors,v.jsonp&&a.log("Using jsonp because this browser doesn't support CORS.")),a.contentType=r._.defaultContentType),a.withCredentials=v.withCredentials,a.ajaxDataType=v.jsonp?"jsonp":"text",n(a).bind(u.onStart,function(){n.type(h)==="function"&&h.call(a);y.resolve(a)}),a._.initHandler=r.transports._logic.initHandler(a),d=function(i,o){var c=r._.error(f.noTransportOnInit);if(o=o||0,o>=i.length){o===0?a.log("No transports supported by the server were selected."):o===1?a.log("No fallback transports were selected."):a.log("Fallback transports exhausted.");n(a).triggerHandler(u.onError,[c]);y.reject(c);a.stop();return}if(a.state!==r.connectionState.disconnected){var p=i[o],h=r.transports[p],v=function(){d(i,o+1)};a.transport=h;try{a._.initHandler.start(h,function(){var i=r._.firefoxMajorVersion(t.navigator.userAgent)>=11,f=!!a.withCredentials&&i;a.log("The start request succeeded. Transitioning to the connected state.");l(a)&&r.transports._logic.monitorKeepAlive(a);r.transports._logic.startHeartbeat(a);r._.configurePingInterval(a);s(a,r.connectionState.connecting,r.connectionState.connected)||a.log("WARNING! The connection was not in the connecting state.");a._.connectingMessageBuffer.drain();n(a).triggerHandler(u.onStart);e.bind("unload",function(){a.log("Window unloading, stopping the connection.");a.stop(f)});i&&e.bind("beforeunload",function(){t.setTimeout(function(){a.stop(f)},0)})},v)}catch(w){a.log(h.name+" transport threw '"+w.message+"' when attempting to start.");v()}}},k=a.url+"/negotiate",g=function(t,i){var e=r._.error(f.errorOnNegotiate,t,i._.negotiateRequest);n(i).triggerHandler(u.onError,e);y.reject(e);i.stop()},n(a).triggerHandler(u.onStarting),k=r.transports._logic.prepareQueryString(a,k),a.log("Negotiating with '"+k+"'."),a._.negotiateRequest=r.transports._logic.ajax(a,{url:k,error:function(n,t){t!==c?g(n,a):y.reject(r._.error(f.stoppedWhileNegotiating,null,a._.negotiateRequest))},success:function(t){var i,e,h,o=[],s=[];try{i=a._parseResponse(t)}catch(c){g(r._.error(f.errorParsingNegotiateResponse,c),a);return}if(e=a._.keepAliveData,a.appRelativeUrl=i.Url,a.id=i.ConnectionId,a.token=i.ConnectionToken,a.webSocketServerUrl=i.WebSocketServerUrl,a._.pollTimeout=i.ConnectionTimeout*1e3+1e4,a.disconnectTimeout=i.DisconnectTimeout*1e3,a._.totalTransportConnectTimeout=a.transportConnectTimeout+i.TransportConnectTimeout*1e3,i.KeepAliveTimeout?(e.activated=!0,e.timeout=i.KeepAliveTimeout*1e3,e.timeoutWarning=e.timeout*a.keepAliveWarnAt,a._.beatInterval=(e.timeout-e.timeoutWarning)/3):e.activated=!1,a.reconnectWindow=a.disconnectTimeout+(e.timeout||0),!i.ProtocolVersion||i.ProtocolVersion!==a.clientProtocol){h=r._.error(r._.format(f.protocolIncompatible,a.clientProtocol,i.ProtocolVersion));n(a).triggerHandler(u.onError,[h]);y.reject(h);return}n.each(r.transports,function(n){if(n.indexOf("_")===0||n==="webSockets"&&!i.TryWebSockets)return!0;s.push(n)});n.isArray(v.transport)?n.each(v.transport,function(t,i){n.inArray(i,s)>=0&&o.push(i)}):v.transport==="auto"?o=s:n.inArray(v.transport,s)>=0&&o.push(v.transport);d(o)}}),y.promise())},starting:function(t){var i=this;return n(i).bind(u.onStarting,function(){t.call(i)}),i},send:function(n){var t=this;if(t.state===r.connectionState.disconnected)throw new Error("SignalR: Connection must be started before data can be sent. Call .start() before .send()");if(t.state===r.connectionState.connecting)throw new Error("SignalR: Connection has not been fully initialized. Use .start().done() or .start().fail() to run logic after the connection has started.");return t.transport.send(t,n),t},received:function(t){var i=this;return n(i).bind(u.onReceived,function(n,r){t.call(i,r)}),i},stateChanged:function(t){var i=this;return n(i).bind(u.onStateChanged,function(n,r){t.call(i,r)}),i},error:function(t){var i=this;return n(i).bind(u.onError,function(n,r,u){i.lastError=r;t.call(i,r,u)}),i},disconnected:function(t){var i=this;return n(i).bind(u.onDisconnect,function(){t.call(i)}),i},connectionSlow:function(t){var i=this;return n(i).bind(u.onConnectionSlow,function(){t.call(i)}),i},reconnecting:function(t){var i=this;return n(i).bind(u.onReconnecting,function(){t.call(i)}),i},reconnected:function(t){var i=this;return n(i).bind(u.onReconnect,function(){t.call(i)}),i},stop:function(i,h){var a=this,v=a._deferral;if(a._.deferredStartHandler&&e.unbind("load",a._.deferredStartHandler),delete a._.config,delete a._.deferredStartHandler,!o&&(!a._.config||a._.config.waitForPageLoad===!0)){a.log("Stopping connection prior to negotiate.");v&&v.reject(r._.error(f.stoppedWhileLoading));return}if(a.state!==r.connectionState.disconnected)return a.log("Stopping connection."),t.clearTimeout(a._.beatHandle),t.clearInterval(a._.pingIntervalId),a.transport&&(a.transport.stop(a),h!==!1&&a.transport.abort(a,i),l(a)&&r.transports._logic.stopMonitoringKeepAlive(a),a.transport=null),a._.negotiateRequest&&(a._.negotiateRequest.abort(c),delete a._.negotiateRequest),a._.initHandler&&a._.initHandler.stop(),delete a._deferral,delete a.messageId,delete a.groupsToken,delete a.id,delete a._.pingIntervalId,delete a._.lastMessageAt,delete a._.lastActiveAt,a._.connectingMessageBuffer.clear(),s(a,a.state,r.connectionState.disconnected),n(a).triggerHandler(u.onDisconnect),a},log:function(n){v(n,this.logging)}};r.fn.init.prototype=r.fn;r.noConflict=function(){return n.connection===r&&(n.connection=h),r};n.connection&&(h=n.connection);n.connection=n.signalR=r})(window.jQuery,window),function(n,t,i){function s(n){n._.keepAliveData.monitoring&&l(n);u.markActive(n)&&(n._.beatHandle=t.setTimeout(function(){s(n)},n._.beatInterval))}function l(t){var i=t._.keepAliveData,u;t.state===r.connectionState.connected&&(u=(new Date).getTime()-t._.lastMessageAt,u>=i.timeout?(t.log("Keep alive timed out.  Notifying transport that connection has been lost."),t.transport.lostConnection(t)):u>=i.timeoutWarning?i.userNotified||(t.log("Keep alive has been missed, connection may be dead/slow."),n(t).triggerHandler(f.onConnectionSlow),i.userNotified=!0):i.userNotified=!1)}function e(n,t){var i=n.url+t;return n.transport&&(i+="?transport="+n.transport.name),u.prepareQueryString(n,i)}function h(n){this.connection=n;this.startRequested=!1;this.startCompleted=!1;this.connectionStopped=!1}var r=n.signalR,f=n.signalR.events,c=n.signalR.changeState,o="__Start Aborted__",u;r.transports={};h.prototype={start:function(n,r,u){var f=this,e=f.connection,o=!1;if(f.startRequested||f.connectionStopped){e.log("WARNING! "+n.name+" transport cannot be started. Initialization ongoing or completed.");return}e.log(n.name+" transport starting.");n.start(e,function(){o||f.initReceived(n,r)},function(t){return o||(o=!0,f.transportFailed(n,t,u)),!f.startCompleted||f.connectionStopped});f.transportTimeoutHandle=t.setTimeout(function(){o||(o=!0,e.log(n.name+" transport timed out when trying to connect."),f.transportFailed(n,i,u))},e._.totalTransportConnectTimeout)},stop:function(){this.connectionStopped=!0;t.clearTimeout(this.transportTimeoutHandle);r.transports._logic.tryAbortStartRequest(this.connection)},initReceived:function(n,i){var u=this,f=u.connection;if(u.startRequested){f.log("WARNING! The client received multiple init messages.");return}u.connectionStopped||(u.startRequested=!0,t.clearTimeout(u.transportTimeoutHandle),f.log(n.name+" transport connected. Initiating start request."),r.transports._logic.ajaxStart(f,function(){u.startCompleted=!0;i()}))},transportFailed:function(i,u,e){var o=this.connection,h=o._deferral,s;this.connectionStopped||(t.clearTimeout(this.transportTimeoutHandle),this.startRequested?this.startCompleted||(s=r._.error(r.resources.errorDuringStartRequest,u),o.log(i.name+" transport failed during the start request. Stopping the connection."),n(o).triggerHandler(f.onError,[s]),h&&h.reject(s),o.stop()):(i.stop(o),o.log(i.name+" transport failed to connect. Attempting to fall back."),e()))}};u=r.transports._logic={ajax:function(t,i){return n.ajax(n.extend(!0,{},n.signalR.ajaxDefaults,{type:"GET",data:{},xhrFields:{withCredentials:t.withCredentials},contentType:t.contentType,dataType:t.ajaxDataType},i))},pingServer:function(t){var e,f,i=n.Deferred();return t.transport?(e=t.url+"/ping",e=u.addQs(e,t.qs),f=u.ajax(t,{url:e,success:function(n){var u;try{u=t._parseResponse(n)}catch(e){i.reject(r._.transportError(r.resources.pingServerFailedParse,t.transport,e,f));t.stop();return}u.Response==="pong"?i.resolve():i.reject(r._.transportError(r._.format(r.resources.pingServerFailedInvalidResponse,n),t.transport,null,f))},error:function(n){n.status===401||n.status===403?(i.reject(r._.transportError(r._.format(r.resources.pingServerFailedStatusCode,n.status),t.transport,n,f)),t.stop()):i.reject(r._.transportError(r.resources.pingServerFailed,t.transport,n,f))}})):i.reject(r._.transportError(r.resources.noConnectionTransport,t.transport)),i.promise()},prepareQueryString:function(n,i){var r;return r=u.addQs(i,"clientProtocol="+n.clientProtocol),r=u.addQs(r,n.qs),n.token&&(r+="&connectionToken="+t.encodeURIComponent(n.token)),n.data&&(r+="&connectionData="+t.encodeURIComponent(n.data)),r},addQs:function(t,i){var r=t.indexOf("?")!==-1?"&":"?",u;if(!i)return t;if(typeof i=="object")return t+r+n.param(i);if(typeof i=="string")return u=i.charAt(0),(u==="?"||u==="&")&&(r=""),t+r+i;throw new Error("Query string property must be either a string or object.");},getUrl:function(n,i,r,f,e){var h=i==="webSockets"?"":n.baseUrl,o=h+n.appRelativeUrl,s="transport="+i;return!e&&n.groupsToken&&(s+="&groupsToken="+t.encodeURIComponent(n.groupsToken)),r?(o+=f?"/poll":"/reconnect",!e&&n.messageId&&(s+="&messageId="+t.encodeURIComponent(n.messageId))):o+="/connect",o+="?"+s,o=u.prepareQueryString(n,o),e||(o+="&tid="+Math.floor(Math.random()*11)),o},maximizePersistentResponse:function(n){return{MessageId:n.C,Messages:n.M,Initialized:typeof n.S!="undefined"?!0:!1,ShouldReconnect:typeof n.T!="undefined"?!0:!1,LongPollDelay:n.L,GroupsToken:n.G}},updateGroups:function(n,t){t&&(n.groupsToken=t)},stringifySend:function(n,t){return typeof t=="string"||typeof t=="undefined"||t===null?t:n.json.stringify(t)},ajaxSend:function(t,i){var h=u.stringifySend(t,i),c=e(t,"/send"),o,s=function(t,u){n(u).triggerHandler(f.onError,[r._.transportError(r.resources.sendFailed,u.transport,t,o),i])};return o=u.ajax(t,{url:c,type:t.ajaxDataType==="jsonp"?"GET":"POST",contentType:r._.defaultContentType,data:{data:h},success:function(n){var i;if(n){try{i=t._parseResponse(n)}catch(r){s(r,t);t.stop();return}u.triggerReceived(t,i)}},error:function(n,i){i!=="abort"&&i!=="parsererror"&&s(n,t)}})},ajaxAbort:function(n,t){if(typeof n.transport!="undefined"){t=typeof t=="undefined"?!0:t;var i=e(n,"/abort");u.ajax(n,{url:i,async:t,timeout:1e3,type:"POST"});n.log("Fired ajax abort async = "+t+".")}},ajaxStart:function(t,i){var h=function(n){var i=t._deferral;i&&i.reject(n)},s=function(i){t.log("The start request failed. Stopping the connection.");n(t).triggerHandler(f.onError,[i]);h(i);t.stop()};t._.startRequest=u.ajax(t,{url:e(t,"/start"),success:function(n,u,f){var e;try{e=t._parseResponse(n)}catch(o){s(r._.error(r._.format(r.resources.errorParsingStartResponse,n),o,f));return}e.Response==="started"?i():s(r._.error(r._.format(r.resources.invalidStartResponse,n),null,f))},error:function(n,i,u){i!==o?s(r._.error(r.resources.errorDuringStartRequest,u,n)):(t.log("The start request aborted because connection.stop() was called."),h(r._.error(r.resources.stoppedDuringStartRequest,null,n)))}})},tryAbortStartRequest:function(n){n._.startRequest&&(n._.startRequest.abort(o),delete n._.startRequest)},tryInitialize:function(n,t,i){t.Initialized&&i?i():t.Initialized&&n.log("WARNING! The client received an init message after reconnecting.")},triggerReceived:function(t,i){t._.connectingMessageBuffer.tryBuffer(i)||n(t).triggerHandler(f.onReceived,[i])},processMessages:function(t,i,r){var f;u.markLastMessage(t);i&&(f=u.maximizePersistentResponse(i),u.updateGroups(t,f.GroupsToken),f.MessageId&&(t.messageId=f.MessageId),f.Messages&&(n.each(f.Messages,function(n,i){u.triggerReceived(t,i)}),u.tryInitialize(t,f,r)))},monitorKeepAlive:function(t){var i=t._.keepAliveData;i.monitoring?t.log("Tried to monitor keep alive but it's already being monitored."):(i.monitoring=!0,u.markLastMessage(t),t._.keepAliveData.reconnectKeepAliveUpdate=function(){u.markLastMessage(t)},n(t).bind(f.onReconnect,t._.keepAliveData.reconnectKeepAliveUpdate),t.log("Now monitoring keep alive with a warning timeout of "+i.timeoutWarning+", keep alive timeout of "+i.timeout+" and disconnecting timeout of "+t.disconnectTimeout))},stopMonitoringKeepAlive:function(t){var i=t._.keepAliveData;i.monitoring&&(i.monitoring=!1,n(t).unbind(f.onReconnect,t._.keepAliveData.reconnectKeepAliveUpdate),t._.keepAliveData={},t.log("Stopping the monitoring of the keep alive."))},startHeartbeat:function(n){n._.lastActiveAt=(new Date).getTime();s(n)},markLastMessage:function(n){n._.lastMessageAt=(new Date).getTime()},markActive:function(n){return u.verifyLastActive(n)?(n._.lastActiveAt=(new Date).getTime(),!0):!1},isConnectedOrReconnecting:function(n){return n.state===r.connectionState.connected||n.state===r.connectionState.reconnecting},ensureReconnectingState:function(t){return c(t,r.connectionState.connected,r.connectionState.reconnecting)===!0&&n(t).triggerHandler(f.onReconnecting),t.state===r.connectionState.reconnecting},clearReconnectTimeout:function(n){n&&n._.reconnectTimeout&&(t.clearTimeout(n._.reconnectTimeout),delete n._.reconnectTimeout)},verifyLastActive:function(t){if((new Date).getTime()-t._.lastActiveAt>=t.reconnectWindow){var i=r._.format(r.resources.reconnectWindowTimeout,new Date(t._.lastActiveAt),t.reconnectWindow);return t.log(i),n(t).triggerHandler(f.onError,[r._.error(i,"TimeoutException")]),t.stop(!1,!1),!1}return!0},reconnect:function(n,i){var f=r.transports[i];if(u.isConnectedOrReconnecting(n)&&!n._.reconnectTimeout){if(!u.verifyLastActive(n))return;n._.reconnectTimeout=t.setTimeout(function(){u.verifyLastActive(n)&&(f.stop(n),u.ensureReconnectingState(n)&&(n.log(i+" reconnecting."),f.start(n)))},n.reconnectDelay)}},handleParseFailure:function(t,i,u,e,o){var s=r._.transportError(r._.format(r.resources.parseFailed,i),t.transport,u,o);e&&e(s)?t.log("Failed to parse server response while attempting to connect."):(n(t).triggerHandler(f.onError,[s]),t.stop())},initHandler:function(n){return new h(n)},foreverFrame:{count:0,connections:{}}}}(window.jQuery,window),function(n,t){var r=n.signalR,u=n.signalR.events,f=n.signalR.changeState,i=r.transports._logic;r.transports.webSockets={name:"webSockets",supportsKeepAlive:function(){return!0},send:function(t,f){var e=i.stringifySend(t,f);try{t.socket.send(e)}catch(o){n(t).triggerHandler(u.onError,[r._.transportError(r.resources.webSocketsInvalidState,t.transport,o,t.socket),f])}},start:function(e,o,s){var h,c=!1,l=this,a=!o,v=n(e);if(!t.WebSocket){s();return}e.socket||(h=e.webSocketServerUrl?e.webSocketServerUrl:e.wsProtocol+e.host,h+=i.getUrl(e,this.name,a),e.log("Connecting to websocket endpoint '"+h+"'."),e.socket=new t.WebSocket(h),e.socket.onopen=function(){c=!0;e.log("Websocket opened.");i.clearReconnectTimeout(e);f(e,r.connectionState.reconnecting,r.connectionState.connected)===!0&&v.triggerHandler(u.onReconnect)},e.socket.onclose=function(t){var i;this===e.socket&&(c&&typeof t.wasClean!="undefined"&&t.wasClean===!1?(i=r._.transportError(r.resources.webSocketClosed,e.transport,t),e.log("Unclean disconnect from websocket: "+(t.reason||"[no reason given]."))):e.log("Websocket closed."),s&&s(i)||(i&&n(e).triggerHandler(u.onError,[i]),l.reconnect(e)))},e.socket.onmessage=function(t){var r;try{r=e._parseResponse(t.data)}catch(u){i.handleParseFailure(e,t.data,u,s,t);return}r&&(n.isEmptyObject(r)||r.M?i.processMessages(e,r,o):i.triggerReceived(e,r))})},reconnect:function(n){i.reconnect(n,this.name)},lostConnection:function(n){this.reconnect(n)},stop:function(n){i.clearReconnectTimeout(n);n.socket&&(n.log("Closing the Websocket."),n.socket.close(),n.socket=null)},abort:function(n,t){i.ajaxAbort(n,t)}}}(window.jQuery,window),function(n,t){var i=n.signalR,u=n.signalR.events,e=n.signalR.changeState,r=i.transports._logic,f=function(n){t.clearTimeout(n._.reconnectAttemptTimeoutHandle);delete n._.reconnectAttemptTimeoutHandle};i.transports.serverSentEvents={name:"serverSentEvents",supportsKeepAlive:function(){return!0},timeOut:3e3,start:function(o,s,h){var c=this,l=!1,a=n(o),v=!s,y;if(o.eventSource&&(o.log("The connection already has an event source. Stopping it."),o.stop()),!t.EventSource){h&&(o.log("This browser doesn't support SSE."),h());return}y=r.getUrl(o,this.name,v);try{o.log("Attempting to connect to SSE endpoint '"+y+"'.");o.eventSource=new t.EventSource(y,{withCredentials:o.withCredentials})}catch(p){o.log("EventSource failed trying to connect with error "+p.Message+".");h?h():(a.triggerHandler(u.onError,[i._.transportError(i.resources.eventSourceFailedToConnect,o.transport,p)]),v&&c.reconnect(o));return}v&&(o._.reconnectAttemptTimeoutHandle=t.setTimeout(function(){l===!1&&o.eventSource.readyState!==t.EventSource.OPEN&&c.reconnect(o)},c.timeOut));o.eventSource.addEventListener("open",function(){o.log("EventSource connected.");f(o);r.clearReconnectTimeout(o);l===!1&&(l=!0,e(o,i.connectionState.reconnecting,i.connectionState.connected)===!0&&a.triggerHandler(u.onReconnect))},!1);o.eventSource.addEventListener("message",function(n){var t;if(n.data!=="initialized"){try{t=o._parseResponse(n.data)}catch(i){r.handleParseFailure(o,n.data,i,h,n);return}r.processMessages(o,t,s)}},!1);o.eventSource.addEventListener("error",function(n){var r=i._.transportError(i.resources.eventSourceError,o.transport,n);this===o.eventSource&&(h&&h(r)||(o.log("EventSource readyState: "+o.eventSource.readyState+"."),n.eventPhase===t.EventSource.CLOSED?(o.log("EventSource reconnecting due to the server connection ending."),c.reconnect(o)):(o.log("EventSource error."),a.triggerHandler(u.onError,[r]))))},!1)},reconnect:function(n){r.reconnect(n,this.name)},lostConnection:function(n){this.reconnect(n)},send:function(n,t){r.ajaxSend(n,t)},stop:function(n){f(n);r.clearReconnectTimeout(n);n&&n.eventSource&&(n.log("EventSource calling close()."),n.eventSource.close(),n.eventSource=null,delete n.eventSource)},abort:function(n,t){r.ajaxAbort(n,t)}}}(window.jQuery,window),function(n,t){var r=n.signalR,e=n.signalR.events,o=n.signalR.changeState,i=r.transports._logic,u=function(){var n=t.document.createElement("iframe");return n.setAttribute("style","position:absolute;top:0;left:0;width:0;height:0;visibility:hidden;"),n},f=function(){var i=null,f=1e3,n=0;return{prevent:function(){r._.ieVersion<=8&&(n===0&&(i=t.setInterval(function(){var n=u();t.document.body.appendChild(n);t.document.body.removeChild(n);n=null},f)),n++)},cancel:function(){n===1&&t.clearInterval(i);n>0&&n--}}}();r.transports.foreverFrame={name:"foreverFrame",supportsKeepAlive:function(){return!0},iframeClearThreshold:50,start:function(n,r,e){var l=this,s=i.foreverFrame.count+=1,h,o=u(),c=function(){n.log("Forever frame iframe finished loading and is no longer receiving messages.");e&&e()||l.reconnect(n)};if(t.EventSource){e&&(n.log("Forever Frame is not supported by SignalR on browsers with SSE support."),e());return}o.setAttribute("data-signalr-connection-id",n.id);f.prevent();h=i.getUrl(n,this.name);h+="&frameId="+s;t.document.documentElement.appendChild(o);n.log("Binding to iframe's load event.");o.addEventListener?o.addEventListener("load",c,!1):o.attachEvent&&o.attachEvent("onload",c);o.src=h;i.foreverFrame.connections[s]=n;n.frame=o;n.frameId=s;r&&(n.onSuccess=function(){n.log("Iframe transport started.");r()})},reconnect:function(n){var r=this;i.isConnectedOrReconnecting(n)&&i.verifyLastActive(n)&&t.setTimeout(function(){if(i.verifyLastActive(n)&&n.frame&&i.ensureReconnectingState(n)){var u=n.frame,t=i.getUrl(n,r.name,!0)+"&frameId="+n.frameId;n.log("Updating iframe src to '"+t+"'.");u.src=t}},n.reconnectDelay)},lostConnection:function(n){this.reconnect(n)},send:function(n,t){i.ajaxSend(n,t)},receive:function(t,u){var f,e,o;if(t.json!==t._originalJson&&(u=t._originalJson.stringify(u)),o=t._parseResponse(u),i.processMessages(t,o,t.onSuccess),t.state===n.signalR.connectionState.connected&&(t.frameMessageCount=(t.frameMessageCount||0)+1,t.frameMessageCount>r.transports.foreverFrame.iframeClearThreshold&&(t.frameMessageCount=0,f=t.frame.contentWindow||t.frame.contentDocument,f&&f.document&&f.document.body)))for(e=f.document.body;e.firstChild;)e.removeChild(e.firstChild)},stop:function(n){var r=null;if(f.cancel(),n.frame){if(n.frame.stop)n.frame.stop();else try{r=n.frame.contentWindow||n.frame.contentDocument;r.document&&r.document.execCommand&&r.document.execCommand("Stop")}catch(u){n.log("Error occurred when stopping foreverFrame transport. Message = "+u.message+".")}n.frame.parentNode===t.document.body&&t.document.body.removeChild(n.frame);delete i.foreverFrame.connections[n.frameId];n.frame=null;n.frameId=null;delete n.frame;delete n.frameId;delete n.onSuccess;delete n.frameMessageCount;n.log("Stopping forever frame.")}},abort:function(n,t){i.ajaxAbort(n,t)},getConnection:function(n){return i.foreverFrame.connections[n]},started:function(t){o(t,r.connectionState.reconnecting,r.connectionState.connected)===!0&&n(t).triggerHandler(e.onReconnect)}}}(window.jQuery,window),function(n,t){var r=n.signalR,u=n.signalR.events,e=n.signalR.changeState,f=n.signalR.isDisconnecting,i=r.transports._logic;r.transports.longPolling={name:"longPolling",supportsKeepAlive:function(){return!1},reconnectDelay:3e3,start:function(o,s,h){var a=this,v=function(){v=n.noop;o.log("LongPolling connected.");s?s():o.log("WARNING! The client received an init message after reconnecting.")},y=function(n){return h(n)?(o.log("LongPolling failed to connect."),!0):!1},c=o._,l=0,p=function(i){t.clearTimeout(c.reconnectTimeoutId);c.reconnectTimeoutId=null;e(i,r.connectionState.reconnecting,r.connectionState.connected)===!0&&(i.log("Raising the reconnect event"),n(i).triggerHandler(u.onReconnect))},w=36e5;o.pollXhr&&(o.log("Polling xhr requests already exists, aborting."),o.stop());o.messageId=null;c.reconnectTimeoutId=null;c.pollTimeoutId=t.setTimeout(function(){(function e(s,h){var g=s.messageId,nt=g===null,k=!nt,tt=!h,d=i.getUrl(s,a.name,k,tt,!0),b={};(s.messageId&&(b.messageId=s.messageId),s.groupsToken&&(b.groupsToken=s.groupsToken),f(s)!==!0)&&(o.log("Opening long polling request to '"+d+"'."),s.pollXhr=i.ajax(o,{xhrFields:{onprogress:function(){i.markLastMessage(o)}},url:d,type:"POST",contentType:r._.defaultContentType,data:b,timeout:o._.pollTimeout,success:function(r){var h,w=0,u,a;o.log("Long poll complete.");l=0;try{h=o._parseResponse(r)}catch(b){i.handleParseFailure(s,r,b,y,s.pollXhr);return}(c.reconnectTimeoutId!==null&&p(s),h&&(u=i.maximizePersistentResponse(h)),i.processMessages(s,h,v),u&&n.type(u.LongPollDelay)==="number"&&(w=u.LongPollDelay),f(s)!==!0)&&(a=u&&u.ShouldReconnect,!a||i.ensureReconnectingState(s))&&(w>0?c.pollTimeoutId=t.setTimeout(function(){e(s,a)},w):e(s,a))},error:function(f,h){var v=r._.transportError(r.resources.longPollFailed,o.transport,f,s.pollXhr);if(t.clearTimeout(c.reconnectTimeoutId),c.reconnectTimeoutId=null,h==="abort"){o.log("Aborted xhr request.");return}if(!y(v)){if(l++,o.state!==r.connectionState.reconnecting&&(o.log("An error occurred using longPolling. Status = "+h+".  Response = "+f.responseText+"."),n(s).triggerHandler(u.onError,[v])),(o.state===r.connectionState.connected||o.state===r.connectionState.reconnecting)&&!i.verifyLastActive(o))return;if(!i.ensureReconnectingState(s))return;c.pollTimeoutId=t.setTimeout(function(){e(s,!0)},a.reconnectDelay)}}}),k&&h===!0&&(c.reconnectTimeoutId=t.setTimeout(function(){p(s)},Math.min(1e3*(Math.pow(2,l)-1),w))))})(o)},250)},lostConnection:function(n){n.pollXhr&&n.pollXhr.abort("lostConnection")},send:function(n,t){i.ajaxSend(n,t)},stop:function(n){t.clearTimeout(n._.pollTimeoutId);t.clearTimeout(n._.reconnectTimeoutId);delete n._.pollTimeoutId;delete n._.reconnectTimeoutId;n.pollXhr&&(n.pollXhr.abort(),n.pollXhr=null,delete n.pollXhr)},abort:function(n,t){i.ajaxAbort(n,t)}}}(window.jQuery,window),function(n){function r(n){return n+e}function s(n,t,i){for(var f=n.length,u=[],r=0;r<f;r+=1)n.hasOwnProperty(r)&&(u[r]=t.call(i,n[r],r,n));return u}function h(t){return n.isFunction(t)?null:n.type(t)==="undefined"?null:t}function u(n){for(var t in n)if(n.hasOwnProperty(t))return!0;return!1}function f(n,t){var i=n._.invocationCallbacks,r,f;u(i)&&n.log("Clearing hub invocation callbacks with error: "+t+".");n._.invocationCallbackId=0;delete n._.invocationCallbacks;n._.invocationCallbacks={};for(f in i)r=i[f],r.method.call(r.scope,{E:t})}function i(n,t){return new i.fn.init(n,t)}function t(i,r){var u={qs:null,logging:!1,useDefaultPath:!0};return n.extend(u,r),(!i||u.useDefaultPath)&&(i=(i||"")+"/signalr"),new t.fn.init(i,u)}var e=".hubProxy",o=n.signalR;i.fn=i.prototype={init:function(n,t){this.state={};this.connection=n;this.hubName=t;this._={callbackMap:{}}},constructor:i,hasSubscriptions:function(){return u(this._.callbackMap)},on:function(t,i){var u=this,f=u._.callbackMap;return t=t.toLowerCase(),f[t]||(f[t]={}),f[t][i]=function(n,t){i.apply(u,t)},n(u).bind(r(t),f[t][i]),u},off:function(t,i){var e=this,o=e._.callbackMap,f;return t=t.toLowerCase(),f=o[t],f&&(f[i]?(n(e).unbind(r(t),f[i]),delete f[i],u(f)||delete o[t]):i||(n(e).unbind(r(t)),delete o[t])),e},invoke:function(t){var i=this,r=i.connection,e=n.makeArray(arguments).slice(1),c=s(e,h),f={H:i.hubName,M:t,A:c,I:r._.invocationCallbackId},u=n.Deferred(),l=function(f){var e=i._maximizeHubResponse(f),h,s;n.extend(i.state,e.State);e.Progress?u.notifyWith?u.notifyWith(i,[e.Progress.Data]):r._.progressjQueryVersionLogged||(r.log("A hub method invocation progress update was received but the version of jQuery in use ("+n.prototype.jquery+") does not support progress updates. Upgrade to jQuery 1.7+ to receive progress notifications."),r._.progressjQueryVersionLogged=!0):e.Error?(e.StackTrace&&r.log(e.Error+"\n"+e.StackTrace+"."),h=e.IsHubException?"HubException":"Exception",s=o._.error(e.Error,h),s.data=e.ErrorData,r.log(i.hubName+"."+t+" failed to execute. Error: "+s.message),u.rejectWith(i,[s])):(r.log("Invoked "+i.hubName+"."+t),u.resolveWith(i,[e.Result]))};return r._.invocationCallbacks[r._.invocationCallbackId.toString()]={scope:i,method:l},r._.invocationCallbackId+=1,n.isEmptyObject(i.state)||(f.S=i.state),r.log("Invoking "+i.hubName+"."+t),r.send(f),u.promise()},_maximizeHubResponse:function(n){return{State:n.S,Result:n.R,Progress:n.P?{Id:n.P.I,Data:n.P.D}:null,Id:n.I,IsHubException:n.H,Error:n.E,StackTrace:n.T,ErrorData:n.D}}};i.fn.init.prototype=i.fn;t.fn=t.prototype=n.connection();t.fn.init=function(t,i){var e={qs:null,logging:!1,useDefaultPath:!0},u=this;n.extend(e,i);n.signalR.fn.init.call(u,t,e.qs,e.logging);u.proxies={};u._.invocationCallbackId=0;u._.invocationCallbacks={};u.received(function(t){var f,o,e,i,s,h;t&&(typeof t.P!="undefined"?(e=t.P.I.toString(),i=u._.invocationCallbacks[e],i&&i.method.call(i.scope,t)):typeof t.I!="undefined"?(e=t.I.toString(),i=u._.invocationCallbacks[e],i&&(u._.invocationCallbacks[e]=null,delete u._.invocationCallbacks[e],i.method.call(i.scope,t))):(f=this._maximizeClientHubInvocation(t),u.log("Triggering client hub event '"+f.Method+"' on hub '"+f.Hub+"'."),s=f.Hub.toLowerCase(),h=f.Method.toLowerCase(),o=this.proxies[s],n.extend(o.state,f.State),n(o).triggerHandler(r(h),[f.Args])))});u.error(function(n,t){var i,r;t&&(i=t.I,r=u._.invocationCallbacks[i],r&&(u._.invocationCallbacks[i]=null,delete u._.invocationCallbacks[i],r.method.call(r.scope,{E:n})))});u.reconnecting(function(){u.transport&&u.transport.name==="webSockets"&&f(u,"Connection started reconnecting before invocation result was received.")});u.disconnected(function(){f(u,"Connection was disconnected before invocation result was received.")})};t.fn._maximizeClientHubInvocation=function(n){return{Hub:n.H,Method:n.M,Args:n.A,State:n.S}};t.fn._registerSubscribedHubs=function(){var t=this;t._subscribedToHubs||(t._subscribedToHubs=!0,t.starting(function(){var i=[];n.each(t.proxies,function(n){this.hasSubscriptions()&&(i.push({name:n}),t.log("Client subscribed to hub '"+n+"'."))});i.length===0&&t.log("No hubs have been subscribed to.  The client will not receive data from hubs.  To fix, declare at least one client side function prior to connection start for each hub you wish to subscribe to.");t.data=t.json.stringify(i)}))};t.fn.createHubProxy=function(n){n=n.toLowerCase();var t=this.proxies[n];return t||(t=i(this,n),this.proxies[n]=t),this._registerSubscribedHubs(),t};t.fn.init.prototype=t.fn;n.hubConnection=t}(window.jQuery,window),function(n){n.signalR.version="2.2.1"}(window.jQuery);
/*!
 * Bootstrap v3.3.7 (http://getbootstrap.com)
 * Copyright 2011-2016 Twitter, Inc.
 * Licensed under the MIT license
 */
if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>3)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){if(a(b.target).is(this))return b.handleObj.handler.apply(this,arguments)}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.7",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a("#"===f?[]:f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.7",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c).prop(c,!0)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c).prop(c,!1))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target).closest(".btn");b.call(d,"toggle"),a(c.target).is('input[type="radio"], input[type="checkbox"]')||(c.preventDefault(),d.is("input,button")?d.trigger("focus"):d.find("input:visible,button:visible").first().trigger("focus"))}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.7",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(!(a>this.$items.length-1||a<0))return this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){if(!this.sliding)return this.slide("next")},c.prototype.prev=function(){if(!this.sliding)return this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.7",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.7",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&j<i.length-1&&j++,~j||(j=0),i.eq(j).trigger("focus")}}}};var h=a.fn.dropdown;a.fn.dropdown=d,a.fn.dropdown.Constructor=g,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=h,this},a(document).on("click.bs.dropdown.data-api",c).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",f,g.prototype.toggle).on("keydown.bs.dropdown.data-api",f,g.prototype.keydown).on("keydown.bs.dropdown.data-api",".dropdown-menu",g.prototype.keydown)}(jQuery),+function(a){"use strict";function b(b,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},c.DEFAULTS,e.data(),"object"==typeof b&&b);f||e.data("bs.modal",f=new c(this,g)),"string"==typeof b?f[b](d):g.show&&f.show(d)})}var c=function(b,c){this.options=c,this.$body=a(document.body),this.$element=a(b),this.$dialog=this.$element.find(".modal-dialog"),this.$backdrop=null,this.isShown=null,this.originalBodyPad=null,this.scrollbarWidth=0,this.ignoreBackdropClick=!1,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};c.VERSION="3.3.7",c.TRANSITION_DURATION=300,c.BACKDROP_TRANSITION_DURATION=150,c.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},c.prototype.toggle=function(a){return this.isShown?this.hide():this.show(a)},c.prototype.show=function(b){var d=this,e=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.$dialog.on("mousedown.dismiss.bs.modal",function(){d.$element.one("mouseup.dismiss.bs.modal",function(b){a(b.target).is(d.$element)&&(d.ignoreBackdropClick=!0)})}),this.backdrop(function(){var e=a.support.transition&&d.$element.hasClass("fade");d.$element.parent().length||d.$element.appendTo(d.$body),d.$element.show().scrollTop(0),d.adjustDialog(),e&&d.$element[0].offsetWidth,d.$element.addClass("in"),d.enforceFocus();var f=a.Event("shown.bs.modal",{relatedTarget:b});e?d.$dialog.one("bsTransitionEnd",function(){d.$element.trigger("focus").trigger(f)}).emulateTransitionEnd(c.TRANSITION_DURATION):d.$element.trigger("focus").trigger(f)}))},c.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal"),this.$dialog.off("mousedown.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(c.TRANSITION_DURATION):this.hideModal())},c.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){document===a.target||this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.trigger("focus")},this))},c.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},c.prototype.resize=function(){this.isShown?a(window).on("resize.bs.modal",a.proxy(this.handleUpdate,this)):a(window).off("resize.bs.modal")},c.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.$body.removeClass("modal-open"),a.resetAdjustments(),a.resetScrollbar(),a.$element.trigger("hidden.bs.modal")})},c.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},c.prototype.backdrop=function(b){var d=this,e=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var f=a.support.transition&&e;if(this.$backdrop=a(document.createElement("div")).addClass("modal-backdrop "+e).appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(a){return this.ignoreBackdropClick?void(this.ignoreBackdropClick=!1):void(a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus():this.hide()))},this)),f&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;f?this.$backdrop.one("bsTransitionEnd",b).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):b()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var g=function(){d.removeBackdrop(),b&&b()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",g).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):g()}else b&&b()},c.prototype.handleUpdate=function(){this.adjustDialog()},c.prototype.adjustDialog=function(){var a=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth<a,this.scrollbarWidth=this.measureScrollbar()},c.prototype.setScrollbar=function(){var a=parseInt(this.$body.css("padding-right")||0,10);this.originalBodyPad=document.body.style.paddingRight||"",this.bodyIsOverflowing&&this.$body.css("padding-right",a+this.scrollbarWidth)},c.prototype.resetScrollbar=function(){this.$body.css("padding-right",this.originalBodyPad)},c.prototype.measureScrollbar=function(){var a=document.createElement("div");a.className="modal-scrollbar-measure",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=b,a.fn.modal.Constructor=c,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(c){var d=a(this),e=d.attr("href"),f=a(d.attr("data-target")||e&&e.replace(/.*(?=#[^\s]+$)/,"")),g=f.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is("a")&&c.preventDefault(),f.one("show.bs.modal",function(a){a.isDefaultPrevented()||f.one("hidden.bs.modal",function(){d.is(":visible")&&d.trigger("focus")})}),b.call(f,g,this)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof b&&b;!e&&/destroy|hide/.test(b)||(e||d.data("bs.tooltip",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.type=null,this.options=null,this.enabled=null,this.timeout=null,this.hoverState=null,this.$element=null,this.inState=null,this.init("tooltip",a,b)};c.VERSION="3.3.7",c.TRANSITION_DURATION=150,c.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);if(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),!c.isInStateTrue())return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-m<o.top?"bottom":"right"==h&&k.right+l>o.width?"left":"left"==h&&k.left-l<o.left?"right":h,f.removeClass(n).addClass(h)}var p=this.getCalculatedOffset(h,k,l,m);this.applyPlacement(p,h);var q=function(){var a=e.hoverState;e.$element.trigger("shown.bs."+e.type),e.hoverState=null,"out"==a&&e.leave(e)};a.support.transition&&this.$tip.hasClass("fade")?f.one("bsTransitionEnd",q).emulateTransitionEnd(c.TRANSITION_DURATION):q()}},c.prototype.applyPlacement=function(b,c){var d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),b.top+=g,b.left+=h,a.offset.setOffset(d[0],a.extend({using:function(a){d.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),d.addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;"top"==c&&j!=f&&(b.top=b.top+f-j);var k=this.getViewportAdjustedDelta(c,b,i,j);k.left?b.left+=k.left:b.top+=k.top;var l=/top|bottom/.test(c),m=l?2*k.left-e+i:2*k.top-f+j,n=l?"offsetWidth":"offsetHeight";d.offset(b),this.replaceArrow(m,d[0][n],l)},c.prototype.replaceArrow=function(a,b,c){this.arrow().css(c?"left":"top",50*(1-a/b)+"%").css(c?"top":"left","")},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},c.prototype.hide=function(b){function d(){"in"!=e.hoverState&&f.detach(),e.$element&&e.$element.removeAttr("aria-describedby").trigger("hidden.bs."+e.type),b&&b()}var e=this,f=a(this.$tip),g=a.Event("hide.bs."+this.type);if(this.$element.trigger(g),!g.isDefaultPrevented())return f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",d).emulateTransitionEnd(c.TRANSITION_DURATION):d(),this.hoverState=null,this},c.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},c.prototype.hasContent=function(){return this.getTitle()},c.prototype.getPosition=function(b){b=b||this.$element;var c=b[0],d="BODY"==c.tagName,e=c.getBoundingClientRect();null==e.width&&(e=a.extend({},e,{width:e.right-e.left,height:e.bottom-e.top}));var f=window.SVGElement&&c instanceof window.SVGElement,g=d?{top:0,left:0}:f?null:b.offset(),h={scroll:d?document.documentElement.scrollTop||document.body.scrollTop:b.scrollTop()},i=d?{width:a(window).width(),height:a(window).height()}:null;return a.extend({},e,h,i,g)},c.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},c.prototype.getViewportAdjustedDelta=function(a,b,c,d){var e={top:0,left:0};if(!this.$viewport)return e;var f=this.options.viewport&&this.options.viewport.padding||0,g=this.getPosition(this.$viewport);if(/right|left/.test(a)){var h=b.top-f-g.scroll,i=b.top+f-g.scroll+d;h<g.top?e.top=g.top-h:i>g.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;j<g.left?e.left=g.left-j:k>g.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null,a.$element=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;!e&&/destroy|hide/.test(b)||(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.7",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.7",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b<e[0])return this.activeTarget=null,this.clear();for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(void 0===e[a+1]||b<e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){
this.activeTarget=b,this.clear();var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.7",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.7",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return e<c&&"top";if("bottom"==this.affixed)return null!=c?!(e+this.unpin<=f.top)&&"bottom":!(e+g<=a-d)&&"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&e<=c?"top":null!=d&&i+j>=a-d&&"bottom"},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);;
/* ===========================================================
 * bootstrap-modalmanager.js v2.1
 * ===========================================================
 * Copyright 2012 Jordan Schroter.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ========================================================== */

!function ($) {

	"use strict"; // jshint ;_;

	/* MODAL MANAGER CLASS DEFINITION
	* ====================== */

	var ModalManager = function (element, options) {
		this.init(element, options);
	};

	ModalManager.prototype = {

		constructor: ModalManager,

		init: function (element, options) {
			this.$element = $(element);
			this.options = $.extend({}, $.fn.modalmanager.defaults, this.$element.data(), typeof options == 'object' && options);
			this.stack = [];
			this.backdropCount = 0;

			if (this.options.resize) {
				var resizeTimeout,
					that = this;

				$(window).on('resize.modal', function(){
					resizeTimeout && clearTimeout(resizeTimeout);
					resizeTimeout = setTimeout(function(){
						for (var i = 0; i < that.stack.length; i++){
							that.stack[i].isShown && that.stack[i].layout();
						}
					}, 10);
				});
			}
		},

		createModal: function (element, options) {
			$(element).modal($.extend({ manager: this }, options));
		},

		appendModal: function (modal) {
			this.stack.push(modal);

			var that = this;

			modal.$element.on('show.modalmanager', targetIsSelf(function (e) {

				var showModal = function(){
					modal.isShown = true;

					var transition = $.support.transition && modal.$element.hasClass('fade');

					that.$element
						.toggleClass('modal-open', that.hasOpenModal())
				    	.toggleClass('page-overflow', $(window).height() < that.$element.height());
				    
					modal.$parent = modal.$element.parent();

					modal.$container = that.createContainer(modal);

					modal.$element.appendTo(modal.$container);

					that.backdrop(modal, function () {

						modal.$element.show();

						if (transition) {       
							//modal.$element[0].style.display = 'run-in';       
							modal.$element[0].offsetWidth;
							//modal.$element.one($.support.transition.end, function () { modal.$element[0].style.display = 'block' });  
						}
						
						modal.layout();

						modal.$element
							.addClass('in')
							.attr('aria-hidden', false);

						var complete = function () {
							that.setFocus();
							modal.$element.triggerHandler('shown');
						};

						transition ?
							modal.$element.one($.support.transition.end, complete) :
							complete();
					});
				};

				modal.options.replace ?
					that.replace(showModal) :
					showModal();
			}));

			modal.$element.on('hidden.modalmanager', targetIsSelf(function (e) {

				that.backdrop(modal);

				if (modal.$backdrop){
					$.support.transition && modal.$element.hasClass('fade') ?
						modal.$backdrop.one($.support.transition.end, function () { that.destroyModal(modal) }) :
						that.destroyModal(modal);
				} else {
					that.destroyModal(modal);
				}

			}));

			modal.$element.on('destroy.modalmanager', targetIsSelf(function (e) {
				that.removeModal(modal);
			}));

		},

		destroyModal: function (modal) {

			modal.destroy();

			var hasOpenModal = this.hasOpenModal();

			this.$element.toggleClass('modal-open', hasOpenModal);

			if (!hasOpenModal){
				this.$element.removeClass('page-overflow');
			}

			this.removeContainer(modal);

			this.setFocus();
		},

		hasOpenModal: function () {
			for (var i = 0; i < this.stack.length; i++){
				if (this.stack[i].isShown) return true;
			}

			return false;
		},

		setFocus: function () {
			var topModal;

			for (var i = 0; i < this.stack.length; i++){
				if (this.stack[i].isShown) topModal = this.stack[i];
			}

			if (!topModal) return;

			topModal.focus();

		},

		removeModal: function (modal) {
			modal.$element.off('.modalmanager');
			if (modal.$backdrop) this.removeBackdrop.call(modal);
			this.stack.splice(this.getIndexOfModal(modal), 1);
		},

		getModalAt: function (index) {
			return this.stack[index];
		},

		getIndexOfModal: function (modal) {
			for (var i = 0; i < this.stack.length; i++){
				if (modal === this.stack[i]) return i;
			}
		},

		replace: function (callback) {
			var topModal;

			for (var i = 0; i < this.stack.length; i++){
				if (this.stack[i].isShown) topModal = this.stack[i];
			}

			if (topModal) {
				this.$backdropHandle = topModal.$backdrop;
				topModal.$backdrop = null;

				callback && topModal.$element.one('hidden',
					targetIsSelf( $.proxy(callback, this) ));

				topModal.hide();
			} else if (callback) {
				callback();
			}
		},

		removeBackdrop: function (modal) {
			modal.$backdrop.remove();
			modal.$backdrop = null;
		},

		createBackdrop: function (animate) {
			var $backdrop;

			if (!this.$backdropHandle) {
				$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
					.appendTo(this.$element);
			} else {
				$backdrop = this.$backdropHandle;
				$backdrop.off('.modalmanager');
				this.$backdropHandle = null;
				this.isLoading && this.removeSpinner();
			}

			return $backdrop
		},

		removeContainer: function (modal) {
			modal.$container.remove();
			modal.$container = null;
		},

		createContainer: function (modal) {
			var $container;

			$container = $('<div class="modal-scrollable">')
				.css('z-index', getzIndex( 'modal',
					modal ? this.getIndexOfModal(modal) : this.stack.length ))
				.appendTo(this.$element);

			if (modal && modal.options.backdrop != 'static') {
				$container.on('click.modal', targetIsSelf(function (e) {
					modal.hide();
				}));
			} else if (modal) {
				$container.on('click.modal', targetIsSelf(function (e) {
					modal.attention();
				}));
			}

			return $container;

		},

		backdrop: function (modal, callback) {
			var animate = modal.$element.hasClass('fade') ? 'fade' : '',
				showBackdrop = modal.options.backdrop &&
					this.backdropCount < this.options.backdropLimit;

			if (modal.isShown && showBackdrop) {
				var doAnimate = $.support.transition && animate && !this.$backdropHandle;

				modal.$backdrop = this.createBackdrop(animate);

				modal.$backdrop.css('z-index', getzIndex( 'backdrop', this.getIndexOfModal(modal) ));

				if (doAnimate) modal.$backdrop[0].offsetWidth; // force reflow

				modal.$backdrop.addClass('in');

				this.backdropCount += 1;

				doAnimate ?
					modal.$backdrop.one($.support.transition.end, callback) :
					callback();

			} else if (!modal.isShown && modal.$backdrop) {
				modal.$backdrop.removeClass('in');

				this.backdropCount -= 1;

				var that = this;

				$.support.transition && modal.$element.hasClass('fade')?
					modal.$backdrop.one($.support.transition.end, function () { that.removeBackdrop(modal) }) :
					that.removeBackdrop(modal);

			} else if (callback) {
				callback();
			}
		},

		removeSpinner: function(){
			this.$spinner && this.$spinner.remove();
			this.$spinner = null;
			this.isLoading = false;
		},

		removeLoading: function () {
			this.$backdropHandle && this.$backdropHandle.remove();
			this.$backdropHandle = null;
			this.removeSpinner();
		},

		loading: function (callback) {
			callback = callback || function () { };

			this.$element
				.toggleClass('modal-open', !this.isLoading || this.hasOpenModal())
				.toggleClass('page-overflow', $(window).height() < this.$element.height());

			if (!this.isLoading) {

				this.$backdropHandle = this.createBackdrop('fade');

				this.$backdropHandle[0].offsetWidth; // force reflow

				this.$backdropHandle
					.css('z-index', getzIndex('backdrop', this.stack.length))
					.addClass('in');

				var $spinner = $(this.options.spinner)
					.css('z-index', getzIndex('modal', this.stack.length))
					.appendTo(this.$element)
					.addClass('in');

				this.$spinner = $(this.createContainer())
					.append($spinner)
					.on('click.modalmanager', $.proxy(this.loading, this));

				this.isLoading = true;

				$.support.transition ?
					this.$backdropHandle.one($.support.transition.end, callback) :
					callback();

			} else if (this.isLoading && this.$backdropHandle) {
				this.$backdropHandle.removeClass('in');

				var that = this;
				$.support.transition ?
					this.$backdropHandle.one($.support.transition.end, function () { that.removeLoading() }) :
					that.removeLoading();

			} else if (callback) {
				callback(this.isLoading);
			}
		}
	};

	/* PRIVATE METHODS
	* ======================= */

	// computes and caches the zindexes
	var getzIndex = (function () {
		var zIndexFactor,
			baseIndex = {};

		return function (type, pos) {

			if (typeof zIndexFactor === 'undefined'){
				var $baseModal = $('<div class="modal" />').appendTo('body'),
					$baseBackdrop = $('<div class="modal-backdrop hide" />').appendTo('body');

				baseIndex['modal'] = +$baseModal.css('z-index');
				baseIndex['backdrop'] = +$baseBackdrop.css('z-index');
				zIndexFactor = baseIndex['modal'] - baseIndex['backdrop'];

				$baseModal.remove();
				$baseBackdrop.remove();
				$baseBackdrop = $baseModal = null;
			}

			return baseIndex[type] + (zIndexFactor * pos);

		}
	}());

	// make sure the event target is the modal itself in order to prevent
	// other components such as tabsfrom triggering the modal manager.
	// if Boostsrap namespaced events, this would not be needed.
	function targetIsSelf(callback){
		return function (e) {
			if (this === e.target){
				return callback.apply(this, arguments);
			}
		}
	}


	/* MODAL MANAGER PLUGIN DEFINITION
	* ======================= */

	$.fn.modalmanager = function (option, args) {
		return this.each(function () {
			var $this = $(this),
				data = $this.data('modalmanager');

			if (!data) $this.data('modalmanager', (data = new ModalManager(this, option)));
			if (typeof option === 'string') data[option].apply(data, [].concat(args))
		})
	};

	$.fn.modalmanager.defaults = {
		backdropLimit: 999,
		resize: true,
		spinner: '<div class="loading-spinner fade" style="width: 200px; margin-left: -100px;"><div class="progress progress-striped active"><div class="bar" style="width: 100%;"></div></div></div>'
	};

	$.fn.modalmanager.Constructor = ModalManager

}(jQuery);
;
/* ===========================================================
 * bootstrap-modal.js v2.1
 * ===========================================================
 * Copyright 2012 Jordan Schroter
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ========================================================== */


!function ($) {

	"use strict"; // jshint ;_;

	/* MODAL CLASS DEFINITION
	* ====================== */

	var Modal = function (element, options) {
		this.init(element, options);
	};

	Modal.prototype = {

		constructor: Modal,

		init: function (element, options) {
			this.options = options;

			this.$element = $(element)
				.delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this));

			this.options.remote && this.$element.find('.modal-body').load(this.options.remote);

			var manager = typeof this.options.manager === 'function' ?
				this.options.manager.call(this) : this.options.manager;

			manager = manager.appendModal ?
				manager : $(manager).modalmanager().data('modalmanager');

			manager.appendModal(this);
		},

		toggle: function () {
			return this[!this.isShown ? 'show' : 'hide']();
		},

		show: function () {
			var e = $.Event('show');

			if (this.isShown) return;

			this.$element.triggerHandler(e);

			if (e.isDefaultPrevented()) return;

			this.escape();

			this.tab();

			this.options.loading && this.loading();
		},

		hide: function (e) {
			e && e.preventDefault();

			e = $.Event('hide');

			this.$element.triggerHandler(e);

			if (!this.isShown || e.isDefaultPrevented()) return (this.isShown = false);

			this.isShown = false;

			this.escape();

			this.tab();

			this.isLoading && this.loading();

			$(document).off('focusin.modal');

			this.$element
				.removeClass('in')
				.removeClass('animated')
				.removeClass(this.options.attentionAnimation)
				.removeClass('modal-overflow')
				.attr('aria-hidden', true);

			$.support.transition && this.$element.hasClass('fade') ?
				this.hideWithTransition() :
				this.hideModal();
		},

		layout: function () {
			var prop = this.options.height ? 'height' : 'max-height',
				value = this.options.height || this.options.maxHeight;

			if (this.options.width){
				this.$element.css('width', this.options.width);

				var that = this;
				this.$element.css('margin-left', function () {
					if (/%/ig.test(that.options.width)){
						return -(parseInt(that.options.width) / 2) + '%';
					} else {
						return -($(this).width() / 2) + 'px';
					}
				});
			} else {
				this.$element.css('width', '');
				this.$element.css('margin-left', '');
			}

			this.$element.find('.modal-body')
				.css('overflow', '')
				.css(prop, '');

			var modalOverflow = $(window).height() - 10 < this.$element.height();

			if (value){
				this.$element.find('.modal-body')
					.css('overflow', 'auto')
					.css(prop, value);
			}

			if (modalOverflow || this.options.modalOverflow) {
				this.$element
					.css('margin-top', 0)
					.addClass('modal-overflow');
			} else {
				this.$element
					.css('margin-top', 0 - this.$element.height() / 2)
					.removeClass('modal-overflow');
			}
		},

		tab: function () {
			var that = this;

			if (this.isShown && this.options.consumeTab) {
				this.$element.on('keydown.tabindex.modal', '[data-tabindex]', function (e) {
			    	if (e.keyCode && e.keyCode == 9){
						var $next = $(this),
							$rollover = $(this);

						that.$element.find('[data-tabindex]:enabled:not([readonly])').each(function (e) {
							if (!e.shiftKey){
						 		$next = $next.data('tabindex') < $(this).data('tabindex') ?
									$next = $(this) :
									$rollover = $(this);
							} else {
								$next = $next.data('tabindex') > $(this).data('tabindex') ?
									$next = $(this) :
									$rollover = $(this);
							}
						});

						$next[0] !== $(this)[0] ?
							$next.focus() : $rollover.focus();

						e.preventDefault();
					}
				});
			} else if (!this.isShown) {
				this.$element.off('keydown.tabindex.modal');
			}
		},

		escape: function () {
			var that = this;
			if (this.isShown && this.options.keyboard) {
				if (!this.$element.attr('tabindex')) this.$element.attr('tabindex', -1);

				this.$element.on('keyup.dismiss.modal', function (e) {
					e.which == 27 && that.hide();
				});
			} else if (!this.isShown) {
				this.$element.off('keyup.dismiss.modal')
			}
		},

		hideWithTransition: function () {
			var that = this
				, timeout = setTimeout(function () {
					that.$element.off($.support.transition.end);
					that.hideModal();
				}, 500);

			this.$element.one($.support.transition.end, function () {
				clearTimeout(timeout);
				that.hideModal();
			});
		},

		hideModal: function () {
			this.$element
				.hide()
				.triggerHandler('hidden');

			var prop = this.options.height ? 'height' : 'max-height';
			var value = this.options.height || this.options.maxHeight;

			if (value){
				this.$element.find('.modal-body')
					.css('overflow', '')
					.css(prop, '');
			}

		},

		removeLoading: function () {
			this.$loading.remove();
			this.$loading = null;
			this.isLoading = false;
		},

		loading: function (callback) {
			callback = callback || function () {};

			var animate = this.$element.hasClass('fade') ? 'fade' : '';

			if (!this.isLoading) {
				var doAnimate = $.support.transition && animate;

				this.$loading = $('<div class="loading-mask ' + animate + '">')
					.append(this.options.spinner)
					.appendTo(this.$element);

				if (doAnimate) this.$loading[0].offsetWidth; // force reflow

				this.$loading.addClass('in');

				this.isLoading = true;

				doAnimate ?
					this.$loading.one($.support.transition.end, callback) :
					callback();

			} else if (this.isLoading && this.$loading) {
				this.$loading.removeClass('in');

				var that = this;
				$.support.transition && this.$element.hasClass('fade')?
					this.$loading.one($.support.transition.end, function () { that.removeLoading() }) :
					that.removeLoading();

			} else if (callback) {
				callback(this.isLoading);
			}
		},

		focus: function () {
			var $focusElem = this.$element.find(this.options.focusOn);

			$focusElem = $focusElem.length ? $focusElem : this.$element;

			$focusElem.focus();
		},

		attention: function (){
			// NOTE: transitionEnd with keyframes causes odd behaviour

			if (this.options.attentionAnimation){
				this.$element
					.removeClass('animated')
					.removeClass(this.options.attentionAnimation);

				var that = this;

				setTimeout(function () {
					that.$element
						.addClass('animated')
						.addClass(that.options.attentionAnimation);
				}, 0);
			}


			this.focus();
		},


		destroy: function () {
			var e = $.Event('destroy');
			this.$element.triggerHandler(e);
			if (e.isDefaultPrevented()) return;

			this.teardown();
		},

		teardown: function () {
			if (!this.$parent.length){
				this.$element.remove();
				this.$element = null;
				return;
			}

			if (this.$parent !== this.$element.parent()){
				this.$element.appendTo(this.$parent);
			}

			this.$element.off('.modal');
			this.$element.removeData('modal');
			this.$element
				.removeClass('in')
				.attr('aria-hidden', true);
		}
	};


	/* MODAL PLUGIN DEFINITION
	* ======================= */

	$.fn.modal = function (option, args) {
		return this.each(function () {
			var $this = $(this),
				data = $this.data('modal'),
				options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option);

			if (!data) $this.data('modal', (data = new Modal(this, options)));
			if (typeof option == 'string') data[option].apply(data, [].concat(args));
			else if (options.show) data.show()
		})
	};

	$.fn.modal.defaults = {
		keyboard: true,
		backdrop: true,
		loading: false,
		show: true,
		width: null,
		height: null,
		maxHeight: null,
		modalOverflow: false,
		consumeTab: true,
		focusOn: null,
		replace: false,
		resize: false,
		attentionAnimation: 'shake',
		manager: 'body',
		spinner: '<div class="loading-spinner" style="width: 200px; margin-left: -100px;"><div class="progress progress-striped active"><div class="bar" style="width: 100%;"></div></div></div>'
	};

	$.fn.modal.Constructor = Modal;


	/* MODAL DATA-API
	* ============== */

	$(function () {
		$(document).off('.modal').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) {
			var $this = $(this),
				href = $this.attr('href'),
				$target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))), //strip for ie7
				option = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data());

			e.preventDefault();
			$target
				.modal(option)
				.one('hide', function () {
					$this.focus();
				})
		});
	});

}(window.jQuery);
;
/*!
 * Knockout JavaScript library v3.4.0
 * (c) Steven Sanderson - http://knockoutjs.com/
 * License: MIT (http://www.opensource.org/licenses/mit-license.php)
 */

(function() {(function(n){var x=this||(0,eval)("this"),u=x.document,M=x.navigator,v=x.jQuery,F=x.JSON;(function(n){"function"===typeof define&&define.amd?define(["exports","require"],n):"object"===typeof exports&&"object"===typeof module?n(module.exports||exports):n(x.ko={})})(function(N,O){function J(a,c){return null===a||typeof a in T?a===c:!1}function U(b,c){var d;return function(){d||(d=a.a.setTimeout(function(){d=n;b()},c))}}function V(b,c){var d;return function(){clearTimeout(d);d=a.a.setTimeout(b,c)}}function W(a,
c){c&&c!==I?"beforeChange"===c?this.Kb(a):this.Ha(a,c):this.Lb(a)}function X(a,c){null!==c&&c.k&&c.k()}function Y(a,c){var d=this.Hc,e=d[s];e.R||(this.lb&&this.Ma[c]?(d.Pb(c,a,this.Ma[c]),this.Ma[c]=null,--this.lb):e.r[c]||d.Pb(c,a,e.s?{ia:a}:d.uc(a)))}function K(b,c,d,e){a.d[b]={init:function(b,g,k,l,m){var h,r;a.m(function(){var q=a.a.c(g()),p=!d!==!q,A=!r;if(A||c||p!==h)A&&a.va.Aa()&&(r=a.a.ua(a.f.childNodes(b),!0)),p?(A||a.f.da(b,a.a.ua(r)),a.eb(e?e(m,q):m,b)):a.f.xa(b),h=p},null,{i:b});return{controlsDescendantBindings:!0}}};
a.h.ta[b]=!1;a.f.Z[b]=!0}var a="undefined"!==typeof N?N:{};a.b=function(b,c){for(var d=b.split("."),e=a,f=0;f<d.length-1;f++)e=e[d[f]];e[d[d.length-1]]=c};a.G=function(a,c,d){a[c]=d};a.version="3.4.0";a.b("version",a.version);a.options={deferUpdates:!1,useOnlyNativeEvents:!1};a.a=function(){function b(a,b){for(var c in a)a.hasOwnProperty(c)&&b(c,a[c])}function c(a,b){if(b)for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a}function d(a,b){a.__proto__=b;return a}function e(b,c,d,e){var h=b[c].match(r)||
[];a.a.q(d.match(r),function(b){a.a.pa(h,b,e)});b[c]=h.join(" ")}var f={__proto__:[]}instanceof Array,g="function"===typeof Symbol,k={},l={};k[M&&/Firefox\/2/i.test(M.userAgent)?"KeyboardEvent":"UIEvents"]=["keyup","keydown","keypress"];k.MouseEvents="click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave".split(" ");b(k,function(a,b){if(b.length)for(var c=0,d=b.length;c<d;c++)l[b[c]]=a});var m={propertychange:!0},h=u&&function(){for(var a=3,b=u.createElement("div"),c=
b.getElementsByTagName("i");b.innerHTML="\x3c!--[if gt IE "+ ++a+"]><i></i><![endif]--\x3e",c[0];);return 4<a?a:n}(),r=/\S+/g;return{cc:["authenticity_token",/^__RequestVerificationToken(_.*)?$/],q:function(a,b){for(var c=0,d=a.length;c<d;c++)b(a[c],c)},o:function(a,b){if("function"==typeof Array.prototype.indexOf)return Array.prototype.indexOf.call(a,b);for(var c=0,d=a.length;c<d;c++)if(a[c]===b)return c;return-1},Sb:function(a,b,c){for(var d=0,e=a.length;d<e;d++)if(b.call(c,a[d],d))return a[d];
return null},La:function(b,c){var d=a.a.o(b,c);0<d?b.splice(d,1):0===d&&b.shift()},Tb:function(b){b=b||[];for(var c=[],d=0,e=b.length;d<e;d++)0>a.a.o(c,b[d])&&c.push(b[d]);return c},fb:function(a,b){a=a||[];for(var c=[],d=0,e=a.length;d<e;d++)c.push(b(a[d],d));return c},Ka:function(a,b){a=a||[];for(var c=[],d=0,e=a.length;d<e;d++)b(a[d],d)&&c.push(a[d]);return c},ra:function(a,b){if(b instanceof Array)a.push.apply(a,b);else for(var c=0,d=b.length;c<d;c++)a.push(b[c]);return a},pa:function(b,c,d){var e=
a.a.o(a.a.zb(b),c);0>e?d&&b.push(c):d||b.splice(e,1)},ka:f,extend:c,Xa:d,Ya:f?d:c,D:b,Ca:function(a,b){if(!a)return a;var c={},d;for(d in a)a.hasOwnProperty(d)&&(c[d]=b(a[d],d,a));return c},ob:function(b){for(;b.firstChild;)a.removeNode(b.firstChild)},jc:function(b){b=a.a.V(b);for(var c=(b[0]&&b[0].ownerDocument||u).createElement("div"),d=0,e=b.length;d<e;d++)c.appendChild(a.$(b[d]));return c},ua:function(b,c){for(var d=0,e=b.length,h=[];d<e;d++){var m=b[d].cloneNode(!0);h.push(c?a.$(m):m)}return h},
da:function(b,c){a.a.ob(b);if(c)for(var d=0,e=c.length;d<e;d++)b.appendChild(c[d])},qc:function(b,c){var d=b.nodeType?[b]:b;if(0<d.length){for(var e=d[0],h=e.parentNode,m=0,l=c.length;m<l;m++)h.insertBefore(c[m],e);m=0;for(l=d.length;m<l;m++)a.removeNode(d[m])}},za:function(a,b){if(a.length){for(b=8===b.nodeType&&b.parentNode||b;a.length&&a[0].parentNode!==b;)a.splice(0,1);for(;1<a.length&&a[a.length-1].parentNode!==b;)a.length--;if(1<a.length){var c=a[0],d=a[a.length-1];for(a.length=0;c!==d;)a.push(c),
c=c.nextSibling;a.push(d)}}return a},sc:function(a,b){7>h?a.setAttribute("selected",b):a.selected=b},$a:function(a){return null===a||a===n?"":a.trim?a.trim():a.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")},nd:function(a,b){a=a||"";return b.length>a.length?!1:a.substring(0,b.length)===b},Mc:function(a,b){if(a===b)return!0;if(11===a.nodeType)return!1;if(b.contains)return b.contains(3===a.nodeType?a.parentNode:a);if(b.compareDocumentPosition)return 16==(b.compareDocumentPosition(a)&16);for(;a&&a!=
b;)a=a.parentNode;return!!a},nb:function(b){return a.a.Mc(b,b.ownerDocument.documentElement)},Qb:function(b){return!!a.a.Sb(b,a.a.nb)},A:function(a){return a&&a.tagName&&a.tagName.toLowerCase()},Wb:function(b){return a.onError?function(){try{return b.apply(this,arguments)}catch(c){throw a.onError&&a.onError(c),c;}}:b},setTimeout:function(b,c){return setTimeout(a.a.Wb(b),c)},$b:function(b){setTimeout(function(){a.onError&&a.onError(b);throw b;},0)},p:function(b,c,d){var e=a.a.Wb(d);d=h&&m[c];if(a.options.useOnlyNativeEvents||
d||!v)if(d||"function"!=typeof b.addEventListener)if("undefined"!=typeof b.attachEvent){var l=function(a){e.call(b,a)},f="on"+c;b.attachEvent(f,l);a.a.F.oa(b,function(){b.detachEvent(f,l)})}else throw Error("Browser doesn't support addEventListener or attachEvent");else b.addEventListener(c,e,!1);else v(b).bind(c,e)},Da:function(b,c){if(!b||!b.nodeType)throw Error("element must be a DOM node when calling triggerEvent");var d;"input"===a.a.A(b)&&b.type&&"click"==c.toLowerCase()?(d=b.type,d="checkbox"==
d||"radio"==d):d=!1;if(a.options.useOnlyNativeEvents||!v||d)if("function"==typeof u.createEvent)if("function"==typeof b.dispatchEvent)d=u.createEvent(l[c]||"HTMLEvents"),d.initEvent(c,!0,!0,x,0,0,0,0,0,!1,!1,!1,!1,0,b),b.dispatchEvent(d);else throw Error("The supplied element doesn't support dispatchEvent");else if(d&&b.click)b.click();else if("undefined"!=typeof b.fireEvent)b.fireEvent("on"+c);else throw Error("Browser doesn't support triggering events");else v(b).trigger(c)},c:function(b){return a.H(b)?
b():b},zb:function(b){return a.H(b)?b.t():b},bb:function(b,c,d){var h;c&&("object"===typeof b.classList?(h=b.classList[d?"add":"remove"],a.a.q(c.match(r),function(a){h.call(b.classList,a)})):"string"===typeof b.className.baseVal?e(b.className,"baseVal",c,d):e(b,"className",c,d))},Za:function(b,c){var d=a.a.c(c);if(null===d||d===n)d="";var e=a.f.firstChild(b);!e||3!=e.nodeType||a.f.nextSibling(e)?a.f.da(b,[b.ownerDocument.createTextNode(d)]):e.data=d;a.a.Rc(b)},rc:function(a,b){a.name=b;if(7>=h)try{a.mergeAttributes(u.createElement("<input name='"+
a.name+"'/>"),!1)}catch(c){}},Rc:function(a){9<=h&&(a=1==a.nodeType?a:a.parentNode,a.style&&(a.style.zoom=a.style.zoom))},Nc:function(a){if(h){var b=a.style.width;a.style.width=0;a.style.width=b}},hd:function(b,c){b=a.a.c(b);c=a.a.c(c);for(var d=[],e=b;e<=c;e++)d.push(e);return d},V:function(a){for(var b=[],c=0,d=a.length;c<d;c++)b.push(a[c]);return b},Yb:function(a){return g?Symbol(a):a},rd:6===h,sd:7===h,C:h,ec:function(b,c){for(var d=a.a.V(b.getElementsByTagName("input")).concat(a.a.V(b.getElementsByTagName("textarea"))),
e="string"==typeof c?function(a){return a.name===c}:function(a){return c.test(a.name)},h=[],m=d.length-1;0<=m;m--)e(d[m])&&h.push(d[m]);return h},ed:function(b){return"string"==typeof b&&(b=a.a.$a(b))?F&&F.parse?F.parse(b):(new Function("return "+b))():null},Eb:function(b,c,d){if(!F||!F.stringify)throw Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");
return F.stringify(a.a.c(b),c,d)},fd:function(c,d,e){e=e||{};var h=e.params||{},m=e.includeFields||this.cc,l=c;if("object"==typeof c&&"form"===a.a.A(c))for(var l=c.action,f=m.length-1;0<=f;f--)for(var g=a.a.ec(c,m[f]),k=g.length-1;0<=k;k--)h[g[k].name]=g[k].value;d=a.a.c(d);var r=u.createElement("form");r.style.display="none";r.action=l;r.method="post";for(var n in d)c=u.createElement("input"),c.type="hidden",c.name=n,c.value=a.a.Eb(a.a.c(d[n])),r.appendChild(c);b(h,function(a,b){var c=u.createElement("input");
c.type="hidden";c.name=a;c.value=b;r.appendChild(c)});u.body.appendChild(r);e.submitter?e.submitter(r):r.submit();setTimeout(function(){r.parentNode.removeChild(r)},0)}}}();a.b("utils",a.a);a.b("utils.arrayForEach",a.a.q);a.b("utils.arrayFirst",a.a.Sb);a.b("utils.arrayFilter",a.a.Ka);a.b("utils.arrayGetDistinctValues",a.a.Tb);a.b("utils.arrayIndexOf",a.a.o);a.b("utils.arrayMap",a.a.fb);a.b("utils.arrayPushAll",a.a.ra);a.b("utils.arrayRemoveItem",a.a.La);a.b("utils.extend",a.a.extend);a.b("utils.fieldsIncludedWithJsonPost",
a.a.cc);a.b("utils.getFormFields",a.a.ec);a.b("utils.peekObservable",a.a.zb);a.b("utils.postJson",a.a.fd);a.b("utils.parseJson",a.a.ed);a.b("utils.registerEventHandler",a.a.p);a.b("utils.stringifyJson",a.a.Eb);a.b("utils.range",a.a.hd);a.b("utils.toggleDomNodeCssClass",a.a.bb);a.b("utils.triggerEvent",a.a.Da);a.b("utils.unwrapObservable",a.a.c);a.b("utils.objectForEach",a.a.D);a.b("utils.addOrRemoveItem",a.a.pa);a.b("utils.setTextContent",a.a.Za);a.b("unwrap",a.a.c);Function.prototype.bind||(Function.prototype.bind=
function(a){var c=this;if(1===arguments.length)return function(){return c.apply(a,arguments)};var d=Array.prototype.slice.call(arguments,1);return function(){var e=d.slice(0);e.push.apply(e,arguments);return c.apply(a,e)}});a.a.e=new function(){function a(b,g){var k=b[d];if(!k||"null"===k||!e[k]){if(!g)return n;k=b[d]="ko"+c++;e[k]={}}return e[k]}var c=0,d="__ko__"+(new Date).getTime(),e={};return{get:function(c,d){var e=a(c,!1);return e===n?n:e[d]},set:function(c,d,e){if(e!==n||a(c,!1)!==n)a(c,!0)[d]=
e},clear:function(a){var b=a[d];return b?(delete e[b],a[d]=null,!0):!1},I:function(){return c++ +d}}};a.b("utils.domData",a.a.e);a.b("utils.domData.clear",a.a.e.clear);a.a.F=new function(){function b(b,c){var e=a.a.e.get(b,d);e===n&&c&&(e=[],a.a.e.set(b,d,e));return e}function c(d){var e=b(d,!1);if(e)for(var e=e.slice(0),l=0;l<e.length;l++)e[l](d);a.a.e.clear(d);a.a.F.cleanExternalData(d);if(f[d.nodeType])for(e=d.firstChild;d=e;)e=d.nextSibling,8===d.nodeType&&c(d)}var d=a.a.e.I(),e={1:!0,8:!0,9:!0},
f={1:!0,9:!0};return{oa:function(a,c){if("function"!=typeof c)throw Error("Callback must be a function");b(a,!0).push(c)},pc:function(c,e){var l=b(c,!1);l&&(a.a.La(l,e),0==l.length&&a.a.e.set(c,d,n))},$:function(b){if(e[b.nodeType]&&(c(b),f[b.nodeType])){var d=[];a.a.ra(d,b.getElementsByTagName("*"));for(var l=0,m=d.length;l<m;l++)c(d[l])}return b},removeNode:function(b){a.$(b);b.parentNode&&b.parentNode.removeChild(b)},cleanExternalData:function(a){v&&"function"==typeof v.cleanData&&v.cleanData([a])}}};
a.$=a.a.F.$;a.removeNode=a.a.F.removeNode;a.b("cleanNode",a.$);a.b("removeNode",a.removeNode);a.b("utils.domNodeDisposal",a.a.F);a.b("utils.domNodeDisposal.addDisposeCallback",a.a.F.oa);a.b("utils.domNodeDisposal.removeDisposeCallback",a.a.F.pc);(function(){var b=[0,"",""],c=[1,"<table>","</table>"],d=[3,"<table><tbody><tr>","</tr></tbody></table>"],e=[1,"<select multiple='multiple'>","</select>"],f={thead:c,tbody:c,tfoot:c,tr:[2,"<table><tbody>","</tbody></table>"],td:d,th:d,option:e,optgroup:e},
g=8>=a.a.C;a.a.ma=function(c,d){var e;if(v)if(v.parseHTML)e=v.parseHTML(c,d)||[];else{if((e=v.clean([c],d))&&e[0]){for(var h=e[0];h.parentNode&&11!==h.parentNode.nodeType;)h=h.parentNode;h.parentNode&&h.parentNode.removeChild(h)}}else{(e=d)||(e=u);var h=e.parentWindow||e.defaultView||x,r=a.a.$a(c).toLowerCase(),q=e.createElement("div"),p;p=(r=r.match(/^<([a-z]+)[ >]/))&&f[r[1]]||b;r=p[0];p="ignored<div>"+p[1]+c+p[2]+"</div>";"function"==typeof h.innerShiv?q.appendChild(h.innerShiv(p)):(g&&e.appendChild(q),
q.innerHTML=p,g&&q.parentNode.removeChild(q));for(;r--;)q=q.lastChild;e=a.a.V(q.lastChild.childNodes)}return e};a.a.Cb=function(b,c){a.a.ob(b);c=a.a.c(c);if(null!==c&&c!==n)if("string"!=typeof c&&(c=c.toString()),v)v(b).html(c);else for(var d=a.a.ma(c,b.ownerDocument),e=0;e<d.length;e++)b.appendChild(d[e])}})();a.b("utils.parseHtmlFragment",a.a.ma);a.b("utils.setHtml",a.a.Cb);a.M=function(){function b(c,e){if(c)if(8==c.nodeType){var f=a.M.lc(c.nodeValue);null!=f&&e.push({Lc:c,cd:f})}else if(1==c.nodeType)for(var f=
0,g=c.childNodes,k=g.length;f<k;f++)b(g[f],e)}var c={};return{wb:function(a){if("function"!=typeof a)throw Error("You can only pass a function to ko.memoization.memoize()");var b=(4294967296*(1+Math.random())|0).toString(16).substring(1)+(4294967296*(1+Math.random())|0).toString(16).substring(1);c[b]=a;return"\x3c!--[ko_memo:"+b+"]--\x3e"},xc:function(a,b){var f=c[a];if(f===n)throw Error("Couldn't find any memo with ID "+a+". Perhaps it's already been unmemoized.");try{return f.apply(null,b||[]),
!0}finally{delete c[a]}},yc:function(c,e){var f=[];b(c,f);for(var g=0,k=f.length;g<k;g++){var l=f[g].Lc,m=[l];e&&a.a.ra(m,e);a.M.xc(f[g].cd,m);l.nodeValue="";l.parentNode&&l.parentNode.removeChild(l)}},lc:function(a){return(a=a.match(/^\[ko_memo\:(.*?)\]$/))?a[1]:null}}}();a.b("memoization",a.M);a.b("memoization.memoize",a.M.wb);a.b("memoization.unmemoize",a.M.xc);a.b("memoization.parseMemoText",a.M.lc);a.b("memoization.unmemoizeDomNodeAndDescendants",a.M.yc);a.Y=function(){function b(){if(e)for(var b=
e,c=0,m;g<e;)if(m=d[g++]){if(g>b){if(5E3<=++c){g=e;a.a.$b(Error("'Too much recursion' after processing "+c+" task groups."));break}b=e}try{m()}catch(h){a.a.$b(h)}}}function c(){b();g=e=d.length=0}var d=[],e=0,f=1,g=0;return{scheduler:x.MutationObserver?function(a){var b=u.createElement("div");(new MutationObserver(a)).observe(b,{attributes:!0});return function(){b.classList.toggle("foo")}}(c):u&&"onreadystatechange"in u.createElement("script")?function(a){var b=u.createElement("script");b.onreadystatechange=
function(){b.onreadystatechange=null;u.documentElement.removeChild(b);b=null;a()};u.documentElement.appendChild(b)}:function(a){setTimeout(a,0)},Wa:function(b){e||a.Y.scheduler(c);d[e++]=b;return f++},cancel:function(a){a-=f-e;a>=g&&a<e&&(d[a]=null)},resetForTesting:function(){var a=e-g;g=e=d.length=0;return a},md:b}}();a.b("tasks",a.Y);a.b("tasks.schedule",a.Y.Wa);a.b("tasks.runEarly",a.Y.md);a.ya={throttle:function(b,c){b.throttleEvaluation=c;var d=null;return a.B({read:b,write:function(e){clearTimeout(d);
d=a.a.setTimeout(function(){b(e)},c)}})},rateLimit:function(a,c){var d,e,f;"number"==typeof c?d=c:(d=c.timeout,e=c.method);a.cb=!1;f="notifyWhenChangesStop"==e?V:U;a.Ta(function(a){return f(a,d)})},deferred:function(b,c){if(!0!==c)throw Error("The 'deferred' extender only accepts the value 'true', because it is not supported to turn deferral off once enabled.");b.cb||(b.cb=!0,b.Ta(function(c){var e;return function(){a.Y.cancel(e);e=a.Y.Wa(c);b.notifySubscribers(n,"dirty")}}))},notify:function(a,c){a.equalityComparer=
"always"==c?null:J}};var T={undefined:1,"boolean":1,number:1,string:1};a.b("extenders",a.ya);a.vc=function(b,c,d){this.ia=b;this.gb=c;this.Kc=d;this.R=!1;a.G(this,"dispose",this.k)};a.vc.prototype.k=function(){this.R=!0;this.Kc()};a.J=function(){a.a.Ya(this,D);D.rb(this)};var I="change",D={rb:function(a){a.K={};a.Nb=1},X:function(b,c,d){var e=this;d=d||I;var f=new a.vc(e,c?b.bind(c):b,function(){a.a.La(e.K[d],f);e.Ia&&e.Ia(d)});e.sa&&e.sa(d);e.K[d]||(e.K[d]=[]);e.K[d].push(f);return f},notifySubscribers:function(b,
c){c=c||I;c===I&&this.zc();if(this.Pa(c))try{a.l.Ub();for(var d=this.K[c].slice(0),e=0,f;f=d[e];++e)f.R||f.gb(b)}finally{a.l.end()}},Na:function(){return this.Nb},Uc:function(a){return this.Na()!==a},zc:function(){++this.Nb},Ta:function(b){var c=this,d=a.H(c),e,f,g;c.Ha||(c.Ha=c.notifySubscribers,c.notifySubscribers=W);var k=b(function(){c.Mb=!1;d&&g===c&&(g=c());e=!1;c.tb(f,g)&&c.Ha(f=g)});c.Lb=function(a){c.Mb=e=!0;g=a;k()};c.Kb=function(a){e||(f=a,c.Ha(a,"beforeChange"))}},Pa:function(a){return this.K[a]&&
this.K[a].length},Sc:function(b){if(b)return this.K[b]&&this.K[b].length||0;var c=0;a.a.D(this.K,function(a,b){"dirty"!==a&&(c+=b.length)});return c},tb:function(a,c){return!this.equalityComparer||!this.equalityComparer(a,c)},extend:function(b){var c=this;b&&a.a.D(b,function(b,e){var f=a.ya[b];"function"==typeof f&&(c=f(c,e)||c)});return c}};a.G(D,"subscribe",D.X);a.G(D,"extend",D.extend);a.G(D,"getSubscriptionsCount",D.Sc);a.a.ka&&a.a.Xa(D,Function.prototype);a.J.fn=D;a.hc=function(a){return null!=
a&&"function"==typeof a.X&&"function"==typeof a.notifySubscribers};a.b("subscribable",a.J);a.b("isSubscribable",a.hc);a.va=a.l=function(){function b(a){d.push(e);e=a}function c(){e=d.pop()}var d=[],e,f=0;return{Ub:b,end:c,oc:function(b){if(e){if(!a.hc(b))throw Error("Only subscribable things can act as dependencies");e.gb.call(e.Gc,b,b.Cc||(b.Cc=++f))}},w:function(a,d,e){try{return b(),a.apply(d,e||[])}finally{c()}},Aa:function(){if(e)return e.m.Aa()},Sa:function(){if(e)return e.Sa}}}();a.b("computedContext",
a.va);a.b("computedContext.getDependenciesCount",a.va.Aa);a.b("computedContext.isInitial",a.va.Sa);a.b("ignoreDependencies",a.qd=a.l.w);var E=a.a.Yb("_latestValue");a.N=function(b){function c(){if(0<arguments.length)return c.tb(c[E],arguments[0])&&(c.ga(),c[E]=arguments[0],c.fa()),this;a.l.oc(c);return c[E]}c[E]=b;a.a.ka||a.a.extend(c,a.J.fn);a.J.fn.rb(c);a.a.Ya(c,B);a.options.deferUpdates&&a.ya.deferred(c,!0);return c};var B={equalityComparer:J,t:function(){return this[E]},fa:function(){this.notifySubscribers(this[E])},
ga:function(){this.notifySubscribers(this[E],"beforeChange")}};a.a.ka&&a.a.Xa(B,a.J.fn);var H=a.N.gd="__ko_proto__";B[H]=a.N;a.Oa=function(b,c){return null===b||b===n||b[H]===n?!1:b[H]===c?!0:a.Oa(b[H],c)};a.H=function(b){return a.Oa(b,a.N)};a.Ba=function(b){return"function"==typeof b&&b[H]===a.N||"function"==typeof b&&b[H]===a.B&&b.Vc?!0:!1};a.b("observable",a.N);a.b("isObservable",a.H);a.b("isWriteableObservable",a.Ba);a.b("isWritableObservable",a.Ba);a.b("observable.fn",B);a.G(B,"peek",B.t);a.G(B,
"valueHasMutated",B.fa);a.G(B,"valueWillMutate",B.ga);a.la=function(b){b=b||[];if("object"!=typeof b||!("length"in b))throw Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");b=a.N(b);a.a.Ya(b,a.la.fn);return b.extend({trackArrayChanges:!0})};a.la.fn={remove:function(b){for(var c=this.t(),d=[],e="function"!=typeof b||a.H(b)?function(a){return a===b}:b,f=0;f<c.length;f++){var g=c[f];e(g)&&(0===d.length&&this.ga(),d.push(g),c.splice(f,1),f--)}d.length&&
this.fa();return d},removeAll:function(b){if(b===n){var c=this.t(),d=c.slice(0);this.ga();c.splice(0,c.length);this.fa();return d}return b?this.remove(function(c){return 0<=a.a.o(b,c)}):[]},destroy:function(b){var c=this.t(),d="function"!=typeof b||a.H(b)?function(a){return a===b}:b;this.ga();for(var e=c.length-1;0<=e;e--)d(c[e])&&(c[e]._destroy=!0);this.fa()},destroyAll:function(b){return b===n?this.destroy(function(){return!0}):b?this.destroy(function(c){return 0<=a.a.o(b,c)}):[]},indexOf:function(b){var c=
this();return a.a.o(c,b)},replace:function(a,c){var d=this.indexOf(a);0<=d&&(this.ga(),this.t()[d]=c,this.fa())}};a.a.ka&&a.a.Xa(a.la.fn,a.N.fn);a.a.q("pop push reverse shift sort splice unshift".split(" "),function(b){a.la.fn[b]=function(){var a=this.t();this.ga();this.Vb(a,b,arguments);var d=a[b].apply(a,arguments);this.fa();return d===a?this:d}});a.a.q(["slice"],function(b){a.la.fn[b]=function(){var a=this();return a[b].apply(a,arguments)}});a.b("observableArray",a.la);a.ya.trackArrayChanges=function(b,
c){function d(){if(!e){e=!0;var c=b.notifySubscribers;b.notifySubscribers=function(a,b){b&&b!==I||++k;return c.apply(this,arguments)};var d=[].concat(b.t()||[]);f=null;g=b.X(function(c){c=[].concat(c||[]);if(b.Pa("arrayChange")){var e;if(!f||1<k)f=a.a.ib(d,c,b.hb);e=f}d=c;f=null;k=0;e&&e.length&&b.notifySubscribers(e,"arrayChange")})}}b.hb={};c&&"object"==typeof c&&a.a.extend(b.hb,c);b.hb.sparse=!0;if(!b.Vb){var e=!1,f=null,g,k=0,l=b.sa,m=b.Ia;b.sa=function(a){l&&l.call(b,a);"arrayChange"===a&&d()};
b.Ia=function(a){m&&m.call(b,a);"arrayChange"!==a||b.Pa("arrayChange")||(g.k(),e=!1)};b.Vb=function(b,c,d){function m(a,b,c){return l[l.length]={status:a,value:b,index:c}}if(e&&!k){var l=[],g=b.length,t=d.length,G=0;switch(c){case "push":G=g;case "unshift":for(c=0;c<t;c++)m("added",d[c],G+c);break;case "pop":G=g-1;case "shift":g&&m("deleted",b[G],G);break;case "splice":c=Math.min(Math.max(0,0>d[0]?g+d[0]:d[0]),g);for(var g=1===t?g:Math.min(c+(d[1]||0),g),t=c+t-2,G=Math.max(g,t),P=[],n=[],Q=2;c<G;++c,
++Q)c<g&&n.push(m("deleted",b[c],c)),c<t&&P.push(m("added",d[Q],c));a.a.dc(n,P);break;default:return}f=l}}}};var s=a.a.Yb("_state");a.m=a.B=function(b,c,d){function e(){if(0<arguments.length){if("function"===typeof f)f.apply(g.pb,arguments);else throw Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");return this}a.l.oc(e);(g.S||g.s&&e.Qa())&&e.aa();return g.T}"object"===typeof b?d=b:(d=d||{},b&&(d.read=
b));if("function"!=typeof d.read)throw Error("Pass a function that returns the value of the ko.computed");var f=d.write,g={T:n,S:!0,Ra:!1,Fb:!1,R:!1,Va:!1,s:!1,jd:d.read,pb:c||d.owner,i:d.disposeWhenNodeIsRemoved||d.i||null,wa:d.disposeWhen||d.wa,mb:null,r:{},L:0,bc:null};e[s]=g;e.Vc="function"===typeof f;a.a.ka||a.a.extend(e,a.J.fn);a.J.fn.rb(e);a.a.Ya(e,z);d.pure?(g.Va=!0,g.s=!0,a.a.extend(e,$)):d.deferEvaluation&&a.a.extend(e,aa);a.options.deferUpdates&&a.ya.deferred(e,!0);g.i&&(g.Fb=!0,g.i.nodeType||
(g.i=null));g.s||d.deferEvaluation||e.aa();g.i&&e.ba()&&a.a.F.oa(g.i,g.mb=function(){e.k()});return e};var z={equalityComparer:J,Aa:function(){return this[s].L},Pb:function(a,c,d){if(this[s].Va&&c===this)throw Error("A 'pure' computed must not be called recursively");this[s].r[a]=d;d.Ga=this[s].L++;d.na=c.Na()},Qa:function(){var a,c,d=this[s].r;for(a in d)if(d.hasOwnProperty(a)&&(c=d[a],c.ia.Uc(c.na)))return!0},bd:function(){this.Fa&&!this[s].Ra&&this.Fa()},ba:function(){return this[s].S||0<this[s].L},
ld:function(){this.Mb||this.ac()},uc:function(a){if(a.cb&&!this[s].i){var c=a.X(this.bd,this,"dirty"),d=a.X(this.ld,this);return{ia:a,k:function(){c.k();d.k()}}}return a.X(this.ac,this)},ac:function(){var b=this,c=b.throttleEvaluation;c&&0<=c?(clearTimeout(this[s].bc),this[s].bc=a.a.setTimeout(function(){b.aa(!0)},c)):b.Fa?b.Fa():b.aa(!0)},aa:function(b){var c=this[s],d=c.wa;if(!c.Ra&&!c.R){if(c.i&&!a.a.nb(c.i)||d&&d()){if(!c.Fb){this.k();return}}else c.Fb=!1;c.Ra=!0;try{this.Qc(b)}finally{c.Ra=!1}c.L||
this.k()}},Qc:function(b){var c=this[s],d=c.Va?n:!c.L,e={Hc:this,Ma:c.r,lb:c.L};a.l.Ub({Gc:e,gb:Y,m:this,Sa:d});c.r={};c.L=0;e=this.Pc(c,e);this.tb(c.T,e)&&(c.s||this.notifySubscribers(c.T,"beforeChange"),c.T=e,c.s?this.zc():b&&this.notifySubscribers(c.T));d&&this.notifySubscribers(c.T,"awake")},Pc:function(b,c){try{var d=b.jd;return b.pb?d.call(b.pb):d()}finally{a.l.end(),c.lb&&!b.s&&a.a.D(c.Ma,X),b.S=!1}},t:function(){var a=this[s];(a.S&&!a.L||a.s&&this.Qa())&&this.aa();return a.T},Ta:function(b){a.J.fn.Ta.call(this,
b);this.Fa=function(){this.Kb(this[s].T);this[s].S=!0;this.Lb(this)}},k:function(){var b=this[s];!b.s&&b.r&&a.a.D(b.r,function(a,b){b.k&&b.k()});b.i&&b.mb&&a.a.F.pc(b.i,b.mb);b.r=null;b.L=0;b.R=!0;b.S=!1;b.s=!1;b.i=null}},$={sa:function(b){var c=this,d=c[s];if(!d.R&&d.s&&"change"==b){d.s=!1;if(d.S||c.Qa())d.r=null,d.L=0,d.S=!0,c.aa();else{var e=[];a.a.D(d.r,function(a,b){e[b.Ga]=a});a.a.q(e,function(a,b){var e=d.r[a],l=c.uc(e.ia);l.Ga=b;l.na=e.na;d.r[a]=l})}d.R||c.notifySubscribers(d.T,"awake")}},
Ia:function(b){var c=this[s];c.R||"change"!=b||this.Pa("change")||(a.a.D(c.r,function(a,b){b.k&&(c.r[a]={ia:b.ia,Ga:b.Ga,na:b.na},b.k())}),c.s=!0,this.notifySubscribers(n,"asleep"))},Na:function(){var b=this[s];b.s&&(b.S||this.Qa())&&this.aa();return a.J.fn.Na.call(this)}},aa={sa:function(a){"change"!=a&&"beforeChange"!=a||this.t()}};a.a.ka&&a.a.Xa(z,a.J.fn);var R=a.N.gd;a.m[R]=a.N;z[R]=a.m;a.Xc=function(b){return a.Oa(b,a.m)};a.Yc=function(b){return a.Oa(b,a.m)&&b[s]&&b[s].Va};a.b("computed",a.m);
a.b("dependentObservable",a.m);a.b("isComputed",a.Xc);a.b("isPureComputed",a.Yc);a.b("computed.fn",z);a.G(z,"peek",z.t);a.G(z,"dispose",z.k);a.G(z,"isActive",z.ba);a.G(z,"getDependenciesCount",z.Aa);a.nc=function(b,c){if("function"===typeof b)return a.m(b,c,{pure:!0});b=a.a.extend({},b);b.pure=!0;return a.m(b,c)};a.b("pureComputed",a.nc);(function(){function b(a,f,g){g=g||new d;a=f(a);if("object"!=typeof a||null===a||a===n||a instanceof RegExp||a instanceof Date||a instanceof String||a instanceof
Number||a instanceof Boolean)return a;var k=a instanceof Array?[]:{};g.save(a,k);c(a,function(c){var d=f(a[c]);switch(typeof d){case "boolean":case "number":case "string":case "function":k[c]=d;break;case "object":case "undefined":var h=g.get(d);k[c]=h!==n?h:b(d,f,g)}});return k}function c(a,b){if(a instanceof Array){for(var c=0;c<a.length;c++)b(c);"function"==typeof a.toJSON&&b("toJSON")}else for(c in a)b(c)}function d(){this.keys=[];this.Ib=[]}a.wc=function(c){if(0==arguments.length)throw Error("When calling ko.toJS, pass the object you want to convert.");
return b(c,function(b){for(var c=0;a.H(b)&&10>c;c++)b=b();return b})};a.toJSON=function(b,c,d){b=a.wc(b);return a.a.Eb(b,c,d)};d.prototype={save:function(b,c){var d=a.a.o(this.keys,b);0<=d?this.Ib[d]=c:(this.keys.push(b),this.Ib.push(c))},get:function(b){b=a.a.o(this.keys,b);return 0<=b?this.Ib[b]:n}}})();a.b("toJS",a.wc);a.b("toJSON",a.toJSON);(function(){a.j={u:function(b){switch(a.a.A(b)){case "option":return!0===b.__ko__hasDomDataOptionValue__?a.a.e.get(b,a.d.options.xb):7>=a.a.C?b.getAttributeNode("value")&&
b.getAttributeNode("value").specified?b.value:b.text:b.value;case "select":return 0<=b.selectedIndex?a.j.u(b.options[b.selectedIndex]):n;default:return b.value}},ha:function(b,c,d){switch(a.a.A(b)){case "option":switch(typeof c){case "string":a.a.e.set(b,a.d.options.xb,n);"__ko__hasDomDataOptionValue__"in b&&delete b.__ko__hasDomDataOptionValue__;b.value=c;break;default:a.a.e.set(b,a.d.options.xb,c),b.__ko__hasDomDataOptionValue__=!0,b.value="number"===typeof c?c:""}break;case "select":if(""===c||
null===c)c=n;for(var e=-1,f=0,g=b.options.length,k;f<g;++f)if(k=a.j.u(b.options[f]),k==c||""==k&&c===n){e=f;break}if(d||0<=e||c===n&&1<b.size)b.selectedIndex=e;break;default:if(null===c||c===n)c="";b.value=c}}}})();a.b("selectExtensions",a.j);a.b("selectExtensions.readValue",a.j.u);a.b("selectExtensions.writeValue",a.j.ha);a.h=function(){function b(b){b=a.a.$a(b);123===b.charCodeAt(0)&&(b=b.slice(1,-1));var c=[],d=b.match(e),r,k=[],p=0;if(d){d.push(",");for(var A=0,y;y=d[A];++A){var t=y.charCodeAt(0);
if(44===t){if(0>=p){c.push(r&&k.length?{key:r,value:k.join("")}:{unknown:r||k.join("")});r=p=0;k=[];continue}}else if(58===t){if(!p&&!r&&1===k.length){r=k.pop();continue}}else 47===t&&A&&1<y.length?(t=d[A-1].match(f))&&!g[t[0]]&&(b=b.substr(b.indexOf(y)+1),d=b.match(e),d.push(","),A=-1,y="/"):40===t||123===t||91===t?++p:41===t||125===t||93===t?--p:r||k.length||34!==t&&39!==t||(y=y.slice(1,-1));k.push(y)}}return c}var c=["true","false","null","undefined"],d=/^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i,
e=RegExp("\"(?:[^\"\\\\]|\\\\.)*\"|'(?:[^'\\\\]|\\\\.)*'|/(?:[^/\\\\]|\\\\.)*/w*|[^\\s:,/][^,\"'{}()/:[\\]]*[^\\s,\"'{}()/:[\\]]|[^\\s]","g"),f=/[\])"'A-Za-z0-9_$]+$/,g={"in":1,"return":1,"typeof":1},k={};return{ta:[],ea:k,yb:b,Ua:function(e,m){function h(b,e){var m;if(!A){var l=a.getBindingHandler(b);if(l&&l.preprocess&&!(e=l.preprocess(e,b,h)))return;if(l=k[b])m=e,0<=a.a.o(c,m)?m=!1:(l=m.match(d),m=null===l?!1:l[1]?"Object("+l[1]+")"+l[2]:m),l=m;l&&g.push("'"+b+"':function(_z){"+m+"=_z}")}p&&(e=
"function(){return "+e+" }");f.push("'"+b+"':"+e)}m=m||{};var f=[],g=[],p=m.valueAccessors,A=m.bindingParams,y="string"===typeof e?b(e):e;a.a.q(y,function(a){h(a.key||a.unknown,a.value)});g.length&&h("_ko_property_writers","{"+g.join(",")+" }");return f.join(",")},ad:function(a,b){for(var c=0;c<a.length;c++)if(a[c].key==b)return!0;return!1},Ea:function(b,c,d,e,f){if(b&&a.H(b))!a.Ba(b)||f&&b.t()===e||b(e);else if((b=c.get("_ko_property_writers"))&&b[d])b[d](e)}}}();a.b("expressionRewriting",a.h);a.b("expressionRewriting.bindingRewriteValidators",
a.h.ta);a.b("expressionRewriting.parseObjectLiteral",a.h.yb);a.b("expressionRewriting.preProcessBindings",a.h.Ua);a.b("expressionRewriting._twoWayBindings",a.h.ea);a.b("jsonExpressionRewriting",a.h);a.b("jsonExpressionRewriting.insertPropertyAccessorsIntoJson",a.h.Ua);(function(){function b(a){return 8==a.nodeType&&g.test(f?a.text:a.nodeValue)}function c(a){return 8==a.nodeType&&k.test(f?a.text:a.nodeValue)}function d(a,d){for(var e=a,f=1,l=[];e=e.nextSibling;){if(c(e)&&(f--,0===f))return l;l.push(e);
b(e)&&f++}if(!d)throw Error("Cannot find closing comment tag to match: "+a.nodeValue);return null}function e(a,b){var c=d(a,b);return c?0<c.length?c[c.length-1].nextSibling:a.nextSibling:null}var f=u&&"\x3c!--test--\x3e"===u.createComment("test").text,g=f?/^\x3c!--\s*ko(?:\s+([\s\S]+))?\s*--\x3e$/:/^\s*ko(?:\s+([\s\S]+))?\s*$/,k=f?/^\x3c!--\s*\/ko\s*--\x3e$/:/^\s*\/ko\s*$/,l={ul:!0,ol:!0};a.f={Z:{},childNodes:function(a){return b(a)?d(a):a.childNodes},xa:function(c){if(b(c)){c=a.f.childNodes(c);for(var d=
0,e=c.length;d<e;d++)a.removeNode(c[d])}else a.a.ob(c)},da:function(c,d){if(b(c)){a.f.xa(c);for(var e=c.nextSibling,f=0,l=d.length;f<l;f++)e.parentNode.insertBefore(d[f],e)}else a.a.da(c,d)},mc:function(a,c){b(a)?a.parentNode.insertBefore(c,a.nextSibling):a.firstChild?a.insertBefore(c,a.firstChild):a.appendChild(c)},gc:function(c,d,e){e?b(c)?c.parentNode.insertBefore(d,e.nextSibling):e.nextSibling?c.insertBefore(d,e.nextSibling):c.appendChild(d):a.f.mc(c,d)},firstChild:function(a){return b(a)?!a.nextSibling||
c(a.nextSibling)?null:a.nextSibling:a.firstChild},nextSibling:function(a){b(a)&&(a=e(a));return a.nextSibling&&c(a.nextSibling)?null:a.nextSibling},Tc:b,pd:function(a){return(a=(f?a.text:a.nodeValue).match(g))?a[1]:null},kc:function(d){if(l[a.a.A(d)]){var h=d.firstChild;if(h){do if(1===h.nodeType){var f;f=h.firstChild;var g=null;if(f){do if(g)g.push(f);else if(b(f)){var k=e(f,!0);k?f=k:g=[f]}else c(f)&&(g=[f]);while(f=f.nextSibling)}if(f=g)for(g=h.nextSibling,k=0;k<f.length;k++)g?d.insertBefore(f[k],
g):d.appendChild(f[k])}while(h=h.nextSibling)}}}}})();a.b("virtualElements",a.f);a.b("virtualElements.allowedBindings",a.f.Z);a.b("virtualElements.emptyNode",a.f.xa);a.b("virtualElements.insertAfter",a.f.gc);a.b("virtualElements.prepend",a.f.mc);a.b("virtualElements.setDomNodeChildren",a.f.da);(function(){a.Q=function(){this.Fc={}};a.a.extend(a.Q.prototype,{nodeHasBindings:function(b){switch(b.nodeType){case 1:return null!=b.getAttribute("data-bind")||a.g.getComponentNameForNode(b);case 8:return a.f.Tc(b);
default:return!1}},getBindings:function(b,c){var d=this.getBindingsString(b,c),d=d?this.parseBindingsString(d,c,b):null;return a.g.Ob(d,b,c,!1)},getBindingAccessors:function(b,c){var d=this.getBindingsString(b,c),d=d?this.parseBindingsString(d,c,b,{valueAccessors:!0}):null;return a.g.Ob(d,b,c,!0)},getBindingsString:function(b){switch(b.nodeType){case 1:return b.getAttribute("data-bind");case 8:return a.f.pd(b);default:return null}},parseBindingsString:function(b,c,d,e){try{var f=this.Fc,g=b+(e&&e.valueAccessors||
""),k;if(!(k=f[g])){var l,m="with($context){with($data||{}){return{"+a.h.Ua(b,e)+"}}}";l=new Function("$context","$element",m);k=f[g]=l}return k(c,d)}catch(h){throw h.message="Unable to parse bindings.\nBindings value: "+b+"\nMessage: "+h.message,h;}}});a.Q.instance=new a.Q})();a.b("bindingProvider",a.Q);(function(){function b(a){return function(){return a}}function c(a){return a()}function d(b){return a.a.Ca(a.l.w(b),function(a,c){return function(){return b()[c]}})}function e(c,e,h){return"function"===
typeof c?d(c.bind(null,e,h)):a.a.Ca(c,b)}function f(a,b){return d(this.getBindings.bind(this,a,b))}function g(b,c,d){var e,h=a.f.firstChild(c),f=a.Q.instance,m=f.preprocessNode;if(m){for(;e=h;)h=a.f.nextSibling(e),m.call(f,e);h=a.f.firstChild(c)}for(;e=h;)h=a.f.nextSibling(e),k(b,e,d)}function k(b,c,d){var e=!0,h=1===c.nodeType;h&&a.f.kc(c);if(h&&d||a.Q.instance.nodeHasBindings(c))e=m(c,null,b,d).shouldBindDescendants;e&&!r[a.a.A(c)]&&g(b,c,!h)}function l(b){var c=[],d={},e=[];a.a.D(b,function Z(h){if(!d[h]){var f=
a.getBindingHandler(h);f&&(f.after&&(e.push(h),a.a.q(f.after,function(c){if(b[c]){if(-1!==a.a.o(e,c))throw Error("Cannot combine the following bindings, because they have a cyclic dependency: "+e.join(", "));Z(c)}}),e.length--),c.push({key:h,fc:f}));d[h]=!0}});return c}function m(b,d,e,h){var m=a.a.e.get(b,q);if(!d){if(m)throw Error("You cannot apply bindings multiple times to the same element.");a.a.e.set(b,q,!0)}!m&&h&&a.tc(b,e);var g;if(d&&"function"!==typeof d)g=d;else{var k=a.Q.instance,r=k.getBindingAccessors||
f,p=a.B(function(){(g=d?d(e,b):r.call(k,b,e))&&e.P&&e.P();return g},null,{i:b});g&&p.ba()||(p=null)}var u;if(g){var v=p?function(a){return function(){return c(p()[a])}}:function(a){return g[a]},s=function(){return a.a.Ca(p?p():g,c)};s.get=function(a){return g[a]&&c(v(a))};s.has=function(a){return a in g};h=l(g);a.a.q(h,function(c){var d=c.fc.init,h=c.fc.update,f=c.key;if(8===b.nodeType&&!a.f.Z[f])throw Error("The binding '"+f+"' cannot be used with virtual elements");try{"function"==typeof d&&a.l.w(function(){var a=
d(b,v(f),s,e.$data,e);if(a&&a.controlsDescendantBindings){if(u!==n)throw Error("Multiple bindings ("+u+" and "+f+") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");u=f}}),"function"==typeof h&&a.B(function(){h(b,v(f),s,e.$data,e)},null,{i:b})}catch(m){throw m.message='Unable to process binding "'+f+": "+g[f]+'"\nMessage: '+m.message,m;}})}return{shouldBindDescendants:u===n}}function h(b){return b&&b instanceof a.U?b:new a.U(b)}
a.d={};var r={script:!0,textarea:!0,template:!0};a.getBindingHandler=function(b){return a.d[b]};a.U=function(b,c,d,e){var h=this,f="function"==typeof b&&!a.H(b),m,g=a.B(function(){var m=f?b():b,l=a.a.c(m);c?(c.P&&c.P(),a.a.extend(h,c),g&&(h.P=g)):(h.$parents=[],h.$root=l,h.ko=a);h.$rawData=m;h.$data=l;d&&(h[d]=l);e&&e(h,c,l);return h.$data},null,{wa:function(){return m&&!a.a.Qb(m)},i:!0});g.ba()&&(h.P=g,g.equalityComparer=null,m=[],g.Ac=function(b){m.push(b);a.a.F.oa(b,function(b){a.a.La(m,b);m.length||
(g.k(),h.P=g=n)})})};a.U.prototype.createChildContext=function(b,c,d){return new a.U(b,this,c,function(a,b){a.$parentContext=b;a.$parent=b.$data;a.$parents=(b.$parents||[]).slice(0);a.$parents.unshift(a.$parent);d&&d(a)})};a.U.prototype.extend=function(b){return new a.U(this.P||this.$data,this,null,function(c,d){c.$rawData=d.$rawData;a.a.extend(c,"function"==typeof b?b():b)})};var q=a.a.e.I(),p=a.a.e.I();a.tc=function(b,c){if(2==arguments.length)a.a.e.set(b,p,c),c.P&&c.P.Ac(b);else return a.a.e.get(b,
p)};a.Ja=function(b,c,d){1===b.nodeType&&a.f.kc(b);return m(b,c,h(d),!0)};a.Dc=function(b,c,d){d=h(d);return a.Ja(b,e(c,d,b),d)};a.eb=function(a,b){1!==b.nodeType&&8!==b.nodeType||g(h(a),b,!0)};a.Rb=function(a,b){!v&&x.jQuery&&(v=x.jQuery);if(b&&1!==b.nodeType&&8!==b.nodeType)throw Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");b=b||x.document.body;k(h(a),b,!0)};a.kb=function(b){switch(b.nodeType){case 1:case 8:var c=a.tc(b);if(c)return c;
if(b.parentNode)return a.kb(b.parentNode)}return n};a.Jc=function(b){return(b=a.kb(b))?b.$data:n};a.b("bindingHandlers",a.d);a.b("applyBindings",a.Rb);a.b("applyBindingsToDescendants",a.eb);a.b("applyBindingAccessorsToNode",a.Ja);a.b("applyBindingsToNode",a.Dc);a.b("contextFor",a.kb);a.b("dataFor",a.Jc)})();(function(b){function c(c,e){var m=f.hasOwnProperty(c)?f[c]:b,h;m?m.X(e):(m=f[c]=new a.J,m.X(e),d(c,function(b,d){var e=!(!d||!d.synchronous);g[c]={definition:b,Zc:e};delete f[c];h||e?m.notifySubscribers(b):
a.Y.Wa(function(){m.notifySubscribers(b)})}),h=!0)}function d(a,b){e("getConfig",[a],function(c){c?e("loadComponent",[a,c],function(a){b(a,c)}):b(null,null)})}function e(c,d,f,h){h||(h=a.g.loaders.slice(0));var g=h.shift();if(g){var q=g[c];if(q){var p=!1;if(q.apply(g,d.concat(function(a){p?f(null):null!==a?f(a):e(c,d,f,h)}))!==b&&(p=!0,!g.suppressLoaderExceptions))throw Error("Component loaders must supply values by invoking the callback, not by returning values synchronously.");}else e(c,d,f,h)}else f(null)}
var f={},g={};a.g={get:function(d,e){var f=g.hasOwnProperty(d)?g[d]:b;f?f.Zc?a.l.w(function(){e(f.definition)}):a.Y.Wa(function(){e(f.definition)}):c(d,e)},Xb:function(a){delete g[a]},Jb:e};a.g.loaders=[];a.b("components",a.g);a.b("components.get",a.g.get);a.b("components.clearCachedDefinition",a.g.Xb)})();(function(){function b(b,c,d,e){function g(){0===--y&&e(k)}var k={},y=2,t=d.template;d=d.viewModel;t?f(c,t,function(c){a.g.Jb("loadTemplate",[b,c],function(a){k.template=a;g()})}):g();d?f(c,d,function(c){a.g.Jb("loadViewModel",
[b,c],function(a){k[l]=a;g()})}):g()}function c(a,b,d){if("function"===typeof b)d(function(a){return new b(a)});else if("function"===typeof b[l])d(b[l]);else if("instance"in b){var e=b.instance;d(function(){return e})}else"viewModel"in b?c(a,b.viewModel,d):a("Unknown viewModel value: "+b)}function d(b){switch(a.a.A(b)){case "script":return a.a.ma(b.text);case "textarea":return a.a.ma(b.value);case "template":if(e(b.content))return a.a.ua(b.content.childNodes)}return a.a.ua(b.childNodes)}function e(a){return x.DocumentFragment?
a instanceof DocumentFragment:a&&11===a.nodeType}function f(a,b,c){"string"===typeof b.require?O||x.require?(O||x.require)([b.require],c):a("Uses require, but no AMD loader is present"):c(b)}function g(a){return function(b){throw Error("Component '"+a+"': "+b);}}var k={};a.g.register=function(b,c){if(!c)throw Error("Invalid configuration for "+b);if(a.g.ub(b))throw Error("Component "+b+" is already registered");k[b]=c};a.g.ub=function(a){return k.hasOwnProperty(a)};a.g.od=function(b){delete k[b];
a.g.Xb(b)};a.g.Zb={getConfig:function(a,b){b(k.hasOwnProperty(a)?k[a]:null)},loadComponent:function(a,c,d){var e=g(a);f(e,c,function(c){b(a,e,c,d)})},loadTemplate:function(b,c,f){b=g(b);if("string"===typeof c)f(a.a.ma(c));else if(c instanceof Array)f(c);else if(e(c))f(a.a.V(c.childNodes));else if(c.element)if(c=c.element,x.HTMLElement?c instanceof HTMLElement:c&&c.tagName&&1===c.nodeType)f(d(c));else if("string"===typeof c){var l=u.getElementById(c);l?f(d(l)):b("Cannot find element with ID "+c)}else b("Unknown element type: "+
c);else b("Unknown template value: "+c)},loadViewModel:function(a,b,d){c(g(a),b,d)}};var l="createViewModel";a.b("components.register",a.g.register);a.b("components.isRegistered",a.g.ub);a.b("components.unregister",a.g.od);a.b("components.defaultLoader",a.g.Zb);a.g.loaders.push(a.g.Zb);a.g.Bc=k})();(function(){function b(b,e){var f=b.getAttribute("params");if(f){var f=c.parseBindingsString(f,e,b,{valueAccessors:!0,bindingParams:!0}),f=a.a.Ca(f,function(c){return a.m(c,null,{i:b})}),g=a.a.Ca(f,function(c){var e=
c.t();return c.ba()?a.m({read:function(){return a.a.c(c())},write:a.Ba(e)&&function(a){c()(a)},i:b}):e});g.hasOwnProperty("$raw")||(g.$raw=f);return g}return{$raw:{}}}a.g.getComponentNameForNode=function(b){var c=a.a.A(b);if(a.g.ub(c)&&(-1!=c.indexOf("-")||"[object HTMLUnknownElement]"==""+b||8>=a.a.C&&b.tagName===c))return c};a.g.Ob=function(c,e,f,g){if(1===e.nodeType){var k=a.g.getComponentNameForNode(e);if(k){c=c||{};if(c.component)throw Error('Cannot use the "component" binding on a custom element matching a component');
var l={name:k,params:b(e,f)};c.component=g?function(){return l}:l}}return c};var c=new a.Q;9>a.a.C&&(a.g.register=function(a){return function(b){u.createElement(b);return a.apply(this,arguments)}}(a.g.register),u.createDocumentFragment=function(b){return function(){var c=b(),f=a.g.Bc,g;for(g in f)f.hasOwnProperty(g)&&c.createElement(g);return c}}(u.createDocumentFragment))})();(function(b){function c(b,c,d){c=c.template;if(!c)throw Error("Component '"+b+"' has no template");b=a.a.ua(c);a.f.da(d,b)}
function d(a,b,c,d){var e=a.createViewModel;return e?e.call(a,d,{element:b,templateNodes:c}):d}var e=0;a.d.component={init:function(f,g,k,l,m){function h(){var a=r&&r.dispose;"function"===typeof a&&a.call(r);q=r=null}var r,q,p=a.a.V(a.f.childNodes(f));a.a.F.oa(f,h);a.m(function(){var l=a.a.c(g()),k,t;"string"===typeof l?k=l:(k=a.a.c(l.name),t=a.a.c(l.params));if(!k)throw Error("No component name specified");var n=q=++e;a.g.get(k,function(e){if(q===n){h();if(!e)throw Error("Unknown component '"+k+
"'");c(k,e,f);var g=d(e,f,p,t);e=m.createChildContext(g,b,function(a){a.$component=g;a.$componentTemplateNodes=p});r=g;a.eb(e,f)}})},null,{i:f});return{controlsDescendantBindings:!0}}};a.f.Z.component=!0})();var S={"class":"className","for":"htmlFor"};a.d.attr={update:function(b,c){var d=a.a.c(c())||{};a.a.D(d,function(c,d){d=a.a.c(d);var g=!1===d||null===d||d===n;g&&b.removeAttribute(c);8>=a.a.C&&c in S?(c=S[c],g?b.removeAttribute(c):b[c]=d):g||b.setAttribute(c,d.toString());"name"===c&&a.a.rc(b,
g?"":d.toString())})}};(function(){a.d.checked={after:["value","attr"],init:function(b,c,d){function e(){var e=b.checked,f=p?g():e;if(!a.va.Sa()&&(!l||e)){var m=a.l.w(c);if(h){var k=r?m.t():m;q!==f?(e&&(a.a.pa(k,f,!0),a.a.pa(k,q,!1)),q=f):a.a.pa(k,f,e);r&&a.Ba(m)&&m(k)}else a.h.Ea(m,d,"checked",f,!0)}}function f(){var d=a.a.c(c());b.checked=h?0<=a.a.o(d,g()):k?d:g()===d}var g=a.nc(function(){return d.has("checkedValue")?a.a.c(d.get("checkedValue")):d.has("value")?a.a.c(d.get("value")):b.value}),k=
"checkbox"==b.type,l="radio"==b.type;if(k||l){var m=c(),h=k&&a.a.c(m)instanceof Array,r=!(h&&m.push&&m.splice),q=h?g():n,p=l||h;l&&!b.name&&a.d.uniqueName.init(b,function(){return!0});a.m(e,null,{i:b});a.a.p(b,"click",e);a.m(f,null,{i:b});m=n}}};a.h.ea.checked=!0;a.d.checkedValue={update:function(b,c){b.value=a.a.c(c())}}})();a.d.css={update:function(b,c){var d=a.a.c(c());null!==d&&"object"==typeof d?a.a.D(d,function(c,d){d=a.a.c(d);a.a.bb(b,c,d)}):(d=a.a.$a(String(d||"")),a.a.bb(b,b.__ko__cssValue,
!1),b.__ko__cssValue=d,a.a.bb(b,d,!0))}};a.d.enable={update:function(b,c){var d=a.a.c(c());d&&b.disabled?b.removeAttribute("disabled"):d||b.disabled||(b.disabled=!0)}};a.d.disable={update:function(b,c){a.d.enable.update(b,function(){return!a.a.c(c())})}};a.d.event={init:function(b,c,d,e,f){var g=c()||{};a.a.D(g,function(g){"string"==typeof g&&a.a.p(b,g,function(b){var m,h=c()[g];if(h){try{var r=a.a.V(arguments);e=f.$data;r.unshift(e);m=h.apply(e,r)}finally{!0!==m&&(b.preventDefault?b.preventDefault():
b.returnValue=!1)}!1===d.get(g+"Bubble")&&(b.cancelBubble=!0,b.stopPropagation&&b.stopPropagation())}})})}};a.d.foreach={ic:function(b){return function(){var c=b(),d=a.a.zb(c);if(!d||"number"==typeof d.length)return{foreach:c,templateEngine:a.W.sb};a.a.c(c);return{foreach:d.data,as:d.as,includeDestroyed:d.includeDestroyed,afterAdd:d.afterAdd,beforeRemove:d.beforeRemove,afterRender:d.afterRender,beforeMove:d.beforeMove,afterMove:d.afterMove,templateEngine:a.W.sb}}},init:function(b,c){return a.d.template.init(b,
a.d.foreach.ic(c))},update:function(b,c,d,e,f){return a.d.template.update(b,a.d.foreach.ic(c),d,e,f)}};a.h.ta.foreach=!1;a.f.Z.foreach=!0;a.d.hasfocus={init:function(b,c,d){function e(e){b.__ko_hasfocusUpdating=!0;var f=b.ownerDocument;if("activeElement"in f){var g;try{g=f.activeElement}catch(h){g=f.body}e=g===b}f=c();a.h.Ea(f,d,"hasfocus",e,!0);b.__ko_hasfocusLastValue=e;b.__ko_hasfocusUpdating=!1}var f=e.bind(null,!0),g=e.bind(null,!1);a.a.p(b,"focus",f);a.a.p(b,"focusin",f);a.a.p(b,"blur",g);a.a.p(b,
"focusout",g)},update:function(b,c){var d=!!a.a.c(c());b.__ko_hasfocusUpdating||b.__ko_hasfocusLastValue===d||(d?b.focus():b.blur(),!d&&b.__ko_hasfocusLastValue&&b.ownerDocument.body.focus(),a.l.w(a.a.Da,null,[b,d?"focusin":"focusout"]))}};a.h.ea.hasfocus=!0;a.d.hasFocus=a.d.hasfocus;a.h.ea.hasFocus=!0;a.d.html={init:function(){return{controlsDescendantBindings:!0}},update:function(b,c){a.a.Cb(b,c())}};K("if");K("ifnot",!1,!0);K("with",!0,!1,function(a,c){return a.createChildContext(c)});var L={};
a.d.options={init:function(b){if("select"!==a.a.A(b))throw Error("options binding applies only to SELECT elements");for(;0<b.length;)b.remove(0);return{controlsDescendantBindings:!0}},update:function(b,c,d){function e(){return a.a.Ka(b.options,function(a){return a.selected})}function f(a,b,c){var d=typeof b;return"function"==d?b(a):"string"==d?a[b]:c}function g(c,e){if(A&&h)a.j.ha(b,a.a.c(d.get("value")),!0);else if(p.length){var f=0<=a.a.o(p,a.j.u(e[0]));a.a.sc(e[0],f);A&&!f&&a.l.w(a.a.Da,null,[b,
"change"])}}var k=b.multiple,l=0!=b.length&&k?b.scrollTop:null,m=a.a.c(c()),h=d.get("valueAllowUnset")&&d.has("value"),r=d.get("optionsIncludeDestroyed");c={};var q,p=[];h||(k?p=a.a.fb(e(),a.j.u):0<=b.selectedIndex&&p.push(a.j.u(b.options[b.selectedIndex])));m&&("undefined"==typeof m.length&&(m=[m]),q=a.a.Ka(m,function(b){return r||b===n||null===b||!a.a.c(b._destroy)}),d.has("optionsCaption")&&(m=a.a.c(d.get("optionsCaption")),null!==m&&m!==n&&q.unshift(L)));var A=!1;c.beforeRemove=function(a){b.removeChild(a)};
m=g;d.has("optionsAfterRender")&&"function"==typeof d.get("optionsAfterRender")&&(m=function(b,c){g(0,c);a.l.w(d.get("optionsAfterRender"),null,[c[0],b!==L?b:n])});a.a.Bb(b,q,function(c,e,g){g.length&&(p=!h&&g[0].selected?[a.j.u(g[0])]:[],A=!0);e=b.ownerDocument.createElement("option");c===L?(a.a.Za(e,d.get("optionsCaption")),a.j.ha(e,n)):(g=f(c,d.get("optionsValue"),c),a.j.ha(e,a.a.c(g)),c=f(c,d.get("optionsText"),g),a.a.Za(e,c));return[e]},c,m);a.l.w(function(){h?a.j.ha(b,a.a.c(d.get("value")),
!0):(k?p.length&&e().length<p.length:p.length&&0<=b.selectedIndex?a.j.u(b.options[b.selectedIndex])!==p[0]:p.length||0<=b.selectedIndex)&&a.a.Da(b,"change")});a.a.Nc(b);l&&20<Math.abs(l-b.scrollTop)&&(b.scrollTop=l)}};a.d.options.xb=a.a.e.I();a.d.selectedOptions={after:["options","foreach"],init:function(b,c,d){a.a.p(b,"change",function(){var e=c(),f=[];a.a.q(b.getElementsByTagName("option"),function(b){b.selected&&f.push(a.j.u(b))});a.h.Ea(e,d,"selectedOptions",f)})},update:function(b,c){if("select"!=
a.a.A(b))throw Error("values binding applies only to SELECT elements");var d=a.a.c(c()),e=b.scrollTop;d&&"number"==typeof d.length&&a.a.q(b.getElementsByTagName("option"),function(b){var c=0<=a.a.o(d,a.j.u(b));b.selected!=c&&a.a.sc(b,c)});b.scrollTop=e}};a.h.ea.selectedOptions=!0;a.d.style={update:function(b,c){var d=a.a.c(c()||{});a.a.D(d,function(c,d){d=a.a.c(d);if(null===d||d===n||!1===d)d="";b.style[c]=d})}};a.d.submit={init:function(b,c,d,e,f){if("function"!=typeof c())throw Error("The value for a submit binding must be a function");
a.a.p(b,"submit",function(a){var d,e=c();try{d=e.call(f.$data,b)}finally{!0!==d&&(a.preventDefault?a.preventDefault():a.returnValue=!1)}})}};a.d.text={init:function(){return{controlsDescendantBindings:!0}},update:function(b,c){a.a.Za(b,c())}};a.f.Z.text=!0;(function(){if(x&&x.navigator)var b=function(a){if(a)return parseFloat(a[1])},c=x.opera&&x.opera.version&&parseInt(x.opera.version()),d=x.navigator.userAgent,e=b(d.match(/^(?:(?!chrome).)*version\/([^ ]*) safari/i)),f=b(d.match(/Firefox\/([^ ]*)/));
if(10>a.a.C)var g=a.a.e.I(),k=a.a.e.I(),l=function(b){var c=this.activeElement;(c=c&&a.a.e.get(c,k))&&c(b)},m=function(b,c){var d=b.ownerDocument;a.a.e.get(d,g)||(a.a.e.set(d,g,!0),a.a.p(d,"selectionchange",l));a.a.e.set(b,k,c)};a.d.textInput={init:function(b,d,g){function l(c,d){a.a.p(b,c,d)}function k(){var c=a.a.c(d());if(null===c||c===n)c="";v!==n&&c===v?a.a.setTimeout(k,4):b.value!==c&&(u=c,b.value=c)}function y(){s||(v=b.value,s=a.a.setTimeout(t,4))}function t(){clearTimeout(s);v=s=n;var c=
b.value;u!==c&&(u=c,a.h.Ea(d(),g,"textInput",c))}var u=b.value,s,v,x=9==a.a.C?y:t;10>a.a.C?(l("propertychange",function(a){"value"===a.propertyName&&x(a)}),8==a.a.C&&(l("keyup",t),l("keydown",t)),8<=a.a.C&&(m(b,x),l("dragend",y))):(l("input",t),5>e&&"textarea"===a.a.A(b)?(l("keydown",y),l("paste",y),l("cut",y)):11>c?l("keydown",y):4>f&&(l("DOMAutoComplete",t),l("dragdrop",t),l("drop",t)));l("change",t);a.m(k,null,{i:b})}};a.h.ea.textInput=!0;a.d.textinput={preprocess:function(a,b,c){c("textInput",
a)}}})();a.d.uniqueName={init:function(b,c){if(c()){var d="ko_unique_"+ ++a.d.uniqueName.Ic;a.a.rc(b,d)}}};a.d.uniqueName.Ic=0;a.d.value={after:["options","foreach"],init:function(b,c,d){if("input"!=b.tagName.toLowerCase()||"checkbox"!=b.type&&"radio"!=b.type){var e=["change"],f=d.get("valueUpdate"),g=!1,k=null;f&&("string"==typeof f&&(f=[f]),a.a.ra(e,f),e=a.a.Tb(e));var l=function(){k=null;g=!1;var e=c(),f=a.j.u(b);a.h.Ea(e,d,"value",f)};!a.a.C||"input"!=b.tagName.toLowerCase()||"text"!=b.type||
"off"==b.autocomplete||b.form&&"off"==b.form.autocomplete||-1!=a.a.o(e,"propertychange")||(a.a.p(b,"propertychange",function(){g=!0}),a.a.p(b,"focus",function(){g=!1}),a.a.p(b,"blur",function(){g&&l()}));a.a.q(e,function(c){var d=l;a.a.nd(c,"after")&&(d=function(){k=a.j.u(b);a.a.setTimeout(l,0)},c=c.substring(5));a.a.p(b,c,d)});var m=function(){var e=a.a.c(c()),f=a.j.u(b);if(null!==k&&e===k)a.a.setTimeout(m,0);else if(e!==f)if("select"===a.a.A(b)){var g=d.get("valueAllowUnset"),f=function(){a.j.ha(b,
e,g)};f();g||e===a.j.u(b)?a.a.setTimeout(f,0):a.l.w(a.a.Da,null,[b,"change"])}else a.j.ha(b,e)};a.m(m,null,{i:b})}else a.Ja(b,{checkedValue:c})},update:function(){}};a.h.ea.value=!0;a.d.visible={update:function(b,c){var d=a.a.c(c()),e="none"!=b.style.display;d&&!e?b.style.display="":!d&&e&&(b.style.display="none")}};(function(b){a.d[b]={init:function(c,d,e,f,g){return a.d.event.init.call(this,c,function(){var a={};a[b]=d();return a},e,f,g)}}})("click");a.O=function(){};a.O.prototype.renderTemplateSource=
function(){throw Error("Override renderTemplateSource");};a.O.prototype.createJavaScriptEvaluatorBlock=function(){throw Error("Override createJavaScriptEvaluatorBlock");};a.O.prototype.makeTemplateSource=function(b,c){if("string"==typeof b){c=c||u;var d=c.getElementById(b);if(!d)throw Error("Cannot find template with ID "+b);return new a.v.n(d)}if(1==b.nodeType||8==b.nodeType)return new a.v.qa(b);throw Error("Unknown template type: "+b);};a.O.prototype.renderTemplate=function(a,c,d,e){a=this.makeTemplateSource(a,
e);return this.renderTemplateSource(a,c,d,e)};a.O.prototype.isTemplateRewritten=function(a,c){return!1===this.allowTemplateRewriting?!0:this.makeTemplateSource(a,c).data("isRewritten")};a.O.prototype.rewriteTemplate=function(a,c,d){a=this.makeTemplateSource(a,d);c=c(a.text());a.text(c);a.data("isRewritten",!0)};a.b("templateEngine",a.O);a.Gb=function(){function b(b,c,d,k){b=a.h.yb(b);for(var l=a.h.ta,m=0;m<b.length;m++){var h=b[m].key;if(l.hasOwnProperty(h)){var r=l[h];if("function"===typeof r){if(h=
r(b[m].value))throw Error(h);}else if(!r)throw Error("This template engine does not support the '"+h+"' binding within its templates");}}d="ko.__tr_ambtns(function($context,$element){return(function(){return{ "+a.h.Ua(b,{valueAccessors:!0})+" } })()},'"+d.toLowerCase()+"')";return k.createJavaScriptEvaluatorBlock(d)+c}var c=/(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:\"[^\"]*\"|\'[^\']*\'|[^>]*))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi,d=/\x3c!--\s*ko\b\s*([\s\S]*?)\s*--\x3e/g;return{Oc:function(b,
c,d){c.isTemplateRewritten(b,d)||c.rewriteTemplate(b,function(b){return a.Gb.dd(b,c)},d)},dd:function(a,f){return a.replace(c,function(a,c,d,e,h){return b(h,c,d,f)}).replace(d,function(a,c){return b(c,"\x3c!-- ko --\x3e","#comment",f)})},Ec:function(b,c){return a.M.wb(function(d,k){var l=d.nextSibling;l&&l.nodeName.toLowerCase()===c&&a.Ja(l,b,k)})}}}();a.b("__tr_ambtns",a.Gb.Ec);(function(){a.v={};a.v.n=function(b){if(this.n=b){var c=a.a.A(b);this.ab="script"===c?1:"textarea"===c?2:"template"==c&&
b.content&&11===b.content.nodeType?3:4}};a.v.n.prototype.text=function(){var b=1===this.ab?"text":2===this.ab?"value":"innerHTML";if(0==arguments.length)return this.n[b];var c=arguments[0];"innerHTML"===b?a.a.Cb(this.n,c):this.n[b]=c};var b=a.a.e.I()+"_";a.v.n.prototype.data=function(c){if(1===arguments.length)return a.a.e.get(this.n,b+c);a.a.e.set(this.n,b+c,arguments[1])};var c=a.a.e.I();a.v.n.prototype.nodes=function(){var b=this.n;if(0==arguments.length)return(a.a.e.get(b,c)||{}).jb||(3===this.ab?
b.content:4===this.ab?b:n);a.a.e.set(b,c,{jb:arguments[0]})};a.v.qa=function(a){this.n=a};a.v.qa.prototype=new a.v.n;a.v.qa.prototype.text=function(){if(0==arguments.length){var b=a.a.e.get(this.n,c)||{};b.Hb===n&&b.jb&&(b.Hb=b.jb.innerHTML);return b.Hb}a.a.e.set(this.n,c,{Hb:arguments[0]})};a.b("templateSources",a.v);a.b("templateSources.domElement",a.v.n);a.b("templateSources.anonymousTemplate",a.v.qa)})();(function(){function b(b,c,d){var e;for(c=a.f.nextSibling(c);b&&(e=b)!==c;)b=a.f.nextSibling(e),
d(e,b)}function c(c,d){if(c.length){var e=c[0],f=c[c.length-1],g=e.parentNode,k=a.Q.instance,n=k.preprocessNode;if(n){b(e,f,function(a,b){var c=a.previousSibling,d=n.call(k,a);d&&(a===e&&(e=d[0]||b),a===f&&(f=d[d.length-1]||c))});c.length=0;if(!e)return;e===f?c.push(e):(c.push(e,f),a.a.za(c,g))}b(e,f,function(b){1!==b.nodeType&&8!==b.nodeType||a.Rb(d,b)});b(e,f,function(b){1!==b.nodeType&&8!==b.nodeType||a.M.yc(b,[d])});a.a.za(c,g)}}function d(a){return a.nodeType?a:0<a.length?a[0]:null}function e(b,
e,f,k,q){q=q||{};var p=(b&&d(b)||f||{}).ownerDocument,n=q.templateEngine||g;a.Gb.Oc(f,n,p);f=n.renderTemplate(f,k,q,p);if("number"!=typeof f.length||0<f.length&&"number"!=typeof f[0].nodeType)throw Error("Template engine must return an array of DOM nodes");p=!1;switch(e){case "replaceChildren":a.f.da(b,f);p=!0;break;case "replaceNode":a.a.qc(b,f);p=!0;break;case "ignoreTargetNode":break;default:throw Error("Unknown renderMode: "+e);}p&&(c(f,k),q.afterRender&&a.l.w(q.afterRender,null,[f,k.$data]));
return f}function f(b,c,d){return a.H(b)?b():"function"===typeof b?b(c,d):b}var g;a.Db=function(b){if(b!=n&&!(b instanceof a.O))throw Error("templateEngine must inherit from ko.templateEngine");g=b};a.Ab=function(b,c,h,k,q){h=h||{};if((h.templateEngine||g)==n)throw Error("Set a template engine before calling renderTemplate");q=q||"replaceChildren";if(k){var p=d(k);return a.B(function(){var g=c&&c instanceof a.U?c:new a.U(a.a.c(c)),n=f(b,g.$data,g),g=e(k,q,n,g,h);"replaceNode"==q&&(k=g,p=d(k))},null,
{wa:function(){return!p||!a.a.nb(p)},i:p&&"replaceNode"==q?p.parentNode:p})}return a.M.wb(function(d){a.Ab(b,c,h,d,"replaceNode")})};a.kd=function(b,d,g,k,q){function p(a,b){c(b,s);g.afterRender&&g.afterRender(b,a);s=null}function u(a,c){s=q.createChildContext(a,g.as,function(a){a.$index=c});var d=f(b,a,s);return e(null,"ignoreTargetNode",d,s,g)}var s;return a.B(function(){var b=a.a.c(d)||[];"undefined"==typeof b.length&&(b=[b]);b=a.a.Ka(b,function(b){return g.includeDestroyed||b===n||null===b||!a.a.c(b._destroy)});
a.l.w(a.a.Bb,null,[k,b,u,g,p])},null,{i:k})};var k=a.a.e.I();a.d.template={init:function(b,c){var d=a.a.c(c());if("string"==typeof d||d.name)a.f.xa(b);else{if("nodes"in d){if(d=d.nodes||[],a.H(d))throw Error('The "nodes" option must be a plain, non-observable array.');}else d=a.f.childNodes(b);d=a.a.jc(d);(new a.v.qa(b)).nodes(d)}return{controlsDescendantBindings:!0}},update:function(b,c,d,e,f){var g=c(),s;c=a.a.c(g);d=!0;e=null;"string"==typeof c?c={}:(g=c.name,"if"in c&&(d=a.a.c(c["if"])),d&&"ifnot"in
c&&(d=!a.a.c(c.ifnot)),s=a.a.c(c.data));"foreach"in c?e=a.kd(g||b,d&&c.foreach||[],c,b,f):d?(f="data"in c?f.createChildContext(s,c.as):f,e=a.Ab(g||b,f,c,b)):a.f.xa(b);f=e;(s=a.a.e.get(b,k))&&"function"==typeof s.k&&s.k();a.a.e.set(b,k,f&&f.ba()?f:n)}};a.h.ta.template=function(b){b=a.h.yb(b);return 1==b.length&&b[0].unknown||a.h.ad(b,"name")?null:"This template engine does not support anonymous templates nested within its templates"};a.f.Z.template=!0})();a.b("setTemplateEngine",a.Db);a.b("renderTemplate",
a.Ab);a.a.dc=function(a,c,d){if(a.length&&c.length){var e,f,g,k,l;for(e=f=0;(!d||e<d)&&(k=a[f]);++f){for(g=0;l=c[g];++g)if(k.value===l.value){k.moved=l.index;l.moved=k.index;c.splice(g,1);e=g=0;break}e+=g}}};a.a.ib=function(){function b(b,d,e,f,g){var k=Math.min,l=Math.max,m=[],h,n=b.length,q,p=d.length,s=p-n||1,u=n+p+1,t,v,x;for(h=0;h<=n;h++)for(v=t,m.push(t=[]),x=k(p,h+s),q=l(0,h-1);q<=x;q++)t[q]=q?h?b[h-1]===d[q-1]?v[q-1]:k(v[q]||u,t[q-1]||u)+1:q+1:h+1;k=[];l=[];s=[];h=n;for(q=p;h||q;)p=m[h][q]-
1,q&&p===m[h][q-1]?l.push(k[k.length]={status:e,value:d[--q],index:q}):h&&p===m[h-1][q]?s.push(k[k.length]={status:f,value:b[--h],index:h}):(--q,--h,g.sparse||k.push({status:"retained",value:d[q]}));a.a.dc(s,l,!g.dontLimitMoves&&10*n);return k.reverse()}return function(a,d,e){e="boolean"===typeof e?{dontLimitMoves:e}:e||{};a=a||[];d=d||[];return a.length<d.length?b(a,d,"added","deleted",e):b(d,a,"deleted","added",e)}}();a.b("utils.compareArrays",a.a.ib);(function(){function b(b,c,d,k,l){var m=[],
h=a.B(function(){var h=c(d,l,a.a.za(m,b))||[];0<m.length&&(a.a.qc(m,h),k&&a.l.w(k,null,[d,h,l]));m.length=0;a.a.ra(m,h)},null,{i:b,wa:function(){return!a.a.Qb(m)}});return{ca:m,B:h.ba()?h:n}}var c=a.a.e.I(),d=a.a.e.I();a.a.Bb=function(e,f,g,k,l){function m(b,c){w=q[c];v!==c&&(D[b]=w);w.qb(v++);a.a.za(w.ca,e);u.push(w);z.push(w)}function h(b,c){if(b)for(var d=0,e=c.length;d<e;d++)c[d]&&a.a.q(c[d].ca,function(a){b(a,d,c[d].ja)})}f=f||[];k=k||{};var r=a.a.e.get(e,c)===n,q=a.a.e.get(e,c)||[],p=a.a.fb(q,
function(a){return a.ja}),s=a.a.ib(p,f,k.dontLimitMoves),u=[],t=0,v=0,x=[],z=[];f=[];for(var D=[],p=[],w,C=0,B,E;B=s[C];C++)switch(E=B.moved,B.status){case "deleted":E===n&&(w=q[t],w.B&&(w.B.k(),w.B=n),a.a.za(w.ca,e).length&&(k.beforeRemove&&(u.push(w),z.push(w),w.ja===d?w=null:f[C]=w),w&&x.push.apply(x,w.ca)));t++;break;case "retained":m(C,t++);break;case "added":E!==n?m(C,E):(w={ja:B.value,qb:a.N(v++)},u.push(w),z.push(w),r||(p[C]=w))}a.a.e.set(e,c,u);h(k.beforeMove,D);a.a.q(x,k.beforeRemove?a.$:
a.removeNode);for(var C=0,r=a.f.firstChild(e),F;w=z[C];C++){w.ca||a.a.extend(w,b(e,g,w.ja,l,w.qb));for(t=0;s=w.ca[t];r=s.nextSibling,F=s,t++)s!==r&&a.f.gc(e,s,F);!w.Wc&&l&&(l(w.ja,w.ca,w.qb),w.Wc=!0)}h(k.beforeRemove,f);for(C=0;C<f.length;++C)f[C]&&(f[C].ja=d);h(k.afterMove,D);h(k.afterAdd,p)}})();a.b("utils.setDomNodeChildrenFromArrayMapping",a.a.Bb);a.W=function(){this.allowTemplateRewriting=!1};a.W.prototype=new a.O;a.W.prototype.renderTemplateSource=function(b,c,d,e){if(c=(9>a.a.C?0:b.nodes)?
b.nodes():null)return a.a.V(c.cloneNode(!0).childNodes);b=b.text();return a.a.ma(b,e)};a.W.sb=new a.W;a.Db(a.W.sb);a.b("nativeTemplateEngine",a.W);(function(){a.vb=function(){var a=this.$c=function(){if(!v||!v.tmpl)return 0;try{if(0<=v.tmpl.tag.tmpl.open.toString().indexOf("__"))return 2}catch(a){}return 1}();this.renderTemplateSource=function(b,e,f,g){g=g||u;f=f||{};if(2>a)throw Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");var k=b.data("precompiled");
k||(k=b.text()||"",k=v.template(null,"{{ko_with $item.koBindingContext}}"+k+"{{/ko_with}}"),b.data("precompiled",k));b=[e.$data];e=v.extend({koBindingContext:e},f.templateOptions);e=v.tmpl(k,b,e);e.appendTo(g.createElement("div"));v.fragments={};return e};this.createJavaScriptEvaluatorBlock=function(a){return"{{ko_code ((function() { return "+a+" })()) }}"};this.addTemplate=function(a,b){u.write("<script type='text/html' id='"+a+"'>"+b+"\x3c/script>")};0<a&&(v.tmpl.tag.ko_code={open:"__.push($1 || '');"},
v.tmpl.tag.ko_with={open:"with($1) {",close:"} "})};a.vb.prototype=new a.O;var b=new a.vb;0<b.$c&&a.Db(b);a.b("jqueryTmplTemplateEngine",a.vb)})()})})();})();
;
ko.observableArray.fn.pushAll = function(valuesToPush) {
    var underlyingArray = this();
    this.valueWillMutate();
    ko.utils.arrayPushAll(underlyingArray, valuesToPush);
    this.valueHasMutated();
    return this;  //optional
};;
ko.bindingHandlers.dtp = {
    init: function (element, valueAccessor, allBindingsAccessor) {
        //initialise datetimepicker with some optional options
        var options = allBindingsAccessor().dtpOptions || {};
        $(element).datetimepicker(options);

        //when a user changes the date, update the view model
        ko.utils.registerEventHandler(element, "changeDate", function (event) {
            var value = valueAccessor();
            if (ko.isObservable(value)) {
                if (moment(value()).toDate().valueOf() !== moment(event.localDate).toDate().valueOf()) {
                    value(event.localDate);
                    $(event.target).children('input').trigger('change');
                } else {
                    event.stopPropagation();
                }
            }
        });
    },
    update: function (element, valueAccessor) {
        var widget = $(element).data("datetimepicker");
        //when the view model is updated, update the widget
        if (widget) {
            widget.setLocalDate(ko.utils.unwrapObservable(valueAccessor()));
            if (widget.date) {
                widget.setValue();
            }
        }
    }
};

ko.bindingHandlers.tp = {
    init: function (element, valueAccessor, allBindingsAccessor) {
        //initialise datetimepicker with some optional options
        var options = allBindingsAccessor().tpOptions || {};
        $(element).datetimepicker(options);

        //when a user changes the date, update the view model
        ko.utils.registerEventHandler(element, "changeDate", function (event) {
            var value = valueAccessor();
            if (ko.isObservable(value)) {
                value(event.localDate);
            }
        });
    },
    update: function (element, valueAccessor) {
        var widget = $(element).data("datetimepicker");
        //when the view model is updated, update the widget
        if (widget) {
            widget.setLocalDate(ko.utils.unwrapObservable(valueAccessor()));
            if (widget.date) {
                widget.setValue();
            }

            // Set the value of the input to '' if the datetime is utc 1970-01-01 (aka default)
            if (moment(ko.utils.unwrapObservable(valueAccessor())).utc().valueOf() === moment.utc('2000-06-30 14:00').valueOf()) {
                $(element).children('input').val('');
            }
        }
    }
};;
/* Refer: https://craigcav.wordpress.com/2012/05/18/simple-inline-editing-with-knockoutjs/ */

ko.extenders.liveEditor = function (target) {
	target.editing = ko.observable(false);

	target.edit = function () {
		target.editing(true);
	};

	target.stopEditing = function () {
		target.editing(false);
	};

    target.toggleEditing = function() {
        target.editing(!target.editing());
    };

	return target;
};

ko.bindingHandlers.liveEditor = {
	init: function (element, valueAccessor) {
		var observable = valueAccessor();
		observable.extend({ liveEditor: this });
	},
	update: function (element, valueAccessor) {
		var observable = valueAccessor();
		ko.bindingHandlers.css.update(element, function () { return { editing: observable.editing }; });
	}
};;
ko.bindingHandlers.iwf = {
    init: function (element, valueAccessor) {
        var $element = $(element);

        //hook up error handling that will unwrap and set the fallback value
        $element.error(function () {
            var value = ko.utils.unwrapObservable(valueAccessor()),
                fallback = ko.utils.unwrapObservable(value.fallback);

            $element.attr('src', fallback);
        });
    },
    update: function (element, valueAccessor) {
        //grab the value of the parameters, making sure to unwrap anything that could be observable
        var value = ko.utils.unwrapObservable(valueAccessor()),
            src = ko.utils.unwrapObservable(value.src),
            fallback = ko.utils.unwrapObservable(value.fallback),
            $element = $(element);

        //now set the src attribute to either the bound or the fallback value
        if (src) {
            $element.attr('src', src);
        } else {
            $element.attr('src', fallback);
        }
    }
};;
//! moment.js
//! version : 2.17.1
//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
//! license : MIT
//! momentjs.com
!function(a,b){"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):a.moment=b()}(this,function(){"use strict";function a(){return od.apply(null,arguments)}
// This is done to register the method called with moment()
// without creating circular dependencies.
function b(a){od=a}function c(a){return a instanceof Array||"[object Array]"===Object.prototype.toString.call(a)}function d(a){
// IE8 will treat undefined and null as object if it wasn't for
// input != null
return null!=a&&"[object Object]"===Object.prototype.toString.call(a)}function e(a){var b;for(b in a)
// even if its not own property I'd still call it non-empty
return!1;return!0}function f(a){return"number"==typeof a||"[object Number]"===Object.prototype.toString.call(a)}function g(a){return a instanceof Date||"[object Date]"===Object.prototype.toString.call(a)}function h(a,b){var c,d=[];for(c=0;c<a.length;++c)d.push(b(a[c],c));return d}function i(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function j(a,b){for(var c in b)i(b,c)&&(a[c]=b[c]);return i(b,"toString")&&(a.toString=b.toString),i(b,"valueOf")&&(a.valueOf=b.valueOf),a}function k(a,b,c,d){return rb(a,b,c,d,!0).utc()}function l(){
// We need to deep clone this object.
return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1,parsedDateParts:[],meridiem:null}}function m(a){return null==a._pf&&(a._pf=l()),a._pf}function n(a){if(null==a._isValid){var b=m(a),c=qd.call(b.parsedDateParts,function(a){return null!=a}),d=!isNaN(a._d.getTime())&&b.overflow<0&&!b.empty&&!b.invalidMonth&&!b.invalidWeekday&&!b.nullInput&&!b.invalidFormat&&!b.userInvalidated&&(!b.meridiem||b.meridiem&&c);if(a._strict&&(d=d&&0===b.charsLeftOver&&0===b.unusedTokens.length&&void 0===b.bigHour),null!=Object.isFrozen&&Object.isFrozen(a))return d;a._isValid=d}return a._isValid}function o(a){var b=k(NaN);return null!=a?j(m(b),a):m(b).userInvalidated=!0,b}function p(a){return void 0===a}function q(a,b){var c,d,e;if(p(b._isAMomentObject)||(a._isAMomentObject=b._isAMomentObject),p(b._i)||(a._i=b._i),p(b._f)||(a._f=b._f),p(b._l)||(a._l=b._l),p(b._strict)||(a._strict=b._strict),p(b._tzm)||(a._tzm=b._tzm),p(b._isUTC)||(a._isUTC=b._isUTC),p(b._offset)||(a._offset=b._offset),p(b._pf)||(a._pf=m(b)),p(b._locale)||(a._locale=b._locale),rd.length>0)for(c in rd)d=rd[c],e=b[d],p(e)||(a[d]=e);return a}
// Moment prototype object
function r(b){q(this,b),this._d=new Date(null!=b._d?b._d.getTime():NaN),this.isValid()||(this._d=new Date(NaN)),
// Prevent infinite loop in case updateOffset creates new moment
// objects.
sd===!1&&(sd=!0,a.updateOffset(this),sd=!1)}function s(a){return a instanceof r||null!=a&&null!=a._isAMomentObject}function t(a){return a<0?Math.ceil(a)||0:Math.floor(a)}function u(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=t(b)),c}
// compare two arrays, return the number of differences
function v(a,b,c){var d,e=Math.min(a.length,b.length),f=Math.abs(a.length-b.length),g=0;for(d=0;d<e;d++)(c&&a[d]!==b[d]||!c&&u(a[d])!==u(b[d]))&&g++;return g+f}function w(b){a.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+b)}function x(b,c){var d=!0;return j(function(){if(null!=a.deprecationHandler&&a.deprecationHandler(null,b),d){for(var e,f=[],g=0;g<arguments.length;g++){if(e="","object"==typeof arguments[g]){e+="\n["+g+"] ";for(var h in arguments[0])e+=h+": "+arguments[0][h]+", ";e=e.slice(0,-2)}else e=arguments[g];f.push(e)}w(b+"\nArguments: "+Array.prototype.slice.call(f).join("")+"\n"+(new Error).stack),d=!1}return c.apply(this,arguments)},c)}function y(b,c){null!=a.deprecationHandler&&a.deprecationHandler(b,c),td[b]||(w(c),td[b]=!0)}function z(a){return a instanceof Function||"[object Function]"===Object.prototype.toString.call(a)}function A(a){var b,c;for(c in a)b=a[c],z(b)?this[c]=b:this["_"+c]=b;this._config=a,
// Lenient ordinal parsing accepts just a number in addition to
// number + (possibly) stuff coming from _ordinalParseLenient.
this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)}function B(a,b){var c,e=j({},a);for(c in b)i(b,c)&&(d(a[c])&&d(b[c])?(e[c]={},j(e[c],a[c]),j(e[c],b[c])):null!=b[c]?e[c]=b[c]:delete e[c]);for(c in a)i(a,c)&&!i(b,c)&&d(a[c])&&(
// make sure changes to properties don't modify parent config
e[c]=j({},e[c]));return e}function C(a){null!=a&&this.set(a)}function D(a,b,c){var d=this._calendar[a]||this._calendar.sameElse;return z(d)?d.call(b,c):d}function E(a){var b=this._longDateFormat[a],c=this._longDateFormat[a.toUpperCase()];return b||!c?b:(this._longDateFormat[a]=c.replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a])}function F(){return this._invalidDate}function G(a){return this._ordinal.replace("%d",a)}function H(a,b,c,d){var e=this._relativeTime[c];return z(e)?e(a,b,c,d):e.replace(/%d/i,a)}function I(a,b){var c=this._relativeTime[a>0?"future":"past"];return z(c)?c(b):c.replace(/%s/i,b)}function J(a,b){var c=a.toLowerCase();Dd[c]=Dd[c+"s"]=Dd[b]=a}function K(a){return"string"==typeof a?Dd[a]||Dd[a.toLowerCase()]:void 0}function L(a){var b,c,d={};for(c in a)i(a,c)&&(b=K(c),b&&(d[b]=a[c]));return d}function M(a,b){Ed[a]=b}function N(a){var b=[];for(var c in a)b.push({unit:c,priority:Ed[c]});return b.sort(function(a,b){return a.priority-b.priority}),b}function O(b,c){return function(d){return null!=d?(Q(this,b,d),a.updateOffset(this,c),this):P(this,b)}}function P(a,b){return a.isValid()?a._d["get"+(a._isUTC?"UTC":"")+b]():NaN}function Q(a,b,c){a.isValid()&&a._d["set"+(a._isUTC?"UTC":"")+b](c)}
// MOMENTS
function R(a){return a=K(a),z(this[a])?this[a]():this}function S(a,b){if("object"==typeof a){a=L(a);for(var c=N(a),d=0;d<c.length;d++)this[c[d].unit](a[c[d].unit])}else if(a=K(a),z(this[a]))return this[a](b);return this}function T(a,b,c){var d=""+Math.abs(a),e=b-d.length,f=a>=0;return(f?c?"+":"":"-")+Math.pow(10,Math.max(0,e)).toString().substr(1)+d}
// token:    'M'
// padded:   ['MM', 2]
// ordinal:  'Mo'
// callback: function () { this.month() + 1 }
function U(a,b,c,d){var e=d;"string"==typeof d&&(e=function(){return this[d]()}),a&&(Id[a]=e),b&&(Id[b[0]]=function(){return T(e.apply(this,arguments),b[1],b[2])}),c&&(Id[c]=function(){return this.localeData().ordinal(e.apply(this,arguments),a)})}function V(a){return a.match(/\[[\s\S]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function W(a){var b,c,d=a.match(Fd);for(b=0,c=d.length;b<c;b++)Id[d[b]]?d[b]=Id[d[b]]:d[b]=V(d[b]);return function(b){var e,f="";for(e=0;e<c;e++)f+=d[e]instanceof Function?d[e].call(b,a):d[e];return f}}
// format date using native date object
function X(a,b){return a.isValid()?(b=Y(b,a.localeData()),Hd[b]=Hd[b]||W(b),Hd[b](a)):a.localeData().invalidDate()}function Y(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(Gd.lastIndex=0;d>=0&&Gd.test(a);)a=a.replace(Gd,c),Gd.lastIndex=0,d-=1;return a}function Z(a,b,c){$d[a]=z(b)?b:function(a,d){return a&&c?c:b}}function $(a,b){return i($d,a)?$d[a](b._strict,b._locale):new RegExp(_(a))}
// Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
function _(a){return aa(a.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e}))}function aa(a){return a.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function ba(a,b){var c,d=b;for("string"==typeof a&&(a=[a]),f(b)&&(d=function(a,c){c[b]=u(a)}),c=0;c<a.length;c++)_d[a[c]]=d}function ca(a,b){ba(a,function(a,c,d,e){d._w=d._w||{},b(a,d._w,d,e)})}function da(a,b,c){null!=b&&i(_d,a)&&_d[a](b,c._a,c,a)}function ea(a,b){return new Date(Date.UTC(a,b+1,0)).getUTCDate()}function fa(a,b){return a?c(this._months)?this._months[a.month()]:this._months[(this._months.isFormat||ke).test(b)?"format":"standalone"][a.month()]:this._months}function ga(a,b){return a?c(this._monthsShort)?this._monthsShort[a.month()]:this._monthsShort[ke.test(b)?"format":"standalone"][a.month()]:this._monthsShort}function ha(a,b,c){var d,e,f,g=a.toLocaleLowerCase();if(!this._monthsParse)for(
// this is not used
this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[],d=0;d<12;++d)f=k([2e3,d]),this._shortMonthsParse[d]=this.monthsShort(f,"").toLocaleLowerCase(),this._longMonthsParse[d]=this.months(f,"").toLocaleLowerCase();return c?"MMM"===b?(e=je.call(this._shortMonthsParse,g),e!==-1?e:null):(e=je.call(this._longMonthsParse,g),e!==-1?e:null):"MMM"===b?(e=je.call(this._shortMonthsParse,g),e!==-1?e:(e=je.call(this._longMonthsParse,g),e!==-1?e:null)):(e=je.call(this._longMonthsParse,g),e!==-1?e:(e=je.call(this._shortMonthsParse,g),e!==-1?e:null))}function ia(a,b,c){var d,e,f;if(this._monthsParseExact)return ha.call(this,a,b,c);
// TODO: add sorting
// Sorting makes sure if one month (or abbr) is a prefix of another
// see sorting in computeMonthsParse
for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),d=0;d<12;d++){
// test the regex
if(
// make the regex if we don't have it already
e=k([2e3,d]),c&&!this._longMonthsParse[d]&&(this._longMonthsParse[d]=new RegExp("^"+this.months(e,"").replace(".","")+"$","i"),this._shortMonthsParse[d]=new RegExp("^"+this.monthsShort(e,"").replace(".","")+"$","i")),c||this._monthsParse[d]||(f="^"+this.months(e,"")+"|^"+this.monthsShort(e,""),this._monthsParse[d]=new RegExp(f.replace(".",""),"i")),c&&"MMMM"===b&&this._longMonthsParse[d].test(a))return d;if(c&&"MMM"===b&&this._shortMonthsParse[d].test(a))return d;if(!c&&this._monthsParse[d].test(a))return d}}
// MOMENTS
function ja(a,b){var c;if(!a.isValid())
// No op
return a;if("string"==typeof b)if(/^\d+$/.test(b))b=u(b);else
// TODO: Another silent failure?
if(b=a.localeData().monthsParse(b),!f(b))return a;return c=Math.min(a.date(),ea(a.year(),b)),a._d["set"+(a._isUTC?"UTC":"")+"Month"](b,c),a}function ka(b){return null!=b?(ja(this,b),a.updateOffset(this,!0),this):P(this,"Month")}function la(){return ea(this.year(),this.month())}function ma(a){return this._monthsParseExact?(i(this,"_monthsRegex")||oa.call(this),a?this._monthsShortStrictRegex:this._monthsShortRegex):(i(this,"_monthsShortRegex")||(this._monthsShortRegex=ne),this._monthsShortStrictRegex&&a?this._monthsShortStrictRegex:this._monthsShortRegex)}function na(a){return this._monthsParseExact?(i(this,"_monthsRegex")||oa.call(this),a?this._monthsStrictRegex:this._monthsRegex):(i(this,"_monthsRegex")||(this._monthsRegex=oe),this._monthsStrictRegex&&a?this._monthsStrictRegex:this._monthsRegex)}function oa(){function a(a,b){return b.length-a.length}var b,c,d=[],e=[],f=[];for(b=0;b<12;b++)
// make the regex if we don't have it already
c=k([2e3,b]),d.push(this.monthsShort(c,"")),e.push(this.months(c,"")),f.push(this.months(c,"")),f.push(this.monthsShort(c,""));for(
// Sorting makes sure if one month (or abbr) is a prefix of another it
// will match the longer piece.
d.sort(a),e.sort(a),f.sort(a),b=0;b<12;b++)d[b]=aa(d[b]),e[b]=aa(e[b]);for(b=0;b<24;b++)f[b]=aa(f[b]);this._monthsRegex=new RegExp("^("+f.join("|")+")","i"),this._monthsShortRegex=this._monthsRegex,this._monthsStrictRegex=new RegExp("^("+e.join("|")+")","i"),this._monthsShortStrictRegex=new RegExp("^("+d.join("|")+")","i")}
// HELPERS
function pa(a){return qa(a)?366:365}function qa(a){return a%4===0&&a%100!==0||a%400===0}function ra(){return qa(this.year())}function sa(a,b,c,d,e,f,g){
//can't just apply() to create a date:
//http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply
var h=new Date(a,b,c,d,e,f,g);
//the date constructor remaps years 0-99 to 1900-1999
return a<100&&a>=0&&isFinite(h.getFullYear())&&h.setFullYear(a),h}function ta(a){var b=new Date(Date.UTC.apply(null,arguments));
//the Date.UTC function remaps years 0-99 to 1900-1999
return a<100&&a>=0&&isFinite(b.getUTCFullYear())&&b.setUTCFullYear(a),b}
// start-of-first-week - start-of-year
function ua(a,b,c){var// first-week day -- which january is always in the first week (4 for iso, 1 for other)
d=7+b-c,
// first-week day local weekday -- which local weekday is fwd
e=(7+ta(a,0,d).getUTCDay()-b)%7;return-e+d-1}
//http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
function va(a,b,c,d,e){var f,g,h=(7+c-d)%7,i=ua(a,d,e),j=1+7*(b-1)+h+i;return j<=0?(f=a-1,g=pa(f)+j):j>pa(a)?(f=a+1,g=j-pa(a)):(f=a,g=j),{year:f,dayOfYear:g}}function wa(a,b,c){var d,e,f=ua(a.year(),b,c),g=Math.floor((a.dayOfYear()-f-1)/7)+1;return g<1?(e=a.year()-1,d=g+xa(e,b,c)):g>xa(a.year(),b,c)?(d=g-xa(a.year(),b,c),e=a.year()+1):(e=a.year(),d=g),{week:d,year:e}}function xa(a,b,c){var d=ua(a,b,c),e=ua(a+1,b,c);return(pa(a)-d+e)/7}
// HELPERS
// LOCALES
function ya(a){return wa(a,this._week.dow,this._week.doy).week}function za(){return this._week.dow}function Aa(){return this._week.doy}
// MOMENTS
function Ba(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")}function Ca(a){var b=wa(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")}
// HELPERS
function Da(a,b){return"string"!=typeof a?a:isNaN(a)?(a=b.weekdaysParse(a),"number"==typeof a?a:null):parseInt(a,10)}function Ea(a,b){return"string"==typeof a?b.weekdaysParse(a)%7||7:isNaN(a)?null:a}function Fa(a,b){return a?c(this._weekdays)?this._weekdays[a.day()]:this._weekdays[this._weekdays.isFormat.test(b)?"format":"standalone"][a.day()]:this._weekdays}function Ga(a){return a?this._weekdaysShort[a.day()]:this._weekdaysShort}function Ha(a){return a?this._weekdaysMin[a.day()]:this._weekdaysMin}function Ia(a,b,c){var d,e,f,g=a.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],d=0;d<7;++d)f=k([2e3,1]).day(d),this._minWeekdaysParse[d]=this.weekdaysMin(f,"").toLocaleLowerCase(),this._shortWeekdaysParse[d]=this.weekdaysShort(f,"").toLocaleLowerCase(),this._weekdaysParse[d]=this.weekdays(f,"").toLocaleLowerCase();return c?"dddd"===b?(e=je.call(this._weekdaysParse,g),e!==-1?e:null):"ddd"===b?(e=je.call(this._shortWeekdaysParse,g),e!==-1?e:null):(e=je.call(this._minWeekdaysParse,g),e!==-1?e:null):"dddd"===b?(e=je.call(this._weekdaysParse,g),e!==-1?e:(e=je.call(this._shortWeekdaysParse,g),e!==-1?e:(e=je.call(this._minWeekdaysParse,g),e!==-1?e:null))):"ddd"===b?(e=je.call(this._shortWeekdaysParse,g),e!==-1?e:(e=je.call(this._weekdaysParse,g),e!==-1?e:(e=je.call(this._minWeekdaysParse,g),e!==-1?e:null))):(e=je.call(this._minWeekdaysParse,g),e!==-1?e:(e=je.call(this._weekdaysParse,g),e!==-1?e:(e=je.call(this._shortWeekdaysParse,g),e!==-1?e:null)))}function Ja(a,b,c){var d,e,f;if(this._weekdaysParseExact)return Ia.call(this,a,b,c);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),d=0;d<7;d++){
// test the regex
if(
// make the regex if we don't have it already
e=k([2e3,1]).day(d),c&&!this._fullWeekdaysParse[d]&&(this._fullWeekdaysParse[d]=new RegExp("^"+this.weekdays(e,"").replace(".",".?")+"$","i"),this._shortWeekdaysParse[d]=new RegExp("^"+this.weekdaysShort(e,"").replace(".",".?")+"$","i"),this._minWeekdaysParse[d]=new RegExp("^"+this.weekdaysMin(e,"").replace(".",".?")+"$","i")),this._weekdaysParse[d]||(f="^"+this.weekdays(e,"")+"|^"+this.weekdaysShort(e,"")+"|^"+this.weekdaysMin(e,""),this._weekdaysParse[d]=new RegExp(f.replace(".",""),"i")),c&&"dddd"===b&&this._fullWeekdaysParse[d].test(a))return d;if(c&&"ddd"===b&&this._shortWeekdaysParse[d].test(a))return d;if(c&&"dd"===b&&this._minWeekdaysParse[d].test(a))return d;if(!c&&this._weekdaysParse[d].test(a))return d}}
// MOMENTS
function Ka(a){if(!this.isValid())return null!=a?this:NaN;var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=Da(a,this.localeData()),this.add(a-b,"d")):b}function La(a){if(!this.isValid())return null!=a?this:NaN;var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")}function Ma(a){if(!this.isValid())return null!=a?this:NaN;
// behaves the same as moment#day except
// as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
// as a setter, sunday should belong to the previous week.
if(null!=a){var b=Ea(a,this.localeData());return this.day(this.day()%7?b:b-7)}return this.day()||7}function Na(a){return this._weekdaysParseExact?(i(this,"_weekdaysRegex")||Qa.call(this),a?this._weekdaysStrictRegex:this._weekdaysRegex):(i(this,"_weekdaysRegex")||(this._weekdaysRegex=ue),this._weekdaysStrictRegex&&a?this._weekdaysStrictRegex:this._weekdaysRegex)}function Oa(a){return this._weekdaysParseExact?(i(this,"_weekdaysRegex")||Qa.call(this),a?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(i(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=ve),this._weekdaysShortStrictRegex&&a?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)}function Pa(a){return this._weekdaysParseExact?(i(this,"_weekdaysRegex")||Qa.call(this),a?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(i(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=we),this._weekdaysMinStrictRegex&&a?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)}function Qa(){function a(a,b){return b.length-a.length}var b,c,d,e,f,g=[],h=[],i=[],j=[];for(b=0;b<7;b++)
// make the regex if we don't have it already
c=k([2e3,1]).day(b),d=this.weekdaysMin(c,""),e=this.weekdaysShort(c,""),f=this.weekdays(c,""),g.push(d),h.push(e),i.push(f),j.push(d),j.push(e),j.push(f);for(
// Sorting makes sure if one weekday (or abbr) is a prefix of another it
// will match the longer piece.
g.sort(a),h.sort(a),i.sort(a),j.sort(a),b=0;b<7;b++)h[b]=aa(h[b]),i[b]=aa(i[b]),j[b]=aa(j[b]);this._weekdaysRegex=new RegExp("^("+j.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+i.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+h.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+g.join("|")+")","i")}
// FORMATTING
function Ra(){return this.hours()%12||12}function Sa(){return this.hours()||24}function Ta(a,b){U(a,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),b)})}
// PARSING
function Ua(a,b){return b._meridiemParse}
// LOCALES
function Va(a){
// IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
// Using charAt should be more compatible.
return"p"===(a+"").toLowerCase().charAt(0)}function Wa(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"}function Xa(a){return a?a.toLowerCase().replace("_","-"):a}
// pick the locale from the array
// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
function Ya(a){for(var b,c,d,e,f=0;f<a.length;){for(e=Xa(a[f]).split("-"),b=e.length,c=Xa(a[f+1]),c=c?c.split("-"):null;b>0;){if(d=Za(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&v(e,c,!0)>=b-1)
//the next array item is better than a shallower substring of this one
break;b--}f++}return null}function Za(a){var b=null;
// TODO: Find a better way to register and load all the locales in Node
if(!Be[a]&&"undefined"!=typeof module&&module&&module.exports)try{b=xe._abbr,require("./locale/"+a),
// because defineLocale currently also sets the global locale, we
// want to undo that for lazy loaded locales
$a(b)}catch(a){}return Be[a]}
// This function will load locale and then set the global locale.  If
// no arguments are passed in, it will simply return the current global
// locale key.
function $a(a,b){var c;
// moment.duration._locale = moment._locale = data;
return a&&(c=p(b)?bb(a):_a(a,b),c&&(xe=c)),xe._abbr}function _a(a,b){if(null!==b){var c=Ae;if(b.abbr=a,null!=Be[a])y("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),c=Be[a]._config;else if(null!=b.parentLocale){if(null==Be[b.parentLocale])return Ce[b.parentLocale]||(Ce[b.parentLocale]=[]),Ce[b.parentLocale].push({name:a,config:b}),null;c=Be[b.parentLocale]._config}
// backwards compat for now: also set the locale
// make sure we set the locale AFTER all child locales have been
// created, so we won't end up with the child locale set.
return Be[a]=new C(B(c,b)),Ce[a]&&Ce[a].forEach(function(a){_a(a.name,a.config)}),$a(a),Be[a]}
// useful for testing
return delete Be[a],null}function ab(a,b){if(null!=b){var c,d=Ae;
// MERGE
null!=Be[a]&&(d=Be[a]._config),b=B(d,b),c=new C(b),c.parentLocale=Be[a],Be[a]=c,
// backwards compat for now: also set the locale
$a(a)}else
// pass null for config to unupdate, useful for tests
null!=Be[a]&&(null!=Be[a].parentLocale?Be[a]=Be[a].parentLocale:null!=Be[a]&&delete Be[a]);return Be[a]}
// returns locale data
function bb(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return xe;if(!c(a)){if(
//short-circuit everything else
b=Za(a))return b;a=[a]}return Ya(a)}function cb(){return wd(Be)}function db(a){var b,c=a._a;return c&&m(a).overflow===-2&&(b=c[be]<0||c[be]>11?be:c[ce]<1||c[ce]>ea(c[ae],c[be])?ce:c[de]<0||c[de]>24||24===c[de]&&(0!==c[ee]||0!==c[fe]||0!==c[ge])?de:c[ee]<0||c[ee]>59?ee:c[fe]<0||c[fe]>59?fe:c[ge]<0||c[ge]>999?ge:-1,m(a)._overflowDayOfYear&&(b<ae||b>ce)&&(b=ce),m(a)._overflowWeeks&&b===-1&&(b=he),m(a)._overflowWeekday&&b===-1&&(b=ie),m(a).overflow=b),a}
// date from iso format
function eb(a){var b,c,d,e,f,g,h=a._i,i=De.exec(h)||Ee.exec(h);if(i){for(m(a).iso=!0,b=0,c=Ge.length;b<c;b++)if(Ge[b][1].exec(i[1])){e=Ge[b][0],d=Ge[b][2]!==!1;break}if(null==e)return void(a._isValid=!1);if(i[3]){for(b=0,c=He.length;b<c;b++)if(He[b][1].exec(i[3])){
// match[2] should be 'T' or space
f=(i[2]||" ")+He[b][0];break}if(null==f)return void(a._isValid=!1)}if(!d&&null!=f)return void(a._isValid=!1);if(i[4]){if(!Fe.exec(i[4]))return void(a._isValid=!1);g="Z"}a._f=e+(f||"")+(g||""),kb(a)}else a._isValid=!1}
// date from iso format or fallback
function fb(b){var c=Ie.exec(b._i);return null!==c?void(b._d=new Date(+c[1])):(eb(b),void(b._isValid===!1&&(delete b._isValid,a.createFromInputFallback(b))))}
// Pick the first defined of two or three arguments.
function gb(a,b,c){return null!=a?a:null!=b?b:c}function hb(b){
// hooks is actually the exported moment object
var c=new Date(a.now());return b._useUTC?[c.getUTCFullYear(),c.getUTCMonth(),c.getUTCDate()]:[c.getFullYear(),c.getMonth(),c.getDate()]}
// convert an array to a date.
// the array should mirror the parameters below
// note: all values past the year are optional and will default to the lowest possible value.
// [year, month, day , hour, minute, second, millisecond]
function ib(a){var b,c,d,e,f=[];if(!a._d){
// Default to current date.
// * if no year, month, day of month are given, default to today
// * if day of month is given, default month and year
// * if month is given, default only year
// * if year is given, don't default anything
for(d=hb(a),
//compute day of the year from weeks and weekdays
a._w&&null==a._a[ce]&&null==a._a[be]&&jb(a),
//if the day of the year is set, figure out what it is
a._dayOfYear&&(e=gb(a._a[ae],d[ae]),a._dayOfYear>pa(e)&&(m(a)._overflowDayOfYear=!0),c=ta(e,0,a._dayOfYear),a._a[be]=c.getUTCMonth(),a._a[ce]=c.getUTCDate()),b=0;b<3&&null==a._a[b];++b)a._a[b]=f[b]=d[b];
// Zero out whatever was not defaulted, including time
for(;b<7;b++)a._a[b]=f[b]=null==a._a[b]?2===b?1:0:a._a[b];
// Check for 24:00:00.000
24===a._a[de]&&0===a._a[ee]&&0===a._a[fe]&&0===a._a[ge]&&(a._nextDay=!0,a._a[de]=0),a._d=(a._useUTC?ta:sa).apply(null,f),
// Apply timezone offset from input. The actual utcOffset can be changed
// with parseZone.
null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[de]=24)}}function jb(a){var b,c,d,e,f,g,h,i;if(b=a._w,null!=b.GG||null!=b.W||null!=b.E)f=1,g=4,
// TODO: We need to take the current isoWeekYear, but that depends on
// how we interpret now (local, utc, fixed offset). So create
// a now version of current config (take local/utc/offset flags, and
// create now).
c=gb(b.GG,a._a[ae],wa(sb(),1,4).year),d=gb(b.W,1),e=gb(b.E,1),(e<1||e>7)&&(i=!0);else{f=a._locale._week.dow,g=a._locale._week.doy;var j=wa(sb(),f,g);c=gb(b.gg,a._a[ae],j.year),
// Default to current week.
d=gb(b.w,j.week),null!=b.d?(
// weekday -- low day numbers are considered next week
e=b.d,(e<0||e>6)&&(i=!0)):null!=b.e?(
// local weekday -- counting starts from begining of week
e=b.e+f,(b.e<0||b.e>6)&&(i=!0)):
// default to begining of week
e=f}d<1||d>xa(c,f,g)?m(a)._overflowWeeks=!0:null!=i?m(a)._overflowWeekday=!0:(h=va(c,d,e,f,g),a._a[ae]=h.year,a._dayOfYear=h.dayOfYear)}
// date from string and format string
function kb(b){
// TODO: Move this to another part of the creation flow to prevent circular deps
if(b._f===a.ISO_8601)return void eb(b);b._a=[],m(b).empty=!0;
// This array is used to make a Date, either with `new Date` or `Date.UTC`
var c,d,e,f,g,h=""+b._i,i=h.length,j=0;for(e=Y(b._f,b._locale).match(Fd)||[],c=0;c<e.length;c++)f=e[c],d=(h.match($(f,b))||[])[0],
// console.log('token', token, 'parsedInput', parsedInput,
//         'regex', getParseRegexForToken(token, config));
d&&(g=h.substr(0,h.indexOf(d)),g.length>0&&m(b).unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),j+=d.length),
// don't parse if it's not a known token
Id[f]?(d?m(b).empty=!1:m(b).unusedTokens.push(f),da(f,d,b)):b._strict&&!d&&m(b).unusedTokens.push(f);
// add remaining unparsed input length to the string
m(b).charsLeftOver=i-j,h.length>0&&m(b).unusedInput.push(h),
// clear _12h flag if hour is <= 12
b._a[de]<=12&&m(b).bigHour===!0&&b._a[de]>0&&(m(b).bigHour=void 0),m(b).parsedDateParts=b._a.slice(0),m(b).meridiem=b._meridiem,
// handle meridiem
b._a[de]=lb(b._locale,b._a[de],b._meridiem),ib(b),db(b)}function lb(a,b,c){var d;
// Fallback
return null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&b<12&&(b+=12),d||12!==b||(b=0),b):b}
// date from string and array of format strings
function mb(a){var b,c,d,e,f;if(0===a._f.length)return m(a).invalidFormat=!0,void(a._d=new Date(NaN));for(e=0;e<a._f.length;e++)f=0,b=q({},a),null!=a._useUTC&&(b._useUTC=a._useUTC),b._f=a._f[e],kb(b),n(b)&&(
// if there is any input that was not parsed add a penalty for that format
f+=m(b).charsLeftOver,
//or tokens
f+=10*m(b).unusedTokens.length,m(b).score=f,(null==d||f<d)&&(d=f,c=b));j(a,c||b)}function nb(a){if(!a._d){var b=L(a._i);a._a=h([b.year,b.month,b.day||b.date,b.hour,b.minute,b.second,b.millisecond],function(a){return a&&parseInt(a,10)}),ib(a)}}function ob(a){var b=new r(db(pb(a)));
// Adding is smart enough around DST
return b._nextDay&&(b.add(1,"d"),b._nextDay=void 0),b}function pb(a){var b=a._i,d=a._f;return a._locale=a._locale||bb(a._l),null===b||void 0===d&&""===b?o({nullInput:!0}):("string"==typeof b&&(a._i=b=a._locale.preparse(b)),s(b)?new r(db(b)):(g(b)?a._d=b:c(d)?mb(a):d?kb(a):qb(a),n(a)||(a._d=null),a))}function qb(b){var d=b._i;void 0===d?b._d=new Date(a.now()):g(d)?b._d=new Date(d.valueOf()):"string"==typeof d?fb(b):c(d)?(b._a=h(d.slice(0),function(a){return parseInt(a,10)}),ib(b)):"object"==typeof d?nb(b):f(d)?
// from milliseconds
b._d=new Date(d):a.createFromInputFallback(b)}function rb(a,b,f,g,h){var i={};
// object construction must be done this way.
// https://github.com/moment/moment/issues/1423
return f!==!0&&f!==!1||(g=f,f=void 0),(d(a)&&e(a)||c(a)&&0===a.length)&&(a=void 0),i._isAMomentObject=!0,i._useUTC=i._isUTC=h,i._l=f,i._i=a,i._f=b,i._strict=g,ob(i)}function sb(a,b,c,d){return rb(a,b,c,d,!1)}
// Pick a moment m from moments so that m[fn](other) is true for all
// other. This relies on the function fn to be transitive.
//
// moments should either be an array of moment objects or an array, whose
// first element is an array of moment objects.
function tb(a,b){var d,e;if(1===b.length&&c(b[0])&&(b=b[0]),!b.length)return sb();for(d=b[0],e=1;e<b.length;++e)b[e].isValid()&&!b[e][a](d)||(d=b[e]);return d}
// TODO: Use [].sort instead?
function ub(){var a=[].slice.call(arguments,0);return tb("isBefore",a)}function vb(){var a=[].slice.call(arguments,0);return tb("isAfter",a)}function wb(a){var b=L(a),c=b.year||0,d=b.quarter||0,e=b.month||0,f=b.week||0,g=b.day||0,h=b.hour||0,i=b.minute||0,j=b.second||0,k=b.millisecond||0;
// representation for dateAddRemove
this._milliseconds=+k+1e3*j+// 1000
6e4*i+// 1000 * 60
1e3*h*60*60,//using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
// Because of dateAddRemove treats 24 hours as different from a
// day when working around DST, we need to store them separately
this._days=+g+7*f,
// It is impossible translate months into days without knowing
// which months you are are talking about, so we have to store
// it separately.
this._months=+e+3*d+12*c,this._data={},this._locale=bb(),this._bubble()}function xb(a){return a instanceof wb}function yb(a){return a<0?Math.round(-1*a)*-1:Math.round(a)}
// FORMATTING
function zb(a,b){U(a,0,0,function(){var a=this.utcOffset(),c="+";return a<0&&(a=-a,c="-"),c+T(~~(a/60),2)+b+T(~~a%60,2)})}function Ab(a,b){var c=(b||"").match(a);if(null===c)return null;var d=c[c.length-1]||[],e=(d+"").match(Me)||["-",0,0],f=+(60*e[1])+u(e[2]);return 0===f?0:"+"===e[0]?f:-f}
// Return a moment from input, that is local/utc/zone equivalent to model.
function Bb(b,c){var d,e;
// Use low-level api, because this fn is low-level api.
return c._isUTC?(d=c.clone(),e=(s(b)||g(b)?b.valueOf():sb(b).valueOf())-d.valueOf(),d._d.setTime(d._d.valueOf()+e),a.updateOffset(d,!1),d):sb(b).local()}function Cb(a){
// On Firefox.24 Date#getTimezoneOffset returns a floating point.
// https://github.com/moment/moment/pull/1871
return 15*-Math.round(a._d.getTimezoneOffset()/15)}
// MOMENTS
// keepLocalTime = true means only change the timezone, without
// affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
// 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
// +0200, so we adjust the time as needed, to be valid.
//
// Keeping the time actually adds/subtracts (one hour)
// from the actual represented time. That is why we call updateOffset
// a second time. In case it wants us to change the offset again
// _changeInProgress == true case, then we have to adjust, because
// there is no such time in the given timezone.
function Db(b,c){var d,e=this._offset||0;if(!this.isValid())return null!=b?this:NaN;if(null!=b){if("string"==typeof b){if(b=Ab(Xd,b),null===b)return this}else Math.abs(b)<16&&(b=60*b);return!this._isUTC&&c&&(d=Cb(this)),this._offset=b,this._isUTC=!0,null!=d&&this.add(d,"m"),e!==b&&(!c||this._changeInProgress?Tb(this,Ob(b-e,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,a.updateOffset(this,!0),this._changeInProgress=null)),this}return this._isUTC?e:Cb(this)}function Eb(a,b){return null!=a?("string"!=typeof a&&(a=-a),this.utcOffset(a,b),this):-this.utcOffset()}function Fb(a){return this.utcOffset(0,a)}function Gb(a){return this._isUTC&&(this.utcOffset(0,a),this._isUTC=!1,a&&this.subtract(Cb(this),"m")),this}function Hb(){if(null!=this._tzm)this.utcOffset(this._tzm);else if("string"==typeof this._i){var a=Ab(Wd,this._i);null!=a?this.utcOffset(a):this.utcOffset(0,!0)}return this}function Ib(a){return!!this.isValid()&&(a=a?sb(a).utcOffset():0,(this.utcOffset()-a)%60===0)}function Jb(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Kb(){if(!p(this._isDSTShifted))return this._isDSTShifted;var a={};if(q(a,this),a=pb(a),a._a){var b=a._isUTC?k(a._a):sb(a._a);this._isDSTShifted=this.isValid()&&v(a._a,b.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function Lb(){return!!this.isValid()&&!this._isUTC}function Mb(){return!!this.isValid()&&this._isUTC}function Nb(){return!!this.isValid()&&(this._isUTC&&0===this._offset)}function Ob(a,b){var c,d,e,g=a,
// matching against regexp is expensive, do it on demand
h=null;// checks for null or undefined
return xb(a)?g={ms:a._milliseconds,d:a._days,M:a._months}:f(a)?(g={},b?g[b]=a:g.milliseconds=a):(h=Ne.exec(a))?(c="-"===h[1]?-1:1,g={y:0,d:u(h[ce])*c,h:u(h[de])*c,m:u(h[ee])*c,s:u(h[fe])*c,ms:u(yb(1e3*h[ge]))*c}):(h=Oe.exec(a))?(c="-"===h[1]?-1:1,g={y:Pb(h[2],c),M:Pb(h[3],c),w:Pb(h[4],c),d:Pb(h[5],c),h:Pb(h[6],c),m:Pb(h[7],c),s:Pb(h[8],c)}):null==g?g={}:"object"==typeof g&&("from"in g||"to"in g)&&(e=Rb(sb(g.from),sb(g.to)),g={},g.ms=e.milliseconds,g.M=e.months),d=new wb(g),xb(a)&&i(a,"_locale")&&(d._locale=a._locale),d}function Pb(a,b){
// We'd normally use ~~inp for this, but unfortunately it also
// converts floats to ints.
// inp may be undefined, so careful calling replace on it.
var c=a&&parseFloat(a.replace(",","."));
// apply sign while we're at it
return(isNaN(c)?0:c)*b}function Qb(a,b){var c={milliseconds:0,months:0};return c.months=b.month()-a.month()+12*(b.year()-a.year()),a.clone().add(c.months,"M").isAfter(b)&&--c.months,c.milliseconds=+b-+a.clone().add(c.months,"M"),c}function Rb(a,b){var c;return a.isValid()&&b.isValid()?(b=Bb(b,a),a.isBefore(b)?c=Qb(a,b):(c=Qb(b,a),c.milliseconds=-c.milliseconds,c.months=-c.months),c):{milliseconds:0,months:0}}
// TODO: remove 'name' arg after deprecation is removed
function Sb(a,b){return function(c,d){var e,f;
//invert the arguments, but complain about it
return null===d||isNaN(+d)||(y(b,"moment()."+b+"(period, number) is deprecated. Please use moment()."+b+"(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info."),f=c,c=d,d=f),c="string"==typeof c?+c:c,e=Ob(c,d),Tb(this,e,a),this}}function Tb(b,c,d,e){var f=c._milliseconds,g=yb(c._days),h=yb(c._months);b.isValid()&&(e=null==e||e,f&&b._d.setTime(b._d.valueOf()+f*d),g&&Q(b,"Date",P(b,"Date")+g*d),h&&ja(b,P(b,"Month")+h*d),e&&a.updateOffset(b,g||h))}function Ub(a,b){var c=a.diff(b,"days",!0);return c<-6?"sameElse":c<-1?"lastWeek":c<0?"lastDay":c<1?"sameDay":c<2?"nextDay":c<7?"nextWeek":"sameElse"}function Vb(b,c){
// We want to compare the start of today, vs this.
// Getting start-of-today depends on whether we're local/utc/offset or not.
var d=b||sb(),e=Bb(d,this).startOf("day"),f=a.calendarFormat(this,e)||"sameElse",g=c&&(z(c[f])?c[f].call(this,d):c[f]);return this.format(g||this.localeData().calendar(f,this,sb(d)))}function Wb(){return new r(this)}function Xb(a,b){var c=s(a)?a:sb(a);return!(!this.isValid()||!c.isValid())&&(b=K(p(b)?"millisecond":b),"millisecond"===b?this.valueOf()>c.valueOf():c.valueOf()<this.clone().startOf(b).valueOf())}function Yb(a,b){var c=s(a)?a:sb(a);return!(!this.isValid()||!c.isValid())&&(b=K(p(b)?"millisecond":b),"millisecond"===b?this.valueOf()<c.valueOf():this.clone().endOf(b).valueOf()<c.valueOf())}function Zb(a,b,c,d){return d=d||"()",("("===d[0]?this.isAfter(a,c):!this.isBefore(a,c))&&(")"===d[1]?this.isBefore(b,c):!this.isAfter(b,c))}function $b(a,b){var c,d=s(a)?a:sb(a);return!(!this.isValid()||!d.isValid())&&(b=K(b||"millisecond"),"millisecond"===b?this.valueOf()===d.valueOf():(c=d.valueOf(),this.clone().startOf(b).valueOf()<=c&&c<=this.clone().endOf(b).valueOf()))}function _b(a,b){return this.isSame(a,b)||this.isAfter(a,b)}function ac(a,b){return this.isSame(a,b)||this.isBefore(a,b)}function bc(a,b,c){var d,e,f,g;// 1000
// 1000 * 60
// 1000 * 60 * 60
// 1000 * 60 * 60 * 24, negate dst
// 1000 * 60 * 60 * 24 * 7, negate dst
return this.isValid()?(d=Bb(a,this),d.isValid()?(e=6e4*(d.utcOffset()-this.utcOffset()),b=K(b),"year"===b||"month"===b||"quarter"===b?(g=cc(this,d),"quarter"===b?g/=3:"year"===b&&(g/=12)):(f=this-d,g="second"===b?f/1e3:"minute"===b?f/6e4:"hour"===b?f/36e5:"day"===b?(f-e)/864e5:"week"===b?(f-e)/6048e5:f),c?g:t(g)):NaN):NaN}function cc(a,b){
// difference in months
var c,d,e=12*(b.year()-a.year())+(b.month()-a.month()),
// b is in (anchor - 1 month, anchor + 1 month)
f=a.clone().add(e,"months");
//check for negative zero, return zero if negative zero
// linear across the month
// linear across the month
return b-f<0?(c=a.clone().add(e-1,"months"),d=(b-f)/(f-c)):(c=a.clone().add(e+1,"months"),d=(b-f)/(c-f)),-(e+d)||0}function dc(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")}function ec(){var a=this.clone().utc();return 0<a.year()&&a.year()<=9999?z(Date.prototype.toISOString)?this.toDate().toISOString():X(a,"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]"):X(a,"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]")}/**
 * Return a human readable representation of a moment that can
 * also be evaluated to get a new moment which is the same
 *
 * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
 */
function fc(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var a="moment",b="";this.isLocal()||(a=0===this.utcOffset()?"moment.utc":"moment.parseZone",b="Z");var c="["+a+'("]',d=0<this.year()&&this.year()<=9999?"YYYY":"YYYYYY",e="-MM-DD[T]HH:mm:ss.SSS",f=b+'[")]';return this.format(c+d+e+f)}function gc(b){b||(b=this.isUtc()?a.defaultFormatUtc:a.defaultFormat);var c=X(this,b);return this.localeData().postformat(c)}function hc(a,b){return this.isValid()&&(s(a)&&a.isValid()||sb(a).isValid())?Ob({to:this,from:a}).locale(this.locale()).humanize(!b):this.localeData().invalidDate()}function ic(a){return this.from(sb(),a)}function jc(a,b){return this.isValid()&&(s(a)&&a.isValid()||sb(a).isValid())?Ob({from:this,to:a}).locale(this.locale()).humanize(!b):this.localeData().invalidDate()}function kc(a){return this.to(sb(),a)}
// If passed a locale key, it will set the locale for this
// instance.  Otherwise, it will return the locale configuration
// variables for this instance.
function lc(a){var b;return void 0===a?this._locale._abbr:(b=bb(a),null!=b&&(this._locale=b),this)}function mc(){return this._locale}function nc(a){
// the following switch intentionally omits break keywords
// to utilize falling through the cases.
switch(a=K(a)){case"year":this.month(0);/* falls through */
case"quarter":case"month":this.date(1);/* falls through */
case"week":case"isoWeek":case"day":case"date":this.hours(0);/* falls through */
case"hour":this.minutes(0);/* falls through */
case"minute":this.seconds(0);/* falls through */
case"second":this.milliseconds(0)}
// weeks are a special case
// quarters are also special
return"week"===a&&this.weekday(0),"isoWeek"===a&&this.isoWeekday(1),"quarter"===a&&this.month(3*Math.floor(this.month()/3)),this}function oc(a){
// 'date' is an alias for 'day', so it should be considered as such.
return a=K(a),void 0===a||"millisecond"===a?this:("date"===a&&(a="day"),this.startOf(a).add(1,"isoWeek"===a?"week":a).subtract(1,"ms"))}function pc(){return this._d.valueOf()-6e4*(this._offset||0)}function qc(){return Math.floor(this.valueOf()/1e3)}function rc(){return new Date(this.valueOf())}function sc(){var a=this;return[a.year(),a.month(),a.date(),a.hour(),a.minute(),a.second(),a.millisecond()]}function tc(){var a=this;return{years:a.year(),months:a.month(),date:a.date(),hours:a.hours(),minutes:a.minutes(),seconds:a.seconds(),milliseconds:a.milliseconds()}}function uc(){
// new Date(NaN).toJSON() === null
return this.isValid()?this.toISOString():null}function vc(){return n(this)}function wc(){return j({},m(this))}function xc(){return m(this).overflow}function yc(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}}function zc(a,b){U(0,[a,a.length],0,b)}
// MOMENTS
function Ac(a){return Ec.call(this,a,this.week(),this.weekday(),this.localeData()._week.dow,this.localeData()._week.doy)}function Bc(a){return Ec.call(this,a,this.isoWeek(),this.isoWeekday(),1,4)}function Cc(){return xa(this.year(),1,4)}function Dc(){var a=this.localeData()._week;return xa(this.year(),a.dow,a.doy)}function Ec(a,b,c,d,e){var f;return null==a?wa(this,d,e).year:(f=xa(a,d,e),b>f&&(b=f),Fc.call(this,a,b,c,d,e))}function Fc(a,b,c,d,e){var f=va(a,b,c,d,e),g=ta(f.year,0,f.dayOfYear);return this.year(g.getUTCFullYear()),this.month(g.getUTCMonth()),this.date(g.getUTCDate()),this}
// MOMENTS
function Gc(a){return null==a?Math.ceil((this.month()+1)/3):this.month(3*(a-1)+this.month()%3)}
// HELPERS
// MOMENTS
function Hc(a){var b=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")}function Ic(a,b){b[ge]=u(1e3*("0."+a))}
// MOMENTS
function Jc(){return this._isUTC?"UTC":""}function Kc(){return this._isUTC?"Coordinated Universal Time":""}function Lc(a){return sb(1e3*a)}function Mc(){return sb.apply(null,arguments).parseZone()}function Nc(a){return a}function Oc(a,b,c,d){var e=bb(),f=k().set(d,b);return e[c](f,a)}function Pc(a,b,c){if(f(a)&&(b=a,a=void 0),a=a||"",null!=b)return Oc(a,b,c,"month");var d,e=[];for(d=0;d<12;d++)e[d]=Oc(a,d,c,"month");return e}
// ()
// (5)
// (fmt, 5)
// (fmt)
// (true)
// (true, 5)
// (true, fmt, 5)
// (true, fmt)
function Qc(a,b,c,d){"boolean"==typeof a?(f(b)&&(c=b,b=void 0),b=b||""):(b=a,c=b,a=!1,f(b)&&(c=b,b=void 0),b=b||"");var e=bb(),g=a?e._week.dow:0;if(null!=c)return Oc(b,(c+g)%7,d,"day");var h,i=[];for(h=0;h<7;h++)i[h]=Oc(b,(h+g)%7,d,"day");return i}function Rc(a,b){return Pc(a,b,"months")}function Sc(a,b){return Pc(a,b,"monthsShort")}function Tc(a,b,c){return Qc(a,b,c,"weekdays")}function Uc(a,b,c){return Qc(a,b,c,"weekdaysShort")}function Vc(a,b,c){return Qc(a,b,c,"weekdaysMin")}function Wc(){var a=this._data;return this._milliseconds=Ze(this._milliseconds),this._days=Ze(this._days),this._months=Ze(this._months),a.milliseconds=Ze(a.milliseconds),a.seconds=Ze(a.seconds),a.minutes=Ze(a.minutes),a.hours=Ze(a.hours),a.months=Ze(a.months),a.years=Ze(a.years),this}function Xc(a,b,c,d){var e=Ob(b,c);return a._milliseconds+=d*e._milliseconds,a._days+=d*e._days,a._months+=d*e._months,a._bubble()}
// supports only 2.0-style add(1, 's') or add(duration)
function Yc(a,b){return Xc(this,a,b,1)}
// supports only 2.0-style subtract(1, 's') or subtract(duration)
function Zc(a,b){return Xc(this,a,b,-1)}function $c(a){return a<0?Math.floor(a):Math.ceil(a)}function _c(){var a,b,c,d,e,f=this._milliseconds,g=this._days,h=this._months,i=this._data;
// if we have a mix of positive and negative values, bubble down first
// check: https://github.com/moment/moment/issues/2166
// The following code bubbles up values, see the tests for
// examples of what that means.
// convert days to months
// 12 months -> 1 year
return f>=0&&g>=0&&h>=0||f<=0&&g<=0&&h<=0||(f+=864e5*$c(bd(h)+g),g=0,h=0),i.milliseconds=f%1e3,a=t(f/1e3),i.seconds=a%60,b=t(a/60),i.minutes=b%60,c=t(b/60),i.hours=c%24,g+=t(c/24),e=t(ad(g)),h+=e,g-=$c(bd(e)),d=t(h/12),h%=12,i.days=g,i.months=h,i.years=d,this}function ad(a){
// 400 years have 146097 days (taking into account leap year rules)
// 400 years have 12 months === 4800
return 4800*a/146097}function bd(a){
// the reverse of daysToMonths
return 146097*a/4800}function cd(a){var b,c,d=this._milliseconds;if(a=K(a),"month"===a||"year"===a)return b=this._days+d/864e5,c=this._months+ad(b),"month"===a?c:c/12;switch(
// handle milliseconds separately because of floating point math errors (issue #1867)
b=this._days+Math.round(bd(this._months)),a){case"week":return b/7+d/6048e5;case"day":return b+d/864e5;case"hour":return 24*b+d/36e5;case"minute":return 1440*b+d/6e4;case"second":return 86400*b+d/1e3;
// Math.floor prevents floating point math errors here
case"millisecond":return Math.floor(864e5*b)+d;default:throw new Error("Unknown unit "+a)}}
// TODO: Use this.as('ms')?
function dd(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*u(this._months/12)}function ed(a){return function(){return this.as(a)}}function fd(a){return a=K(a),this[a+"s"]()}function gd(a){return function(){return this._data[a]}}function hd(){return t(this.days()/7)}
// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
function id(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function jd(a,b,c){var d=Ob(a).abs(),e=of(d.as("s")),f=of(d.as("m")),g=of(d.as("h")),h=of(d.as("d")),i=of(d.as("M")),j=of(d.as("y")),k=e<pf.s&&["s",e]||f<=1&&["m"]||f<pf.m&&["mm",f]||g<=1&&["h"]||g<pf.h&&["hh",g]||h<=1&&["d"]||h<pf.d&&["dd",h]||i<=1&&["M"]||i<pf.M&&["MM",i]||j<=1&&["y"]||["yy",j];return k[2]=b,k[3]=+a>0,k[4]=c,id.apply(null,k)}
// This function allows you to set the rounding function for relative time strings
function kd(a){return void 0===a?of:"function"==typeof a&&(of=a,!0)}
// This function allows you to set a threshold for relative time strings
function ld(a,b){return void 0!==pf[a]&&(void 0===b?pf[a]:(pf[a]=b,!0))}function md(a){var b=this.localeData(),c=jd(this,!a,b);return a&&(c=b.pastFuture(+this,c)),b.postformat(c)}function nd(){
// for ISO strings we do not use the normal bubbling rules:
//  * milliseconds bubble up until they become hours
//  * days do not bubble at all
//  * months bubble up until they become years
// This is because there is no context-free conversion between hours and days
// (think of clock changes)
// and also not between days and months (28-31 days per month)
var a,b,c,d=qf(this._milliseconds)/1e3,e=qf(this._days),f=qf(this._months);
// 3600 seconds -> 60 minutes -> 1 hour
a=t(d/60),b=t(a/60),d%=60,a%=60,
// 12 months -> 1 year
c=t(f/12),f%=12;
// inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
var g=c,h=f,i=e,j=b,k=a,l=d,m=this.asSeconds();return m?(m<0?"-":"")+"P"+(g?g+"Y":"")+(h?h+"M":"")+(i?i+"D":"")+(j||k||l?"T":"")+(j?j+"H":"")+(k?k+"M":"")+(l?l+"S":""):"P0D"}var od,pd;pd=Array.prototype.some?Array.prototype.some:function(a){for(var b=Object(this),c=b.length>>>0,d=0;d<c;d++)if(d in b&&a.call(this,b[d],d,b))return!0;return!1};var qd=pd,rd=a.momentProperties=[],sd=!1,td={};a.suppressDeprecationWarnings=!1,a.deprecationHandler=null;var ud;ud=Object.keys?Object.keys:function(a){var b,c=[];for(b in a)i(a,b)&&c.push(b);return c};var vd,wd=ud,xd={sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},yd={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},zd="Invalid date",Ad="%d",Bd=/\d{1,2}/,Cd={future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},Dd={},Ed={},Fd=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,Gd=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Hd={},Id={},Jd=/\d/,Kd=/\d\d/,Ld=/\d{3}/,Md=/\d{4}/,Nd=/[+-]?\d{6}/,Od=/\d\d?/,Pd=/\d\d\d\d?/,Qd=/\d\d\d\d\d\d?/,Rd=/\d{1,3}/,Sd=/\d{1,4}/,Td=/[+-]?\d{1,6}/,Ud=/\d+/,Vd=/[+-]?\d+/,Wd=/Z|[+-]\d\d:?\d\d/gi,Xd=/Z|[+-]\d\d(?::?\d\d)?/gi,Yd=/[+-]?\d+(\.\d{1,3})?/,Zd=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,$d={},_d={},ae=0,be=1,ce=2,de=3,ee=4,fe=5,ge=6,he=7,ie=8;vd=Array.prototype.indexOf?Array.prototype.indexOf:function(a){
// I know
var b;for(b=0;b<this.length;++b)if(this[b]===a)return b;return-1};var je=vd;
// FORMATTING
U("M",["MM",2],"Mo",function(){return this.month()+1}),U("MMM",0,0,function(a){return this.localeData().monthsShort(this,a)}),U("MMMM",0,0,function(a){return this.localeData().months(this,a)}),
// ALIASES
J("month","M"),
// PRIORITY
M("month",8),
// PARSING
Z("M",Od),Z("MM",Od,Kd),Z("MMM",function(a,b){return b.monthsShortRegex(a)}),Z("MMMM",function(a,b){return b.monthsRegex(a)}),ba(["M","MM"],function(a,b){b[be]=u(a)-1}),ba(["MMM","MMMM"],function(a,b,c,d){var e=c._locale.monthsParse(a,d,c._strict);
// if we didn't find a month name, mark the date as invalid.
null!=e?b[be]=e:m(c).invalidMonth=a});
// LOCALES
var ke=/D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/,le="January_February_March_April_May_June_July_August_September_October_November_December".split("_"),me="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),ne=Zd,oe=Zd;
// FORMATTING
U("Y",0,0,function(){var a=this.year();return a<=9999?""+a:"+"+a}),U(0,["YY",2],0,function(){return this.year()%100}),U(0,["YYYY",4],0,"year"),U(0,["YYYYY",5],0,"year"),U(0,["YYYYYY",6,!0],0,"year"),
// ALIASES
J("year","y"),
// PRIORITIES
M("year",1),
// PARSING
Z("Y",Vd),Z("YY",Od,Kd),Z("YYYY",Sd,Md),Z("YYYYY",Td,Nd),Z("YYYYYY",Td,Nd),ba(["YYYYY","YYYYYY"],ae),ba("YYYY",function(b,c){c[ae]=2===b.length?a.parseTwoDigitYear(b):u(b)}),ba("YY",function(b,c){c[ae]=a.parseTwoDigitYear(b)}),ba("Y",function(a,b){b[ae]=parseInt(a,10)}),
// HOOKS
a.parseTwoDigitYear=function(a){return u(a)+(u(a)>68?1900:2e3)};
// MOMENTS
var pe=O("FullYear",!0);
// FORMATTING
U("w",["ww",2],"wo","week"),U("W",["WW",2],"Wo","isoWeek"),
// ALIASES
J("week","w"),J("isoWeek","W"),
// PRIORITIES
M("week",5),M("isoWeek",5),
// PARSING
Z("w",Od),Z("ww",Od,Kd),Z("W",Od),Z("WW",Od,Kd),ca(["w","ww","W","WW"],function(a,b,c,d){b[d.substr(0,1)]=u(a)});var qe={dow:0,// Sunday is the first day of the week.
doy:6};
// FORMATTING
U("d",0,"do","day"),U("dd",0,0,function(a){return this.localeData().weekdaysMin(this,a)}),U("ddd",0,0,function(a){return this.localeData().weekdaysShort(this,a)}),U("dddd",0,0,function(a){return this.localeData().weekdays(this,a)}),U("e",0,0,"weekday"),U("E",0,0,"isoWeekday"),
// ALIASES
J("day","d"),J("weekday","e"),J("isoWeekday","E"),
// PRIORITY
M("day",11),M("weekday",11),M("isoWeekday",11),
// PARSING
Z("d",Od),Z("e",Od),Z("E",Od),Z("dd",function(a,b){return b.weekdaysMinRegex(a)}),Z("ddd",function(a,b){return b.weekdaysShortRegex(a)}),Z("dddd",function(a,b){return b.weekdaysRegex(a)}),ca(["dd","ddd","dddd"],function(a,b,c,d){var e=c._locale.weekdaysParse(a,d,c._strict);
// if we didn't get a weekday name, mark the date as invalid
null!=e?b.d=e:m(c).invalidWeekday=a}),ca(["d","e","E"],function(a,b,c,d){b[d]=u(a)});
// LOCALES
var re="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),se="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),te="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),ue=Zd,ve=Zd,we=Zd;U("H",["HH",2],0,"hour"),U("h",["hh",2],0,Ra),U("k",["kk",2],0,Sa),U("hmm",0,0,function(){return""+Ra.apply(this)+T(this.minutes(),2)}),U("hmmss",0,0,function(){return""+Ra.apply(this)+T(this.minutes(),2)+T(this.seconds(),2)}),U("Hmm",0,0,function(){return""+this.hours()+T(this.minutes(),2)}),U("Hmmss",0,0,function(){return""+this.hours()+T(this.minutes(),2)+T(this.seconds(),2)}),Ta("a",!0),Ta("A",!1),
// ALIASES
J("hour","h"),
// PRIORITY
M("hour",13),Z("a",Ua),Z("A",Ua),Z("H",Od),Z("h",Od),Z("HH",Od,Kd),Z("hh",Od,Kd),Z("hmm",Pd),Z("hmmss",Qd),Z("Hmm",Pd),Z("Hmmss",Qd),ba(["H","HH"],de),ba(["a","A"],function(a,b,c){c._isPm=c._locale.isPM(a),c._meridiem=a}),ba(["h","hh"],function(a,b,c){b[de]=u(a),m(c).bigHour=!0}),ba("hmm",function(a,b,c){var d=a.length-2;b[de]=u(a.substr(0,d)),b[ee]=u(a.substr(d)),m(c).bigHour=!0}),ba("hmmss",function(a,b,c){var d=a.length-4,e=a.length-2;b[de]=u(a.substr(0,d)),b[ee]=u(a.substr(d,2)),b[fe]=u(a.substr(e)),m(c).bigHour=!0}),ba("Hmm",function(a,b,c){var d=a.length-2;b[de]=u(a.substr(0,d)),b[ee]=u(a.substr(d))}),ba("Hmmss",function(a,b,c){var d=a.length-4,e=a.length-2;b[de]=u(a.substr(0,d)),b[ee]=u(a.substr(d,2)),b[fe]=u(a.substr(e))});var xe,ye=/[ap]\.?m?\.?/i,ze=O("Hours",!0),Ae={calendar:xd,longDateFormat:yd,invalidDate:zd,ordinal:Ad,ordinalParse:Bd,relativeTime:Cd,months:le,monthsShort:me,week:qe,weekdays:re,weekdaysMin:te,weekdaysShort:se,meridiemParse:ye},Be={},Ce={},De=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Ee=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Fe=/Z|[+-]\d\d(?::?\d\d)?/,Ge=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],
// YYYYMM is NOT allowed by the standard
["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],He=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],Ie=/^\/?Date\((\-?\d+)/i;a.createFromInputFallback=x("value provided is not in a recognized ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.",function(a){a._d=new Date(a._i+(a._useUTC?" UTC":""))}),
// constant that refers to the ISO standard
a.ISO_8601=function(){};var Je=x("moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var a=sb.apply(null,arguments);return this.isValid()&&a.isValid()?a<this?this:a:o()}),Ke=x("moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var a=sb.apply(null,arguments);return this.isValid()&&a.isValid()?a>this?this:a:o()}),Le=function(){return Date.now?Date.now():+new Date};zb("Z",":"),zb("ZZ",""),
// PARSING
Z("Z",Xd),Z("ZZ",Xd),ba(["Z","ZZ"],function(a,b,c){c._useUTC=!0,c._tzm=Ab(Xd,a)});
// HELPERS
// timezone chunker
// '+10:00' > ['10',  '00']
// '-1530'  > ['-15', '30']
var Me=/([\+\-]|\d\d)/gi;
// HOOKS
// This function will be called whenever a moment is mutated.
// It is intended to keep the offset in sync with the timezone.
a.updateOffset=function(){};
// ASP.NET json date format regex
var Ne=/^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/,Oe=/^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;Ob.fn=wb.prototype;var Pe=Sb(1,"add"),Qe=Sb(-1,"subtract");a.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",a.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var Re=x("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(a){return void 0===a?this.localeData():this.locale(a)});
// FORMATTING
U(0,["gg",2],0,function(){return this.weekYear()%100}),U(0,["GG",2],0,function(){return this.isoWeekYear()%100}),zc("gggg","weekYear"),zc("ggggg","weekYear"),zc("GGGG","isoWeekYear"),zc("GGGGG","isoWeekYear"),
// ALIASES
J("weekYear","gg"),J("isoWeekYear","GG"),
// PRIORITY
M("weekYear",1),M("isoWeekYear",1),
// PARSING
Z("G",Vd),Z("g",Vd),Z("GG",Od,Kd),Z("gg",Od,Kd),Z("GGGG",Sd,Md),Z("gggg",Sd,Md),Z("GGGGG",Td,Nd),Z("ggggg",Td,Nd),ca(["gggg","ggggg","GGGG","GGGGG"],function(a,b,c,d){b[d.substr(0,2)]=u(a)}),ca(["gg","GG"],function(b,c,d,e){c[e]=a.parseTwoDigitYear(b)}),
// FORMATTING
U("Q",0,"Qo","quarter"),
// ALIASES
J("quarter","Q"),
// PRIORITY
M("quarter",7),
// PARSING
Z("Q",Jd),ba("Q",function(a,b){b[be]=3*(u(a)-1)}),
// FORMATTING
U("D",["DD",2],"Do","date"),
// ALIASES
J("date","D"),
// PRIOROITY
M("date",9),
// PARSING
Z("D",Od),Z("DD",Od,Kd),Z("Do",function(a,b){return a?b._ordinalParse:b._ordinalParseLenient}),ba(["D","DD"],ce),ba("Do",function(a,b){b[ce]=u(a.match(Od)[0],10)});
// MOMENTS
var Se=O("Date",!0);
// FORMATTING
U("DDD",["DDDD",3],"DDDo","dayOfYear"),
// ALIASES
J("dayOfYear","DDD"),
// PRIORITY
M("dayOfYear",4),
// PARSING
Z("DDD",Rd),Z("DDDD",Ld),ba(["DDD","DDDD"],function(a,b,c){c._dayOfYear=u(a)}),
// FORMATTING
U("m",["mm",2],0,"minute"),
// ALIASES
J("minute","m"),
// PRIORITY
M("minute",14),
// PARSING
Z("m",Od),Z("mm",Od,Kd),ba(["m","mm"],ee);
// MOMENTS
var Te=O("Minutes",!1);
// FORMATTING
U("s",["ss",2],0,"second"),
// ALIASES
J("second","s"),
// PRIORITY
M("second",15),
// PARSING
Z("s",Od),Z("ss",Od,Kd),ba(["s","ss"],fe);
// MOMENTS
var Ue=O("Seconds",!1);
// FORMATTING
U("S",0,0,function(){return~~(this.millisecond()/100)}),U(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),U(0,["SSS",3],0,"millisecond"),U(0,["SSSS",4],0,function(){return 10*this.millisecond()}),U(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),U(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),U(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),U(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),U(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),
// ALIASES
J("millisecond","ms"),
// PRIORITY
M("millisecond",16),
// PARSING
Z("S",Rd,Jd),Z("SS",Rd,Kd),Z("SSS",Rd,Ld);var Ve;for(Ve="SSSS";Ve.length<=9;Ve+="S")Z(Ve,Ud);for(Ve="S";Ve.length<=9;Ve+="S")ba(Ve,Ic);
// MOMENTS
var We=O("Milliseconds",!1);
// FORMATTING
U("z",0,0,"zoneAbbr"),U("zz",0,0,"zoneName");var Xe=r.prototype;Xe.add=Pe,Xe.calendar=Vb,Xe.clone=Wb,Xe.diff=bc,Xe.endOf=oc,Xe.format=gc,Xe.from=hc,Xe.fromNow=ic,Xe.to=jc,Xe.toNow=kc,Xe.get=R,Xe.invalidAt=xc,Xe.isAfter=Xb,Xe.isBefore=Yb,Xe.isBetween=Zb,Xe.isSame=$b,Xe.isSameOrAfter=_b,Xe.isSameOrBefore=ac,Xe.isValid=vc,Xe.lang=Re,Xe.locale=lc,Xe.localeData=mc,Xe.max=Ke,Xe.min=Je,Xe.parsingFlags=wc,Xe.set=S,Xe.startOf=nc,Xe.subtract=Qe,Xe.toArray=sc,Xe.toObject=tc,Xe.toDate=rc,Xe.toISOString=ec,Xe.inspect=fc,Xe.toJSON=uc,Xe.toString=dc,Xe.unix=qc,Xe.valueOf=pc,Xe.creationData=yc,
// Year
Xe.year=pe,Xe.isLeapYear=ra,
// Week Year
Xe.weekYear=Ac,Xe.isoWeekYear=Bc,
// Quarter
Xe.quarter=Xe.quarters=Gc,
// Month
Xe.month=ka,Xe.daysInMonth=la,
// Week
Xe.week=Xe.weeks=Ba,Xe.isoWeek=Xe.isoWeeks=Ca,Xe.weeksInYear=Dc,Xe.isoWeeksInYear=Cc,
// Day
Xe.date=Se,Xe.day=Xe.days=Ka,Xe.weekday=La,Xe.isoWeekday=Ma,Xe.dayOfYear=Hc,
// Hour
Xe.hour=Xe.hours=ze,
// Minute
Xe.minute=Xe.minutes=Te,
// Second
Xe.second=Xe.seconds=Ue,
// Millisecond
Xe.millisecond=Xe.milliseconds=We,
// Offset
Xe.utcOffset=Db,Xe.utc=Fb,Xe.local=Gb,Xe.parseZone=Hb,Xe.hasAlignedHourOffset=Ib,Xe.isDST=Jb,Xe.isLocal=Lb,Xe.isUtcOffset=Mb,Xe.isUtc=Nb,Xe.isUTC=Nb,
// Timezone
Xe.zoneAbbr=Jc,Xe.zoneName=Kc,
// Deprecations
Xe.dates=x("dates accessor is deprecated. Use date instead.",Se),Xe.months=x("months accessor is deprecated. Use month instead",ka),Xe.years=x("years accessor is deprecated. Use year instead",pe),Xe.zone=x("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",Eb),Xe.isDSTShifted=x("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",Kb);var Ye=C.prototype;Ye.calendar=D,Ye.longDateFormat=E,Ye.invalidDate=F,Ye.ordinal=G,Ye.preparse=Nc,Ye.postformat=Nc,Ye.relativeTime=H,Ye.pastFuture=I,Ye.set=A,
// Month
Ye.months=fa,Ye.monthsShort=ga,Ye.monthsParse=ia,Ye.monthsRegex=na,Ye.monthsShortRegex=ma,
// Week
Ye.week=ya,Ye.firstDayOfYear=Aa,Ye.firstDayOfWeek=za,
// Day of Week
Ye.weekdays=Fa,Ye.weekdaysMin=Ha,Ye.weekdaysShort=Ga,Ye.weekdaysParse=Ja,Ye.weekdaysRegex=Na,Ye.weekdaysShortRegex=Oa,Ye.weekdaysMinRegex=Pa,
// Hours
Ye.isPM=Va,Ye.meridiem=Wa,$a("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===u(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),
// Side effect imports
a.lang=x("moment.lang is deprecated. Use moment.locale instead.",$a),a.langData=x("moment.langData is deprecated. Use moment.localeData instead.",bb);var Ze=Math.abs,$e=ed("ms"),_e=ed("s"),af=ed("m"),bf=ed("h"),cf=ed("d"),df=ed("w"),ef=ed("M"),ff=ed("y"),gf=gd("milliseconds"),hf=gd("seconds"),jf=gd("minutes"),kf=gd("hours"),lf=gd("days"),mf=gd("months"),nf=gd("years"),of=Math.round,pf={s:45,// seconds to minute
m:45,// minutes to hour
h:22,// hours to day
d:26,// days to month
M:11},qf=Math.abs,rf=wb.prototype;
// Deprecations
// Side effect imports
// FORMATTING
// PARSING
// Side effect imports
return rf.abs=Wc,rf.add=Yc,rf.subtract=Zc,rf.as=cd,rf.asMilliseconds=$e,rf.asSeconds=_e,rf.asMinutes=af,rf.asHours=bf,rf.asDays=cf,rf.asWeeks=df,rf.asMonths=ef,rf.asYears=ff,rf.valueOf=dd,rf._bubble=_c,rf.get=fd,rf.milliseconds=gf,rf.seconds=hf,rf.minutes=jf,rf.hours=kf,rf.days=lf,rf.weeks=hd,rf.months=mf,rf.years=nf,rf.humanize=md,rf.toISOString=nd,rf.toString=nd,rf.toJSON=nd,rf.locale=lc,rf.localeData=mc,rf.toIsoString=x("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",nd),rf.lang=Re,U("X",0,0,"unix"),U("x",0,0,"valueOf"),Z("x",Vd),Z("X",Yd),ba("X",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),ba("x",function(a,b,c){c._d=new Date(u(a))}),a.version="2.17.1",b(sb),a.fn=Xe,a.min=ub,a.max=vb,a.now=Le,a.utc=k,a.unix=Lc,a.months=Rc,a.isDate=g,a.locale=$a,a.invalid=o,a.duration=Ob,a.isMoment=s,a.weekdays=Tc,a.parseZone=Mc,a.localeData=bb,a.isDuration=xb,a.monthsShort=Sc,a.weekdaysMin=Vc,a.defineLocale=_a,a.updateLocale=ab,a.locales=cb,a.weekdaysShort=Uc,a.normalizeUnits=K,a.relativeTimeRounding=kd,a.relativeTimeThreshold=ld,a.calendarFormat=Ub,a.prototype=Xe,a});;
!function(t){"use strict";if("function"==typeof bootstrap)bootstrap("promise",t);else if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeQ=t}else{if("undefined"==typeof window&&"undefined"==typeof self)throw new Error("This environment was not anticipated by Q. Please file a bug.");var n="undefined"!=typeof window?window:self,e=n.Q;n.Q=t(),n.Q.noConflict=function(){return n.Q=e,this}}}(function(){"use strict";function t(t){return function(){return K.apply(t,arguments)}}function n(t){return t===Object(t)}function e(t){return"[object StopIteration]"===en(t)||t instanceof _}function r(t,n){if(V&&n.stack&&"object"==typeof t&&null!==t&&t.stack&&-1===t.stack.indexOf(rn)){for(var e=[],r=n;r;r=r.source)r.stack&&e.unshift(r.stack);e.unshift(t.stack);var i=e.join("\n"+rn+"\n");t.stack=o(i)}}function o(t){for(var n=t.split("\n"),e=[],r=0;r<n.length;++r){var o=n[r];c(o)||i(o)||!o||e.push(o)}return e.join("\n")}function i(t){return-1!==t.indexOf("(module.js:")||-1!==t.indexOf("(node.js:")}function u(t){var n=/at .+ \((.+):(\d+):(?:\d+)\)$/.exec(t);if(n)return[n[1],Number(n[2])];var e=/at ([^ ]+):(\d+):(?:\d+)$/.exec(t);if(e)return[e[1],Number(e[2])];var r=/.*@(.+):(\d+)$/.exec(t);return r?[r[1],Number(r[2])]:void 0}function c(t){var n=u(t);if(!n)return!1;var e=n[0],r=n[1];return e===H&&r>=q&&fn>=r}function s(){if(V)try{throw new Error}catch(t){var n=t.stack.split("\n"),e=n[0].indexOf("@")>0?n[1]:n[2],r=u(e);if(!r)return;return H=r[0],r[1]}}function f(t,n,e){return function(){return"undefined"!=typeof console&&"function"==typeof console.warn&&console.warn(n+" is deprecated, use "+e+" instead.",new Error("").stack),t.apply(t,arguments)}}function p(t){return t instanceof h?t:g(t)?O(t):E(t)}function a(){function t(t){n=t,i.source=t,W(e,function(n,e){p.nextTick(function(){t.promiseDispatch.apply(t,e)})},void 0),e=void 0,r=void 0}var n,e=[],r=[],o=Z(a.prototype),i=Z(h.prototype);if(i.promiseDispatch=function(t,o,i){var u=L(arguments);e?(e.push(u),"when"===o&&i[1]&&r.push(i[1])):p.nextTick(function(){n.promiseDispatch.apply(n,u)})},i.valueOf=function(){if(e)return i;var t=v(n);return m(t)&&(n=t),t},i.inspect=function(){return n?n.inspect():{state:"pending"}},p.longStackSupport&&V)try{throw new Error}catch(u){i.stack=u.stack.substring(u.stack.indexOf("\n")+1)}return o.promise=i,o.resolve=function(e){n||t(p(e))},o.fulfill=function(e){n||t(E(e))},o.reject=function(e){n||t(R(e))},o.notify=function(t){n||W(r,function(n,e){p.nextTick(function(){e(t)})},void 0)},o}function l(t){if("function"!=typeof t)throw new TypeError("resolver must be a function.");var n=a();try{t(n.resolve,n.reject,n.notify)}catch(e){n.reject(e)}return n.promise}function d(t){return l(function(n,e){for(var r=0,o=t.length;o>r;r++)p(t[r]).then(n,e)})}function h(t,n,e){void 0===n&&(n=function(t){return R(new Error("Promise does not support operation: "+t))}),void 0===e&&(e=function(){return{state:"unknown"}});var r=Z(h.prototype);if(r.promiseDispatch=function(e,o,i){var u;try{u=t[o]?t[o].apply(r,i):n.call(r,o,i)}catch(c){u=R(c)}e&&e(u)},r.inspect=e,e){var o=e();"rejected"===o.state&&(r.exception=o.reason),r.valueOf=function(){var t=e();return"pending"===t.state||"rejected"===t.state?r:t.value}}return r}function y(t,n,e,r){return p(t).then(n,e,r)}function v(t){if(m(t)){var n=t.inspect();if("fulfilled"===n.state)return n.value}return t}function m(t){return t instanceof h}function g(t){return n(t)&&"function"==typeof t.then}function k(t){return m(t)&&"pending"===t.inspect().state}function j(t){return!m(t)||"fulfilled"===t.inspect().state}function w(t){return m(t)&&"rejected"===t.inspect().state}function b(){on.length=0,un.length=0,sn||(sn=!0)}function x(t,n){sn&&("object"==typeof process&&"function"==typeof process.emit&&p.nextTick.runAfter(function(){-1!==X(un,t)&&(process.emit("unhandledRejection",n,t),cn.push(t))}),un.push(t),on.push(n&&"undefined"!=typeof n.stack?n.stack:"(no stack) "+n))}function T(t){if(sn){var n=X(un,t);-1!==n&&("object"==typeof process&&"function"==typeof process.emit&&p.nextTick.runAfter(function(){var e=X(cn,t);-1!==e&&(process.emit("rejectionHandled",on[n],t),cn.splice(e,1))}),un.splice(n,1),on.splice(n,1))}}function R(t){var n=h({when:function(n){return n&&T(this),n?n(t):this}},function(){return this},function(){return{state:"rejected",reason:t}});return x(n,t),n}function E(t){return h({when:function(){return t},get:function(n){return t[n]},set:function(n,e){t[n]=e},"delete":function(n){delete t[n]},post:function(n,e){return null===n||void 0===n?t.apply(void 0,e):t[n].apply(t,e)},apply:function(n,e){return t.apply(n,e)},keys:function(){return nn(t)}},void 0,function(){return{state:"fulfilled",value:t}})}function O(t){var n=a();return p.nextTick(function(){try{t.then(n.resolve,n.reject,n.notify)}catch(e){n.reject(e)}}),n.promise}function S(t){return h({isDef:function(){}},function(n,e){return A(t,n,e)},function(){return p(t).inspect()})}function N(t,n,e){return p(t).spread(n,e)}function D(t){return function(){function n(t,n){var u;if("undefined"==typeof StopIteration){try{u=r[t](n)}catch(c){return R(c)}return u.done?p(u.value):y(u.value,o,i)}try{u=r[t](n)}catch(c){return e(c)?p(c.value):R(c)}return y(u,o,i)}var r=t.apply(this,arguments),o=n.bind(n,"next"),i=n.bind(n,"throw");return o()}}function P(t){p.done(p.async(t)())}function C(t){throw new _(t)}function Q(t){return function(){return N([this,I(arguments)],function(n,e){return t.apply(n,e)})}}function A(t,n,e){return p(t).dispatch(n,e)}function I(t){return y(t,function(t){var n=0,e=a();return W(t,function(r,o,i){var u;m(o)&&"fulfilled"===(u=o.inspect()).state?t[i]=u.value:(++n,y(o,function(r){t[i]=r,0===--n&&e.resolve(t)},e.reject,function(t){e.notify({index:i,value:t})}))},void 0),0===n&&e.resolve(t),e.promise})}function U(t){if(0===t.length)return p.resolve();var n=p.defer(),e=0;return W(t,function(r,o,i){function u(t){n.resolve(t)}function c(){e--,0===e&&n.reject(new Error("Can't get fulfillment value from any promise, all promises were rejected."))}function s(t){n.notify({index:i,value:t})}var f=t[i];e++,y(f,u,c,s)},void 0),n.promise}function F(t){return y(t,function(t){return t=Y(t,p),y(I(Y(t,function(t){return y(t,z,z)})),function(){return t})})}function M(t){return p(t).allSettled()}function B(t,n){return p(t).then(void 0,void 0,n)}function $(t,n){return p(t).nodeify(n)}var V=!1;try{throw new Error}catch(G){V=!!G.stack}var H,_,q=s(),z=function(){},J=function(){function t(){for(var t,r;e.next;)e=e.next,t=e.task,e.task=void 0,r=e.domain,r&&(e.domain=void 0,r.enter()),n(t,r);for(;c.length;)t=c.pop(),n(t);o=!1}function n(n,e){try{n()}catch(r){if(u)throw e&&e.exit(),setTimeout(t,0),e&&e.enter(),r;setTimeout(function(){throw r},0)}e&&e.exit()}var e={task:void 0,next:null},r=e,o=!1,i=void 0,u=!1,c=[];if(J=function(t){r=r.next={task:t,domain:u&&process.domain,next:null},o||(o=!0,i())},"object"==typeof process&&"[object process]"===process.toString()&&process.nextTick)u=!0,i=function(){process.nextTick(t)};else if("function"==typeof setImmediate)i="undefined"!=typeof window?setImmediate.bind(window,t):function(){setImmediate(t)};else if("undefined"!=typeof MessageChannel){var s=new MessageChannel;s.port1.onmessage=function(){i=f,s.port1.onmessage=t,t()};var f=function(){s.port2.postMessage(0)};i=function(){setTimeout(t,0),f()}}else i=function(){setTimeout(t,0)};return J.runAfter=function(t){c.push(t),o||(o=!0,i())},J}(),K=Function.call,L=t(Array.prototype.slice),W=t(Array.prototype.reduce||function(t,n){var e=0,r=this.length;if(1===arguments.length)for(;;){if(e in this){n=this[e++];break}if(++e>=r)throw new TypeError}for(;r>e;e++)e in this&&(n=t(n,this[e],e));return n}),X=t(Array.prototype.indexOf||function(t){for(var n=0;n<this.length;n++)if(this[n]===t)return n;return-1}),Y=t(Array.prototype.map||function(t,n){var e=this,r=[];return W(e,function(o,i,u){r.push(t.call(n,i,u,e))},void 0),r}),Z=Object.create||function(t){function n(){}return n.prototype=t,new n},tn=t(Object.prototype.hasOwnProperty),nn=Object.keys||function(t){var n=[];for(var e in t)tn(t,e)&&n.push(e);return n},en=t(Object.prototype.toString);_="undefined"!=typeof ReturnValue?ReturnValue:function(t){this.value=t};var rn="From previous event:";p.resolve=p,p.nextTick=J,p.longStackSupport=!1,"object"==typeof process&&process&&process.env&&process.env.Q_DEBUG&&(p.longStackSupport=!0),p.defer=a,a.prototype.makeNodeResolver=function(){var t=this;return function(n,e){n?t.reject(n):t.resolve(arguments.length>2?L(arguments,1):e)}},p.Promise=l,p.promise=l,l.race=d,l.all=I,l.reject=R,l.resolve=p,p.passByCopy=function(t){return t},h.prototype.passByCopy=function(){return this},p.join=function(t,n){return p(t).join(n)},h.prototype.join=function(t){return p([this,t]).spread(function(t,n){if(t===n)return t;throw new Error("Can't join: not the same: "+t+" "+n)})},p.race=d,h.prototype.race=function(){return this.then(p.race)},p.makePromise=h,h.prototype.toString=function(){return"[object Promise]"},h.prototype.then=function(t,n,e){function o(n){try{return"function"==typeof t?t(n):n}catch(e){return R(e)}}function i(t){if("function"==typeof n){r(t,c);try{return n(t)}catch(e){return R(e)}}return R(t)}function u(t){return"function"==typeof e?e(t):t}var c=this,s=a(),f=!1;return p.nextTick(function(){c.promiseDispatch(function(t){f||(f=!0,s.resolve(o(t)))},"when",[function(t){f||(f=!0,s.resolve(i(t)))}])}),c.promiseDispatch(void 0,"when",[void 0,function(t){var n,e=!1;try{n=u(t)}catch(r){if(e=!0,!p.onerror)throw r;p.onerror(r)}e||s.notify(n)}]),s.promise},p.tap=function(t,n){return p(t).tap(n)},h.prototype.tap=function(t){return t=p(t),this.then(function(n){return t.fcall(n).thenResolve(n)})},p.when=y,h.prototype.thenResolve=function(t){return this.then(function(){return t})},p.thenResolve=function(t,n){return p(t).thenResolve(n)},h.prototype.thenReject=function(t){return this.then(function(){throw t})},p.thenReject=function(t,n){return p(t).thenReject(n)},p.nearer=v,p.isPromise=m,p.isPromiseAlike=g,p.isPending=k,h.prototype.isPending=function(){return"pending"===this.inspect().state},p.isFulfilled=j,h.prototype.isFulfilled=function(){return"fulfilled"===this.inspect().state},p.isRejected=w,h.prototype.isRejected=function(){return"rejected"===this.inspect().state};var on=[],un=[],cn=[],sn=!0;p.resetUnhandledRejections=b,p.getUnhandledReasons=function(){return on.slice()},p.stopUnhandledRejectionTracking=function(){b(),sn=!1},b(),p.reject=R,p.fulfill=E,p.master=S,p.spread=N,h.prototype.spread=function(t,n){return this.all().then(function(n){return t.apply(void 0,n)},n)},p.async=D,p.spawn=P,p["return"]=C,p.promised=Q,p.dispatch=A,h.prototype.dispatch=function(t,n){var e=this,r=a();return p.nextTick(function(){e.promiseDispatch(r.resolve,t,n)}),r.promise},p.get=function(t,n){return p(t).dispatch("get",[n])},h.prototype.get=function(t){return this.dispatch("get",[t])},p.set=function(t,n,e){return p(t).dispatch("set",[n,e])},h.prototype.set=function(t,n){return this.dispatch("set",[t,n])},p.del=p["delete"]=function(t,n){return p(t).dispatch("delete",[n])},h.prototype.del=h.prototype["delete"]=function(t){return this.dispatch("delete",[t])},p.mapply=p.post=function(t,n,e){return p(t).dispatch("post",[n,e])},h.prototype.mapply=h.prototype.post=function(t,n){return this.dispatch("post",[t,n])},p.send=p.mcall=p.invoke=function(t,n){return p(t).dispatch("post",[n,L(arguments,2)])},h.prototype.send=h.prototype.mcall=h.prototype.invoke=function(t){return this.dispatch("post",[t,L(arguments,1)])},p.fapply=function(t,n){return p(t).dispatch("apply",[void 0,n])},h.prototype.fapply=function(t){return this.dispatch("apply",[void 0,t])},p["try"]=p.fcall=function(t){return p(t).dispatch("apply",[void 0,L(arguments,1)])},h.prototype.fcall=function(){return this.dispatch("apply",[void 0,L(arguments)])},p.fbind=function(t){var n=p(t),e=L(arguments,1);return function(){return n.dispatch("apply",[this,e.concat(L(arguments))])}},h.prototype.fbind=function(){var t=this,n=L(arguments);return function(){return t.dispatch("apply",[this,n.concat(L(arguments))])}},p.keys=function(t){return p(t).dispatch("keys",[])},h.prototype.keys=function(){return this.dispatch("keys",[])},p.all=I,h.prototype.all=function(){return I(this)},p.any=U,h.prototype.any=function(){return U(this)},p.allResolved=f(F,"allResolved","allSettled"),h.prototype.allResolved=function(){return F(this)},p.allSettled=M,h.prototype.allSettled=function(){return this.then(function(t){return I(Y(t,function(t){function n(){return t.inspect()}return t=p(t),t.then(n,n)}))})},p.fail=p["catch"]=function(t,n){return p(t).then(void 0,n)},h.prototype.fail=h.prototype["catch"]=function(t){return this.then(void 0,t)},p.progress=B,h.prototype.progress=function(t){return this.then(void 0,void 0,t)},p.fin=p["finally"]=function(t,n){return p(t)["finally"](n)},h.prototype.fin=h.prototype["finally"]=function(t){return t=p(t),this.then(function(n){return t.fcall().then(function(){return n})},function(n){return t.fcall().then(function(){throw n})})},p.done=function(t,n,e,r){return p(t).done(n,e,r)},h.prototype.done=function(t,n,e){var o=function(t){p.nextTick(function(){if(r(t,i),!p.onerror)throw t;p.onerror(t)})},i=t||n||e?this.then(t,n,e):this;"object"==typeof process&&process&&process.domain&&(o=process.domain.bind(o)),i.then(void 0,o)},p.timeout=function(t,n,e){return p(t).timeout(n,e)},h.prototype.timeout=function(t,n){var e=a(),r=setTimeout(function(){n&&"string"!=typeof n||(n=new Error(n||"Timed out after "+t+" ms"),n.code="ETIMEDOUT"),e.reject(n)},t);return this.then(function(t){clearTimeout(r),e.resolve(t)},function(t){clearTimeout(r),e.reject(t)},e.notify),e.promise},p.delay=function(t,n){return void 0===n&&(n=t,t=void 0),p(t).delay(n)},h.prototype.delay=function(t){return this.then(function(n){var e=a();return setTimeout(function(){e.resolve(n)},t),e.promise})},p.nfapply=function(t,n){return p(t).nfapply(n)},h.prototype.nfapply=function(t){var n=a(),e=L(t);return e.push(n.makeNodeResolver()),this.fapply(e).fail(n.reject),n.promise},p.nfcall=function(t){var n=L(arguments,1);return p(t).nfapply(n)},h.prototype.nfcall=function(){var t=L(arguments),n=a();return t.push(n.makeNodeResolver()),this.fapply(t).fail(n.reject),n.promise},p.nfbind=p.denodeify=function(t){var n=L(arguments,1);return function(){var e=n.concat(L(arguments)),r=a();return e.push(r.makeNodeResolver()),p(t).fapply(e).fail(r.reject),r.promise}},h.prototype.nfbind=h.prototype.denodeify=function(){var t=L(arguments);return t.unshift(this),p.denodeify.apply(void 0,t)},p.nbind=function(t,n){var e=L(arguments,2);return function(){function r(){return t.apply(n,arguments)}var o=e.concat(L(arguments)),i=a();return o.push(i.makeNodeResolver()),p(r).fapply(o).fail(i.reject),i.promise}},h.prototype.nbind=function(){var t=L(arguments,0);return t.unshift(this),p.nbind.apply(void 0,t)},p.nmapply=p.npost=function(t,n,e){return p(t).npost(n,e)},h.prototype.nmapply=h.prototype.npost=function(t,n){var e=L(n||[]),r=a();return e.push(r.makeNodeResolver()),this.dispatch("post",[t,e]).fail(r.reject),r.promise},p.nsend=p.nmcall=p.ninvoke=function(t,n){var e=L(arguments,2),r=a();return e.push(r.makeNodeResolver()),p(t).dispatch("post",[n,e]).fail(r.reject),r.promise},h.prototype.nsend=h.prototype.nmcall=h.prototype.ninvoke=function(t){var n=L(arguments,1),e=a();return n.push(e.makeNodeResolver()),this.dispatch("post",[t,n]).fail(e.reject),e.promise},p.nodeify=$,h.prototype.nodeify=function(t){return t?void this.then(function(n){p.nextTick(function(){t(null,n)})},function(n){p.nextTick(function(){t(n)})}):this},p.noConflict=function(){throw new Error("Q.noConflict only works when Q is used as a global")};var fn=s();return p});;
/*
 * Copyright 2012-2018 IdeaBlade, Inc.  All Rights Reserved.  
 * Use, reproduction, distribution, and modification of this code is subject to the terms and 
 * conditions of the IdeaBlade Breeze license, available at http://www.breezejs.com/license
 *
 * Author: Jay Traband
 */

(function (global, definition) {
    var def = function(){ return definition(global); };

    // CommonJS
    if (typeof exports === "object" && typeof module === "object") {
        module.exports = def();
        // RequireJS
    } else if (typeof define === "function" && define["amd"]) {
        define(def);
        // <script>
    } else {
        breeze = def();
    }

})(this, function (global) {
    "use strict"; 
    var breeze = {
        version: "1.7.1",
        metadataVersion: "1.0.5"
    };
    ;/**
 @module core
 **/

var __hasOwnProperty = uncurry(Object.prototype.hasOwnProperty);
var __arraySlice = uncurry(Array.prototype.slice);
var __isES5Supported = function () {
  try {
    return !!(Object.getPrototypeOf && Object.defineProperty({}, 'x', {}));
  } catch (e) {
    return false;
  }
}();

// iterate over object
function __objectForEach(obj, kvFn) {
  for (var key in obj) {
    if (__hasOwnProperty(obj, key)) {
      kvFn(key, obj[key]);
    }
  }
}

function __objectMap(obj, kvFn) {
  var results = [];
  for (var key in obj) {
    if (__hasOwnProperty(obj, key)) {
      var result = kvFn ? kvFn(key, obj[key]) : obj[key];
      if (result !== undefined) {
        results.push(result);
      }
    }
  }
  return results;
}

function __objectFirst(obj, kvPredicate) {
  for (var key in obj) {
    if (__hasOwnProperty(obj, key)) {
      var value = obj[key];
      if (kvPredicate(key, value)) {
        return { key: key, value: value };
      }
    }
  }
  return null;
}

function __isSettable(entity, propertyName) {
  var pd = __getPropDescriptor(entity, propertyName);
  if (pd == null) return true;
  return !!(pd.writable || pd.set);
}

function __getPropDescriptor(obj, propertyName) {
  if (!__isES5Supported) return null;

  if (obj.hasOwnProperty(propertyName)) {
    return Object.getOwnPropertyDescriptor(obj, propertyName);
  } else {
    var nextObj = Object.getPrototypeOf(obj);
    if (nextObj == null) return null;
    return __getPropDescriptor(nextObj, propertyName);
  }
}

// Functional extensions

// can be used like: persons.filter(propEq("firstName", "John"))
function __propEq(propertyName, value) {
  return function (obj) {
    return obj[propertyName] === value;
  };
}

// can be used like persons.map(pluck("firstName"))
function __pluck(propertyName) {
  return function (obj) {
    return obj[propertyName];
  };
}

// end functional extensions


function __getOwnPropertyValues(source) {
  var result = [];
  for (var name in source) {
    if (__hasOwnProperty(source, name)) {
      result.push(source[name]);
    }
  }
  return result;
}

function __extend(target, source, propNames) {
  if (!source) return target;
  if (propNames) {
    propNames.forEach(function (propName) {
      target[propName] = source[propName];
    });
  } else {
    for (var propName in source) {
      if (__hasOwnProperty(source, propName)) {
        target[propName] = source[propName];
      }
    }
  }
  return target;
}


function __updateWithDefaults(target, defaults) {
  for (var name in defaults) {
    if (target[name] === undefined) {
      target[name] = defaults[name];
    }
  }
  return target;
}


function __setAsDefault(target, ctor) {
  // we want to insure that the object returned by ctor.defaultInstance is always immutable
  // Use 'target' as the primary template for the ctor.defaultInstance;
  // Use current 'ctor.defaultInstance' as the template for any missing properties
  // creates a new instance for ctor.defaultInstance
  // returns target unchanged
  ctor.defaultInstance = __updateWithDefaults(new ctor(target), ctor.defaultInstance);
  return target;
}

// 'source' is an object that will be transformed into another
// 'template' is a map where the
//    keys: are the keys to return
//      if a key contains ','s then the key is treated as a delimited string with first of the
//      keys being the key to return and the others all valid aliases for this key
//    'values' are either
//        1) the 'default' value of the key
//        2) a function that takes in the source value and should return the value to set
//      The value from the source is then set on the target,
//      after first passing thru the fn, if provided, UNLESS:
//        1) it is the default value
//        2) it is undefined ( nulls WILL be set)
// 'target' is optional
//    - if it exists then properties of the target will be set ( overwritten if the exist)
//    - if it does not exist then a new object will be created as filled.
// 'target is returned.
function __toJson(source, template, target) {
  target = target || {};

  for (var key in template) {
    var aliases = key.split(",");
    var defaultValue = template[key];
    // using some as a forEach with a 'break'
    aliases.some(function(propName) {
      if (!(propName in source)) return false;
      var value = source[propName];
      // there is a functional property defined with this alias ( not what we want to replace).
      if (typeof value == 'function') return false;
      // '==' is deliberate here - idea is that null or undefined values will never get serialized
      // if default value is set to null.
      if (value == defaultValue) return true;
      if (Array.isArray(value) && value.length === 0) return true;
      if (typeof(defaultValue) === "function") {
        value = defaultValue(value);
      } else if (typeof (value) === "object") {
        if (value && value.parentEnum) {
          value = value.name;
        }
      }
      if (value === undefined) return true;
      target[aliases[0]] = value;
      return true;
    });
  }
  return target;
}

// default replacer function for __toJSONSafe.  Excludes entityAspect and other internal properties
function __safeReplacer(prop, val) {
	if (prop === "entityAspect" || prop === "complexAspect" || prop === "entityType" || prop === "complexType"
	|| prop === "constructor" || prop.charAt(0) === '_' || prop.charAt(0) === '$') return;
	return val;
}

// safely perform toJSON logic on objects with cycles.
function __toJSONSafe(obj, replacer) {
  if (obj !== Object(obj)) return obj; // primitive value
  if (obj._$visited) return undefined;
  replacer = replacer || __safeReplacer;
  if (obj.toJSON) {
    var newObj = obj.toJSON();
    if (newObj !== Object(newObj)) return newObj; // primitive value
    if (newObj !== obj) return __toJSONSafe(newObj, replacer);
    // toJSON returned the object unchanged.
    obj = newObj;
  }
  obj._$visited = true;
  var result;
  if (obj instanceof Array) {
    result = obj.map(function (o) {
      return __toJSONSafe(o, replacer);
    });
  } else if (typeof (obj) === "function") {
    result = undefined;
  } else {
    result = {};
    for (var prop in obj) {
      if (prop === "_$visited") continue;
      var val = obj[prop];
      if (replacer) {
        val = replacer(prop, val);
        if (val === undefined) continue;
      }
      val = __toJSONSafe(val, replacer);
      if (val === undefined) continue;
      result[prop] = val;
    }
  }
  delete obj._$visited;
  return result;
}

// resolves the values of a list of properties by checking each property in multiple sources until a value is found.
function __resolveProperties(sources, propertyNames) {
  var r = {};
  var length = sources.length;
  propertyNames.forEach(function (pn) {
    for (var i = 0; i < length; i++) {
      var src = sources[i];
      if (src) {
        var val = src[pn];
        if (val !== undefined) {
          r[pn] = val;
          break;
        }
      }
    }
  });
  return r;
}


// array functions

function __toArray(item) {
  if (item == null) {
    return [];
  } else if (Array.isArray(item)) {
    return item;
  } else {
    return [item];
  }
}

// a version of Array.map that doesn't require an array, i.e. works on arrays and scalars.
function __map(items, fn, includeNull) {
  // whether to return nulls in array of results; default = true;
  includeNull = includeNull == null ? true : includeNull;
  if (items == null) return items;
  var result;
  if (Array.isArray(items)) {
    result = [];
    items.forEach(function (v, ix) {
      var r = fn(v, ix);
      if (r != null || includeNull) {
        result[ix] = r;
      }
    });
  } else {
    result = fn(items);
  }
  return result;
}


function __arrayFirst(array, predicate) {
  for (var i = 0, j = array.length; i < j; i++) {
    if (predicate(array[i])) {
      return array[i];
    }
  }
  return null;
}

function __arrayIndexOf(array, predicate) {
  for (var i = 0, j = array.length; i < j; i++) {
    if (predicate(array[i])) return i;
  }
  return -1;
}

function __arrayAddItemUnique(array, item) {
  var ix = array.indexOf(item);
  if (ix === -1) array.push(item);
}

function __arrayRemoveItem(array, predicateOrItem, shouldRemoveMultiple) {
  var predicate = __isFunction(predicateOrItem) ? predicateOrItem : undefined;
  var lastIx = array.length - 1;
  var removed = false;
  for (var i = lastIx; i >= 0; i--) {
    if (predicate ? predicate(array[i]) : (array[i] === predicateOrItem)) {
      array.splice(i, 1);
      removed = true;
      if (!shouldRemoveMultiple) {
        return true;
      }
    }
  }
  return removed;
}

function __arrayZip(a1, a2, callback) {
  var result = [];
  var n = Math.min(a1.length, a2.length);
  for (var i = 0; i < n; ++i) {
    result.push(callback(a1[i], a2[i]));
  }
  return result;
}

//function __arrayDistinct(array) {
//    array = array || [];
//    var result = [];
//    for (var i = 0, j = array.length; i < j; i++) {
//        if (result.indexOf(array[i]) < 0)
//            result.push(array[i]);
//    }
//    return result;
//}

// Not yet needed
//// much faster but only works on array items with a toString method that
//// returns distinct string for distinct objects.  So this is safe for arrays with primitive
//// types but not for arrays with object types, unless toString() has been implemented.
//function arrayDistinctUnsafe(array) {
//    var o = {}, i, l = array.length, r = [];
//    for (i = 0; i < l; i += 1) {
//        var v = array[i];
//        o[v] = v;
//    }
//    for (i in o) r.push(o[i]);
//    return r;
//}

function __arrayEquals(a1, a2, equalsFn) {
  //Check if the arrays are undefined/null
  if (!a1 || !a2) return false;

  if (a1.length !== a2.length) return false;

  //go thru all the vars
  for (var i = 0; i < a1.length; i++) {
    //if the var is an array, we need to make a recursive check
    //otherwise we'll just compare the values
    if (Array.isArray(a1[i])) {
      if (!__arrayEquals(a1[i], a2[i])) return false;
    } else {
      if (equalsFn) {
        if (!equalsFn(a1[i], a2[i])) return false;
      } else {
        if (a1[i] !== a2[i]) return false;
      }
    }
  }
  return true;
}

// end of array functions

// returns and array for a source and a prop, and creates the prop if needed.
function __getArray(source, propName) {
  var arr = source[propName];
  if (!arr) {
    arr = [];
    source[propName] = arr;
  }
  return arr;
}

function __requireLib(libNames, errMessage) {
  var arrNames = libNames.split(";");
  for (var i = 0, j = arrNames.length; i < j; i++) {
    var lib = __requireLibCore(arrNames[i]);
    if (lib) return lib;
  }
  if (errMessage) {
    throw new Error("Unable to initialize " + libNames + ".  " + errMessage);
  }
}

// Returns the 'libName' module if loaded or else returns undefined
function __requireLibCore(libName) {
  var window = global.window;
  if (!window) return; // Must run in a browser. Todo: add commonjs support

  // get library from browser globals if we can
  var lib = window[libName];
  if (lib) return lib;

  // if require exists, maybe require can get it.
  // This method is synchronous so it can't load modules with AMD.
  // It can only obtain modules from require that have already been loaded.
  // Developer should bootstrap such that the breeze module
  // loads after all other libraries that breeze should find with this method
  // See documentation
  var r = window.require;
  if (r) { // if require exists
    if (r.defined) { // require.defined is not standard and may not exist
      // require.defined returns true if module has been loaded
      return r.defined(libName) ? r(libName) : undefined;
    } else {
      // require.defined does not exist so we have to call require('libName') directly.
      // The require('libName') overload is synchronous and does not load modules.
      // It throws an exception if the module isn't already loaded.
      try {
        return r(libName);
      } catch (e) {
        // require('libName') threw because module not loaded
        return;
      }
    }
  }
}

function __using(obj, property, tempValue, fn) {
  var originalValue = obj[property];
  if (tempValue === originalValue) {
    return fn();
  }
  obj[property] = tempValue;
  try {
    return fn();
  } finally {
    if (originalValue === undefined) {
      delete obj[property];
    } else {
      obj[property] = originalValue;
    }
  }
}

function __wrapExecution(startFn, endFn, fn) {
  var state;
  try {
    state = startFn();
    return fn();
  } catch (e) {
    if (typeof(state) === 'object') {
      state.error = e;
    }
    throw e;
  } finally {
    endFn(state);
  }
}

function __memoize(fn) {
  return function () {
    var args = __arraySlice(arguments),
        hash = "",
        i = args.length,
        currentArg = null;
    while (i--) {
      currentArg = args[i];
      hash += (currentArg === Object(currentArg)) ? JSON.stringify(currentArg) : currentArg;
      fn.memoize || (fn.memoize = {});
    }
    return (hash in fn.memoize) ?
           fn.memoize[hash] :
           fn.memoize[hash] = fn.apply(this, args);
  };
}

function __getUuid() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
    //noinspection NonShortCircuitBooleanExpressionJS
    var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
}

function __durationToSeconds(duration) {
  // basic algorithm from https://github.com/nezasa/iso8601-js-period
  if (typeof duration !== "string") throw new Error("Invalid ISO8601 duration '" + duration + "'");

  // regex splits as follows - grp0, grp1, y, m, d, grp2, h, m, s
  //                           0     1     2  3  4  5     6  7  8
  var struct = /^P((\d+Y)?(\d+M)?(\d+D)?)?(T(\d+H)?(\d+M)?(\d+S)?)?$/.exec(duration);
  if (!struct) throw new Error("Invalid ISO8601 duration '" + duration + "'");

  var ymdhmsIndexes = [2, 3, 4, 6, 7, 8]; // -> grp1,y,m,d,grp2,h,m,s
  var factors = [31104000, // year (360*24*60*60)
                 2592000,             // month (30*24*60*60)
                 86400,               // day (24*60*60)
                 3600,                // hour (60*60)
                 60,                  // minute (60)
                 1];                  // second (1)

  var seconds = 0;
  for (var i = 0; i < 6; i++) {
    var digit = struct[ymdhmsIndexes[i]];
    // remove letters, replace by 0 if not defined
    digit = digit ? +digit.replace(/[A-Za-z]+/g, '') : 0;
    seconds += digit * factors[i];
  }
  return seconds;

}

// is functions

function __noop() {
  // does nothing
}

function __identity(x) {
  return x;
}

function __classof(o) {
  if (o === null) {
    return "null";
  }
  if (o === undefined) {
    return "undefined";
  }
  return Object.prototype.toString.call(o).slice(8, -1).toLowerCase();
}

function __isDate(o) {
  return __classof(o) === "date" && !isNaN(o.getTime());
}

function __isDateString(s) {
  // var rx = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/;
  var rx = /^((\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z)))$/;
  return (typeof s === "string") && rx.test(s);
}

function __isFunction(o) {
  return __classof(o) === "function";
}

function __isString(o) {
  return (typeof o === "string");
}

function __isObject(o) {
  return (typeof o === "object");
}

function __isGuid(value) {
  return (typeof value === "string") && /[a-fA-F\d]{8}-(?:[a-fA-F\d]{4}-){3}[a-fA-F\d]{12}/.test(value);
}

function __isDuration(value) {
  return (typeof value === "string") && /^(-|)?P[T]?[\d\.,\-]+[YMDTHS]/.test(value);
}

function __isEmpty(obj) {
  if (obj === null || obj === undefined) {
    return true;
  }
  for (var key in obj) {
    if (__hasOwnProperty(obj, key)) {
      return false;
    }
  }
  return true;
}

function __isNumeric(n) {
  return !isNaN(parseFloat(n)) && isFinite(n);
}

// returns true for booleans, numbers, strings and dates
// false for null, and non-date objects, functions, and arrays
function __isPrimitive(obj) {
  if (obj == null) return false;
  // true for numbers, strings, booleans and null, false for objects
  if (obj != Object(obj)) return true;
  return __isDate(obj);
}

// end of is Functions

// string functions

function __stringStartsWith(str, prefix) {
  // returns true for empty string or null prefix
  if ((!str)) return false;
  if (prefix == "" || prefix == null) return true;
  return str.indexOf(prefix, 0) === 0;
}

function __stringEndsWith(str, suffix) {
  // returns true for empty string or null suffix
  if ((!str)) return false;
  if (suffix == "" || suffix == null) return true;
  return str.indexOf(suffix, str.length - suffix.length) !== -1;
}

// Based on fragment from Dean Edwards' Base 2 library
// format("a %1 and a %2", "cat", "dog") -> "a cat and a dog"
function __formatString(string) {
  var args = arguments;
  var pattern = RegExp("%([1-" + (arguments.length - 1) + "])", "g");
  return string.replace(pattern, function (match, index) {
    return args[index];
  });
}

// Change text to title case with spaces, e.g. 'myPropertyName12' to 'My Property Name 12'
// See http://stackoverflow.com/questions/7225407/convert-camelcasetext-to-camel-case-text
var __camelEdges = /([A-Z](?=[A-Z][a-z])|[^A-Z](?=[A-Z])|[a-zA-Z](?=[^a-zA-Z]))/g;
function __titleCaseSpace(text) {
  text = text.replace(__camelEdges, '$1 ');
  text = text.charAt(0).toUpperCase() + text.slice(1);
  return text;
}

// end of string functions

// See Mark Miller’s explanation of what this does.
// http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming
function uncurry(f) {
  var call = Function.call;
  return function () {
    return call.apply(f, arguments);
  };
}

// shims

if (!Object.create) {
  Object.create = function (parent) {
    var F = function () {
    };
    F.prototype = parent;
    return new F();
  };
}

var core = {};

// not all methods above are exported
core.__isES5Supported = __isES5Supported;

core.objectForEach = __objectForEach;

core.extend = __extend;
core.propEq = __propEq;
core.pluck = __pluck;

core.arrayEquals = __arrayEquals;
core.arrayFirst = __arrayFirst;
core.arrayIndexOf = __arrayIndexOf;
core.arrayRemoveItem = __arrayRemoveItem;
core.arrayZip = __arrayZip;

core.requireLib = __requireLib;
core.using = __using;

core.memoize = __memoize;
core.getUuid = __getUuid;
core.durationToSeconds = __durationToSeconds;

core.isDate = __isDate;
core.isGuid = __isGuid;
core.isDuration = __isDuration;
core.isFunction = __isFunction;
core.isEmpty = __isEmpty;
core.isNumeric = __isNumeric;

core.stringStartsWith = __stringStartsWith;
core.stringEndsWith = __stringEndsWith;
core.formatString = __formatString;
core.titleCase = __titleCaseSpace;

core.getPropertyDescriptor = __getPropDescriptor;

core.toJSONSafe = __toJSONSafe;
core.toJSONSafeReplacer = __safeReplacer;

core.parent = breeze;
breeze.core = core;


;/**
 @module core
 **/

var Param = (function () {
  // The %1 parameter
  // is required
  // must be a %2
  // must be an instance of %2
  // must be an instance of the %2 enumeration
  // must have a %2 property
  // must be an array where each element
  // is optional or

  var ctor = function (v, name) {
    this.v = v;
    this.name = name;
    this._contexts = [null];

  };
  var proto = ctor.prototype;

  proto.isObject = function () {
    return this.isTypeOf("object");
  };

  proto.isBoolean = function () {
    return this.isTypeOf('boolean');
  };

  proto.isString = function () {
    return this.isTypeOf('string');
  };

  proto.isNonEmptyString = function () {
    return addContext(this, {
      fn: isNonEmptyString,
      msg: "must be a nonEmpty string"
    });
  };

  function isNonEmptyString(context, v) {
    if (v == null) return false;
    return (typeof(v) === 'string') && v.length > 0;
  }

  proto.isNumber = function () {
    return this.isTypeOf('number');
  };

  proto.isFunction = function () {
    return this.isTypeOf('function');
  };


  proto.isTypeOf = function (typeName) {
    return addContext(this, {
      fn: isTypeOf,
      typeName: typeName,
       msg: "must be a '" + typeName + "'"
    });
  };

  function isTypeOf(context, v) {
    if (v == null) return false;
    if (typeof(v) === context.typeName) return true;
    return false;
  }

  proto.isInstanceOf = function (type, typeName) {
    typeName = typeName || type.prototype._$typeName;
    return addContext(this, {
      fn: isInstanceOf,
      type: type,
      typeName: typeName,
      msg: "must be an instance of '" + typeName + "'"
    });
  };

  function isInstanceOf(context, v) {
    if (v == null) return false;
    return (v instanceof context.type);
  }

  proto.hasProperty = function (propertyName) {
    return addContext(this, {
      fn: hasProperty,
      propertyName: propertyName,
      msg: "must have a '" + propertyName + "' property"
    });
  };

  function hasProperty(context, v) {
    if (v == null) return false;
    return (v[context.propertyName] !== undefined);
  }

  proto.isEnumOf = function (enumType) {
    return addContext(this, {
      fn: isEnumOf,
      enumType: enumType,
      msg: "must be an instance of the '" + enumType.name + "' enumeration"
    });
  };

  function isEnumOf(context, v) {
    if (v == null) return false;
    return context.enumType.contains(v);
  }

  proto.isRequired = function (allowNull) {
    return addContext(this, {
      fn: isRequired,
      allowNull: allowNull,
      msg: "is required"
    });
  };

  function isRequired(context, v) {
    if (context.allowNull) {
      return v !== undefined;
    } else {
      return v != null;
    }
  }

  // combinable methods.

  proto.isOptional = function () {
    var context = {
      fn: isOptional,
      prevContext: null,
      msg: isOptionalMessage
    };
    return addContext(this, context);
  };

  function isOptional(context, v) {
    if (v == null) return true;
    var prevContext = context.prevContext;
    if (prevContext) {
      return prevContext.fn(prevContext, v);
    } else {
      return true;
    }
  }

  function isOptionalMessage(context, v) {
    var prevContext = context.prevContext;
    var element = prevContext ? " or it " + getMessage(prevContext, v) : "";
    return "is optional" + element;
  }

  proto.isNonEmptyArray = function () {
    return this.isArray(true);
  };

  proto.isArray = function (mustNotBeEmpty) {
    var context = {
      fn: isArray,
      mustNotBeEmpty: mustNotBeEmpty,
      prevContext: null,
      msg: isArrayMessage
    };
    return addContext(this, context);
  };


  function isArray(context, v) {
    if (!Array.isArray(v)) {
      return false;
    }
    if (context.mustNotBeEmpty) {
      if (v.length === 0) return false;
    }
    // allow standalone is array call.
    var prevContext = context.prevContext;
    if (!prevContext) return true;

    return v.every(function (v1) {
      return prevContext.fn(prevContext, v1);
    });
  }

  function isArrayMessage(context, v) {
    var arrayDescr = context.mustNotBeEmpty ? "a nonEmpty array" : "an array";
    var prevContext = context.prevContext;
    var element = prevContext ? " where each element " + getMessage(prevContext, v) : "";
    return " must be " + arrayDescr + element;
  }

  function getMessage(context, v) {
    var msg = context.msg;
    if (typeof(msg) === "function") {
      msg = msg(context, v);
    }
    return msg;
  }

  proto.or = function () {
    this._contexts.push(null);
    this._context = null;
    return this;
  };

  proto.check = function (defaultValue) {
    var ok = exec(this);
    if (ok === undefined) return;
    if (!ok) {
      throw new Error(this.getMessage());
    }

    if (this.v !== undefined) {
      return this.v;
    } else {
      return defaultValue;
    }
  };

  // called from outside this file.
  proto._addContext = function (context) {
    return addContext(this, context);
  };

  function addContext(that, context) {
    if (that._context) {
      var curContext = that._context;

      while (curContext.prevContext != null) {
        curContext = curContext.prevContext;
      }

      if (curContext.prevContext === null) {
        curContext.prevContext = context;
        // just update the prevContext but don't change the curContext.
        return that;
      } else if (context.prevContext == null) {
        context.prevContext = that._context;
      } else {
        throw new Error("Illegal construction - use 'or' to combine checks");
      }
    }
    return setContext(that, context);
  }

  function setContext(that, context) {
    that._contexts[that._contexts.length - 1] = context;
    that._context = context;
    return that;
  }


  function exec(self) {
    // clear off last one if null
    var contexts = self._contexts;
    if (contexts[contexts.length - 1] == null) {
      contexts.pop();
    }
    if (contexts.length === 0) {
      return undefined;
    }
    return contexts.some(function (context) {
      return context.fn(context, self.v);
    });
  }


  proto.getMessage = function () {
    var that = this;
    var message = this._contexts.map(function (context) {
      return getMessage(context, that.v);
    }).join(", or it ");
    return __formatString(this.MESSAGE_PREFIX, this.name) + " " + message;
  };

  proto.withDefault = function (defaultValue) {
    this.defaultValue = defaultValue;
    return this;
  };

  proto.whereParam = function (propName) {
    return this.parent.whereParam(propName);
  };


  proto.applyAll = function (instance, checkOnly) {
    var parentTypeName = instance._$typeName;
    var allowUnknownProperty = (parentTypeName && this.parent.config._$typeName === parentTypeName);

    var clone = __extend({}, this.parent.config);
    this.parent.params.forEach(function (p) {
      if (!allowUnknownProperty) delete clone[p.name];
      try {
        p.check();
      } catch (e) {
        throwConfigError(instance, e.message);
      }
      (!checkOnly) && p._applyOne(instance);
    });
    // should be no properties left in the clone
    if (!allowUnknownProperty) {
      for (var key in clone) {
        // allow props with an undefined value
        if (clone[key] !== undefined) {
          throwConfigError(instance, __formatString("Unknown property: '%1'.", key));
        }
      }
    }
  };

  function throwConfigError(instance, message) {
    throw new Error(__formatString("Error configuring an instance of '%1'. %2", (instance && instance._$typeName) || "object", message));
  }

  proto._applyOne = function (instance) {
    if (this.v !== undefined) {
      instance[this.name] = this.v;
    } else {
      if (this.defaultValue !== undefined) {
        instance[this.name] = this.defaultValue;
      }
    }
  };

  proto.MESSAGE_PREFIX = "The '%1' parameter ";
  return ctor;
})();

var assertParam = function (v, name) {
  return new Param(v, name);
};

var ConfigParam = (function () {
  var ctor = function (config) {
    if (typeof(config) !== "object") {
      throw new Error("Configuration parameter should be an object, instead it is a: " + typeof(config));
    }
    this.config = config;
    this.params = [];
  };
  var proto = ctor.prototype;

  proto.whereParam = function (propName) {
    var param = new Param(this.config[propName], propName);
    param.parent = this;
    this.params.push(param);
    return param;
  };
  return ctor;
})();

var assertConfig = function (config) {
  return new ConfigParam(config);
};

// Param is exposed so that additional 'is' methods can be added to the prototype.
core.Param = Param;
core.assertParam = assertParam;
core.assertConfig = assertConfig;



;/**
@module core
**/

var Enum = (function () {

  // TODO: think about CompositeEnum (flags impl).

  /**
  Base class for all Breeze enumerations, such as EntityState, DataType, FetchStrategy, MergeStrategy etc.
  A Breeze Enum is a namespaced set of constant values.  Each Enum consists of a group of related constants, called 'symbols'.
  Unlike enums in some other environments, each 'symbol' can have both methods and properties.

  @example
      // Example of creating a new Enum
      var prototype = {
          nextDay: function () {
              var nextIndex = (this.dayIndex+1) % 7;
              return DayOfWeek.getSymbols()[nextIndex];
          }
      };

      var DayOfWeek = new Enum("DayOfWeek", prototype);
      DayOfWeek.Monday    = DayOfWeek.addSymbol( { dayIndex: 0 });
      DayOfWeek.Tuesday   = DayOfWeek.addSymbol( { dayIndex: 1 });
      DayOfWeek.Wednesday = DayOfWeek.addSymbol( { dayIndex: 2 });
      DayOfWeek.Thursday  = DayOfWeek.addSymbol( { dayIndex: 3 });
      DayOfWeek.Friday    = DayOfWeek.addSymbol( { dayIndex: 4 });
      DayOfWeek.Saturday  = DayOfWeek.addSymbol( { dayIndex: 5, isWeekend: true });
      DayOfWeek.Sunday    = DayOfWeek.addSymbol( { dayIndex: 6, isWeekend: true });
      DayOfWeek.resolveSymbols();

      // custom methods
      ok(DayOfWeek.Monday.nextDay() === DayOfWeek.Tuesday);
      ok(DayOfWeek.Sunday.nextDay() === DayOfWeek.Monday);
      // custom properties
      ok(DayOfWeek.Tuesday.isWeekend === undefined);
      ok(DayOfWeek.Saturday.isWeekend == true);
      // Standard enum capabilities
      ok(DayOfWeek instanceof Enum);
      ok(Enum.isSymbol(DayOfWeek.Wednesday));
      ok(DayOfWeek.contains(DayOfWeek.Thursday));
      ok(DayOfWeek.Tuesday.parentEnum == DayOfWeek);
      ok(DayOfWeek.getSymbols().length === 7);
      ok(DayOfWeek.Friday.toString() === "Friday");


  @class Enum
  **/

  /**
  Enum constructor - may be used to create new Enums.
  @example
      var prototype = {
          nextDay: function () {
              var nextIndex = (this.dayIndex+1) % 7;
              return DayOfWeek.getSymbols()[nextIndex];
          }
      };

      var DayOfWeek = new Enum("DayOfWeek", prototype);
  @method <ctor> Enum
  @param name {String}
  @param [methodObj] {Object}
  **/

  var ctor = function Enum(name, methodObj) {
    this.name = name;
    var prototype = new EnumSymbol(methodObj);
    prototype.parentEnum = this;
    this._symbolPrototype = prototype;
    if (methodObj) {
      Object.keys(methodObj).forEach(function (key) {
        prototype[key] = methodObj[key];
      });
    }
  };
  var proto = ctor.prototype;

  /**
  Checks if an object is an Enum 'symbol'.
  @example
      if (Enum.isSymbol(DayOfWeek.Wednesday)) {
        // do something ...
      };
  @method isSymbol
  @return {Boolean}
  @static
  **/
  ctor.isSymbol = function (obj) {
    return obj instanceof EnumSymbol;
  };

  /**
  Returns an Enum symbol given its name.
  @example
      var dayOfWeek = DayOfWeek.from("Thursday");
      // nowdayOfWeek === DayOfWeek.Thursday
  @method fromName
  @param name {String} Name for which an enum symbol should be returned.
  @return {EnumSymbol} The symbol that matches the name or 'undefined' if not found.
  **/
  proto.fromName = function (name) {
    return this[name];
  };

  /**
  Adds a new symbol to an Enum.
  @example
      var DayOfWeek = new Enum("DayOfWeek", prototype);
      DayOfWeek.Monday    = DayOfWeek.addSymbol( { dayIndex: 0 });
  @method addSymbol
  @param [propertiesObj] {Object} A collection of properties that should be added to the new symbol.
  In other words, the 'propertiesObj' is any state that should be held by the symbol.
  @return {EnumSymbol} The new symbol
  **/
  proto.addSymbol = function (propertiesObj) {
    // TODO: check if sealed.
    var newSymbol = Object.create(this._symbolPrototype);
    if (propertiesObj) {
      Object.keys(propertiesObj).forEach(function (key) {
        newSymbol[key] = propertiesObj[key];
      });
    }
    setTimeout(function () {
      newSymbol.getName();
    }, 0);
    return newSymbol;
  };

  /**
  Seals this enum so that no more symbols may be added to it. This should only be called after all symbols
  have already been added to the Enum.
  @example
      DayOfWeek.resolveSymbols();
  @method resolveSymbols
  **/
  proto.resolveSymbols = function () {
    this.getSymbols().forEach(function (sym) {
      return sym.getName();
    });
  };

  //// TODO: remove or rethink this.
  //Enum.prototype.combineSymbols = function () {
  //    var proto = this._symbolPrototype;
  //    var newSymbol = Object.create(proto);
  //    newSymbol._symbols = __arraySlice(arguments);

  //    Object.keys(proto).forEach(function (key) {
  //        var result;
  //        var oldMethod = proto[key];
  //        if (__isFunction(oldMethod)) {
  //            var newMethod = function () {

  //                if (this._symbols) {
  //                    result = this._symbols.map(function (sym) {
  //                        return oldMethod.apply(sym);
  //                    });
  //                } else {
  //                    result = oldMethod.apply(this);
  //                }
  //                return result;
  //            };
  //            proto[key] = newMethod;
  //        }
  //    });
  //    return newSymbol;
  //};

  /**
  Returns all of the symbols contained within this Enum.
  @example
      var symbols = DayOfWeek.getSymbols();
  @method getSymbols
  @return {Array of EnumSymbol} All of the symbols contained within this Enum.
  **/
  proto.getSymbols = function () {
    return this.getNames().map(function (key) {
      return this[key];
    }, this);
  };

  /**
  Returns the names of all of the symbols contained within this Enum.
  @example
      var symbols = DayOfWeek.getNames();
  @method getNames
  @return {Array of String} All of the names of the symbols contained within this Enum.
  **/
  proto.getNames = function () {
    var result = [];
    for (var key in this) {
      if (this.hasOwnProperty(key)) {
        if (key !== "name" && key.substr(0, 1) !== "_" && !__isFunction(this[key])) {
          result.push(key);
        }
      }
    }
    return result;
  };

  /**
  Returns whether an Enum contains a specified symbol.
  @example
      var symbol = DayOfWeek.Friday;
      if (DayOfWeek.contains(symbol)) {
          // do something
      }
  @method contains
  @param {Object} Object or symbol to test.
  @return {Boolean} Whether this Enum contains the specified symbol.
  **/
  proto.contains = function (sym) {
    if (!(sym instanceof EnumSymbol)) {
      return false;
    }
    return this[sym.getName()] === sym;
  };

  /**
  One of the constant values that is generated by the {{#crossLink "Enum"}}{{/crossLink}} "addSymbol" method.  EnumSymbols should ONLY be created via
  the Enum.addSymbol method.
  @example
      var DayOfWeek = new Enum("DayOfWeek");
      DayOfWeek.Monday    = DayOfWeek.addSymbol();
  @class EnumSymbol
  **/

  function EnumSymbol() {
  }

  /**
  The {{#crossLink "Enum"}}{{/crossLink}} to which this symbol belongs.
  __readOnly__
  @property parentEnum {Enum}
  **/

  /**
  Returns the name of this symbol.
  @example
      var name = DayOfWeek.Monday.getName();
      // name === "Monday"
  @method getName
  **/
  EnumSymbol.prototype.getName = function () {
    if (!this.name) {
      var that = this;
      this.name = __arrayFirst(this.parentEnum.getNames(), function (name) {
        return that.parentEnum[name] === that;
      });
    }
    return this.name;
  };

  /**
  Same as the getName method. Returns the name of this symbol.
  @example
      var name = DayOfWeek.Monday.toString();
      // name === "Monday"
  @method toString
  **/
  EnumSymbol.prototype.toString = function () {
    return this.getName();
  };

  EnumSymbol.prototype.toJSON = function () {
    return {
      _$typeName: this.parentEnum.name,
      name: this.name
    };
  };

  return ctor;
})();
core.Enum = Enum;


;/**
@module core
**/

var Event = (function () {

  var __eventNameMap = {};
  var __nextUnsubKey = 1;

  /**
  Class to support basic event publication and subscription semantics.
  @class Event
  **/

  /**
  Constructor for an Event
  @example
      salaryEvent = new Event("salaryEvent", person);
  @method <ctor> Event
  @param name {String}
  @param publisher {Object} The object that will be doing the publication. i.e. the object to which this event is attached.
  @param [defaultErrorCallback] {Function} If omitted then subscriber notification failures will be ignored.

  errorCallback([e])
  @param [defaultErrorCallback.e] {Error} Any error encountered during subscription execution.
  **/

  var ctor = function Event(name, publisher, defaultErrorCallback) {
    assertParam(name, "eventName").isNonEmptyString().check();
    assertParam(publisher, "publisher").isObject().check();

    this.name = name;
    // register the name
    __eventNameMap[name] = true;
    this.publisher = publisher;
    if (defaultErrorCallback) {
      this._defaultErrorCallback = defaultErrorCallback;
    }
  };
  var proto = ctor.prototype;

  /**
  Publish data for this event.
  @example
      // Assume 'salaryEvent' is previously constructed Event
      salaryEvent.publish( { eventType: "payRaise", amount: 100 });
  This event can also be published asychronously
  @example
      salaryEvent.publish( { eventType: "payRaise", amount: 100 }, true);
  And we can add a handler in case the subscriber 'mishandles' the event.
  @example
      salaryEvent.publish( { eventType: "payRaise", amount: 100 }, true, function(error) {
          // do something with the 'error' object
      });
  @method publish
  @param data {Object} Data to publish
  @param [publishAsync=false] {Boolean} Whether to publish asynchonously or not.
  @param [errorCallback] {Function} Will be called for any errors that occur during publication. If omitted,
  errors will be eaten.

  errorCallback([e])
  @param [errorCallback.e] {Error} Any error encountered during publication execution.
  @return {Boolean} false if event is disabled; true otherwise.
  **/
  proto.publish = function (data, publishAsync, errorCallback) {

    if (!ctor._isEnabled(this.name, this.publisher)) return false;

    if (publishAsync === true) {
      setTimeout(publishCore, 0, this, data, errorCallback);
    } else {
      publishCore(this, data, errorCallback);
    }
    return true;
  };

  function publishCore(that, data, errorCallback) {
    var subscribers = that._subscribers;
    if (!subscribers) return true;
    // subscribers from outer scope.
    subscribers.forEach(function (s) {
      try {
        s.callback(data);
      } catch (e) {
        e.context = "unable to publish on topic: " + that.name;
        if (errorCallback) {
          errorCallback(e);
        } else if (that._defaultErrorCallback) {
          that._defaultErrorCallback(e);
        } else {
          fallbackErrorHandler(e);
        }
      }
    });
  }

  /**
  Publish data for this event asynchronously.
  @example
      // Assume 'salaryEvent' is previously constructed Event
      salaryEvent.publishAsync( { eventType: "payRaise", amount: 100 });
  And we can add a handler in case the subscriber 'mishandles' the event.
  @example
      salaryEvent.publishAsync( { eventType: "payRaise", amount: 100 }, function(error) {
          // do something with the 'error' object
      });
  @method publishAsync
  @param data {Object} Data to publish
  @param [errorCallback] {Function} Will be called for any errors that occur during publication. If omitted,
  errors will be eaten.

  errorCallback([e])
  @param [errorCallback.e] {Error} Any error encountered during publication execution.
  **/
  proto.publishAsync = function (data, errorCallback) {
    this.publish(data, true, errorCallback);
  };

  /**
  Subscribe to this event.
  @example
      // Assume 'salaryEvent' is previously constructed Event
      salaryEvent.subscribe(function (eventArgs) {
          if (eventArgs.eventType === "payRaise") {
              // do something
          }
      });
  There are several built in Breeze events, such as EntityAspect.propertyChanged, EntityAspect.validationErrorsChanged as well.
  @example
      // Assume order is a preexisting 'order' entity
      order.entityAspect.propertyChanged.subscribe(function (pcEvent) {
          if ( pcEvent.propertyName === "OrderDate") {
              // do something
          }
      });
  @method subscribe
  @param [callback] {Function} Will be called whenever 'data' is published for this event.

  callback([data])
  @param [callback.data] {Object} Whatever 'data' was published.  This should be documented on the specific event.
  @return {Number} This is a key for 'unsubscription'.  It can be passed to the 'unsubscribe' method.
  **/
  proto.subscribe = function (callback) {
    if (!this._subscribers) {
      this._subscribers = [];
    }

    var unsubKey = __nextUnsubKey;
    this._subscribers.push({ unsubKey: unsubKey, callback: callback });
    ++__nextUnsubKey;
    return unsubKey;
  };

  /**
  Unsubscribe from this event.
  @example
      // Assume order is a preexisting 'order' entity
      var token = order.entityAspect.propertyChanged.subscribe(function (pcEvent) {
              // do something
      });
      // sometime later
      order.entityAspect.propertyChanged.unsubscribe(token);
  @method unsubscribe
  @param unsubKey {Number} The value returned from the 'subscribe' method may be used to unsubscribe here.
  @return {Boolean} Whether unsubscription occured. This will return false if already unsubscribed or if the key simply
  cannot be found.
  **/
  proto.unsubscribe = function (unsubKey) {
    if (!this._subscribers) return false;
    var subs = this._subscribers;
    var ix = __arrayIndexOf(subs, function (s) {
      return s.unsubKey === unsubKey;
    });
    if (ix !== -1) {
      subs.splice(ix, 1);
      if (subs.length === 0) {
        this._subscribers = null;
      }
      return true;
    } else {
      return false;
    }
  };

  proto.clear = function () {
    this._subscribers = null;
  };

  // event bubbling - document later.
  ctor.bubbleEvent = function (target, getParentFn) {
    target._getEventParent = getParentFn;
  };

  /**
  Enables or disables the named event for an object and all of its children.
  @example
      Event.enable(“propertyChanged”, myEntityManager, false)
  will disable all EntityAspect.propertyChanged events within a EntityManager.
  @example
      Event.enable(“propertyChanged”, myEntityManager, true)
  will enable all EntityAspect.propertyChanged events within a EntityManager.
  @example
      Event.enable(“propertyChanged”, myEntity.entityAspect, false)
  will disable EntityAspect.propertyChanged events for a specific entity.
  @example
      Event.enable(“propertyChanged”, myEntity.entityAspect, null)
  will removes any enabling / disabling at the entity aspect level so now any 'Event.enable' calls at the EntityManager level,
  made either previously or in the future, will control notification.
  @example
      Event.enable(“validationErrorsChanged”, myEntityManager, function(em) {
          return em.customTag === “blue”;
      })
  will either enable or disable myEntityManager based on the current value of a ‘customTag’ property on myEntityManager.
  Note that this is dynamic, changing the customTag value will cause events to be enabled or disabled immediately.
  @method enable
  @static
  @param eventName {String} The name of the event.
  @param target {Object} The object at which enabling or disabling will occur.  All event notifications that occur to this object or
  children of this object will be enabled or disabled.
  @param isEnabled {Boolean|null|Function} A boolean, a null or a function that returns either a boolean or a null.
  **/
  ctor.enable = function (eventName, obj, isEnabled) {
    assertParam(eventName, "eventName").isNonEmptyString().check();
    assertParam(obj, "obj").isObject().check();
    assertParam(isEnabled, "isEnabled").isBoolean().isOptional().or().isFunction().check();
    if (!obj._$eventMap) {
      obj._$eventMap = {};
    }
    obj._$eventMap[eventName] = isEnabled;
  };


  /**
  Returns whether for a specific event and a specific object and its children, notification is enabled or disabled or not set.
  @example
      Event.isEnabled(“propertyChanged”, myEntityManager)

  @method isEnabled
  @static
  @param eventName {String} The name of the event.
  @param target {Object} The object for which we want to know if notifications are enabled.
  @return {Boolean|null} A null is returned if this value has not been set.
  **/
  ctor.isEnabled = function (eventName, obj) {
    assertParam(eventName, "eventName").isNonEmptyString().check();
    assertParam(obj, "obj").isObject().check();
    // null is ok - it just means that the object is at the top level.
    if (obj._getEventParent === undefined) {
      throw new Error("This object does not support event enabling/disabling");
    }
    // return ctor._isEnabled(getFullEventName(eventName), obj);
    return ctor._isEnabled(eventName, obj);
  };

  ctor._isEnabled = function (eventName, obj) {
    var isEnabled = null;
    var eventMap = obj._$eventMap;
    if (eventMap) {
      isEnabled = eventMap[eventName];
    }
    if (isEnabled != null) {
      if (typeof isEnabled === 'function') {
        return isEnabled(obj);
      } else {
        return !!isEnabled;
      }
    } else {
      var parent = obj._getEventParent && obj._getEventParent();
      if (parent) {
        return ctor._isEnabled(eventName, parent);
      } else {
        // default if not explicitly disabled.
        return true;
      }
    }
  };

  function fallbackErrorHandler(e) {
    // TODO: maybe log this
    // for now do nothing;
  }

  return ctor;

})();

core.Event = Event;;/**
@module breeze
**/

var __config = (function () {

  // alias for within fns with a config param
  var __config = {};

  __config.functionRegistry = {};
  __config.typeRegistry = {};
  __config.objectRegistry = {};
  __config.interfaceInitialized = new Event("interfaceInitialized", __config);

  var InterfaceDef = function (name) {
    this.name = name;
    this.defaultInstance = null;
    this._implMap = {};
  };

  InterfaceDef.prototype.registerCtor = function (adapterName, ctor) {
    this._implMap[adapterName.toLowerCase()] = { ctor: ctor, defaultInstance: null };
  };
  InterfaceDef.prototype.getImpl = function (adapterName) {
    return this._implMap[adapterName.toLowerCase()];
  };
  InterfaceDef.prototype.getFirstImpl = function () {
    var kv = __objectFirst(this._implMap, function () {
      return true;
    });
    return kv ? kv.value : null;
  };

  __config.interfaceRegistry = {
    ajax: new InterfaceDef("ajax"),
    modelLibrary: new InterfaceDef("modelLibrary"),
    dataService: new InterfaceDef("dataService"),
    uriBuilder: new InterfaceDef("uriBuilder")
  };

  __config.interfaceRegistry.modelLibrary.getDefaultInstance = function () {
    if (!this.defaultInstance) {
      throw new Error("Unable to locate the default implementation of the '" + this.name +
          "' interface.  Possible options are 'ko', 'backingStore' or 'backbone'. See the breeze.config.initializeAdapterInstances method.");
    }
    return this.defaultInstance;
  };

  /**
  A singleton object that is the repository of all configuration options.
  @example
      config.initializeAdapterInstance( {
          modelLibrary: "ko",
          dataService: "webApi"
      });

  @class config
  **/

  /**
  This method is now OBSOLETE.  Use the "initializeAdapterInstances" to accomplish the same result.
  @method setProperties
  @deprecated
  @param config {Object}
  @param [config.remoteAccessImplementation] { implementation of remoteAccess-interface }
  @param [config.trackingImplementation] { implementation of entityTracking-interface }
  @param [config.ajaxImplementation] {implementation of ajax-interface }
  **/
  __config.setProperties = function (config) {
    assertConfig(config)
        .whereParam("remoteAccessImplementation").isOptional()
        .whereParam("trackingImplementation").isOptional()
        .whereParam("ajaxImplementation").isOptional()
        .applyAll(config);
    if (config.remoteAccessImplementation) {
      __config.initializeAdapterInstance("dataService", config.remoteAccessImplementation);
    }
    if (config.trackingImplementation) {
      // note the name change
      __config.initializeAdapterInstance("modelLibrary", config.trackingImplementation);
    }
    if (config.ajaxImplementation) {
      __config.initializeAdapterInstance("ajax", config.ajaxImplementation);
    }
  };

  /**
  Method use to register implementations of standard breeze interfaces.  Calls to this method are usually
  made as the last step within an adapter implementation.
  @method registerAdapter
  @param interfaceName {String} - one of the following interface names "ajax", "dataService" or "modelLibrary"
  @param adapterCtor {Function} - an ctor function that returns an instance of the specified interface.
  **/
  __config.registerAdapter = function (interfaceName, adapterCtor) {
    assertParam(interfaceName, "interfaceName").isNonEmptyString().check();
    assertParam(adapterCtor, "adapterCtor").isFunction().check();
    // this impl will be thrown away after the name is retrieved.
    var impl = new adapterCtor();
    var implName = impl.name;
    if (!implName) {
      throw new Error("Unable to locate a 'name' property on the constructor passed into the 'registerAdapter' call.");
    }
    var idef = getInterfaceDef(interfaceName);
    idef.registerCtor(implName, adapterCtor);

  };

  /**
  Returns the ctor function used to implement a specific interface with a specific adapter name.
  @method getAdapter
  @param interfaceName {String} One of the following interface names "ajax", "dataService" or "modelLibrary"
  @param [adapterName] {String} The name of any previously registered adapter. If this parameter is omitted then
  this method returns the "default" adapter for this interface. If there is no default adapter, then a null is returned.
  @return {Function|null} Returns either a ctor function or null.
  **/
  __config.getAdapter = function (interfaceName, adapterName) {
    var idef = getInterfaceDef(interfaceName);
    if (adapterName) {
      var impl = idef.getImpl(adapterName);
      return impl ? impl.ctor : null;
    } else {
      return idef.defaultInstance ? idef.defaultInstance._$impl.ctor : null;
    }
  };

  /**
  Initializes a collection of adapter implementations and makes each one the default for its corresponding interface.
  @method initializeAdapterInstances
  @param config {Object}
  @param [config.ajax] {String} - the name of a previously registered "ajax" adapter
  @param [config.dataService] {String} - the name of a previously registered "dataService" adapter
  @param [config.modelLibrary] {String} - the name of a previously registered "modelLibrary" adapter
  @param [config.uriBuilder] {String} - the name of a previously registered "uriBuilder" adapter
  @return [array of instances]
  **/
  __config.initializeAdapterInstances = function (config) {
    assertConfig(config)
        .whereParam("dataService").isOptional()
        .whereParam("modelLibrary").isOptional()
        .whereParam("ajax").isOptional()
        .whereParam("uriBuilder").isOptional()
        .applyAll(this, false);
    return __objectMap(config, __config.initializeAdapterInstance);

  };

  /**
  Initializes a single adapter implementation. Initialization means either newing a instance of the
  specified interface and then calling "initialize" on it or simply calling "initialize" on the instance
  if it already exists.
  @method initializeAdapterInstance
  @param interfaceName {String} The name of the interface to which the adapter to initialize belongs.
  @param adapterName {String} - The name of a previously registered adapter to initialize.
  @param [isDefault=true] {Boolean} - Whether to make this the default "adapter" for this interface.
  @return {an instance of the specified adapter}
  **/
  __config.initializeAdapterInstance = function (interfaceName, adapterName, isDefault) {
    isDefault = isDefault === undefined ? true : isDefault;
    assertParam(interfaceName, "interfaceName").isNonEmptyString().check();
    assertParam(adapterName, "adapterName").isNonEmptyString().check();
    assertParam(isDefault, "isDefault").isBoolean().check();

    var idef = getInterfaceDef(interfaceName);
    var impl = idef.getImpl(adapterName);
    if (!impl) {
      throw new Error("Unregistered adapter.  Interface: " + interfaceName + " AdapterName: " + adapterName);
    }

    return initializeAdapterInstanceCore(idef, impl, isDefault);
  };

  /**
  Returns the adapter instance corresponding to the specified interface and adapter names.
  @method getAdapterInstance
  @param interfaceName {String} The name of the interface.
  @param [adapterName] {String} - The name of a previously registered adapter.  If this parameter is
  omitted then the default implementation of the specified interface is returned. If there is
  no defaultInstance of this interface, then the first registered instance of this interface is returned.
  @return {an instance of the specified adapter}
  **/
  __config.getAdapterInstance = function (interfaceName, adapterName) {
    var idef = getInterfaceDef(interfaceName);
    var impl;

    var isDefault = adapterName == null || adapterName == "";
    if (isDefault) {
      if (idef.defaultInstance) return idef.defaultInstance;
      impl = idef.getFirstImpl();
    } else {
      impl = idef.getImpl(adapterName);
    }
    if (!impl) return null;
    if (impl.defaultInstance) {
      return impl.defaultInstance;
    } else {
      return initializeAdapterInstanceCore(idef, impl, isDefault);
    }
  };

  // this is needed for reflection purposes when deserializing an object that needs a fn or ctor
  // used to register validators.
  __config.registerFunction = function (fn, fnName) {
    assertParam(fn, "fn").isFunction().check();
    assertParam(fnName, "fnName").isString().check();
    fn.prototype._$fnName = fnName;
    __config.functionRegistry[fnName] = fn;
  };

  __config.getRegisteredFunction = function (fnName) {
    return __config.functionRegistry[fnName];
  };

  __config._storeObject = function (obj, type, name) {
    // uncomment this if we make this public.
    //assertParam(obj, "obj").isObject().check();
    //assertParam(name, "objName").isString().check();
    var key = (typeof(type) === "string" ? type : type.prototype._$typeName) + "." + name;
    __config.objectRegistry[key] = obj;
  };

  __config._fetchObject = function (type, name) {
    if (!name) return undefined;
    var key = (typeof(type) === "string" ? type : type.prototype._$typeName) + "." + name;
    var result = __config.objectRegistry[key];
    if (!result) {
      throw new Error("Unable to locate a registered object by the name: " + key);
    }
    return result;
  };

  __config.registerType = function (ctor, typeName) {
    assertParam(ctor, "ctor").isFunction().check();
    assertParam(typeName, "typeName").isString().check();
    ctor.prototype._$typeName = typeName;
    __config.typeRegistry[typeName] = ctor;
  };

  __config.stringifyPad = '';

  function initializeAdapterInstanceCore(interfaceDef, impl, isDefault) {
    var instance = impl.defaultInstance;
    if (!instance) {
      instance = new (impl.ctor)();
      impl.defaultInstance = instance;
      instance._$impl = impl;
    }

    instance.initialize();

    if (isDefault) {
      // next line needs to occur before any recomposition
      interfaceDef.defaultInstance = instance;
    }

    // recomposition of other impls will occur here.
    __config.interfaceInitialized.publish({ interfaceName: interfaceDef.name, instance: instance, isDefault: true });

    if (instance.checkForRecomposition) {
      // now register for own dependencies.
      __config.interfaceInitialized.subscribe(function (interfaceInitializedArgs) {
        instance.checkForRecomposition(interfaceInitializedArgs);
      });
    }

    return instance;
  }

  function getInterfaceDef(interfaceName) {
    var lcName = interfaceName.toLowerCase();
    // source may be null
    var kv = __objectFirst(__config.interfaceRegistry || {}, function (k, v) {
      return k.toLowerCase() === lcName;
    });
    if (!kv) {
      throw new Error("Unknown interface name: " + interfaceName);
    }
    return kv.value;
  }

  return __config;
})();

var __modelLibraryDef = __config.interfaceRegistry.modelLibrary;

// legacy
core.config = __config;

breeze.config = __config;;var observableArray = (function () {

  var mixin = {};
  mixin.push = function () {
    if (this._inProgress) {
      return -1;
    }

    var goodAdds = this._getGoodAdds(__arraySlice(arguments));
    if (!goodAdds.length) {
      return this.length;
    }
    this._beforeChange();
    var result = Array.prototype.push.apply(this, goodAdds);
    processAdds(this, goodAdds);
    return result;
  };

  mixin._push = function () {
    if (this._inProgress) {
      return -1;
    }
    var goodAdds = __arraySlice(arguments);
    this._beforeChange();
    var result = Array.prototype.push.apply(this, goodAdds);
    processAdds(this, goodAdds);
    return result;
  };

  mixin.unshift = function () {
    var goodAdds = this._getGoodAdds(__arraySlice(arguments));
    if (!goodAdds.length) {
      return this.length;
    }
    this._beforeChange();
    var result = Array.prototype.unshift.apply(this, goodAdds);
    processAdds(this, __arraySlice(goodAdds));
    return result;
  };

  mixin.pop = function () {
    this._beforeChange();
    var result = Array.prototype.pop.apply(this);
    processRemoves(this, [result]);
    return result;
  };

  mixin.shift = function () {
    this._beforeChange();
    var result = Array.prototype.shift.apply(this);
    processRemoves(this, [result]);
    return result;
  };

  mixin.splice = function () {
    var goodAdds = this._getGoodAdds(__arraySlice(arguments, 2));
    var newArgs = __arraySlice(arguments, 0, 2).concat(goodAdds);
    this._beforeChange();
    var result = Array.prototype.splice.apply(this, newArgs);
    processRemoves(this, result);

    if (goodAdds.length) {
      processAdds(this, goodAdds);
    }
    return result;
  };

  mixin.getEntityAspect = function () {
    return this.parent.entityAspect || this.parent.complexAspect.getEntityAspect();
  }

  mixin._getEventParent = function () {
    return this.getEntityAspect();
  };

  mixin._getPendingPubs = function () {
    var em = this.getEntityAspect().entityManager;
    return em && em._pendingPubs;
  };

  mixin._beforeChange = function () {
    // default is to do nothing
  };

  function updateEntityState(obsArray) {
    var entityAspect = obsArray.getEntityAspect();
    if (entityAspect.entityState.isUnchanged()) {
      entityAspect.setModified();
    }
    if (entityAspect.entityState.isModified() && !obsArray._origValues) {
      obsArray._origValues = obsArray.slice(0);
    }
  }

  function processAdds(obsArray, adds) {
    obsArray._processAdds(adds);
    // this is referencing the name of the method on the complexArray not the name of the event
    //var args = { added: adds };
    //args[obsArray._typeName] = obsArray;
    publish(obsArray, "arrayChanged", { array: obsArray, added: adds });
  }

  function processRemoves(obsArray, removes) {
    obsArray._processRemoves(removes);
    // this is referencing the name of the method on the array not the name of the event
    publish(obsArray, "arrayChanged", { array: obsArray, removed: removes });
  }

  function publish(publisher, eventName, eventArgs) {
    var pendingPubs = publisher._getPendingPubs();
    if (pendingPubs) {
      if (!publisher._pendingArgs) {
        publisher._pendingArgs = eventArgs;
        pendingPubs.push(function () {
          publisher[eventName].publish(publisher._pendingArgs);
          publisher._pendingArgs = null;
        });
      } else {
        combineArgs(publisher._pendingArgs, eventArgs);
      }
    } else {
      publisher[eventName].publish(eventArgs);
    }
  }

  function combineArgs(target, source) {
    for (var key in source) {
      if (key !== "array" && target.hasOwnProperty(key)) {
        var sourceValue = source[key];
        var targetValue = target[key];
        if (targetValue) {
          if (!Array.isArray(targetValue)) {
            throw new Error("Cannot combine non array args");
          }
          Array.prototype.push.apply(targetValue, sourceValue);
        } else {
          target[key] = sourceValue;
        }
      }
    }
  }

  function initializeParent(obsArray, parent, parentProperty) {
    obsArray.parent = parent;
    obsArray.parentProperty = parentProperty;
  }


  return {
    mixin: mixin,
    publish: publish,
    updateEntityState: updateEntityState,
    initializeParent: initializeParent
  };


})();;/**
@module breeze
**/

var Validator = (function () {

  var INT16_MIN = -32768;
  var INT16_MAX = 32767;

  var INT32_MIN = -2147483648;
  var INT32_MAX = 2147483647;

  var BYTE_MIN = 0;
  var BYTE_MAX = 255;

  // add common props and methods for every validator 'context' here.
  var rootContext = {
    displayName: function (context) {
      if (context.property) {
        return context.property.resolveProperty("displayName") || context.propertyName || context.property.name;
      } else {
        return "Value";
      }
    }
  };

  /**
  Instances of the Validator class provide the logic to validate another object and provide a description of any errors
  encountered during the validation process.  They are typically associated with a 'validators' property on the following types: {{#crossLink "EntityType"}}{{/crossLink}},
  {{#crossLink "DataProperty"}}{{/crossLink}} or {{#crossLink "NavigationProperty"}}{{/crossLink}}.

  A number of property level validators are registered automatically, i.e added to each DataProperty.validators property
  based on {{#crossLink "DataProperty"}}{{/crossLink}} metadata.  For example,

  - DataProperty.dataType -> one of the 'dataType' validator methods such as Validator.int64, Validator.date, Validator.bool etc.
  - DataProperty.maxLength -> Validator.maxLength
  - DataProperty.isNullable -> Validator.required (if not nullable)

  @class Validator
  **/

  /**
  Validator constructor - This method is used to create create custom validations.  Several
  basic "Validator" construction methods are also provided as static methods to this class. These methods
  provide a simpler syntax for creating basic validations.

  Many of these stock validators are inspired by and implemented to conform to the validators defined at
  http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.aspx

  Sometimes a custom validator will be required.
  @example
  Most validators will be 'property' level validators, like this.
  @example
      // v is this function is the value to be validated, in this case a "country" string.
      var valFn = function (v) {
          if (v == null) return true;
          return (core.stringStartsWith(v, "US"));
      };
      var countryValidator = new Validator("countryIsUS", valFn, {
          displayName: "Country", 
          messageTemplate: "'%displayName%' must start with 'US'" 
      });

      // Now plug it into Breeze.
      // Assume em1 is a preexisting EntityManager.
      var custType = metadataStore.getEntityType("Customer");
      var countryProp = custType.getProperty("Country");
      // Note that validator is added to a 'DataProperty' validators collection.
      prop.validators.push(countryValidator);
  Entity level validators are also possible
  @example
      function isValidZipCode(value) {
          var re = /^\d{5}([\-]\d{4})?$/;
          return (re.test(value));
      }

      // v in this case will be a Customer entity
      var valFn = function (v) {
          // This validator only validates US Zip Codes.
          if ( v.getProperty("Country") === "USA") {
              var postalCode = v.getProperty("PostalCode");
              return isValidZipCode(postalCode);
          }
          return true;
      };
      var zipCodeValidator = new Validator("zipCodeValidator", valFn,
          { messageTemplate: "For the US, this is not a valid PostalCode" });

      // Now plug it into Breeze.
      // Assume em1 is a preexisting EntityManager.
      var custType = em1.metadataStore.getEntityType("Customer");
      // Note that validator is added to an 'EntityType' validators collection.
      custType.validators.push(zipCodeValidator);
  What is commonly needed is a way of creating a parameterized function that will itself
  return a new Validator.  This requires the use of a 'context' object.
  @example
      // create a function that will take in a config object
      // and will return a validator
      var numericRangeValidator = function(context) {
          var valFn = function(v, ctx) {
              if (v == null) return true;
              if (typeof(v) !== "number") return false;
              if (ctx.min != null && v < ctx.min) return false;
              if (ctx.max != null && v > ctx.max) return false;
              return true;
          };
          // The last parameter below is the 'context' object that will be passed into the 'ctx' parameter above
          // when this validator executes. Several other properties, such as displayName will get added to this object as well.
          return new Validator("numericRange", valFn, {
              messageTemplate: "'%displayName%' must be a number between the values of %min% and %max%",
              min: context.min,
              max: context.max
          });
      };
      // Assume that freightProperty is a DataEntityProperty that describes numeric values.
      // register the validator
      freightProperty.validators.push(numericRangeValidator({ min: 100, max: 500 }));

  Breeze substitutes context values and functions for the tokens in the messageTemplate when preparing the runtime error message;
  'displayName' is a pre-defined context function that is always available.

  Please note that Breeze substitutes the empty string for falsey parameters. That usually works in your favor.
  Sometimes it doesn't as when the 'min' value is zero in which case the message text would have a hole
  where the 'min' value goes, saying: "... an integer between the values of and ...". That is not what you want.

  To avoid this effect, you may can bake certain of the context values into the 'messageTemplate' itself
  as shown in this revision to the pertinent part of the previous example:
  @example
      // ... as before
      // ... but bake the min/max values into the message template.
      var template = breeze.core.formatString(
          "'%displayName%' must be a number between the values of %1 and %2",
          context.min, context.max);
      return new Validator("numericRange", valFn, {
          messageTemplate: template,
          min: context.min,
          max: context.max
      });

  @method <ctor> Validator
  @param name {String} The name of this validator.
  @param validatorFn {Function} A function to perform validation.

  validatorFn(value, context)
  @param validatorFn.value {Object} Value to be validated
  @param validatorFn.context {Object} The same context object passed into the constructor with the following additional properties if not
  otherwise specified.
  @param validatorFn.context.value {Object} The value being validated.
  @param validatorFn.context.name {String} The name of the validator being executed.
  @param validatorFn.context.displayName {String} This will be either the value of the property's 'displayName' property or
  the value of its 'name' property or the string 'Value'
  @param validatorFn.context.messageTemplate {String} This will either be the value of Validator.messageTemplates[ {this validators name}] or null. Validator.messageTemplates
  is an object that is keyed by validator name and that can be added to in order to 'register' your own message for a given validator.
  The following property can also be specified for any validator to force a specific errorMessage string
  @param [validatorFn.context.message] {String} If this property is set it will be used instead of the 'messageTemplate' property when an
  error message is generated.

  @param [context] {Object} A free form object whose properties will made available during the validation and error message creation process.
  This object will be passed into the Validator's validation function whenever 'validate' is called. See above for a description
  of additional properties that will be automatically added to this object if not otherwise specified.
  **/
  var ctor = function Validator(name, valFn, context) {
    // _baseContext is what will get serialized
    this._baseContext = context || {};
    this._baseContext.name = name;
    context = __extend(Object.create(rootContext), this._baseContext);
    context.messageTemplate = context.messageTemplate || ctor.messageTemplates[name];
    this.name = name;
    this.valFn = valFn;
    this.context = context;
  };
  var proto = ctor.prototype;
  proto._$typeName = "Validator";

  /**
  The name of this validator.

  __readOnly__
  @property name {String}
  **/

  /**
  The context for this validator.

  This object will typically contain at a minimum the following properties. "name", "displayName", and "message" or "messageTemplate".
  __readOnly__
  @property context {Object}
  **/


  /**
  Run this validator against the specified value.  This method will usually be called internally either
  automatically by an property change, entity attach, query or save operation, or manually as a result of
  a validateEntity call on the EntityAspect. The resulting ValidationResults are available via the
  EntityAspect.getValidationErrors method.

  However, you can also call a validator directly either for testing purposes or some other reason if needed.
  @example
      // using one of the predefined validators
      var validator = Validator.maxLength({ maxLength: 5, displayName: "City" });
      // should be ok because "asdf".length < 5
      var result = validator.validate("asdf");
      ok(result === null);
      result = validator.validate("adasdfasdf");
      // extract all of the properties of the 'result'
      var errMsg = result.errorMessage;
      var context = result.context;
      var sameValidator = result.validator;
  @method validate
  @param value {Object} Value to validate
  @param additionalContext {Object} Any additional contextual information that the Validator
  can make use of.
  @return {ValidationError|null} A ValidationError if validation fails, null otherwise
  **/
  proto.validate = function (value, additionalContext) {
    var currentContext;
    if (additionalContext) {
      currentContext = __extend(Object.create(this.context), additionalContext);
    } else {
      currentContext = this.context;
    }
    this.currentContext = currentContext;

    try {
      if (this.valFn(value, currentContext)) {
        return null;
      } else {
        currentContext.value = value;
        return new ValidationError(this, currentContext, this.getMessage());
      }
    } catch (e) {
      return new ValidationError(this, currentContext, "Exception occured while executing this validator: " + this.name);
    }
  };


  // context.value is not avail unless validate was called first.

  /**
  Returns the message generated by the most recent execution of this Validator.
  @example
      var v0 = Validator.maxLength({ maxLength: 5, displayName: "City" });
      v0.validate("adasdfasdf");
      var errMessage = v0.getMessage());
  @method getMessage
  @return {String}
  **/
  proto.getMessage = function () {
    try {
      var context = this.currentContext;
      var message = context.message;
      if (message) {
        if (typeof (message) === "function") {
          return message(context);
        } else {
          return message;
        }
      } else if (context.messageTemplate) {
        return formatTemplate(context.messageTemplate, context);
      } else {
        return "invalid value: " + (this.name || "{unnamed validator}");
      }
    } catch (e) {
      return "Unable to format error message" + e.toString();
    }
  };

  proto.toJSON = function () {
    return this._baseContext;
  };

  /**
  Creates a validator instance from a JSON object or an array of instances from an array of JSON objects.
  @method fromJSON
  @static
  @param json {Object} JSON object that represents the serialized version of a validator.
  **/
  ctor.fromJSON = function (json) {
    if (Array.isArray(json)) {
      return json.map(function (js) {
        return ctor.fromJSON(js);
      });
    }
    ;
    var validatorName = "Validator." + json.name;
    var fn = __config.getRegisteredFunction(validatorName);
    if (!fn) {
      throw new Error("Unable to locate a validator named:" + json.name);
    }
    return fn(json);
  };

  /**
  Register a validator instance so that any deserialized metadata can reference it.
  @method register
  @static
  @param validator {Validator} Validator to register.
  **/
  ctor.register = function (validator) {
    __config.registerFunction(function () {
      return validator;
    }, "Validator." + validator.name);
  };

  /**
  Register a validator factory so that any deserialized metadata can reference it.
  @method registerFactory
  @static
  @param validatorFactory {Function} A function that optionally takes a context property and returns a Validator instance.
  @param name {String} The name of the validator.
  **/
  ctor.registerFactory = function (validatorFn, name) {
    __config.registerFunction(validatorFn, "Validator." + name);
  };

  /**
  Map of standard error message templates keyed by validator name.
  You can add to or modify this object to customize the template used for any validation error message.
  @example
      // v is this function is the value to be validated, in this case a "country" string.
      var valFn = function (v) {
          if (v == null) return true;
          return (core.stringStartsWith(v, "US"));
      };
      var countryValidator = new Validator("countryIsUS", valFn, { displayName: "Country" });
      Validator.messageTemplates.countryIsUS = "'%displayName%' must start with 'US'";
      // This will have a similar effect to this
      var countryValidator = new Validator("countryIsUS", valFn, {
          displayName: "Country", 
          messageTemplate: "'%displayName%' must start with 'US'" 
      });
  @property messageTemplates {Object}
  @static
  **/
  ctor.messageTemplates = {
    bool: "'%displayName%' must be a 'true' or 'false' value",
    creditCard: "The %displayName% is not a valid credit card number",
    date: "'%displayName%' must be a date",
    duration: "'%displayName%' must be a ISO8601 duration string, such as 'P3H24M60S'",
    emailAddress: "The %displayName% '%value%' is not a valid email address",
    guid: "'%displayName%' must be a GUID",
    integer: "'%displayName%' must be an integer",
    integerRange: "'%displayName%' must be an integer between the values of %minValue% and %maxValue%",
    maxLength: "'%displayName%' must be a string with %maxLength% characters or less",
    number: "'%displayName%' must be a number",
    phone: "The %displayName% '%value%' is not a valid phone number",
    regularExpression: "The %displayName% '%value%' does not match '%expression%'",
    required: "'%displayName%' is required",
    string: "'%displayName%' must be a string",
    stringLength: "'%displayName%' must be a string with between %minLength% and %maxLength% characters",
    url: "The %displayName% '%value%' is not a valid url"
  };

  /**
  Returns a standard 'required value' Validator
  @example
      // Assume em1 is a preexisting EntityManager.
      var custType = em1.metadataStore.getEntityType("Customer");
      var regionProperty - custType.getProperty("Region");
      // Makes "Region" on Customer a required property.
      regionProperty.validators.push(Validator.required());
      // or to allow empty strings
      regionProperty.validators.push(Validator.required({ allowEmptyStrings: true }););
  @method required
  @static
  @param context {Object}
  @param [context.allowEmptyStrings] {Boolean} If this parameter is omitted or false then empty strings do NOT pass validation.
  @return {Validator} A new Validator
  **/
  ctor.required = function (context) {
    var valFn = function (v, ctx) {
      if (typeof v === "string") {
        if (ctx && ctx.allowEmptyStrings) return true;
        return v.length > 0;
      } else {
        return v != null;
      }
    };
    return new ctor("required", valFn, context);
  };

  /**
  Returns a standard maximum string length Validator; the maximum length must be specified
  @example
      // Assume em1 is a preexisting EntityManager.
      var custType = em1.metadataStore.getEntityType("Customer");
      var regionProperty - custType.getProperty("Region");
      // Validates that the value of the Region property on Customer will be less than or equal to 5 characters.
      regionProperty.validators.push(Validator.maxLength( {maxLength: 5}));
  @method maxLength
  @static
  @param context {Object}
  @param context.maxLength {Integer}
  @return {Validator} A new Validator
  **/
  ctor.maxLength = function (context) {
    var valFn = function (v, ctx) {
      if (v == null) return true;
      if (typeof (v) !== "string") return false;
      return v.length <= ctx.maxLength;
    };
    return new ctor("maxLength", valFn, context);
  };

  /**
  Returns a standard string length Validator; both minimum and maximum lengths must be specified.
  @example
      // Assume em1 is a preexisting EntityManager.
      var custType = em1.metadataStore.getEntityType("Customer");
      var regionProperty - custType.getProperty("Region");
      // Validates that the value of the Region property on Customer will be
      // between 2 and 5 characters
      regionProperty.validators.push(Validator.stringLength( {minLength: 2, maxLength: 5});
  @method stringLength
  @static
  @param context {Object}
  @param context.maxLength {Integer}
  @param context.minLength {Integer}
  @return {Validator} A new Validator
  **/
  ctor.stringLength = function (context) {
    var valFn = function (v, ctx) {
      if (v == null) return true;
      if (typeof (v) !== "string") return false;
      if (ctx.minLength != null && v.length < ctx.minLength) return false;
      if (ctx.maxLength != null && v.length > ctx.maxLength) return false;
      return true;
    };
    return new ctor("stringLength", valFn, context);
  };

  /**
  Returns a standard string dataType Validator.
  @example
      // Assume em1 is a preexisting EntityManager.
      var custType = em1.metadataStore.getEntityType("Customer");
      var regionProperty - custType.getProperty("Region");
      // Validates that the value of the Region property on Customer is a string.
      regionProperty.validators.push(Validator.string());
  @method string
  @static
  @return {Validator} A new Validator
  **/
  ctor.string = function () {
    var valFn = function (v) {
      if (v == null) return true;
      return (typeof v === "string");
    };
    return new ctor("string", valFn);
  };

  /**
  Returns a Guid data type Validator.
  @example
      // Assume em1 is a preexisting EntityManager.
      var custType = em1.metadataStore.getEntityType("Customer");
      var customerIdProperty - custType.getProperty("CustomerID");
      // Validates that the value of the CustomerID property on Customer is a Guid.
      customerIdProperty.validators.push(Validator.guid());
  @method guid
  @static
  @return {Validator} A new Validator
  **/
  ctor.guid = function () {
    var valFn = function (v) {
      if (v == null) return true;
      return __isGuid(v);
    };
    return new ctor("guid", valFn);
  };

  /**
  Returns a ISO 8601 duration string  Validator.
  @example
      // Assume em1 is a preexisting EntityManager.
      var eventType = em1.metadataStore.getEntityType("Event");
      var elapsedTimeProperty - eventType.getProperty("ElapsedTime");
      // Validates that the value of the ElapsedTime property on Customer is a duration.
      elapsedTimeProperty.validators.push(Validator.duration());
  @method duration
  @static
  @return {Validator} A new Validator
  **/
  ctor.duration = function () {
    var valFn = function (v) {
      if (v == null) return true;
      return __isDuration(v);
    };
    return new ctor("duration", valFn);
  };

  /**
  Returns a standard numeric data type Validator.
  @example
      // Assume em1 is a preexisting EntityManager.
      var orderType = em1.metadataStore.getEntityType("Order");
      var freightProperty - orderType.getProperty("Freight");
      // Validates that the value of the Freight property on Order is a number.
      freightProperty.validators.push(Validator.number());
  @method number
  @static
  @return {Validator} A new Validator
  **/

    // TODO: may need to have seperate logic for single.
  ctor.number = ctor.double = ctor.single = function (context) {
    var valFn = function (v, ctx) {
      if (v == null) return true;
      if (typeof v === "string" && ctx && ctx.allowString) {
        v = parseFloat(v, 10);
      }
      return (typeof v === "number" && !isNaN(v));
    };
    return new ctor("number", valFn, context);
  };

  /**
  Returns a standard large integer data type - 64 bit - Validator.
  @example
      // Assume em1 is a preexisting EntityManager.
      var orderType = em1.metadataStore.getEntityType("Order");
      var freightProperty - orderType.getProperty("Freight");
      // Validates that the value of the Freight property on Order is within the range of a 64 bit integer.
      freightProperty.validators.push(Validator.int64());
  @method int64
  @static
  @return {Validator} A new Validator
  **/
  ctor.integer = ctor.int64 = function (context) {
    var valFn = function (v, ctx) {
      if (v == null) return true;
      if (typeof v === "string" && ctx && ctx.allowString) {
        v = parseInt(v, 10);
      }
      return (typeof v === "number") && (!isNaN(v)) && Math.floor(v) === v;
    };
    return new ctor("integer", valFn, context);
  };

  /**
  Returns a standard 32 bit integer data type Validator.
  @example
      // Assume em1 is a preexisting EntityManager.
      var orderType = em1.metadataStore.getEntityType("Order");
      var freightProperty - orderType.getProperty("Freight");
      freightProperty.validators.push(Validator.int32());
  @method int32
  @static
  @return {Validator} A new Validator
  **/
  ctor.int32 = function (context) {
    return intRangeValidatorCtor("int32", INT32_MIN, INT32_MAX, context)();
  };

  /**
  Returns a standard 16 bit integer data type Validator.
  @example
      // Assume em1 is a preexisting EntityManager.
      var orderType = em1.metadataStore.getEntityType("Order");
      var freightProperty - orderType.getProperty("Freight");
      // Validates that the value of the Freight property on Order is within the range of a 16 bit integer.
      freightProperty.validators.push(Validator.int16());
  @method int16
  @static
  @return {Validator} A new Validator
  **/
  ctor.int16 = function (context) {
    return intRangeValidatorCtor("int16", INT16_MIN, INT16_MAX, context)();
  };

  /**
  Returns a standard byte data type Validator. (This is a integer between 0 and 255 inclusive for js purposes).
  @example
      // Assume em1 is a preexisting EntityManager.
      var orderType = em1.metadataStore.getEntityType("Order");
      var freightProperty - orderType.getProperty("Freight");
      // Validates that the value of the Freight property on Order is within the range of a 16 bit integer.
      // Probably not a very good validation to place on the Freight property.
      regionProperty.validators.push(Validator.byte());
  @method byte
  @static
  @return {Validator} A new Validator
  **/
  ctor.byte = function (context) {
    return intRangeValidatorCtor("byte", BYTE_MIN, BYTE_MAX, context)();
  };

  /**
  Returns a standard boolean data type Validator.
  @example
      // Assume em1 is a preexisting EntityManager.
      var productType = em1.metadataStore.getEntityType("Product");
      var discontinuedProperty - productType.getProperty("Discontinued");
      // Validates that the value of the Discontinued property on Product is a boolean
      discontinuedProperty.validators.push(Validator.bool());
  @method bool
  @static
  @return {Validator} A new Validator
  **/
  ctor.bool = function () {
    var valFn = function (v) {
      if (v == null) return true;
      return (v === true) || (v === false);
    };
    return new ctor("bool", valFn);
  };

  ctor.none = function () {
    var valFn = function (v) {
      return true;
    };
    return new ctor("none", valFn);
  };

  /**
  Returns a standard date data type Validator.
  @example
      // Assume em1 is a preexisting EntityManager.
      var orderType = em1.metadataStore.getEntityType("Order");
      var orderDateProperty - orderType.getProperty("OrderDate");
      // Validates that the value of the OrderDate property on Order is a date
      // Probably not a very good validation to place on the Freight property.
      orderDateProperty.validators.push(Validator.date());
  @method date
  @static
  @return {Validator} A new Validator
  **/
  ctor.date = function () {
    var valFn = function (v) {
      if (v == null) return true;
      if (typeof v === "string") {
        try {
          return !isNaN(Date.parse(v));
          // old code
          // return __isDate(new Date(v));
        } catch (e) {
          return false;
        }
      } else {
        return __isDate(v);
      }
    };
    return new ctor("date", valFn);
  };

  /**
  Returns a credit card number validator
  Performs a luhn algorithm checksum test for plausability
  catches simple mistakes; only service knows for sure
  @example
      // Assume em is a preexisting EntityManager.
      var personType = em.metadataStore.getEntityType("Person");
      var creditCardProperty = personType.getProperty("creditCard");
      // Validates that the value of the Person.creditCard property is credit card.
      creditCardProperty.validators.push(Validator.creditCard());
  @method creditCard
  @static
  @param [context] {Object} optional parameters to pass through to validation constructor
  @return {Validator} A new Validator
  **/
  ctor.creditCard = function (context) {
    function valFn(v) {
      if (v == null || v === '') return true;
      if (typeof (v) !== 'string') return false;
      v = v.replace(/(\-|\s)/g, ""); // remove dashes and spaces
      if (!v || /\D/.test(v)) return false; // all digits, not empty
      return luhn(v);
    };
    return new ctor('creditCard', valFn, context);
  };

  // http://rosettacode.org/wiki/Luhn_test_of_credit_card_numbers#JavaScript
  function luhn(a, b, c, d, e) {
    for (d = +a[b = a.length - 1], e = 0; b--;)
      c = +a[b], d += ++e % 2 ? 2 * c % 10 + (c > 4) : c;
    return !(d % 10);
  };

  /**
  Returns a regular expression validator; the expression must be specified
  @example
      // Add validator to a property. Assume em is a preexisting EntityManager.
      var customerType = em.metadataStore.getEntityType("Customer");
      var regionProperty = customerType.getProperty("Region");
      // Validates that the value of Customer.Region is 2 char uppercase alpha.
      regionProperty.validators.push(Validator.regularExpression( {expression: '^[A-Z]{2}$'} );
  @method regularExpression
  @static
  @param context {Object}
  @param context.expression {String} String form of the regular expression to apply
  @return {Validator} A new Validator
  **/
  ctor.regularExpression = function (context) {
    function valFn(v, ctx) {
      // do not invalidate if empty; use a separate required test
      if (v == null || v === '') return true;
      if (typeof (v) !== 'string') return false;
      try {
        var re = new RegExp(ctx.expression);
      } catch (e) {
        throw new Error('Missing or invalid expression parameter to regExp validator');
      }
      return re.test(v);
    };
    return new ctor('regularExpression', valFn, context);
  };

  /**
  Returns the email address validator
  @example
      // Assume em is a preexisting EntityManager.
      var personType = em.metadataStore.getEntityType("Person");
      var emailProperty = personType.getProperty("email");
      // Validates that the value of the Person.email property is an email address.
      emailProperty.validators.push(Validator.emailAddress());
  @method emailAddress
  @static
  @param [context] {Object} optional parameters to pass through to validation constructor
  @return {Validator} A new Validator
  **/
  ctor.emailAddress = function (context) {
    // See https://github.com/srkirkland/DataAnnotationsExtensions/blob/master/DataAnnotationsExtensions/EmailAttribute.cs
    var reEmailAddress = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i;
    return makeRegExpValidator('emailAddress', reEmailAddress, null, context);
  };

  /**
  Returns the phone validator
  Provides basic assertions on the format and will help to eliminate most nonsense input
  Matches:
  International dialing prefix: {{}, +, 0, 0000} (with or without a trailing break character, if not '+': [-/. ])
  > ((\+)|(0(\d+)?[-/.\s]))
  Country code: {{}, 1, ..., 999} (with or without a trailing break character: [-/. ])
  > [1-9]\d{,2}[-/.\s]?
  Area code: {(0), ..., (000000), 0, ..., 000000} (with or without a trailing break character: [-/. ])
  > ((\(\d{1,6}\)|\d{1,6})[-/.\s]?)?
  Local: {0, ...}+ (with or without a trailing break character: [-/. ])
  > (\d+[-/.\s]?)+\d+
  @example
      // Assume em is a preexisting EntityManager.
      var customerType = em.metadataStore.getEntityType("Customer");
      var phoneProperty = customerType.getProperty("phone");
      // Validates that the value of the Customer.phone property is phone.
      phoneProperty.validators.push(Validator.phone());
  @method phone
  @static
  @param [context] {Object} optional parameters to pass through to validation constructor
  @return {Validator} A new Validator
  **/
  ctor.phone = function (context) {
    // See https://github.com/srkirkland/DataAnnotationsExtensions/blob/master/DataAnnotationsExtensions/Expressions.cs
    var rePhone = /^((\+|(0(\d+)?[-/.\s]?))[1-9]\d{0,2}[-/.\s]?)?((\(\d{1,6}\)|\d{1,6})[-/.\s]?)?(\d+[-/.\s]?)+\d+$/;
    return makeRegExpValidator('phone', rePhone, null, context);
  };

  /**
  Returns the URL (protocol required) validator
  @example
      // Assume em is a preexisting EntityManager.
      var personType = em.metadataStore.getEntityType("Person");
      var websiteProperty = personType.getProperty("website");
      // Validates that the value of the Person.website property is a URL.
      websiteProperty.validators.push(Validator.url());
  @method url
  @static
  @param [context] {Object} optional parameters to pass through to validation constructor
  @return {Validator} A new Validator
  **/
  ctor.url = function (context) {
    //See https://github.com/srkirkland/DataAnnotationsExtensions/blob/master/DataAnnotationsExtensions/UrlAttribute.cs
    var reUrlProtocolRequired = /^(https?|ftp):\/\/(((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-fA-F]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|([a-zA-Z][\-a-zA-Z0-9]*)|((([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-fA-F]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-fA-F]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-fA-F]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-fA-F]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/;
    return makeRegExpValidator('url', reUrlProtocolRequired, null, context);
  };

  /**
  Creates a regular expression validator with a fixed expression.
  Many of the stock validators are built with this factory method.
  Their expressions are often derived from
  https://github.com/srkirkland/DataAnnotationsExtensions/blob/master/DataAnnotationsExtensions
  You can try many of them at http://dataannotationsextensions.org/
  @example
      // Make a zipcode validator
      function zipValidator = Validator.makeRegExpValidator(
      "zipVal,
      /^\d{5}([\-]\d{4})?$/,
      "The %displayName% '%value%' is not a valid U.S. zipcode");
      // Register it.
      Validator.register(zipValidator);
      // Add it to a data property. Assume em is a preexisting EntityManager.
      var custType = em.metadataStore.getEntityType("Customer");
      var zipProperty = custType.getProperty("PostalCode");
      zipProperty.validators.push(zipValidator);
  @method makeRegExpValidator
  @static
  @param validatorName {String} name of this validator
  @param expression {String | RegExp} regular expression to apply
  @param [defaultMessage] {String} default message for failed validations
  @param [context] {Object} optional parameters to pass through to validation constructor
  @return {Validator} A new Validator
  **/
  ctor.makeRegExpValidator = makeRegExpValidator;

  function makeRegExpValidator(validatorName, expression, defaultMessage, context) {
    if (defaultMessage) {
      ctor.messageTemplates[validatorName] = defaultMessage;
    }
    var re = (typeof (expression) === 'string') ? new RegExp(expression) : expression;
    var valFn = function (v) {
      // do not invalidate if empty; use a separate required test
      if (v == null || v === '') return true;
      if (typeof (v) !== 'string') return false;
      return re.test(v);
    };
    return new ctor(validatorName, valFn, context);
  };

  // register all validators
  __objectForEach(ctor, function (key, value) {
    if (typeof (value) !== "function") {
      return;
    }
    if (key === "fromJSON" || key === "register" ||
        key === "registerFactory" || key === "makeRegExpValidator") {
      return;
    }

    __config.registerFunction(value, "Validator." + key);
  });


  // private funcs

  function formatTemplate(template, vars, ownPropertiesOnly) {
    if (!vars) return template;
    return template.replace(/%([^%]+)%/g, function (_, key) {
      var valOrFn;
      if (ownPropertiesOnly) {
        valOrFn = vars.hasOwnProperty(key) ? vars[key] : '';
      } else {
        valOrFn = vars[key];
      }
      if (valOrFn != null) {
        if (__isFunction(valOrFn)) {
          return valOrFn(vars);
        } else {
          return valOrFn;
        }
      } else {
        return "";
      }
    });
  }

  function intRangeValidatorCtor(validatorName, minValue, maxValue, context) {
    context = context || {};
    if (minValue !== undefined) { context.min = minValue; }
    if (maxValue !== undefined) { context.max = maxValue; }
    var templateExists = context.messageTemplate || ctor.messageTemplates[validatorName];
    if (!templateExists) {
      ctor.messageTemplates[validatorName] = __formatString("'%displayName%' must be an integer between the values of %1 and %2",
          minValue, maxValue);
    }
    return function () {
      var valFn = function (v, ctx) {
        if (v == null) return true;
        if (typeof v === "string" && ctx && ctx.allowString) {
          v = parseInt(v, 0);
        }
        if ((typeof v === "number") && (!isNaN(v)) && Math.floor(v) === v) {
          if (minValue != null && v < minValue) {
            return false;
          }
          if (maxValue != null && v > maxValue) {
            return false;
          }
          return true;
        } else {
          return false;
        }
      };
      return new ctor(validatorName, valFn, context);
    };
  }


  return ctor;
})();

var ValidationError = (function () {
  /**
  A ValidationError is used to describe a failed validation.

  @class ValidationError
  **/

  /**
  Constructs a new ValidationError
  @method <ctor> ValidationError

  @param validator {Validator || null} The Validator used to create this error, if any.
  @param context { ContextObject || null} The Context object used in conjunction with the Validator to create this error.
  @param errorMessage { String} The actual error message
  @param [key] {String} An optional key used to define a key for this error. One will be created automatically if not provided here.
  **/
  var ctor = function ValidationError(validator, context, errorMessage, key) {
    assertParam(validator, "validator").isOptional().isInstanceOf(Validator).check();
    assertParam(errorMessage, "errorMessage").isNonEmptyString().check();
    assertParam(key, "key").isOptional().isNonEmptyString().check();
    this.validator = validator;
    context = context || {};
    this.context = context;
    this.errorMessage = errorMessage;

    this.property = context.property;
    this.propertyName = context.propertyName || (context.property && context.property.name);

    if (key) {
      this.key = key;
    } else {
      this.key = ValidationError.getKey(validator || errorMessage, this.propertyName);
    }
    this.isServerError = false;
  };


  /**
  The Validator associated with this ValidationError.

  __readOnly__
  @property validator {Validator}
  **/

  /**
  A 'context' object associated with this ValidationError.

  __readOnly__
  @property context {Object}
  **/

  /**
  The DataProperty or NavigationProperty associated with this ValidationError.

  __readOnly__
  @property property {DataProperty|NavigationProperty}
  **/

  /**
  The property name associated with this ValidationError. This will be a "property path" for any properties of a complex object.

  __readOnly__
  @property propertyName {String}
  **/

  /**
  The error message associated with the ValidationError.

  __readOnly__
  @property errorMessage {string}
  **/

  /**
  The key by which this validation error may be removed from a collection of ValidationErrors.

  __readOnly__
  @property key {string}
  **/

  /**
  Whether this is a server error.

  __readOnly__
  @property isServerError {bool}
  **/


  /**
  Composes a ValidationError 'key' given a validator or an errorName and an optional propertyName
  @method getKey
  @static
  @param validator {ValidatorOrErrorKey} A Validator or an "error name" if no validator is available.
  @param [propertyName] A property name
  @return {String} A ValidationError 'key'
  **/
  ctor.getKey = function (validatorOrErrorName, propertyName) {
    return (validatorOrErrorName.name || validatorOrErrorName) + (propertyName ? ":" + propertyName : "");
  };


  return ctor;
})();

breeze.Validator = Validator;
breeze.ValidationError = ValidationError;
 
;/**
@module breeze
**/

var ValidationOptions = (function () {

  /**
  A ValidationOptions instance is used to specify the conditions under which validation will be executed.

  @class ValidationOptions
  **/

  /**
  ValidationOptions constructor
  @example
      var newVo = new ValidationOptions( { validateOnSave: false, validateOnAttach: false });
      // assume em1 is a preexisting EntityManager
      em1.setProperties( { validationOptions: newVo });
  @method <ctor> ValidationOptions
  @param [config] {Object}
  @param [config.validateOnAttach=true] {Boolean}
  @param [config.validateOnSave=true] {Boolean}
  @param [config.validateOnQuery=false] {Boolean}
  @param [config.validateOnPropertyChange=true] {Boolean}
  **/
  var ctor = function ValidationOptions(config) {
    updateWithConfig(this, config);
  };
  var proto = ctor.prototype;

  /**
  Whether entity and property level validation should occur when entities are attached to the EntityManager other than via a query.

  __readOnly__
  @property validateOnAttach {Boolean}
  **/

  /**
  Whether entity and property level validation should occur before entities are saved. A failed validation will force the save to fail early.

  __readOnly__
  @property validateOnSave {Boolean}
  **/

  /**
  Whether entity and property level validation should occur after entities are queried from a remote server.

  __readOnly__
  @property validateOnQuery {Boolean}
  **/

  /**
  Whether property level validation should occur after entities are modified.

  __readOnly__
  @property validateOnPropertyChange {Boolean}
  **/

  proto._$typeName = "ValidationOptions";

  /**
  Returns a copy of this ValidationOptions with changes to the specified config properties.
  @example
      var validationOptions = new ValidationOptions();
      var newOptions = validationOptions.using( { validateOnQuery: true, validateOnSave: false} );
  @method using
  @param config {Object} The object to apply to create a new QueryOptions.
  @param [config.validateOnAttach] {Boolean}
  @param [config.validateOnSave] {Boolean}
  @param [config.validateOnQuery] {Boolean}
  @param [config.validateOnPropertyChange] {Boolean}
  @return {ValidationOptions}
  @chainable
  **/
  proto.using = function (config) {
    if (!config) return this;
    var result = new ValidationOptions(this);
    updateWithConfig(result, config);
    return result;
  };

  /**
  Sets the 'defaultInstance' by creating a copy of the current 'defaultInstance' and then applying all of the properties of the current instance.
  The current instance is returned unchanged.
  @example
      var validationOptions = new ValidationOptions()
      var newOptions = validationOptions.using( { validateOnQuery: true, validateOnSave: false} );
      var newOptions.setAsDefault();
  @method setAsDefault
  @chainable
  **/
  proto.setAsDefault = function () {
    return __setAsDefault(this, ctor);
  };

  /**
  The default value whenever ValidationOptions are not specified.
  @property defaultInstance {ValidationOptions}
  @static
  **/
  ctor.defaultInstance = new ctor({
    validateOnAttach: true,
    validateOnSave: true,
    validateOnQuery: false,
    validateOnPropertyChange: true
  });

  function updateWithConfig(obj, config) {
    if (config) {
      assertConfig(config)
          .whereParam("validateOnAttach").isBoolean().isOptional()
          .whereParam("validateOnSave").isBoolean().isOptional()
          .whereParam("validateOnQuery").isBoolean().isOptional()
          .whereParam("validateOnPropertyChange").isBoolean().isOptional()
          .applyAll(obj);
    }
    return obj;
  }

  return ctor;
})();

// expose

breeze.ValidationOptions = ValidationOptions;



;breeze.makeComplexArray = (function () {
  var complexArrayMixin = {};

  // complexArray will have the following props
  //    parent
  //    propertyPath
  //    parentProperty
  //    addedItems  - only if modified
  //    removedItems  - only if modified
  //  each complexAspect of any entity within a complexArray
  //  will have its own _complexState = "A/M";

  /**
   Complex arrays are not actually classes, they are objects that mimic arrays. A complex array is collection of
   complexTypes associated with a data property on a single entity or other complex object. i.e. customer.orders or order.orderDetails.
   This collection looks like an array in that the basic methods on arrays such as 'push', 'pop', 'shift', 'unshift', 'splice'
   are all provided as well as several special purpose methods.
   @class {complexArray}
   **/

  /**
  An {{#crossLink "Event"}}{{/crossLink}} that fires whenever the contents of this array changed.  This event
  is fired any time a new entity is attached or added to the EntityManager and happens to belong to this collection.
  Adds that occur as a result of query or import operations are batched so that all of the adds or removes to any individual
  collections are collected into a single notification event for each relation array.
  @example
      // assume order is an order entity attached to an EntityManager.
      orders.arrayChanged.subscribe(
      function (arrayChangedArgs) {
          var addedEntities = arrayChangedArgs.added;
          var removedEntities = arrayChanged.removed;
      });
  @event arrayChanged
  @param added {Array of Entity} An array of all of the entities added to this collection.
  @param removed {Array of Entity} An array of all of the removed from this collection.
  @readOnly
  **/

    // virtual impls
  complexArrayMixin._getGoodAdds = function (adds) {
    return getGoodAdds(this, adds);
  };

  complexArrayMixin._beforeChange = function () {
    observableArray.updateEntityState(this);
  };

  complexArrayMixin._processAdds = function (adds) {
    processAdds(this, adds);
  };

  complexArrayMixin._processRemoves = function (removes) {
    processRemoves(this, removes);
  };
  //

  complexArrayMixin._rejectChanges = function() {
    if (!this._origValues) return;
    var that = this;
    this.forEach(function (co) {
      clearAspect(co, that);
    });
    this.length = 0;
    this._origValues.forEach(function (co) {
      that.push(co);
    });
  };

  complexArrayMixin._acceptChanges = function () {
    this._origValues = null;
  };

  // local functions


  function getGoodAdds(complexArray, adds) {
    // remove any that are already added here
    return adds.filter(function (a) {
      return a.parent !== complexArray.parent;
    });
  }

  function processAdds(complexArray, adds) {
    adds.forEach(function (a) {
      if (a.parent != null) {
        throw new Error("The complexObject is already attached. Either clone it or remove it from its current owner");
      }
      setAspect(a, complexArray);
    });
  }

  function processRemoves(complexArray, removes) {
    removes.forEach(function (a) {
      clearAspect(a, complexArray);
    });
  }

  function clearAspect(co, arr) {
    var coAspect = co.complexAspect;
    // if not already attached - exit
    if (coAspect.parent !== arr.parent) return null;

    coAspect.parent = null;
    coAspect.parentProperty = null;
    return coAspect;
  }

  function setAspect(co, arr) {
    var coAspect = co.complexAspect;
    // if already attached - exit
    if (coAspect.parent === arr.parent) return null;
    coAspect.parent = arr.parent;
    coAspect.parentProperty = arr.parentProperty;

    return coAspect;
  }

  function makeComplexArray(arr, parent, parentProperty) {

    observableArray.initializeParent(arr, parent, parentProperty);
    arr.arrayChanged = new Event("arrayChanged", arr);
    __extend(arr, observableArray.mixin);
    return __extend(arr, complexArrayMixin);
  }

  return makeComplexArray;
})();;/**
@module breeze
**/


var EntityAction = (function () {
  /**
  EntityAction is an 'Enum' containing all of the valid actions that can occur to an 'Entity'.

  @class EntityAction
  @static
  **/
  var entityActionMethods = {
    isAttach: function () {
      return !!this.isAttach;
    },
    isDetach: function () {
      return !!this.isDetach;
    },
    isModification: function () {
      return !!this.isModification;
    }
  };

  var EntityAction = new Enum("EntityAction", entityActionMethods);

  /**
  Attach - Entity was attached via an AttachEntity call.

  @property Attach {EntityAction}
  @final
  @static
  **/
  EntityAction.Attach = EntityAction.addSymbol({ isAttach: true});

  /**
  AttachOnQuery - Entity was attached as a result of a query.

  @property AttachOnQuery {EntityAction}
  @final
  @static
  **/
  EntityAction.AttachOnQuery = EntityAction.addSymbol({ isAttach: true});

  /**
  AttachOnImport - Entity was attached as a result of an import.

  @property AttachOnImport {EntityAction}
  @final
  @static
  **/
  EntityAction.AttachOnImport = EntityAction.addSymbol({ isAttach: true});


  /**
  Detach - Entity was detached.

  @property Detach {EntityAction}
  @final
  @static
  **/
  EntityAction.Detach = EntityAction.addSymbol({ isDetach: true });

  /**
  MergeOnQuery - Properties on the entity were merged as a result of a query.

  @property MergeOnQuery {EntityAction}
  @final
  @static
  **/
  EntityAction.MergeOnQuery = EntityAction.addSymbol({ isModification: true });

  /**
  MergeOnImport - Properties on the entity were merged as a result of an import.

  @property MergeOnImport {EntityAction}
  @final
  @static
  **/
  EntityAction.MergeOnImport = EntityAction.addSymbol({ isModification: true });

  /**
  MergeOnSave - Properties on the entity were merged as a result of a save

  @property MergeOnSave {EntityAction}
  @final
  @static
  **/
  EntityAction.MergeOnSave = EntityAction.addSymbol({ isModification: true });

  /**
  PropertyChange - A property on the entity was changed.

  @property PropertyChange {EntityAction}
  @final
  @static
  **/
  EntityAction.PropertyChange = EntityAction.addSymbol({ isModification: true});

  /**
  EntityStateChange - The EntityState of the entity was changed.

  @property EntityStateChange {EntityAction}
  @final
  @static
  **/
  EntityAction.EntityStateChange = EntityAction.addSymbol();


  /**
  AcceptChanges - AcceptChanges was called on the entity, or its entityState was set to Unmodified.

  @property AcceptChanges {EntityAction}
  @final
  @static
  **/
  EntityAction.AcceptChanges = EntityAction.addSymbol();

  /**
  RejectChanges - RejectChanges was called on the entity.

  @property RejectChanges {EntityAction}
  @final
  @static
  **/
  EntityAction.RejectChanges = EntityAction.addSymbol({ isModification: true});

  /**
  Clear - The EntityManager was cleared.  All entities detached.

  @property Clear {EntityAction}
  @final
  @static
  **/
  EntityAction.Clear = EntityAction.addSymbol({ isDetach: true});

  EntityAction.resolveSymbols();
  return EntityAction;
})();

breeze.EntityAction = EntityAction;

;/**
@module breeze
**/

var EntityAspect = (function () {
  /**
  An EntityAspect instance is associated with every attached entity and is accessed via the entity's 'entityAspect' property.

  The EntityAspect itself provides properties to determine and modify the EntityState of the entity and has methods
  that provide a variety of services including validation and change tracking.

  An EntityAspect will almost never need to be constructed directly. You will usually get an EntityAspect by accessing
  an entities 'entityAspect' property.  This property will be automatically attached when an entity is created via either
  a query, import or EntityManager.createEntity call.
  @example
      // assume order is an order entity attached to an EntityManager.
      var aspect = order.entityAspect;
      var currentState = aspect.entityState;
  @class EntityAspect
  **/
  var ctor = function EntityAspect(entity) {
    if (entity === null) {
      var nullInstance = EntityAspect._nullInstance;
      if (nullInstance) return nullInstance;
      EntityAspect._nullInstance = this;
    } else if (entity === undefined) {
      throw new Error("The EntityAspect ctor requires an entity as its only argument.");
    } else if (entity.entityAspect) {
      return entity.entityAspect;
    }

    // if called without new
    if (!(this instanceof EntityAspect)) {
      return new EntityAspect(entity);
    }

    this.entity = entity;
    // TODO: keep public or not?
    this.entityGroup = null;
    this.entityManager = null;
    this.entityState = EntityState.Detached;
    this.isBeingSaved = false;
    this.originalValues = {};
    this.hasValidationErrors = false;
    this._validationErrors = {};

    // Uncomment when we implement entityAspect.isNavigationPropertyLoaded method
    // this._loadedNavPropMap = {};

    this.validationErrorsChanged = new Event("validationErrorsChanged", this);
    this.propertyChanged = new Event("propertyChanged", this);
    // in case this is the NULL entityAspect. - used with ComplexAspects that have no parent.

    if (entity != null) {
      entity.entityAspect = this;
      // entityType should already be on the entity from 'watch'
      var entityType = entity.entityType || entity._$entityType;
      if (!entityType) {
        var typeName = entity.prototype._$typeName;
        if (!typeName) {
          throw new Error("This entity is not registered as a valid EntityType");
        } else {
          throw new Error("Metadata for this entityType has not yet been resolved: " + typeName);
        }
      }
      var entityCtor = entityType.getEntityCtor();
      __modelLibraryDef.getDefaultInstance().startTracking(entity, entityCtor.prototype);
    }
  };
  var proto = ctor.prototype;


  Event.bubbleEvent(proto, function () {
    return this.entityManager;
  });

  /**
  The Entity that this aspect is associated with.

  __readOnly__
  @property entity {Entity}
  **/

  /**
  The {{#crossLink "EntityManager"}}{{/crossLink}} that contains this entity.

  __readOnly__
  @property entityManager {EntityManager}
  **/

  /**
  The {{#crossLink "EntityState"}}{{/crossLink}} of this entity.

  __readOnly__
  @property entityState {EntityState}
  **/

  /**
  Extra metadata about this entity such as the entity's etag.
  You may extend this object with your own metadata information.
  Breeze (de)serializes this object when importing/exporting the entity.

  @property extraMetadata {Object}
  **/

  /**
  Whether this entity is in the process of being saved.

  __readOnly__
  @property isBeingSaved {Boolean}
  **/

  /**
  Whether this entity has any validation errors.

  __readOnly__
  @property hasValidationErrors {Boolean}
  **/

  /**
  The 'original values' of this entity where they are different from the 'current values'.
  This is a map where the key is a property name and the value is the 'original value' of the property.

  __readOnly__
  @property originalValues {Object}
  **/

  /**
  An {{#crossLink "Event"}}{{/crossLink}} that fires whenever a value of one of this entity's properties change.
  @example
      // assume order is an order entity attached to an EntityManager.
      order.entityAspect.propertyChanged.subscribe(
      function (propertyChangedArgs) {
          // this code will be executed anytime a property value changes on the 'order' entity.
          var entity = propertyChangedArgs.entity; // Note: entity === order
          var propertyNameChanged = propertyChangedArgs.propertyName;
          var oldValue = propertyChangedArgs.oldValue;
          var newValue = propertyChangedArgs.newValue;
      });
  @event propertyChanged
  @param entity {Entity} The entity whose property has changed.
  @param property {DataProperty} The DataProperty that changed.
  @param propertyName {String} The name of the property that changed. This value will be 'null' for operations that replace the entire entity.  This includes
  queries, imports and saves that require a merge. The remaining parameters will not exist in this case either. This will actually be a "property path"
  for any properties of a complex type.
  @param oldValue {Object} The old value of this property before the change.
  @param newValue {Object} The new value of this property after the change.
  @param parent {Object} The immediate parent object for the changed property.  This will be different from the 'entity' for any complex type or nested complex type properties.
  @readOnly
  **/

  /**
  An {{#crossLink "Event"}}{{/crossLink}} that fires whenever any of the validation errors on this entity change.
  Note that this might be the removal of an error when some data on the entity is fixed.
  @example
      // assume order is an order entity attached to an EntityManager.
      order.entityAspect.validationErrorsChanged.subscribe(
      function (validationChangeArgs) {
          // this code will be executed anytime a property value changes on the 'order' entity.
          var entity == validationChangeArgs.entity; // Note: entity === order
          var errorsAdded = validationChangeArgs.added;
          var errorsCleared = validationChangeArgs.removed;
      });
  @event validationErrorsChanged
  @param entity {Entity} The entity on which the validation errors are being added or removed.
  @param added {Array of ValidationError} An array containing any newly added {{#crossLink "ValidationError"}}{{/crossLink}}s
  @param removed {Array of ValidationError} An array containing any newly removed {{#crossLink "ValidationError"}}{{/crossLink}}s. This is those
  errors that have been 'fixed'
  @readOnly
  **/

  /**
  Returns the {{#crossLink "EntityKey"}}{{/crossLink}} for this Entity.
  @example
      // assume order is an order entity attached to an EntityManager.
      var entityKey = order.entityAspect.getKey();
  @method getKey
  @param [forceRefresh=false] {Boolean} Forces the recalculation of the key.  This should normally be unnecessary.
  @return {EntityKey} The {{#crossLink "EntityKey"}}{{/crossLink}} associated with this Entity.
  **/
  proto.getKey = function (forceRefresh) {
    forceRefresh = assertParam(forceRefresh, "forceRefresh").isBoolean().isOptional().check(false);
    if (forceRefresh || !this._entityKey) {
      var entityType = this.entity.entityType;
      var keyProps = entityType.keyProperties;
      var values = keyProps.map(function (p) {
        return this.entity.getProperty(p.name);
      }, this);
      this._entityKey = new EntityKey(entityType, values);
    }
    return this._entityKey;
  };

  /**
  Returns the entity to an {{#crossLink "EntityState"}}{{/crossLink}} of 'Unchanged' by committing all changes made since the entity was last queried
  had 'acceptChanges' called on it.
  @example
      // assume order is an order entity attached to an EntityManager.
      order.entityAspect.acceptChanges();
      // The 'order' entity will now be in an 'Unchanged' state with any changes committed.
  @method acceptChanges
  **/
  proto.acceptChanges = function () {
    this._checkOperation("acceptChanges");
    var em = this.entityManager;
    if (this.entityState.isDeleted()) {
      em.detachEntity(this.entity);
    } else {
      this.setUnchanged();
    }
    em.entityChanged.publish({ entityAction: EntityAction.AcceptChanges, entity: this.entity });
  };

  /**
  Returns the entity to an EntityState of 'Unchanged' by rejecting all changes made to it since the entity was last queried
  had 'rejectChanges' called on it.
  @example
      // assume order is an order entity attached to an EntityManager.
      order.entityAspect.rejectChanges();
      // The 'order' entity will now be in an 'Unchanged' state with any changes rejected.
  @method rejectChanges
  **/
  proto.rejectChanges = function () {
    this._checkOperation("rejectChanges");
    var entity = this.entity;
    var entityManager = this.entityManager;
    // we do not want PropertyChange or EntityChange events to occur here
    __using(entityManager, "isRejectingChanges", true, function () {
      rejectChangesCore(entity);
    });
    if (this.entityState.isAdded()) {
      // next line is needed because the following line will cause this.entityManager -> null;
      entityManager.detachEntity(entity);
      // need to tell em that an entity that needed to be saved no longer does.
      entityManager._notifyStateChange(entity, false);
    } else {
      if (this.entityState.isDeleted()) {
        this.entityManager._linkRelatedEntities(entity);
      }
      this.setUnchanged();
      // propertyChanged propertyName is null because more than one property may have changed.
      this.propertyChanged.publish({ entity: entity, propertyName: null });
      this.entityManager.entityChanged.publish({ entityAction: EntityAction.RejectChanges, entity: entity });
    }
  };

  function rejectChangesCore(target) {
    var aspect = target.entityAspect || target.complexAspect;
    var stype = target.entityType || target.complexType;
    var originalValues = aspect.originalValues;
    for (var propName in originalValues) {
      target.setProperty(propName, originalValues[propName]);
    }
    stype.complexProperties.forEach(function (cp) {
      var cos = target.getProperty(cp.name);
      if (cp.isScalar) {
        rejectChangesCore(cos);
      } else {
        cos._rejectChanges();
        cos.forEach(rejectChangesCore);
      }
    });
  }

  proto.getPropertyPath = function (propName) {
    return propName;
  }


  /**
  Sets the entity to an EntityState of 'Added'.  This is NOT the equivalent of calling {{#crossLink "EntityManager/addEntity"}}{{/crossLink}}
  because no key generation will occur for autogenerated keys as a result of this operation. As a result this operation can be problematic
  unless you are certain that the entity being marked 'Added' does not already exist in the database and does not have an autogenerated key.
  The same operation can be performed by calling  {{#crossLink "EntityAspect/setEntityState"}}{{/crossLink}}.
  @example
      // assume order is an order entity attached to an EntityManager.
      order.entityAspect.setAdded();
      // The 'order' entity will now be in an 'Added' state.
  @method setAdded
  **/
  proto.setAdded = function () {
    return this.setEntityState(EntityState.Added);
  }

  /**
  Sets the entity to an EntityState of 'Unchanged'.  This is also the equivalent of calling {{#crossLink "EntityAspect/acceptChanges"}}{{/crossLink}}.
  The same operation can be performed by calling  {{#crossLink "EntityAspect/setEntityState"}}{{/crossLink}}.
  @example
      // assume order is an order entity attached to an EntityManager.
      order.entityAspect.setUnchanged();
      // The 'order' entity will now be in an 'Unchanged' state with any changes committed.
  @method setUnchanged
  **/
  proto.setUnchanged = function () {
    return this.setEntityState(EntityState.Unchanged);
  };


  /**
  Sets the entity to an EntityState of 'Modified'.  This can also be achieved by changing the value of any property on an 'Unchanged' entity.
  The same operation can be performed by calling  {{#crossLink "EntityAspect/setEntityState"}}{{/crossLink}}.
  @example
      // assume order is an order entity attached to an EntityManager.
      order.entityAspect.setModified();
      // The 'order' entity will now be in a 'Modified' state.
  @method setModified
  **/
  proto.setModified = function () {
    return this.setEntityState(EntityState.Modified);
  };

  /**
  Sets the entity to an EntityState of 'Deleted'.  This both marks the entity as being scheduled for deletion during the next 'Save' call
  but also removes the entity from all of its related entities.
  The same operation can be performed by calling  {{#crossLink "EntityAspect/setEntityState"}}{{/crossLink}}.
  @example
      // assume order is an order entity attached to an EntityManager.
      order.entityAspect.setDeleted();
      // The 'order' entity will now be in a 'Deleted' state and it will no longer have any 'related' entities.
  @method setDeleted
  **/
  proto.setDeleted = function () {
    return this.setEntityState(EntityState.Deleted);
  };

  /**
  Sets the entity to an EntityState of 'Detached'.  This removes the entity from all of its related entities, but does NOT change the EntityState of any existing entities.
  The same operation can be performed by calling  {{#crossLink "EntityAspect/setEntityState"}}{{/crossLink}}.
  @example
      // assume order is an order entity attached to an EntityManager.
      order.entityAspect.setDetached();
      // The 'order' entity will now be in a 'Detached' state and it will no longer have any 'related' entities.
  @method setDetached
  **/
  proto.setDetached = function () {
    return this.setEntityState(EntityState.Detached);
  }

  /**
  Sets the entity to the specified EntityState. See also 'setUnchanged', 'setModified', 'setDetached', etc.
  @example
      // assume order is an order entity attached to an EntityManager.
      order.entityAspect.setEntityState(EntityState.Unchanged);
      // The 'order' entity will now be in a 'Unchanged' state.
  @method setEntityState
  **/
  proto.setEntityState = function (entityState) {
    if (this.entityState === entityState) return false;
    this._checkOperation("setEntityState");
    if (this.entityState.isDetached()) {
      throw new Error("You cannot set the 'entityState' of an entity when it is detached - except by first attaching it to an EntityManager");
    }
    var entity = this.entity;
    var em = this.entityManager;
    var needsSave = true;
    if (entityState === EntityState.Unchanged) {
      clearOriginalValues(entity);
      delete this.hasTempKey;
      needsSave = false;
    } else if (entityState === EntityState.Added) {
      clearOriginalValues(entity);
      // TODO: more to do here... like regenerating key ???
    } else if (entityState === EntityState.Deleted) {
      if (this.entityState.isAdded()) {
        // turn it into a detach and exit early
        this.setEntityState(EntityState.Detached);
        return true;
      } else {
        // TODO: think about cascade deletes
        // entityState needs to be set it early in this one case to insure that fk's are not cleared.
        this.entityState = EntityState.Deleted;
        removeFromRelations(entity, EntityState.Deleted);
      }
    } else if (entityState === EntityState.Modified) {
      // nothing extra needed
    } else if (entityState === EntityState.Detached) {
      var group = this.entityGroup;
      // no group === already detached.
      if (!group) return false;
      group.detachEntity(entity);
      // needs to occur early here - so this IS deliberately redundent with the same code later in this method.
      this.entityState = entityState;
      removeFromRelations(entity, EntityState.Detached);
      this._detach();
      em.entityChanged.publish({ entityAction: EntityAction.Detach, entity: entity });
      needsSave = false;
    }
    this.entityState = entityState;
    em._notifyStateChange(entity, needsSave);
    return true;
  }

  function clearOriginalValues(target) {
    var aspect = target.entityAspect || target.complexAspect;
    aspect.originalValues = {};
    var stype = target.entityType || target.complexType;
    stype.complexProperties.forEach(function (cp) {
      var cos = target.getProperty(cp.name);
      if (cp.isScalar) {
        clearOriginalValues(cos);
      } else {
        cos._acceptChanges();
        cos.forEach(clearOriginalValues);
      }
    });
  }

  /**
  Performs a query for the value of a specified {{#crossLink "NavigationProperty"}}{{/crossLink}}.
  @example
      emp.entityAspect.loadNavigationProperty("Orders").then(function (data) {
          var orders = data.results;
      }).fail(function (exception) {
          // handle exception here;
      });
  @method loadNavigationProperty
  @async
  @param navigationProperty {NavigationProperty|String} The NavigationProperty or the name of the NavigationProperty to 'load'.
  @param [callback] {Function} Function to call on success.
  @param [errorCallback] {Function} Function to call on failure.
  @return {Promise}
    - properties of success promise
      - results {Array of Entity}
      - query {EntityQuery} The original query
      - httpResponse {httpResponse} The HttpResponse returned from the server.
  **/
  proto.loadNavigationProperty = function (navigationProperty, callback, errorCallback) {
    var entity = this.entity;
    var navProperty = entity.entityType._checkNavProperty(navigationProperty);
    var query = EntityQuery.fromEntityNavigation(entity, navProperty);
    // return entity.entityAspect.entityManager.executeQuery(query, callback, errorCallback);
    var promise = entity.entityAspect.entityManager.executeQuery(query);
    var that = this;
    return promise.then(function (data) {
      that._markAsLoaded(navProperty.name);
      if (callback) callback(data);
      return Q.resolve(data);
    }, function (error) {
      if (errorCallback) errorCallback(error);
      return Q.reject(error);
    });

  };

  /**
  Marks this navigationProperty on this entity as already having been loaded.
  @example
      emp.entityAspect.markNavigationPropertyAsLoaded("Orders");

  @method markAsLoaded
  @async
  @param navigationProperty {NavigationProperty|String} The NavigationProperty or name of NavigationProperty to 'load'.
  **/
  proto.markNavigationPropertyAsLoaded = function (navigationProperty) {
    var navProperty = this.entity.entityType._checkNavProperty(navigationProperty);
    this._markAsLoaded(navProperty.name);
  }

  /**
  Determines whether a navigationProperty on this entity has already been loaded.

  @example
      A navigation property is considered loaded when any of the following three conditions applies:

      1) It was fetched from the backend server.
      a) This can be the result of an expand query or a call to the EntityAspect.loadNavigationProperty method.
      b) Note that even if the fetch returns nothing the property is still marked as loaded in this case.
      2) The property is scalar and has been set to a nonnull value.
      3) The EntityAspect.markNavigationPropertyAsLoaded was called.

  @example
      var wasLoaded = emp.entityAspect.isNavigationPropertyLoaded("Orders");

  @method isNavigationPropertyLoaded
  @param navigationProperty {NavigationProperty|String} The NavigationProperty or name of NavigationProperty to 'load'.
  **/
  proto.isNavigationPropertyLoaded = function (navigationProperty) {
    var navProperty = this.entity.entityType._checkNavProperty(navigationProperty);
    if (navProperty.isScalar && this.entity.getProperty(navProperty.name) != null) {
      return true;
    }
    return this._loadedNps && this._loadedNps.indexOf(navProperty.name) >= 0;
  }

  proto._markAsLoaded = function (navPropName) {
    this._loadedNps = this._loadedNps || [];
    __arrayAddItemUnique(this._loadedNps, navPropName);
  }


  /**
  Performs validation on the entity, any errors encountered during the validation are available via the
  {{#crossLink "EntityAspect.getValidationErrors"}}{{/crossLink}} method. Validating an entity means executing
  all of the validators on both the entity itself as well as those on each of its properties.
  @example
      // assume order is an order entity attached to an EntityManager.
      var isOk = order.entityAspect.validateEntity();
      // isOk will be 'true' if there are no errors on the entity.
      if (!isOk) {
          var errors = order.entityAspect.getValidationErrors();
      }
  @method validateEntity
  @return {Boolean} Whether the entity passed validation.
  **/
  proto.validateEntity = function () {
    var ok = true;
    this._processValidationOpAndPublish(function (that) {
      ok = validateTarget(that.entity);
    });
    return ok;
  };

  // coIndex is only used where target is a complex object that is part of an array of complex objects
  // in which case ctIndex is the index of the target within the array.
  function validateTarget(target, coIndex) {
    var ok = true;
    var stype = target.entityType || target.complexType;
    var aspect = target.entityAspect || target.complexAspect;
    var entityAspect = target.entityAspect || target.complexAspect.getEntityAspect();
    var context = { entity: entityAspect.entity  };
    if (coIndex !== undefined) {
      context.index = coIndex;
    }

    stype.getProperties().forEach(function (p) {
      var value = target.getProperty(p.name);
      var validators = p.getAllValidators();
      if (validators.length > 0) {
        context.property = p;
        context.propertyName = aspect.getPropertyPath(p.name);
        ok = entityAspect._validateProperty(value, context) && ok;
      }
      if (p.isComplexProperty) {
        if (p.isScalar) {
          ok = validateTarget(value) && ok;
        } else {
          ok = value.reduce(function (pv, cv, ix) {
            return validateTarget(cv, ix) && pv;
          }, ok);
        }
      }
    });


    // then target level
    stype.getAllValidators().forEach(function (validator) {
      ok = validate(entityAspect, validator, target) && ok;
    });
    return ok;
  }


  /**
  Performs validation on a specific property of this entity, any errors encountered during the validation are available via the
  {{#crossLink "EntityAspect.getValidationErrors"}}{{/crossLink}} method. Validating a property means executing
  all of the validators on the specified property.  This call is also made automatically anytime a property
  of an entity is changed.
  @example
      // assume order is an order entity attached to an EntityManager.
      var isOk = order.entityAspect.validateProperty("Order");
  or
  @example
      var orderDateProperty = order.entityType.getProperty("OrderDate");
      var isOk = order.entityAspect.validateProperty(OrderDateProperty);
  @method validateProperty
  @param property {DataProperty|NavigationProperty|String} The {{#crossLink "DataProperty"}}{{/crossLink}} or
  {{#crossLink "NavigationProperty"}}{{/crossLink}} to validate or a string with the name of the property or a property path with
  the path to a property of a complex object.
  @param [context] {Object} A context object used to pass additional information to each  {{#crossLink "Validator"}}{{/crossLink}}
  @return {Boolean} Whether the entity passed validation.
  **/
  proto.validateProperty = function (property, context) {
    var value = this.getPropertyValue(property); // performs validations
    if (value && value.complexAspect) {
      return validateTarget(value);
    }
    context = context || {};
    context.entity = this.entity;
    if (typeof(property) === 'string') {
      context.property = this.entity.entityType.getProperty(property, true);
      context.propertyName = property;
    } else {
      context.property = property;
      context.propertyName = property.name;
    }

    return this._validateProperty(value, context);
  };

  /**
  Returns the validation errors associated with either the entire entity or any specified property.
  @example
  This method can return all of the errors for an Entity
  @example
      // assume order is an order entity attached to an EntityManager.
      var valErrors = order.entityAspect.getValidationErrors();
  as well as those for just a specific property.
  @example
      // assume order is an order entity attached to an EntityManager.
      var orderDateErrors = order.entityAspect.getValidationErrors("OrderDate");
  which can also be expressed as
  @example
      // assume order is an order entity attached to an EntityManager.
      var orderDateProperty = order.entityType.getProperty("OrderDate");
      var orderDateErrors = order.entityAspect.getValidationErrors(orderDateProperty);
  @method getValidationErrors
  @param [property] {DataProperty|NavigationProperty} The property for which validation errors should be retrieved.
  If omitted, all of the validation errors for this entity will be returned.
  @return {Array of ValidationError}
  **/
  proto.getValidationErrors = function (property) {
    assertParam(property, "property").isOptional().isEntityProperty().or().isString().check();
    var result = __getOwnPropertyValues(this._validationErrors);
    if (property) {
      var propertyName = typeof (property) === 'string' ? property : property.name;
      result = result.filter(function (ve) {
        return ve.property && (ve.property.name === propertyName || (propertyName.indexOf(".") != -1 && ve.propertyName == propertyName));
      });
    }
    return result;
  };

  /**
  Adds a validation error.
  @method addValidationError
  @param validationError {ValidationError}
  **/
  proto.addValidationError = function (validationError) {
    assertParam(validationError, "validationError").isInstanceOf(ValidationError).check();
    this._processValidationOpAndPublish(function (that) {
      that._addValidationError(validationError);
    });
  };

  /**
  Removes a validation error.
  @method removeValidationError
  @param validationErrorOrKey {ValidationError|String} Either a ValidationError or a ValidationError 'key' value
  **/
  proto.removeValidationError = function (validationErrorOrKey) {
    assertParam(validationErrorOrKey, "validationErrorOrKey").isString().or().isInstanceOf(ValidationError).or().isInstanceOf(Validator).check();

    var key = (typeof (validationErrorOrKey) === "string") ? validationErrorOrKey : validationErrorOrKey.key;
    this._processValidationOpAndPublish(function (that) {
      that._removeValidationError(key);
    });
  };

  /**
  Removes all of the validation errors for a specified entity
  @method clearValidationErrors
  **/
  proto.clearValidationErrors = function () {
    this._processValidationOpAndPublish(function (that) {
      __objectForEach(that._validationErrors, function (key, valError) {
        if (valError) {
          delete that._validationErrors[key];
          that._pendingValidationResult.removed.push(valError);
        }
      });
      that.hasValidationErrors = !__isEmpty(that._validationErrors);
    });
  };


  // returns null for np's that do not have a parentKey
  proto.getParentKey = function (navigationProperty) {
    // NavigationProperty doesn't yet exist
    // assertParam(navigationProperty, "navigationProperty").isInstanceOf(NavigationProperty).check();
    var fkNames = navigationProperty.foreignKeyNames;
    if (fkNames.length === 0) return null;
    var that = this;
    var fkValues = fkNames.map(function (fkn) {
      return that.entity.getProperty(fkn);
    });
    return new EntityKey(navigationProperty.entityType, fkValues);
  };

  proto.getPropertyValue = function (property) {
    assertParam(property, "property").isString().or().isEntityProperty().check();
    var value;
    if (typeof (property) === 'string') {
      var propNames = property.trim().split(".");
      var propName = propNames.shift();
      value = this.entity;
      value = value.getProperty(propName);
      while (propNames.length > 0) {
        propName = propNames.shift();
        value = value.getProperty(propName);
      }
    } else {
      if (!(property.parentType instanceof EntityType)) {
        throw new Error("The validateProperty method does not accept a 'property' parameter whose parentType is a ComplexType; " +
            "Pass a 'property path' string as the 'property' parameter instead ");
      }
      value = this.entity.getProperty(property.name);
    }
    return value;
  };

  // internal methods

  proto._checkOperation = function(operationName) {
    if (this.isBeingSaved) {
      throw new Error("Cannot perform a '" + operationName + "' on an entity that is in the process of being saved");
    }
    // allows chaining
    return this;
  }

  proto._detach = function () {
    this.entityGroup = null;
    this.entityManager = null;
    this.entityState = EntityState.Detached;
    this.originalValues = {};
    this._validationErrors = {};
    this.hasValidationErrors = false;
    this.validationErrorsChanged.clear();
    this.propertyChanged.clear();
  };


  // called from defaultInterceptor.
  proto._validateProperty = function (value, context) {
    var ok = true;
    this._processValidationOpAndPublish(function (that) {
      context.property.getAllValidators().forEach(function (validator) {
        ok = validate(that, validator, value, context) && ok;
      });
    });
    return ok;
  };

  proto._processValidationOpAndPublish = function (validationFn) {
    if (this._pendingValidationResult) {
      // only top level processValidations call publishes
      validationFn(this);
    } else {
      try {
        this._pendingValidationResult = { entity: this.entity, added: [], removed: [] };
        validationFn(this);
        if (this._pendingValidationResult.added.length > 0 || this._pendingValidationResult.removed.length > 0) {
          this.validationErrorsChanged.publish(this._pendingValidationResult);
          // this might be a detached entity hence the guard below.
          this.entityManager && this.entityManager.validationErrorsChanged.publish(this._pendingValidationResult);

        }
      } finally {
        this._pendingValidationResult = undefined;
      }
    }
  };

  proto._addValidationError = function (validationError) {
    this._validationErrors[validationError.key] = validationError;
    this.hasValidationErrors = true;
    this._pendingValidationResult.added.push(validationError);
  };

  proto._removeValidationError = function (key) {
    var valError = this._validationErrors[key];
    if (valError) {
      delete this._validationErrors[key];
      this.hasValidationErrors = !__isEmpty(this._validationErrors);
      this._pendingValidationResult.removed.push(valError);
    }
  };

  function removeFromRelations(entity, entityState) {
    // remove this entity from any collections.
    // mark the entity deleted or detached

    var isDeleted = entityState.isDeleted();
    if (isDeleted) {
      removeFromRelationsCore(entity);
    } else {
      __using(entity.entityAspect.entityManager, "isLoading", true, function () {
        removeFromRelationsCore(entity);
      });
    }
  }

  function removeFromRelationsCore(entity) {
    entity.entityType.navigationProperties.forEach(function (np) {
      var inverseNp = np.getInverse();
      var npValue = entity.getProperty(np.name);
      if (np.isScalar) {
        if (npValue) {
          if (inverseNp) {
            if (inverseNp.isScalar) {
              npValue.setProperty(inverseNp.name, null);
            } else {
              var collection = npValue.getProperty(inverseNp.name);
              if (collection.length) {
                __arrayRemoveItem(collection, entity);
              }
            }
          }
          entity.setProperty(np.name, null);
        }
      } else {
        if (inverseNp) {
          // npValue is a live list so we need to copy it first.
          npValue.slice(0).forEach(function (v) {
            if (inverseNp.isScalar) {
              v.setProperty(inverseNp.name, null);
            } else {
              // TODO: many to many - not yet handled.
            }
          });
        }
        // now clear it.
        npValue.length = 0;
      }
    });

  };

  // note entityAspect only - ( no complex aspect allowed on the call).
  function validate(entityAspect, validator, value, context) {
    var ve = validator.validate(value, context);
    if (ve) {
      entityAspect._addValidationError(ve);
      return false;
    } else {
      var key = ValidationError.getKey(validator, context ? context.propertyName : null);
      entityAspect._removeValidationError(key);
      return true;
    }
  }



  return ctor;

})();

var ComplexAspect = (function () {

  /**
  An ComplexAspect instance is associated with every complex object instance and is accessed via the complex object's 'complexAspect' property.

  The ComplexAspect itself provides properties to determine the parent object, parent property and original values for the complex object.

  A ComplexAspect will almost never need to be constructed directly. You will usually get an ComplexAspect by accessing
  an entities 'complexAspect' property.  This property will be automatically attached when an complex object is created as part of an
  entity via either a query, import or EntityManager.createEntity call.
  @example
      // assume address is a complex property on the 'Customer' type
      var aspect = aCustomer.address.complexAspect;
      // aCustomer === aspect.parent;
  @class ComplexAspect
  **/
  var ctor = function ComplexAspect(complexObject, parent, parentProperty) {
    if (!complexObject) {
      throw new Error("The  ComplexAspect ctor requires an entity as its only argument.");
    }
    if (complexObject.complexAspect) {
      return complexObject.complexAspect;
    }
    // if called without new
    if (!(this instanceof ComplexAspect)) {
      return new ComplexAspect(complexObject, parent, parentProperty);
    }

    // entityType should already be on the entity from 'watch'
    this.complexObject = complexObject;
    complexObject.complexAspect = this;

    // TODO: keep public or not?
    this.originalValues = {};

    // if a standalone complexObject
    if (parent != null) {
      this.parent = parent;
      this.parentProperty = parentProperty;
    }

    var complexType = complexObject.complexType;
    if (!complexType) {
      var typeName = complexObject.prototype._$typeName;
      if (!typeName) {
        throw new Error("This entity is not registered as a valid ComplexType");
      } else {
        throw new Error("Metadata for this complexType has not yet been resolved: " + typeName);
      }
    }
    var complexCtor = complexType.getCtor();
    __modelLibraryDef.getDefaultInstance().startTracking(complexObject, complexCtor.prototype);

  };
  var proto = ctor.prototype;


  /**
  The complex object that this aspect is associated with.

  __readOnly__
  @property complexObject {Entity}
  **/

  /**
  The parent object that to which this aspect belongs; this will either be an entity or another complex object.

  __readOnly__
  @property parent {Entity|ComplexObject}
  **/

  /**
  The {{#crossLink "DataProperty"}}{{/crossLink}} on the 'parent' that contains this complex object.

  __readOnly__
  @property parentProperty {DataProperty}
  **/

  /**
  The 'original values' of this complex object where they are different from the 'current values'.
  This is a map where the key is a property name and the value is the 'original value' of the property.

  __readOnly__
  @property originalValues {Object}
  **/

  /**
  Returns the EntityAspect for the top level entity tht contains this complex object.

  @method getEntityAspect
  @return  {String}
  **/
  proto.getEntityAspect = function () {
    var parent = this.parent;
    if (!parent) return new EntityAspect(null);
    var entityAspect = parent.entityAspect;
    while (parent && !entityAspect) {
      parent = parent.complexAspect && parent.complexAspect.parent;
      entityAspect = parent && parent.entityAspect;
    }
    return entityAspect || new EntityAspect(null);
  }

  /**
  Executes the specified query against this EntityManager's local cache.

  @method getPropertyPath
  @param propName {String}  The property name of a property on this complex aspect for which we want the full path.
  @return  {String}    The 'property path' from the top level entity that contains this complex object to this object.
  **/
  proto.getPropertyPath = function (propName) {
    var parent = this.parent;
    if (!parent) return null;
    var aspect = parent.complexAspect || parent.entityAspect;
    return aspect.getPropertyPath(this.parentProperty.name + "." + propName);
  }

  return ctor;

})();


breeze.EntityAspect = EntityAspect;
breeze.ComplexAspect = ComplexAspect;
;/**
@module breeze
**/

var EntityKey = (function () {

  var ENTITY_KEY_DELIMITER = ":::";

  /**
  An EntityKey is an object that represents the unique identity of an entity.  EntityKey's are immutable.

  @class EntityKey
  **/

  /**
  Constructs a new EntityKey.  Each entity within an EntityManager will have a unique EntityKey.
  @example
      // assume em1 is an EntityManager containing a number of existing entities.
      var empType = em1.metadataStore.getEntityType("Employee");
      var entityKey = new EntityKey(empType, 1);
  EntityKey's may also be found by calling EntityAspect.getKey()
  @example
      // assume employee1 is an existing Employee entity
      var empKey = employee1.entityAspect.getKey();
  Multipart keys are created by passing an array as the 'keyValues' parameter
  @example
      var empTerrType = em1.metadataStore.getEntityType("EmployeeTerritory");
      var empTerrKey = new EntityKey(empTerrType, [ 1, 77]);
      // The order of the properties in the 'keyValues' array must be the same as that
      // returned by empTerrType.keyProperties
  @method <ctor> EntityKey
  @param entityType {EntityType} The {{#crossLink "EntityType"}}{{/crossLink}} of the entity.
  @param keyValues {value|Array of values} A single value or an array of values.
  **/
  var ctor = function EntityKey(entityType, keyValues) {
    assertParam(entityType, "entityType").isInstanceOf(EntityType).check();
    var subtypes = entityType.getSelfAndSubtypes();
    if (subtypes.length > 1) {
      this._subtypes = subtypes.filter(function (st) {
        return st.isAbstract === false;
      });
    }

    if (!Array.isArray(keyValues)) {
      keyValues = __arraySlice(arguments, 1);
    }

    this.entityType = entityType;
    entityType.keyProperties.forEach(function (kp, i) {
      // insure that guid keys are comparable.
      if (kp.dataType === DataType.Guid) {
        keyValues[i] = keyValues[i] && keyValues[i].toLowerCase();
      }
    });

    this.values = keyValues;
    this._keyInGroup = createKeyString(keyValues);

  };

  ctor._$typeName = "EntityKey";
  var proto = ctor.prototype;

  /**
  The 'EntityType' that this is a key for.

  __readOnly__
  @property entityType {EntityType}
  **/

  /**
  An array of the values for this key. This will usually only have a single element, unless the entity type has a multipart key.

  __readOnly__
  @property values {Array}
  **/

  proto.toJSON = function () {
    return {
      entityType: this.entityType.name,
      values: this.values
    };
  };

  ctor.fromJSON = function (json, metadataStore) {
    var et = metadataStore._getEntityType(json.entityType, true);
    return new EntityKey(et, json.values);
  };

  /**
  Used to compare EntityKeys are determine if they refer to the same Entity.
  There is also an static version of 'equals' with the same functionality.
  @example
      // assume em1 is an EntityManager containing a number of existing entities.
      var empType = em1.metadataStore.getEntityType("Employee");
      var empKey1 = new EntityKey(empType, 1);
      // assume employee1 is an existing Employee entity
      var empKey2 = employee1.entityAspect.getKey();
      if (empKey1.equals(empKey2)) {
          // do something  ...
      }
  @method equals
  @param entityKey {EntityKey}
  **/
  proto.equals = function (entityKey) {
    if (!(entityKey instanceof EntityKey)) return false;
    return (this.entityType === entityKey.entityType) &&
        __arrayEquals(this.values, entityKey.values);
  };

  /*
  Returns a human readable representation of this EntityKey.
  @method toString
  */
  proto.toString = function (altEntityType) {
    return (altEntityType || this.entityType).name + '-' + this._keyInGroup;
  };

  /**
  Used to compare EntityKeys are determine if they refer to the same Entity.
  There is also an instance version of 'equals' with the same functionality.
  @example
      // assume em1 is an EntityManager containing a number of existing entities.
      var empType = em1.metadataStore.getEntityType("Employee");
      var empKey1 = new EntityKey(empType, 1);
      // assume employee1 is an existing Employee entity
      var empKey2 = employee1.entityAspect.getKey();
      if (EntityKey.equals(empKey1, empKey2)) {
          // do something  ...
      }
  @method equals
  @static
  @param k1 {EntityKey}
  @param k2 {EntityKey}
  **/
  ctor.equals = function (k1, k2) {
    if (!(k1 instanceof EntityKey)) return false;
    return k1.equals(k2);
  };

  // TODO: we may want to compare to default values later.
  proto._isEmpty = function () {
    return this.values.join("").length === 0;
  };

  ctor.createKeyString = createKeyString;

  function createKeyString(keyValues) {
    return keyValues.join(ENTITY_KEY_DELIMITER);
  }

  return ctor;
})();

breeze.EntityKey = EntityKey;
;/**
@module breeze
**/

var EntityState = (function () {
  /**
  EntityState is an 'Enum' containing all of the valid states for an 'Entity'.

  @class EntityState
  @static
  **/
  var entityStateMethods = {
    /**
    @example
        var es = anEntity.entityAspect.entityState;
        return es.isUnchanged();
    is the same as
    @example
        return es === EntityState.Unchanged;
    @method isUnchanged
    @return {Boolean} Whether an entityState instance is EntityState.Unchanged.
    **/
    isUnchanged: function () {
      return this === EntityState.Unchanged;
    },
    /**
    @example
        var es = anEntity.entityAspect.entityState;
        return es.isAdded();
    is the same as
    @example
        return es === EntityState.Added;
    @method isAdded
    @return {Boolean} Whether an entityState instance is EntityState.Added.
    **/
    isAdded: function () {
      return this === EntityState.Added;
    },
    /**
    @example
        var es = anEntity.entityAspect.entityState;
        return es.isModified();
    is the same as
    @example
        return es === EntityState.Modified;
    @method isModified
    @return {Boolean} Whether an entityState instance is EntityState.Modified.
    **/
    isModified: function () {
      return this === EntityState.Modified;
    },
    /**
    @example
        var es = anEntity.entityAspect.entityState;
        return es.isDeleted();
    is the same as
    @example
        return es === EntityState.Deleted;
    @method isDeleted
    @return  {Boolean} Whether an entityState instance is EntityState.Deleted.
    **/
    isDeleted: function () {
      return this === EntityState.Deleted;
    },
    /**
    @example
        var es = anEntity.entityAspect.entityState;
        return es.isDetached();
    is the same as
    @example
        return es === EntityState.Detached;
    @method isDetached
    @return  {Boolean} Whether an entityState instance is EntityState.Detached.
    **/
    isDetached: function () {
      return this === EntityState.Detached;
    },
    /**
    @example
        var es = anEntity.entityAspect.entityState;
        return es.isUnchangedOrModified();
    is the same as
    @example
        return es === EntityState.Unchanged || es === EntityState.Modified
    @method isUnchangedOrModified
    @return {Boolean} Whether an entityState instance is EntityState.Unchanged or EntityState.Modified.
    **/
    isUnchangedOrModified: function () {
      return this === EntityState.Unchanged || this === EntityState.Modified;
    },
    /**
    @example
        var es = anEntity.entityAspect.entityState;
        return es.isAddedModifiedOrDeleted();
    is the same as
    @example
        return es === EntityState.Added || es === EntityState.Modified || es === EntityState.Deleted
    @method isAddedModifiedOrDeleted
    @return {Boolean} Whether an entityState instance is EntityState.Added or EntityState.Modified or EntityState.Deleted.
    **/
    isAddedModifiedOrDeleted: function () {
      return this === EntityState.Added ||
          this === EntityState.Modified ||
          this === EntityState.Deleted;
    }
  };

  var EntityState = new Enum("EntityState", entityStateMethods);
  /**
  The 'Unchanged' state.

  @property Unchanged {EntityState}
  @final
  @static
  **/
  EntityState.Unchanged = EntityState.addSymbol();
  /**
  The 'Added' state.

  @property Added {EntityState}
  @final
  @static
  **/
  EntityState.Added = EntityState.addSymbol();
  /**
  The 'Modified' state.

  @property Modified {EntityState}
  @final
  @static
  **/
  EntityState.Modified = EntityState.addSymbol();
  /**
  The 'Deleted' state.

  @property Deleted {EntityState}
  @final
  @static
  **/
  EntityState.Deleted = EntityState.addSymbol();
  /**
  The 'Detached' state.

  @property Detached {EntityState}
  @final
  @static
  **/
  EntityState.Detached = EntityState.addSymbol();
  EntityState.resolveSymbols();
  return EntityState;
})();

breeze.EntityState = EntityState;
;breeze.makePrimitiveArray = (function () {
  var primitiveArrayMixin = {};

  // complexArray will have the following props
  //    parent
  //    propertyPath
  //    parentProperty
  //    addedItems  - only if modified
  //    removedItems  - only if modified
  //  each complexAspect of any entity within a complexArray
  //  will have its own _complexState = "A/M";

  /**
  Primitive arrays are not actually classes, they are objects that mimic arrays. A primitive array is collection of
  primitive types associated with a data property on a single entity or complex object. i.e. customer.invoiceNumbers.
  This collection looks like an array in that the basic methods on arrays such as 'push', 'pop', 'shift', 'unshift', 'splice'
  are all provided as well as several special purpose methods.
  @class {primitiveArray}
  **/

  /**
  An {{#crossLink "Event"}}{{/crossLink}} that fires whenever the contents of this array changed.  This event
  is fired any time a new entity is attached or added to the EntityManager and happens to belong to this collection.
  Adds that occur as a result of query or import operations are batched so that all of the adds or removes to any individual
  collections are collected into a single notification event for each relation array.
  @example
      // assume order is an order entity attached to an EntityManager.
      orders.arrayChanged.subscribe(
      function (arrayChangedArgs) {
          var addedEntities = arrayChangedArgs.added;
          var removedEntities = arrayChanged.removed;
      });
  @event arrayChanged
  @param added {Array of Primitives} An array of all of the items added to this collection.
  @param removed {Array of Primitives} An array of all of the items removed from this collection.
  @readOnly
  **/

    // virtual impls
  primitiveArrayMixin._getGoodAdds = function (adds) {
    return adds;
  };

  primitiveArrayMixin._beforeChange = function () {
    var entityAspect = this.getEntityAspect();
    if (entityAspect.entityState.isUnchanged()) {
      entityAspect.setModified();
    }
    if (entityAspect.entityState.isModified() && !this._origValues) {
      this._origValues = this.slice(0);
    }
  };

  primitiveArrayMixin._processAdds = function (adds) {
    // nothing needed
  };

  primitiveArrayMixin._processRemoves = function (removes) {
    // nothing needed;
  };
  //

  primitiveArrayMixin._rejectChanges = function () {
    if (!this._origValues) return;
    this.length = 0;
    Array.prototype.push.apply(this, this._origValues);
  };

  primitiveArrayMixin._acceptChanges = function () {
    this._origValues = null;
  };

  // local functions

  function makePrimitiveArray(arr, parent, parentProperty) {

    observableArray.initializeParent(arr, parent, parentProperty);
    arr.arrayChanged = new Event("arrayChanged", arr);
    __extend(arr, observableArray.mixin);
    return __extend(arr, primitiveArrayMixin);
  }

  return makePrimitiveArray;
})();;breeze.makeRelationArray = (function () {

  var relationArrayMixin = {};

  /**
  Relation arrays are not actually classes, they are objects that mimic arrays. A relation array is collection of
  entities associated with a navigation property on a single entity. i.e. customer.orders or order.orderDetails.
  This collection looks like an array in that the basic methods on arrays such as 'push', 'pop', 'shift', 'unshift', 'splice'
  are all provided as well as several special purpose methods.
  @class {relationArray}
  **/

  /**
  An {{#crossLink "Event"}}{{/crossLink}} that fires whenever the contents of this array changed.  This event
  is fired any time a new entity is attached or added to the EntityManager and happens to belong to this collection.
  Adds that occur as a result of query or import operations are batched so that all of the adds or removes to any individual
  collections are collected into a single notification event for each relation array.
  @example
      // assume order is an order entity attached to an EntityManager.
      orders.arrayChanged.subscribe(
      function (arrayChangedArgs) {
          var addedEntities = arrayChangedArgs.added;
          var removedEntities = arrayChanged.removed;
      });
  @event arrayChanged
  @param added {Array of Entity} An array of all of the entities added to this collection.
  @param removed {Array of Entity} An array of all of the removed from this collection.
  @readOnly
  **/


  /**
  Performs an asynchronous load of all other the entities associated with this relationArray.
  @example
      // assume orders is an empty, as yet unpopulated, relation array of orders
      // associated with a specific customer.
      orders.load().then(...)
  @method load
  @param [callback] {Function}
  @param [errorCallback] {Function}
  @return {Promise}
  **/
  relationArrayMixin.load = function (callback, errorCallback) {
    var parent = this.parentEntity;
    var query = EntityQuery.fromEntityNavigation(this.parentEntity, this.navigationProperty);
    var em = parent.entityAspect.entityManager;
    return em.executeQuery(query, callback, errorCallback);
  };

  relationArrayMixin._getEventParent = function () {
    return this.parentEntity.entityAspect;
  };

  relationArrayMixin._getPendingPubs = function () {
    var em = this.parentEntity.entityAspect.entityManager;
    return em && em._pendingPubs;
  };

  // virtual impls
  relationArrayMixin._getGoodAdds = function (adds) {
    return getGoodAdds(this, adds);
  };

  relationArrayMixin._processAdds = function (adds) {
    processAdds(this, adds);
  };

  relationArrayMixin._processRemoves = function (removes) {
    processRemoves(this, removes);
  };
  //

  function getGoodAdds(relationArray, adds) {
    var goodAdds = checkForDups(relationArray, adds);
    if (!goodAdds.length) {
      return goodAdds;
    }
    var parentEntity = relationArray.parentEntity;
    var entityManager = parentEntity.entityAspect.entityManager;
    // we do not want to attach an entity during loading
    // because these will all be 'attached' at a later step.
    if (entityManager && !entityManager.isLoading) {
      goodAdds.forEach(function (add) {
        if (add.entityAspect.entityState.isDetached()) {
          relationArray._inProgress = true;
          try {
            entityManager.attachEntity(add, EntityState.Added);
          } finally {
            relationArray._inProgress = false;
          }
        }
      });
    }
    return goodAdds;
  }

  function processAdds(relationArray, adds) {
    var parentEntity = relationArray.parentEntity;
    var np = relationArray.navigationProperty;
    var addsInProcess = relationArray._addsInProcess;

    var invNp = np.getInverse();
    var startIx = addsInProcess.length;
    try {
      adds.forEach(function (childEntity) {
        addsInProcess.push(childEntity);
        if (invNp) {
          childEntity.setProperty(invNp.name, parentEntity);
        } else {
          // This occurs with a unidirectional 1-n navigation - in this case
          // we need to update the fks instead of the navProp
          var pks = parentEntity.entityType.keyProperties;
          np.invForeignKeyNames.forEach(function (fk, i) {
            childEntity.setProperty(fk, parentEntity.getProperty(pks[i].name));
          });
        }
      });
    } finally {
      addsInProcess.splice(startIx, adds.length);
    }

  }

  function processRemoves(relationArray, removes) {
    var inp = relationArray.navigationProperty.getInverse();
    if (inp) {
      removes.forEach(function (childEntity) {
        childEntity.setProperty(inp.name, null);
      });
    }
  }

  function checkForDups(relationArray, adds) {
    // don't allow dups in this array. - also prevents recursion
    var parentEntity = relationArray.parentEntity;
    var navProp = relationArray.navigationProperty;
    var inverseProp = navProp.getInverse();
    var goodAdds;
    if (inverseProp) {
      goodAdds = adds.filter(function (a) {
        if (relationArray._addsInProcess.indexOf(a) >= 0) {
          return false;
        }
        var inverseValue = a.getProperty(inverseProp.name);
        return inverseValue !== parentEntity;
      });
    } else {
      // This occurs with a unidirectional 1->N relation ( where there is no n -> 1)
      // in this case we compare fks.
      var fkPropNames = navProp.invForeignKeyNames;
      if (navProp.baseProperty && (!fkPropNames.length)) fkPropNames = navProp.baseProperty.invForeignKeyNames; // TODO climb hierarchy
      var keyProps = parentEntity.entityType.keyProperties;
      goodAdds = adds.filter(function (a) {
        if (relationArray._addsInProcess.indexOf(a) >= 0) {
          return false;
        }
        return fkPropNames.some(function (fk, i) {
          var keyProp = keyProps[i].name;
          var keyVal = parentEntity.getProperty(keyProp);
          var fkVal = a.getProperty(fk);
          return keyVal !== fkVal;
        });
      });
    }
    return goodAdds;
  }

  function makeRelationArray(arr, parentEntity, navigationProperty) {
    arr.parentEntity = parentEntity;
    arr.navigationProperty = navigationProperty;
    arr.arrayChanged = new Event("arrayChanged", arr);
    // array of pushes currently in process on this relation array - used to prevent recursion.
    arr._addsInProcess = [];
    // need to use mixins here instead of inheritance because we are starting from an existing array object.
    __extend(arr, observableArray.mixin);
    return __extend(arr, relationArrayMixin);
  }

  return makeRelationArray;
})();;function defaultPropertyInterceptor(property, newValue, rawAccessorFn) {
  // 'this' is the entity itself in this context.

  if (newValue === undefined) newValue = null;
  var oldValue = rawAccessorFn();

  var dataType = property.dataType;
  if (dataType && dataType.parse) {
    // attempts to coerce a value to the correct type - if this fails return the value unchanged
    if (Array.isArray(newValue) && !property.isScalar) {
      newValue = newValue.map(function (nv) {
        return dataType.parse(nv, typeof nv);
      });
    } else {
      newValue = dataType.parse(newValue, typeof newValue);
    }
  }

  // exit if no change - extra cruft is because dateTimes don't compare cleanly.
  if (newValue === oldValue || (dataType && dataType.normalize && newValue && oldValue && dataType.normalize(newValue) === dataType.normalize(oldValue))) {
    return;
  }

  // CANNOT DO NEXT LINE because it has the possibility of creating a new property
  // 'entityAspect' on 'this'.  - Not permitted by IE inside of a defined property on a prototype.
  // var entityAspect = new EntityAspect(this);

  var propertyName;
  var entityAspect = this.entityAspect;
  if (entityAspect) {
    propertyName = property.name;
  } else {
    var localAspect = this.complexAspect;
    if (localAspect) {
      entityAspect = localAspect.getEntityAspect();
      propertyName = localAspect.getPropertyPath(property.name);
    } else {
      // does not yet have an EntityAspect so just set the prop
      rawAccessorFn(newValue);
      return;
    }
  }

  // Note that we need to handle multiple properties in process, not just one in order to avoid recursion.
  // ( except in the case of null propagation with fks where null -> 0 in some cases.)
  // (this may not be needed because of the newValue === oldValue test above)
  var inProcess = entityAspect._inProcess = entityAspect._inProcess || [];
  // check for recursion
  if (inProcess.indexOf(property) >= 0) return;
  inProcess.push(property);

  try {

    var context = {
      parent: this,
      property: property,
      newValue: newValue,
      oldValue: oldValue,
      propertyName: propertyName,
      entityAspect: entityAspect
    }

    if (property.isComplexProperty) {
      setDpValueComplex(context, rawAccessorFn);
    } else if (property.isDataProperty) {
      setDpValueSimple(context, rawAccessorFn);
    } else {
      setNpValue(context, rawAccessorFn);
    }

    postChangeEvents(context);

  } finally {
    inProcess.pop();
  }
}

function setDpValueSimple(context, rawAccessorFn) {
  var parent = context.parent;
  var property = context.property;
  var entityAspect = context.entityAspect;
  var oldValue = context.oldValue;
  var newValue = context.newValue;

  var entityManager = entityAspect.entityManager;
  // 'entityType' on the next line be null for complex properties but it will only be ref'd within this
  // fn when the property is part of the key
  var entityType = parent.entityType;

  if (!property.isScalar) {
    throw new Error("Nonscalar data properties are readonly - items may be added or removed but the collection may not be changed.");
  }

  // store an original value for this property if not already set
  if (entityAspect.entityState.isUnchangedOrModified()) {
    var propName = property.name;
    // localAspect is not the same as entityAspect for complex props
    var localAspect = parent.entityAspect || parent.complexAspect;
    if (localAspect.originalValues[propName] === undefined) {
      // otherwise this entry will be skipped during serialization
      localAspect.originalValues[propName] = oldValue !== undefined ? oldValue : property.defaultValue;
    }
  }

  // if we are changing the key update our internal entityGroup indexes.
  if (property.isPartOfKey && entityManager && !entityManager.isLoading) {
    var keyProps = entityType.keyProperties;
    var values = keyProps.map(function (p) {
      if (p === property) {
        return newValue;
      } else {
        return parent.getProperty(p.name);
      }
    });
    var newKey = new EntityKey(entityType, values);
    if (entityManager.findEntityByKey(newKey)) {
      throw new Error("An entity with this key is already in the cache: " + newKey.toString());
    }
    var oldKey = parent.entityAspect.getKey();
    var eg = entityManager._findEntityGroup(entityType);
    eg._replaceKey(oldKey, newKey);
  }

  // process related updates ( the inverse relationship) first so that collection dups check works properly.
  // update inverse relationship

  var relatedNavProp = property.relatedNavigationProperty;
  if (relatedNavProp && entityManager) {
    // Example: bidirectional fkDataProperty: 1->n: order -> orderDetails
    // orderDetail.orderId <- newOrderId || null
    //    ==> orderDetail.order = lookupOrder(newOrderId)
    //    ==> (see set navProp above)
    //       and
    // Example: bidirectional fkDataProperty: 1->1: order -> internationalOrder
    // internationalOrder.orderId <- newOrderId || null
    //    ==> internationalOrder.order = lookupOrder(newOrderId)
    //    ==> (see set navProp above)

    if (newValue != null) {
      var key = new EntityKey(relatedNavProp.entityType, [newValue]);
      var relatedEntity = entityManager.findEntityByKey(key);

      if (relatedEntity) {
        parent.setProperty(relatedNavProp.name, relatedEntity);
      } else {
        // it may not have been fetched yet in which case we want to add it as an unattachedChild.
        entityManager._unattachedChildrenMap.addChild(key, relatedNavProp, parent);
        parent.setProperty(relatedNavProp.name, null);
      }
    } else {
      parent.setProperty(relatedNavProp.name, null);
    }
  } else if (property.inverseNavigationProperty && entityManager && !entityManager._inKeyFixup) {
    // Example: unidirectional fkDataProperty: 1->n: region -> territories
    // territory.regionId <- newRegionId
    //    ==> lookupRegion(newRegionId).territories.push(territory)
    //                and
    // Example: unidirectional fkDataProperty: 1->1: order -> internationalOrder
    // internationalOrder.orderId <- newOrderId
    //    ==> lookupOrder(newOrderId).internationalOrder = internationalOrder
    //                and
    // Example: unidirectional fkDataProperty: 1->n: region -> territories
    // territory.regionId <- null
    //    ==> lookupRegion(territory.oldRegionId).territories.remove(oldTerritory);
    //                and
    // Example: unidirectional fkDataProperty: 1->1: order -> internationalOrder
    // internationalOrder.orderId <- null
    //    ==> lookupOrder(internationalOrder.oldOrderId).internationalOrder = null;

    var invNavProp = property.inverseNavigationProperty;

    if (oldValue != null) {
      key = new EntityKey(invNavProp.parentType, [oldValue]);
      relatedEntity = entityManager.findEntityByKey(key);
      if (relatedEntity) {
        if (invNavProp.isScalar) {
          relatedEntity.setProperty(invNavProp.name, null);
        } else {
          // remove 'this' from old related nav prop
          var relatedArray = relatedEntity.getProperty(invNavProp.name);
          // arr.splice(arr.indexOf(value_to_remove), 1);
          relatedArray.splice(relatedArray.indexOf(parent), 1);
        }
      }
    }

    if (newValue != null) {
      key = new EntityKey(invNavProp.parentType, [newValue]);
      relatedEntity = entityManager.findEntityByKey(key);

      if (relatedEntity) {
        if (invNavProp.isScalar) {
          relatedEntity.setProperty(invNavProp.name, parent);
        } else {
          relatedEntity.getProperty(invNavProp.name).push(parent);
        }
      } else {
        // it may not have been fetched yet in which case we want to add it as an unattachedChild.
        entityManager._unattachedChildrenMap.addChild(key, invNavProp, parent);
      }
    }

  }

  rawAccessorFn(newValue);

  updateStateAndValidate(context);

  // if (property.isPartOfKey && (!this.complexAspect)) {
  if (property.isPartOfKey) {
    // propogate pk change to all related entities;

    var propertyIx = entityType.keyProperties.indexOf(property);
    // this part handles order.orderId => orderDetail.orderId
    // but won't handle product.productId => orderDetail.productId because product
    // doesn't have an orderDetails property.
    entityType.navigationProperties.forEach(function (np) {
      var inverseNp = np.getInverse();
      var fkNames = inverseNp ? inverseNp.foreignKeyNames : np.invForeignKeyNames;

      if (fkNames.length === 0) return;
      var npValue = parent.getProperty(np.name);
      if (!npValue) return;
      var fkName = fkNames[propertyIx];
      if (np.isScalar) {
        npValue.setProperty(fkName, newValue);
      } else {
        npValue.forEach(function (iv) {
          iv.setProperty(fkName, newValue);
        });
      }
    });
    // this handles unidirectional problems not covered above.
    if (entityManager) {
      var inverseForeignKeyProperties = entityType.inverseForeignKeyProperties;
      var baseEntityType = entityType.baseEntityType;
      while (baseEntityType) {
        inverseForeignKeyProperties = inverseForeignKeyProperties.concat(baseEntityType.inverseForeignKeyProperties);
        baseEntityType = baseEntityType.baseEntityType;
      }
      inverseForeignKeyProperties.forEach(function (invFkProp) {
        if (invFkProp.relatedNavigationProperty.inverse == null) {
          // this next step may be slow - it iterates over all of the entities in a group;
          // hopefully it doesn't happen often.
          entityManager._updateFkVal(invFkProp, oldValue, newValue);
        }
        ;
      });
    }

    // insure that cached key is updated.
    entityAspect.getKey(true);
  }
}

function setDpValueComplex(context, rawAccessorFn) {
  var property = context.property;
  var oldValue = context.oldValue;
  var newValue = context.newValue;

  var dataType = property.dataType;
  if (property.isScalar) {
    if (!newValue) {
      throw new Error(__formatString("You cannot set the '%1' property to null because it's datatype is the ComplexType: '%2'", property.name, property.dataType.name));
    }
    // To get here it must be a ComplexProperty
    // 'dataType' will be a complexType
    if (!oldValue) {
      var ctor = dataType.getCtor();
      oldValue = new ctor();
      rawAccessorFn(oldValue);
    }
    dataType.dataProperties.forEach(function (dp) {
      var pn = dp.name;
      var nv = newValue.getProperty(pn);
      oldValue.setProperty(pn, nv);
    });
  } else {
    throw new Error(__formatString("You cannot set the non-scalar complex property: '%1' on the type: '%2'." +
            "Instead get the property and use array functions like 'push' or 'splice' to change its contents.",
        property.name, property.parentType.name));
  }
}

function setNpValue(context, rawAccessorFn) {

  var parent = context.parent;
  var property = context.property;
  var entityAspect = context.entityAspect;
  var oldValue = context.oldValue;
  var newValue = context.newValue;

  if (!property.isScalar) {
    throw new Error("Nonscalar navigation properties are readonly - entities can be added or removed but the collection may not be changed.");
  }

  var entityManager = entityAspect.entityManager;
  var inverseProp = property.getInverse();

  // manage attachment -
  if (newValue != null) {
    var newAspect = newValue.entityAspect;
    if (entityManager) {
      if (newAspect.entityState.isDetached()) {
        if (!entityManager.isLoading) {
          entityManager.attachEntity(newValue, EntityState.Added);
        }
      } else {
        if (newAspect.entityManager !== entityManager) {
          throw new Error("An Entity cannot be attached to an entity in another EntityManager. One of the two entities must be detached first.");
        }
      }
    } else {
      if (newAspect && newAspect.entityManager) {
        entityManager = newAspect.entityManager;
        if (!entityManager.isLoading) {
          entityManager.attachEntity(entityAspect.entity, EntityState.Added);
        }
      }
    }
  }

  // process related updates ( the inverse relationship) first so that collection dups check works properly.
  // update inverse relationship
  if (inverseProp) {
    ///
    if (inverseProp.isScalar) {
      // Example: bidirectional navProperty: 1->1: order -> internationalOrder
      // order.internationalOrder <- internationalOrder || null
      //    ==> (oldInternationalOrder.order = null)
      //    ==> internationalOrder.order = order
      if (oldValue != null) {
        // TODO: null -> NullEntity later
        oldValue.setProperty(inverseProp.name, null);
      }
      if (newValue != null) {
        newValue.setProperty(inverseProp.name, parent);
      }
    } else {
      // Example: bidirectional navProperty: 1->n: order -> orderDetails
      // orderDetail.order <- newOrder || null
      //    ==> (oldOrder).orderDetails.remove(orderDetail)
      //    ==> order.orderDetails.push(newOrder)
      if (oldValue != null) {
        var oldSiblings = oldValue.getProperty(inverseProp.name);
        var ix = oldSiblings.indexOf(parent);
        if (ix !== -1) {
          oldSiblings.splice(ix, 1);
        }
      }
      if (newValue != null) {
        var siblings = newValue.getProperty(inverseProp.name);
        // recursion check if already in the collection is performed by the relationArray
        siblings.push(parent);
      }
    }
  } else if (property.invForeignKeyNames && entityManager && !entityManager._inKeyFixup) {
    var invForeignKeyNames = property.invForeignKeyNames;
    if (newValue != null) {
      // Example: unidirectional navProperty: 1->1: order -> internationalOrder
      // order.InternationalOrder <- internationalOrder
      //    ==> internationalOrder.orderId = orderId
      //      and
      // Example: unidirectional navProperty: 1->n: order -> orderDetails
      // orderDetail.order <-xxx newOrder
      //    ==> CAN'T HAPPEN because if unidirectional because orderDetail will not have an order prop
      var pkValues = parent.entityAspect.getKey().values;
      invForeignKeyNames.forEach(function (fkName, i) {
        newValue.setProperty(fkName, pkValues[i]);
      });
    } else {
      // Example: unidirectional navProperty: 1->1: order -> internationalOrder
      // order.internationalOrder <- null
      //    ==> (old internationalOrder).orderId = null
      //        and
      // Example: unidirectional navProperty: 1->n: order -> orderDetails
      // orderDetail.order <-xxx newOrder
      //    ==> CAN'T HAPPEN because if unidirectional because orderDetail will not have an order prop
      if (oldValue != null) {
        invForeignKeyNames.forEach(function (fkName) {
          var fkProp = oldValue.entityType.getProperty(fkName);
          if (!fkProp.isPartOfKey) {
            // don't update with null if fk is part of the key
            oldValue.setProperty(fkName, null);
          }
        });
      }
    }
  }

  rawAccessorFn(newValue);

  updateStateAndValidate(context);

  // update fk data property - this can only occur if this navProperty has
  // a corresponding fk on this entity.
  if (property.relatedDataProperties) {
    var entityState = entityAspect.entityState;
    // if either side of nav prop is detached don't clear fks. Note: oldValue in next line cannot be null so no check is needed.
    if (newValue == null && (entityState.isDetached() || oldValue.entityAspect.entityState.isDetached())) return;
    if (entityState.isDeleted()) return;
    var inverseKeyProps = property.entityType.keyProperties;
    inverseKeyProps.forEach(function (keyProp, i) {
      var relatedDataProp = property.relatedDataProperties[i];
      // Do not trash related property if it is part of that entity's key
      if (newValue || !relatedDataProp.isPartOfKey) {
        var relatedValue = newValue ? newValue.getProperty(keyProp.name) : relatedDataProp.defaultValue;
        parent.setProperty(relatedDataProp.name, relatedValue);
      }
    });
  }
}

function postChangeEvents(context) {
  var entityAspect = context.entityAspect;

  var entityManager = entityAspect.entityManager;
  var entity = entityAspect.entity;

  var propChangedArgs = { entity: entity, parent: context.parent, property: context.property, propertyName: context.propertyName, oldValue: context.oldValue, newValue: context.newValue };
  if (entityManager) {
    // propertyChanged will be fired during loading but we only want to fire it once per entity, not once per property.
    // so propertyChanged is fired in the entityManager mergeEntity method if not fired here.
    if ((!entityManager.isLoading) && (!entityManager.isRejectingChanges)) {
      entityAspect.propertyChanged.publish(propChangedArgs);
      // don't fire entityChanged event if propertyChanged is suppressed.
      entityManager.entityChanged.publish({ entityAction: EntityAction.PropertyChange, entity: entity, args: propChangedArgs });
    }
  } else {
    entityAspect.propertyChanged.publish(propChangedArgs);
  }
}

function updateStateAndValidate(context) {
  var entityAspect = context.entityAspect;
  var entityManager = entityAspect.entityManager;
  if (entityManager == null || entityManager.isLoading) return;
  var property = context.property;

  if (entityAspect.entityState.isUnchanged() && !property.isUnmapped) {
    entityAspect.setModified();
  }

  if (entityManager.validationOptions.validateOnPropertyChange) {
    // entityAspect.entity is NOT the same as parent in the code below. It's use is deliberate.
    entityAspect._validateProperty(context.newValue,
        { entity: entityAspect.entity, property: property, propertyName: context.propertyName, oldValue: context.oldValue });
  }
}
;/**
@module breeze
**/

var DataType = (function () {

  /**
  DataType is an 'Enum' containing all of the supported data types.

  @class DataType
  @static
  **/

  /**
  The default value of this DataType.
  @property defaultValue {any}
  **/

  /**
  Whether this is a 'numeric' DataType.
  @property isNumeric {Boolean}
  **/

  /**
  Whether this is an 'integer' DataType.
  @property isInteger {Boolean}
  **/

  /**
  Function to convert a value from string to this DataType.  Note that this will be called each time a property is changed, so make it fast.
  @method parse {Function}
  @param value {any}
  @param sourceTypeName {String}
  @return value appropriate for this DataType
  **/

  /**
  Function to format this DataType for OData queries.
  @method fmtOData {Function}
  @return value appropriate for OData query
  **/

  /**
  Optional function to get the next value for key generation, if this datatype is used as a key.  Uses an internal table of previous values.
  @method getNext {Function}
  @return value appropriate for this DataType
  **/

  /**
  Optional function to normalize a data value for comparison, if its value cannot be used directly.  Note that this will be called each time a property is changed, so make it fast.
  @method normalize {Function}
  @param value
  @return value appropriate for this DataType
  **/

  /**
  Optional function to get the next value when the datatype is used as a concurrency property.
  @method getConcurrencyValue {Function}
  @param previousValue
  @return the next concurrency value, which may be a function of the previousValue.
  **/

  /**
  Optional function to convert a raw (server) value from string to this DataType.
  @method parseRawValue {Function}
  @param value {any}
  @return value appropriate for this DataType
  **/

  var dataTypeMethods = {
    // default
  };

  var constants;
  var resetConstants = function () {
    constants = {
      stringPrefix: "K_",
      nextNumber: -1,
      nextNumberIncrement: -1
    };
  };

  resetConstants();

  var getNextString = function () {
    return constants.stringPrefix + getNextNumber().toString();
  };

  var getNextNumber = function () {
    var result = constants.nextNumber;
    constants.nextNumber += constants.nextNumberIncrement;
    return result;
  };

  var getNextGuid = function () {
    return __getUuid();
  };

  var getNextDateTime = function () {
    return new Date();
  };

  var getConcurrencyDateTime = function(val) {
    // use the current datetime but insure that it is different from previous call.
    var dt = new Date();
    var dt2 = new Date();
    while (dt.getTime() === dt2.getTime()) {
      dt2 = new Date();
    }
    return dt2;
  };

  var coerceToString = function (source, sourceTypeName) {
    return (source == null) ? source : source.toString();
  };

  var coerceToGuid = function (source, sourceTypeName) {
    if (sourceTypeName === "string") {
      return source.trim().toLowerCase();
    }
    return source;
  };

  var coerceToInt = function (source, sourceTypeName) {
    if (sourceTypeName === "string") {
      var src = source.trim();
      if (src === "") return null;
      var val = parseInt(src, 10);
      return isNaN(val) ? source : val;
    } else if (sourceTypeName === "number") {
      return Math.round(source);
    }
    // do we want to coerce floats -> ints
    return source;
  };

  var coerceToFloat = function (source, sourceTypeName) {
    if (sourceTypeName === "string") {
      var src = source.trim();
      if (src === "") return null;
      var val = parseFloat(src);
      return isNaN(val) ? source : val;
    }
    return source;
  };

  var coerceToDate = function (source, sourceTypeName) {
    var val;
    if (sourceTypeName === "string") {
      var src = source.trim();
      if (src === "") return null;
      val = new Date(Date.parse(src));
      return __isDate(val) ? val : source;
    } else if (sourceTypeName === "number") {
      val = new Date(source);
      return __isDate(val) ? val : source;
    }
    return source;
  };

  var coerceToBool = function (source, sourceTypeName) {
    if (sourceTypeName === "string") {
      var src = source.trim().toLowerCase();
      if (src === "false" || src === "") {
        return false;
      } else if (src === "true") {
        return true;
      } else {
        return source;
      }
    }
    return source;
  };

  var fmtString = function (val) {
    return val == null ? null : "'" + val.replace(/'/g, "''") + "'";
  };

  var fmtInt = function (val) {
    return val == null ? null : ((typeof val === "string") ? parseInt(val, 10) : val);
  };

  var makeFloatFmt = function (fmtSuffix) {
    return function (val) {
      if (val == null) return null;
      if (typeof val === "string") {
        val = parseFloat(val);
      }
      return val + fmtSuffix;
    };
  };

  var fmtDateTime = function (val) {
    if (val == null) return null;
    try {
      return "datetime'" + val.toISOString() + "'";
    } catch (e) {
      throwError("'%1' is not a valid dateTime", val);
    }
  };

  var fmtDateTimeOffset = function (val) {
    if (val == null) return null;
    try {
      return "datetimeoffset'" + val.toISOString() + "'";
    } catch (e) {
      throwError("'%1' is not a valid dateTime", val);
    }
  };

  var fmtTime = function (val) {
    if (val == null) return null;
    if (!__isDuration(val)) {
      throwError("'%1' is not a valid ISO 8601 duration", val);
    }
    return "time'" + val + "'";
  };

  var fmtGuid = function (val) {
    if (val == null) return null;
    if (!__isGuid(val)) {
      throwError("'%1' is not a valid guid", val);
    }
    return "guid'" + val + "'";
  };

  var fmtBoolean = function (val) {
    if (val == null) return null;
    if (typeof val === "string") {
      return val.trim().toLowerCase() === "true";
    } else {
      return !!val;
    }
  };

  var fmtBinary = function (val) {
    if (val == null) return val;
    return "binary'" + val + "'";
  };

  // TODO: __identity;
  var fmtUndefined = function (val) {
    return val;
  };

  function throwError(msg, val) {
    msg = __formatString(msg, val);
    throw new Error(msg);
  }

  var parseRawDate = function(val) {
    if (!__isDate(val)) {
      val = DataType.parseDateFromServer(val);
    }
    return val;
  }

  var parseRawBinary = function(val) {
    if (val && val.$value !== undefined) {
      val = val.$value; // this will be a byte[] encoded as a string
    }
    return val;
  }

  var DataType = new Enum("DataType", dataTypeMethods);


  /**
  @property String {DataType}
  @final
  @static
  **/
  DataType.String = DataType.addSymbol({
    defaultValue: "",
    parse: coerceToString,
    fmtOData: fmtString,
    getNext: getNextString
  });
  /**
  @property Int64 {DataType}
  @final
  @static
  **/
  DataType.Int64 = DataType.addSymbol({
    defaultValue: 0,
    isNumeric: true,
    isInteger: true,
    quoteJsonOData: true,
    parse: coerceToInt,
    fmtOData: makeFloatFmt("L"),
    getNext: getNextNumber
  });
  /**
  @property Int32 {DataType}
  @final
  @static
  **/
  DataType.Int32 = DataType.addSymbol({
    defaultValue: 0,
    isNumeric: true,
    isInteger: true,
    parse: coerceToInt,
    fmtOData: fmtInt,
    getNext: getNextNumber
  });
  /**
  @property Int16 {DataType}
  @final
  @static
  **/
  DataType.Int16 = DataType.addSymbol({
    defaultValue: 0,
    isNumeric: true,
    isInteger: true,
    parse: coerceToInt,
    fmtOData: fmtInt,
    getNext: getNextNumber
  });
  /**
  @property Byte {DataType}
  @final
  @static
  **/
  DataType.Byte = DataType.addSymbol({
    defaultValue: 0,
    isNumeric: true,
    isInteger: true,
    parse: coerceToInt,
    fmtOData: fmtInt
  });
  /**
  @property Decimal {DataType}
  @final
  @static
  **/
  DataType.Decimal = DataType.addSymbol({
    defaultValue: 0,
    isNumeric: true,
    quoteJsonOData: true,
    isFloat: true,
    parse: coerceToFloat,
    fmtOData: makeFloatFmt("m"),
    getNext: getNextNumber
  });
  /**
  @property Double {DataType}
  @final
  @static
  **/
  DataType.Double = DataType.addSymbol({
    defaultValue: 0,
    isNumeric: true,
    isFloat: true,
    parse: coerceToFloat,
    fmtOData: makeFloatFmt("d"),
    getNext: getNextNumber
  });
  /**
  @property Single {DataType}
  @final
  @static
  **/
  DataType.Single = DataType.addSymbol({
    defaultValue: 0,
    isNumeric: true,
    isFloat: true,
    parse: coerceToFloat,
    fmtOData: makeFloatFmt("f"),
    getNext: getNextNumber
  });
  /**
  @property DateTime {DataType}
  @final
  @static
  **/
  DataType.DateTime = DataType.addSymbol({
    defaultValue: new Date(1900, 0, 1),
    isDate: true,
    parse: coerceToDate,
    parseRawValue: parseRawDate,
    normalize: function(value) { return value && value.getTime && value.getTime(); }, // dates don't perform equality comparisons properly
    fmtOData: fmtDateTime,
    getNext: getNextDateTime,
    getConcurrencyValue: getConcurrencyDateTime
  });

  /**
  @property DateTimeOffset {DataType}
  @final
  @static
  **/
  DataType.DateTimeOffset = DataType.addSymbol({
    defaultValue: new Date(1900, 0, 1),
    isDate: true,
    parse: coerceToDate,
    parseRawValue: parseRawDate,
    normalize: function (value) { return value && value.getTime && value.getTime(); }, // dates don't perform equality comparisons properly
    fmtOData: fmtDateTimeOffset,
    getNext: getNextDateTime,
    getConcurrencyValue: getConcurrencyDateTime
  });
  /**
  @property Time {DataType}
  @final
  @static
  **/
  DataType.Time = DataType.addSymbol({
    defaultValue: "PT0S",
    fmtOData: fmtTime,
    parseRawValue: DataType.parseTimeFromServer
  });
  /**
  @property Boolean {DataType}
  @final
  @static
  **/
  DataType.Boolean = DataType.addSymbol({
    defaultValue: false,
    parse: coerceToBool,
    fmtOData: fmtBoolean
  });
  /**
  @property Guid {DataType}
  @final
  @static
  **/
  DataType.Guid = DataType.addSymbol({
    defaultValue: "00000000-0000-0000-0000-000000000000",
    parse: coerceToGuid,
    fmtOData: fmtGuid,
    getNext: getNextGuid,
    parseRawValue: function(val) { return val.toLowerCase(); },
    getConcurrencyValue: __getUuid
  });

  /**
  @property Binary {DataType}
  @final
  @static
  **/
  DataType.Binary = DataType.addSymbol({
    defaultValue: null,
    fmtOData: fmtBinary,
    parseRawValue: parseRawBinary
  });
  /**
  @property Undefined {DataType}
  @final
  @static
  **/
  DataType.Undefined = DataType.addSymbol({
    defaultValue: undefined,
    fmtOData: fmtUndefined
  });
  DataType.resolveSymbols();

  DataType.getComparableFn = function(dataType) {
    if (dataType && dataType.normalize) {
      return dataType.normalize;
    } else if (dataType === DataType.Time) {
      // durations must be converted to compare them
      return function (value) {
        return value && __durationToSeconds(value);
      };
    } else {
      // TODO: __identity
      return function (value) {
        return value;
      };
    }
  };

  /**
  Returns the DataType for a specified EDM type name.
  @method fromEdmDataType
  @static
  @param typeName {String}
  @return {DataType} A DataType.
  **/
  DataType.fromEdmDataType = function (typeName) {
    var dt = null;
    var parts = typeName.split(".");
    if (parts.length > 1) {
      var simpleName = parts[1];
      if (simpleName === "image") {
        // hack
        dt = DataType.Byte;
      } else if (parts.length === 2) {
        dt = DataType.fromName(simpleName) || DataType.Undefined;
      } else {
        // enum
        // dt = DataType.Int32;
        dt = DataType.String;
      }
    }

    return dt;
  };

  DataType.fromValue = function (val) {
    if (__isDate(val)) return DataType.DateTime;
    switch (typeof val) {
      case "string":
        if (__isGuid(val)) return DataType.Guid;
        // the >3 below is a hack to insure that if we are inferring datatypes that
        // very short strings that are valid but unlikely ISO encoded Time's are treated as strings instead.
        else if (__isDuration(val) && val.length > 3) return DataType.Time;
        else if (__isDateString(val)) return DataType.DateTime;
        return DataType.String;
      case "boolean":
        return DataType.Boolean;
      case "number":
        return DataType.Double;
    }
    return DataType.Undefined;
  };

  var _localTimeRegex = /.\d{3}$/;

  DataType.parseTimeFromServer = function (source) {
    if (typeof source === 'string') {
      return source;
    }
    // ODATA v3 format
    if (source && source.__edmType === 'Edm.Time') {
      var seconds = Math.floor(source.ms / 1000);
      return 'PT' + seconds + 'S';
    }
    return source;
  }

  DataType.parseDateAsUTC = function (source) {
    if (typeof source === 'string') {
      // convert to UTC string if no time zone specifier.
      var isLocalTime = _localTimeRegex.test(source);
      // var isLocalTime = !hasTimeZone(source);
      source = isLocalTime ? source + 'Z' : source;
    }
    source = new Date(Date.parse(source));
    return source;
  };

  //function hasTimeZone(source) {
  //  var ix = source.indexOf("T");
  //  var timePart = source.substring(ix+1);
  //  return  timePart.indexOf("-") >= 0 || timePart.indexOf("+") >= 0 || timePart.indexOf("Z");
  //}

  // NOT YET NEEDED --------------------------------------------------
  // var _utcOffsetMs = (new Date()).getTimezoneOffset() * 60000;

  //DataType.parseDateAsLocal = function (source) {
  //    var dt = DataType.parseDatesAsUTC(source);
  //    if (__isDate(dt)) {
  //        dt = new Date(dt.getTime() + _utcOffsetMs);
  //    }
  //    return dt;
  //};
  // -----------------------------------------------------------------

  DataType.parseDateFromServer = DataType.parseDateAsUTC;

  DataType.parseRawValue = function (val, dataType) {
    // undefined values will be the default for most unmapped properties EXCEPT when they are set
    // in a jsonResultsAdapter ( an unusual use case).
    if (val === undefined) return undefined;
    if (!val) return val;
    if (dataType && dataType.parseRawValue) {
      val = dataType.parseRawValue(val);
    }
    return val;
  }

  DataType.constants = constants;
  // for internal testing only
  DataType._resetConstants = resetConstants;

  DataType.getSymbols().forEach(function (sym) {
    sym.validatorCtor = getValidatorCtor(sym);
  });

  function getValidatorCtor(symbol) {
    switch (symbol) {
      case DataType.String:
        return Validator.string;
      case DataType.Int64:
        return Validator.int64;
      case DataType.Int32:
        return Validator.int32;
      case DataType.Int16:
        return Validator.int16;
      case DataType.Decimal:
        return Validator.number;
      case DataType.Double:
        return Validator.number;
      case DataType.Single:
        return Validator.number;
      case DataType.DateTime:
        return Validator.date;
      case DataType.DateTimeOffset:
        return Validator.date;
      case DataType.Boolean:
        return Validator.bool;
      case DataType.Guid:
        return Validator.guid;
      case DataType.Byte:
        return Validator.byte;
      case DataType.Binary:
        // TODO: don't quite know how to validate this yet.
        return Validator.none;
      case DataType.Time:
        return Validator.duration;
      case DataType.Undefined:
        return Validator.none;
    }
  }

  return DataType;

})();

breeze.DataType = DataType;

;/**
@module breeze
**/

var DataService = (function () {
  
  /**
  A DataService instance is used to encapsulate the details of a single 'service'; this includes a serviceName, a dataService adapterInstance,
  and whether the service has server side metadata.

  You can construct an EntityManager with either a serviceName or a DataService instance, if you use a serviceName then a DataService
  is constructed for you.  (It can also be set via the EntityManager.setProperties method).

  The same applies to the MetadataStore.fetchMetadata method, i.e. it takes either a serviceName or a DataService instance.

  Each metadataStore contains a list of DataServices, each accessible via its ‘serviceName’.
  ( see MetadataStore.getDataService and MetadataStore.addDataService).  The ‘addDataService’ method is called internally
  anytime a MetadataStore.fetchMetadata call occurs with a new dataService ( or service name).
  @class DataService
  **/

  /**
  DataService constructor

  @example
      var dataService = new DataService({
          serviceName: altServiceName,
          hasServerMetadata: false
      });

      var metadataStore = new MetadataStore({
          namingConvention: NamingConvention.camelCase
      });

      return new EntityManager({
          dataService: dataService,
          metadataStore: metadataStore
      });

  @method <ctor> DataService
  @param config {Object}
  @param config.serviceName {String} The name of the service.
  @param [config.adapterName] {String} The name of the dataServiceAdapter to be used with this service.
  @param [config.uriBuilderName] {String} The name of the uriBuilder to be used with this service.
  @param [config.hasServerMetadata] {bool} Whether the server can provide metadata for this service.
  @param [config.jsonResultsAdapter] {JsonResultsAdapter}  The JsonResultsAdapter used to process the results of any query against this service.
  @param [config.useJsonp] {Boolean}  Whether to use JSONP when making a 'get' request against this service.
  **/
  var ctor = function DataService(config) {
    // this.uriBuilder = uriBuilderForOData;
    updateWithConfig(this, config);
  };
  var proto = ctor.prototype;
  proto._$typeName = "DataService";
  
  /**
  The serviceName for this DataService.

  __readOnly__
  @property serviceName {String}
  **/

  /**
  The adapter name for the dataServiceAdapter to be used with this service.

  __readOnly__
  @property adapterName {String}
  **/

  /**
  The "dataService" adapter implementation instance associated with this EntityManager.

  __readOnly__
  @property adapterInstance {an instance of the "dataService" adapter interface}
  **/

  /**
  Whether the server can provide metadata for this service.

  __readOnly__
  @property hasServerMetadata {Boolean}
  **/

  /**
  The JsonResultsAdapter used to process the results of any query against this DataService.

  __readOnly__
  @property jsonResultsAdapter {JsonResultsAdapter}
  **/

  /**
  Whether to use JSONP when performing a 'GET' request against this service.

  __readOnly__
  @property useJsonP {Boolean}
  **/

  /**
  Returns a copy of this DataService with the specified properties applied.
  @method using
  @param config {Configuration Object} The object to apply to create a new DataService.
  @return {DataService}
  @chainable
  **/
  proto.using = function (config) {
    if (!config) return this;
    var result = new DataService(this);
    return updateWithConfig(result, config);
  };
  
  ctor.resolve = function (dataServices) {
    // final defaults
    dataServices.push({
      hasServerMetadata: true,
      useJsonp: false
    });
    var ds = new DataService(__resolveProperties(dataServices,
        ["serviceName", "adapterName", "uriBuilderName", "hasServerMetadata", "jsonResultsAdapter", "useJsonp"]));
    
    if (!ds.serviceName) {
      throw new Error("Unable to resolve a 'serviceName' for this dataService");
    }
    ds.adapterInstance = ds.adapterInstance || __config.getAdapterInstance("dataService", ds.adapterName);
    ds.jsonResultsAdapter = ds.jsonResultsAdapter || ds.adapterInstance.jsonResultsAdapter;
    ds.uriBuilder = ds.uriBuilder || __config.getAdapterInstance("uriBuilder", ds.uriBuilderName);
    return ds;
  };
  
  function updateWithConfig(obj, config) {
    if (config) {
      assertConfig(config)
          .whereParam("serviceName").isOptional()
          .whereParam("adapterName").isString().isOptional()
          .whereParam("uriBuilderName").isString().isOptional()
          .whereParam("hasServerMetadata").isBoolean().isOptional()
          .whereParam("jsonResultsAdapter").isInstanceOf(JsonResultsAdapter).isOptional()
          .whereParam("useJsonp").isBoolean().isOptional()
          .applyAll(obj);
      obj.serviceName = obj.serviceName && DataService._normalizeServiceName(obj.serviceName);
      obj.adapterInstance = obj.adapterName && __config.getAdapterInstance("dataService", obj.adapterName);
      obj.uriBuilder = obj.uriBuilderName && __config.getAdapterInstance("uriBuilder", obj.uriBuilderName);
    }
    return obj;
  }
  
  ctor._normalizeServiceName = function (serviceName) {
    serviceName = serviceName.trim();
    if (serviceName.substr(-1) !== "/") {
      return serviceName + '/';
    } else {
      return serviceName;
    }
  };
  
  proto.toJSON = function () {
    // don't use default value here - because we want to be able to distinguish undefined props for inheritence purposes.
    return __toJson(this, {
      serviceName: null,
      adapterName: null,
      uriBuilderName: null,
      hasServerMetadata: null,
      jsonResultsAdapter: function (v) {
        return v && v.name;
      },
      useJsonp: null
    });
  };
  
  ctor.fromJSON = function (json) {
    json.jsonResultsAdapter = __config._fetchObject(JsonResultsAdapter, json.jsonResultsAdapter);
    return new DataService(json);
  };

  /**
   Returns a url for this dataService with the specified suffix. This method handles dataService names either
   with or without trailing '/'s.
   @method qualifyUrl
   @param suffix {String} The resulting url.
   @return {a Url string}
   **/
  proto.qualifyUrl = function (suffix) {
    var url = this.serviceName;
    // remove any trailing "/"
    if (core.stringEndsWith(url, "/")) {
      url = url.substr(0, url.length - 1);
    }
    // ensure that it ends with "/" + suffix
    suffix = "/" + suffix;
    if (!core.stringEndsWith(url, suffix)) {
      url = url + suffix;
    }
    return url;
  };
  
  return ctor;
})();

var JsonResultsAdapter = (function () {
  /**
  A JsonResultsAdapter instance is used to provide custom extraction and parsing logic on the json results returned by any web service.
  This facility makes it possible for breeze to talk to virtually any web service and return objects that will be first class 'breeze' citizens.

  @class JsonResultsAdapter
  **/

  /**
  JsonResultsAdapter constructor

  @example
      //
      var jsonResultsAdapter = new JsonResultsAdapter({
          name: "test1e",
          extractResults: function(json) {
              return json.results;
          },
          visitNode: function(node, mappingContext, nodeContext) {
              var entityType = normalizeTypeName(node.$type);
              var propertyName = nodeContext.propertyName;
              var ignore = propertyName && propertyName.substr(0, 1) === "$";

              return {
                  entityType: entityType,
                  nodeId: node.$id,
                  nodeRefId: node.$ref,
                  ignore: ignore,
                  passThru: false // default
              };
          }
      });

      var dataService = new DataService( {
              serviceName: "breeze/foo",
              jsonResultsAdapter: jsonResultsAdapter
      });

      var entityManager = new EntityManager( {
          dataService: dataService
      });

  @method <ctor> JsonResultsAdapter
  @param config {Object}
  @param config.name {String} The name of this adapter.  This name is used to uniquely identify and locate this instance when an 'exported' JsonResultsAdapter is later imported.
  @param [config.extractResults] {Function} Called once per query operation to extract the 'payload' from any json received over the wire.
  This method has a default implementation which to simply return the "results" property from any json returned as a result of executing the query.
  @param [config.extractSaveResults] {Function} Called once per save operation to extract the entities from any json received over the wire.  Must return an array.
  This method has a default implementation which to simply return the "entities" property from any json returned as a result of executing the save.
  @param [config.extractKeyMappings] {Function} Called once per save operation to extract the key mappings from any json received over the wire.  Must return an array.
  This method has a default implementation which to simply return the "keyMappings" property from any json returned as a result of executing the save.
  @param config.visitNode {Function} A visitor method that will be called on each node of the returned payload.
  **/
  var ctor = function JsonResultsAdapter(config) {
    if (arguments.length !== 1) {
      throw new Error("The JsonResultsAdapter ctor should be called with a single argument that is a configuration object.");
    }
    
    assertConfig(config)
        .whereParam("name").isNonEmptyString()
        .whereParam("extractResults").isFunction().isOptional().withDefault(extractResultsDefault)
        .whereParam("extractSaveResults").isFunction().isOptional().withDefault(extractSaveResultsDefault)
        .whereParam("extractKeyMappings").isFunction().isOptional().withDefault(extractKeyMappingsDefault)
        .whereParam("extractDeletedKeys").isFunction().isOptional().withDefault(extractDeletedKeysDefault)
        .whereParam("visitNode").isFunction()
        .applyAll(this);
    __config._storeObject(this, proto._$typeName, this.name);
  };
  
  var proto = ctor.prototype;
  proto._$typeName = "JsonResultsAdapter";
  
  function extractResultsDefault(data) {
    return data.results;
  }

  function extractSaveResultsDefault(data) {
    return data.entities || data.Entities || [];
  }
  
  function extractKeyMappingsDefault(data) {
    return data.keyMappings || data.KeyMappings || [];
  }

  function extractDeletedKeysDefault(data) {
    return data.deletedKeys || data.DeletedKeys || [];
  }

  return ctor;
})();

breeze.DataService = DataService;
breeze.JsonResultsAdapter = JsonResultsAdapter;


;/**
@module breeze
**/

// Get the promises library called Q
// define a quick failing version if not found.
var Q = core.requireLib("Q;q");

if (!Q) {
  // No Q.js! Substitute a placeholder Q which always fails
  // Should be replaced by the app via breeze.config.setQ
  // For example, see Breeze Labs "breeze.angular"
  Q = function () {
    var eMsg = 'Q is undefined. Are you missing Q.js? See https://github.com/kriskowal/q';
    throw new Error(eMsg);
  }

  // all Q methods called by Breeze should fail
  Q.defer = Q.resolve = Q.reject = Q;
}

/**
 (Re)set Q with a promises implementation suitable for Breeze internal use.  Note: This API is likely to change.
 @method setQ
 @param q {Object} - a  "thenable" promises implementation like Q.js with the API that Breeze requires internally.
 @param [q.defer] {Function} A function returning a deferred.
 @param [q.resolve] {Function} A function returning a resolved promise.
 @param [q.reject] {Function} A function returning a rejected promise.
 **/
breeze.config.setQ = function (q) {
  breeze.Q = Q = q;
}
breeze.Q = Q; // Todo: consider a "safer" way for apps to get breeze's Q. 


var MetadataStore = (function () {

  /**
  An instance of the MetadataStore contains all of the metadata about a collection of {{#crossLink "EntityType"}}{{/crossLink}}'s.
  MetadataStores may be shared across {{#crossLink "EntityManager"}}{{/crossLink}}'s.  If an EntityManager is created without an
  explicit MetadataStore, the MetadataStore from the MetadataStore.defaultInstance property will be used.
  @class MetadataStore
  **/

  var __id = 0;

  /**
  Constructs a new MetadataStore.
  @example
      var ms = new MetadataStore();
  The store can then be associated with an EntityManager
  @example
      var entityManager = new EntityManager( {
          serviceName: "breeze/NorthwindIBModel", 
          metadataStore: ms 
      });
  or for an existing EntityManager
  @example
      // Assume em1 is an existing EntityManager
      em1.setProperties( { metadataStore: ms });
  @method <ctor> MetadataStore
  @param [config] {Object} Configuration settings .
  @param [config.namingConvention=NamingConvention.defaultInstance] {NamingConvention} NamingConvention to be used in mapping property names
  between client and server. Uses the NamingConvention.defaultInstance if not specified.
  @param [config.localQueryComparisonOptions=LocalQueryComparisonOptions.defaultInstance] {LocalQueryComparisonOptions} The LocalQueryComparisonOptions to be
  used when performing "local queries" in order to match the semantics of queries against a remote service.
  @param [config.serializerFn] A function that is used to mediate the serialization of instances of this type.
  **/
  var ctor = function MetadataStore(config) {
    config = config || { };
    assertConfig(config)
        .whereParam("namingConvention").isOptional().isInstanceOf(NamingConvention).withDefault(NamingConvention.defaultInstance)
        .whereParam("localQueryComparisonOptions").isOptional().isInstanceOf(LocalQueryComparisonOptions).withDefault(LocalQueryComparisonOptions.defaultInstance)
        .whereParam("serializerFn").isOptional().isFunction()
        .applyAll(this);
    this.dataServices = []; // array of dataServices;
    this._resourceEntityTypeMap = {}; // key is resource name - value is qualified entityType name
    this._structuralTypeMap = {}; // key is qualified structuraltype name - value is structuralType. ( structural = entityType or complexType).
    this._shortNameMap = {}; // key is shortName, value is qualified name - does not need to be serialized.
    this._ctorRegistry = {}; // key is either short or qual type name - value is ctor;
    this._incompleteTypeMap = {}; // key is entityTypeName; value is array of nav props
    this._incompleteComplexTypeMap = {}; // key is complexTypeName; value is array of complexType props
    this._id = __id++;
    this.metadataFetched = new Event("metadataFetched", this);

  };
  var proto = ctor.prototype;
  proto._$typeName = "MetadataStore";
  Event.bubbleEvent(proto, null);
  ctor.ANONTYPE_PREFIX = "_IB_";


  // needs to be made avail to breeze.dataService.xxx files
  ctor.normalizeTypeName = __memoize(function (rawTypeName) {
    return rawTypeName && parseTypeName(rawTypeName).typeName;
  });
  // for debugging use the line below instead.
  //ctor.normalizeTypeName = function (rawTypeName) { return parseTypeName(rawTypeName).typeName; };

  /**
  An {{#crossLink "Event"}}{{/crossLink}} that fires after a MetadataStore has completed fetching metadata from a remote service.

  @example
      var ms = myEntityManager.metadataStore;
      ms.metadataFetched.subscribe(function(args) {
              var metadataStore = args.metadataStore;
              var dataService = args.dataService;
          });
      });

  @event metadataFetched
  @param metadataStore {MetadataStore} The MetadataStore into which the metadata was fetched.
  @param dataService {DataService} The DataService that metadata was fetched from.
  @param rawMetadata {Object} The raw metadata returned from the service. (It will have already been processed by this point).
  @readOnly
  **/

  /**
  General purpose property set method
  @example
      // assume em1 is an EntityManager containing a number of existing entities.

      em1.metadataStore.setProperties( {
          version: "6.1.3",
          serializerFn: function(prop, value) {
          return (prop.isUnmapped) ? undefined : value;
          }
      )};
  @method setProperties
  @param config [object]
  @param [config.name] {String} A name for the collection of metadata in this store.
  @param [config.serializerFn] A function that is used to mediate the serialization of instances of this type.
  **/
  proto.setProperties = function (config) {
    assertConfig(config)
        .whereParam("name").isString().isOptional()
        .whereParam("serializerFn").isFunction().isOptional()
        .applyAll(this);
  };

  /**
  Adds a DataService to this MetadataStore. If a DataService with the same serviceName is already
  in the MetadataStore an exception will be thrown.
  @method addDataService
  @param dataService {DataService} The DataService to add
  @param [shouldOverwrite=false] {Boolean} Permit overwrite of existing DataService rather than throw exception
  **/
  proto.addDataService = function (dataService, shouldOverwrite) {
    assertParam(dataService, "dataService").isInstanceOf(DataService).check();
    assertParam(shouldOverwrite, "shouldOverwrite").isBoolean().isOptional().check();
    var ix = this._getDataServiceIndex(dataService.serviceName);
    if (ix >= 0) {
      if (!!shouldOverwrite) {
        this.dataServices[ix] = dataService;
      } else {
        throw new Error("A dataService with this name '" + dataService.serviceName + "' already exists in this MetadataStore");
      }
    } else {
      this.dataServices.push(dataService);
    }
  };

  proto._getDataServiceIndex = function (serviceName) {
    return __arrayIndexOf(this.dataServices, function (ds) {
      return ds.serviceName === serviceName;
    });
  };

  /**
  Adds an EntityType to this MetadataStore.  No additional properties may be added to the EntityType after its has
  been added to the MetadataStore.
  @method addEntityType
  @param structuralType {EntityType|ComplexType} The EntityType or ComplexType to add
  **/
  proto.addEntityType = function (structuralType) {
    if (!(structuralType instanceof EntityType || structuralType instanceof ComplexType)) {
      structuralType = structuralType.isComplexType ? new ComplexType(structuralType) : new EntityType(structuralType);
    }

    if (!structuralType.isComplexType) {
      if (structuralType.baseTypeName && !structuralType.baseEntityType) {
        var baseEntityType = this._getEntityType(structuralType.baseTypeName, true);
        structuralType._updateFromBase(baseEntityType);
      }
      if (structuralType.keyProperties.length === 0 && !structuralType.isAbstract) {
        throw new Error("Unable to add " + structuralType.name +
            " to this MetadataStore.  An EntityType must have at least one property designated as a key property - See the 'DataProperty.isPartOfKey' property.");
      }
    }

    structuralType.metadataStore = this;
    // don't register anon types
    if (!structuralType.isAnonymous) {
      if (this._structuralTypeMap[structuralType.name]) {
        throw new Error("Type " + structuralType.name + " already exists in this MetadataStore.");
      }

      this._structuralTypeMap[structuralType.name] = structuralType;
      this._shortNameMap[structuralType.shortName] = structuralType.name;
    }

    structuralType.getProperties().forEach(function (property) {
      structuralType._updateNames(property);
      if (!property.isUnmapped) {
        structuralType._mappedPropertiesCount++;
      }
    });

    structuralType._updateCps();

    if (!structuralType.isComplexType) {
      structuralType._updateNps();
      // give the type it's base's resource name if it doesn't have its own.
      var defResourceName = structuralType.defaultResourceName || (structuralType.baseEntityType && structuralType.baseEntityType.defaultResourceName);
      if (defResourceName && !this.getEntityTypeNameForResourceName(defResourceName)) {
        this.setEntityTypeForResourceName(defResourceName, structuralType.name);
      }
      structuralType.defaultResourceName = defResourceName;
      // check if this structural type's name, short version or qualified version has a registered ctor.
      structuralType.getEntityCtor();
    }

  };

  /**
  The  {{#crossLink "NamingConvention"}}{{/crossLink}} associated with this MetadataStore.

  __readOnly__
  @property namingConvention {NamingConvention}
  **/

  /**
  Exports this MetadataStore to a serialized string appropriate for local storage.   This operation is also called
  internally when exporting an EntityManager.
  @example
      // assume ms is a previously created MetadataStore
      var metadataAsString = ms.exportMetadata();
      window.localStorage.setItem("metadata", metadataAsString);
      // and later, usually in a different session imported
      var metadataFromStorage = window.localStorage.getItem("metadata");
      var newMetadataStore = new MetadataStore();
      newMetadataStore.importMetadata(metadataFromStorage);
  @method exportMetadata
  @return {String} A serialized version of this MetadataStore that may be stored locally and later restored.
  **/
  proto.exportMetadata = function () {
    var result = JSON.stringify({
      "metadataVersion": breeze.metadataVersion,
      "name": this.name,
      "namingConvention": this.namingConvention.name,
      "localQueryComparisonOptions": this.localQueryComparisonOptions.name,
      "dataServices": this.dataServices,
      "structuralTypes": __objectMap(this._structuralTypeMap),
      "resourceEntityTypeMap": this._resourceEntityTypeMap
    }, null, __config.stringifyPad);
    return result;
  };

  /**
  Imports a previously exported serialized MetadataStore into this MetadataStore.
  @example
      // assume ms is a previously created MetadataStore
      var metadataAsString = ms.exportMetadata();
      window.localStorage.setItem("metadata", metadataAsString);
      // and later, usually in a different session
      var metadataFromStorage = window.localStorage.getItem("metadata");
      var newMetadataStore = new MetadataStore();
      newMetadataStore.importMetadata(metadataFromStorage);
  @method importMetadata
  @param exportedMetadata {String|JSON Object} A previously exported MetadataStore.
  @param [allowMerge] {Boolean} Allows custom metadata to be merged into existing metadata types.
  @return {MetadataStore} This MetadataStore.
  @chainable
  **/
  proto.importMetadata = function (exportedMetadata, allowMerge) {
    assertParam(allowMerge, "allowMerge").isOptional().isBoolean().check();
    this._deferredTypes = {};
    var json = (typeof (exportedMetadata) === "string") ? JSON.parse(exportedMetadata) : exportedMetadata;

    if (json.schema) {
      return CsdlMetadataParser.parse(this, json.schema, json.altMetadata);
    }

    if (json.metadataVersion && json.metadataVersion !== breeze.metadataVersion) {
      var msg = __formatString("Cannot import metadata with a different 'metadataVersion' (%1) than the current 'breeze.metadataVersion' (%2) ",
          json.metadataVersion, breeze.metadataVersion);
      throw new Error(msg);
    }

    var ncName = json.namingConvention;
    var lqcoName = json.localQueryComparisonOptions;
    if (this.isEmpty()) {
      this.namingConvention = __config._fetchObject(NamingConvention, ncName) || this.namingConvention;
      this.localQueryComparisonOptions = __config._fetchObject(LocalQueryComparisonOptions, lqcoName) || this.localQueryComparisonOptions;
    } else {
      if (ncName && this.namingConvention.name !== ncName) {
        throw new Error("Cannot import metadata with a different 'namingConvention' from the current MetadataStore");
      }
      if (lqcoName && this.localQueryComparisonOptions.name !== lqcoName) {
        throw new Error("Cannot import metadata with different 'localQueryComparisonOptions' from the current MetadataStore");
      }
    }

    var that = this;

    //noinspection JSHint
    json.dataServices && json.dataServices.forEach(function (ds) {
      ds = DataService.fromJSON(ds);
      that.addDataService(ds, true);
    });
    var structuralTypeMap = this._structuralTypeMap;

    json.structuralTypes && json.structuralTypes.forEach(function (stype) {
      structuralTypeFromJson(that, stype, allowMerge);
    });
    __extend(this._resourceEntityTypeMap, json.resourceEntityTypeMap);
    __extend(this._incompleteTypeMap, json.incompleteTypeMap);

    return this;
  };

  /**
  Creates a new MetadataStore from a previously exported serialized MetadataStore
  @example
      // assume ms is a previously created MetadataStore
      var metadataAsString = ms.exportMetadata();
      window.localStorage.setItem("metadata", metadataAsString);
      // and later, usually in a different session
      var metadataFromStorage = window.localStorage.getItem("metadata");
      var newMetadataStore = MetadataStore.importMetadata(metadataFromStorage);
  @method importMetadata
  @static
  @param exportedString {String} A previously exported MetadataStore.
  @return {MetadataStore} A new MetadataStore.

  **/
  ctor.importMetadata = function (exportedString) {
    var ms = new MetadataStore();
    ms.importMetadata(exportedString);
    return ms;
  };

  /**
  Returns whether Metadata has been retrieved for a specified service name.
  @example
      // Assume em1 is an existing EntityManager.
      if (!em1.metadataStore.hasMetadataFor("breeze/NorthwindIBModel"))) {
          // do something interesting
      }
  @method hasMetadataFor
  @param serviceName {String} The service name.
  @return {Boolean}
  **/
  proto.hasMetadataFor = function (serviceName) {
    return !!this.getDataService(serviceName);
  };

  /**
  Returns the DataService for a specified service name
  @example
      // Assume em1 is an existing EntityManager.
      var ds = em1.metadataStore.getDataService("breeze/NorthwindIBModel");
      var adapterName = ds.adapterName; // may be null

  @method getDataService
  @param serviceName {String} The service name.
  @return {DataService}
  **/
  proto.getDataService = function (serviceName) {
    assertParam(serviceName, "serviceName").isString().check();

    serviceName = DataService._normalizeServiceName(serviceName);
    return __arrayFirst(this.dataServices, function (ds) {
      return ds.serviceName === serviceName;
    });
  };

  /**
  Fetches the metadata for a specified 'service'. This method is automatically called
  internally by an EntityManager before its first query against a new service.

  @example
  Usually you will not actually process the results of a fetchMetadata call directly, but will instead
  ask for the metadata from the EntityManager after the fetchMetadata call returns.
  @example
      var ms = new MetadataStore();
      // or more commonly
      // var ms = anEntityManager.metadataStore;
      ms.fetchMetadata("breeze/NorthwindIBModel").then(function(rawMetadata) {
            // do something with the metadata
      }).fail(function(exception) {
          // handle exception here
      });
  @method fetchMetadata
  @async
  @param dataService {DataService|String}  Either a DataService or just the name of the DataService to fetch metadata for.

  @param [callback] {Function} Function called on success.

  successFunction([data])
  @param [callback.data] {rawMetadata}

  @param [errorCallback] {Function} Function called on failure.

  failureFunction([error])
  @param [errorCallback.error] {Error} Any error that occured wrapped into an Error object.

  @return {Promise} Promise
  **/
  proto.fetchMetadata = function (dataService, callback, errorCallback) {
    try {
      assertParam(dataService, "dataService").isString().or().isInstanceOf(DataService).check();
      assertParam(callback, "callback").isFunction().isOptional().check();
      assertParam(errorCallback, "errorCallback").isFunction().isOptional().check();

      if (typeof dataService === "string") {
        // use the dataService with a matching name or create a new one.
        dataService = this.getDataService(dataService) || new DataService({ serviceName: dataService });
      }

      dataService = DataService.resolve([dataService]);


      if (this.hasMetadataFor(dataService.serviceName)) {
        throw new Error("Metadata for a specific serviceName may only be fetched once per MetadataStore. ServiceName: " + dataService.serviceName);
      }
      var that = this;
      return dataService.adapterInstance.fetchMetadata(this, dataService).then(function (rawMetadata) {
        that.metadataFetched.publish({ metadataStore: that, dataService: dataService, rawMetadata: rawMetadata });
        if (callback) callback(rawMetadata);
        return Q.resolve(rawMetadata);
      }, function (error) {
        if (errorCallback) errorCallback(error);
        return Q.reject(error);
      });
    } catch (e) {
      return Q.reject(e);
    }
  };


  /**
  Used to register a constructor for an EntityType that is not known via standard Metadata discovery;
  i.e. an unmapped type.

  @method trackUnmappedType
  @param entityCtor {Function} The constructor for the 'unmapped' type.
  @param [interceptor] {Function} A function
  **/
  proto.trackUnmappedType = function (entityCtor, interceptor) {
    assertParam(entityCtor, "entityCtor").isFunction().check();
    assertParam(interceptor, "interceptor").isFunction().isOptional().check();
    // TODO: think about adding this to the MetadataStore.
    var entityType = new EntityType(this);
    entityType._setCtor(entityCtor, interceptor);
  };

  /**
  Provides a mechanism to register a 'custom' constructor to be used when creating new instances
  of the specified entity type.  If this call is not made, a default constructor is created for
  the entity as needed.
  This call may be made before or after the corresponding EntityType has been discovered via
  Metadata discovery.
  @example
      var Customer = function () {
              this.miscData = "asdf";
          };
      Customer.prototype.doFoo() {
              ...
          }
      // assume em1 is a preexisting EntityManager;
      em1.metadataStore.registerEntityTypeCtor("Customer", Customer);
      // any queries or EntityType.create calls from this point on will call the Customer constructor
      // registered above.
  @method registerEntityTypeCtor
  @param structuralTypeName {String} The name of the EntityType or ComplexType.
  @param aCtor {Function}  The constructor for this EntityType or ComplexType; may be null if all you want to do is set the next parameter.
  @param [initFn] {Function} A function or the name of a function on the entity that is to be executed immediately after the entity has been created
  and populated with any initial values.
  initFn(entity)
  @param initFn.entity {Entity} The entity being created or materialized.
  @param [noTrackingFn] {Function} A function that is executed immediately after a noTracking entity has been created and whose return
  value will be used in place of the noTracking entity.
  @param noTrackingFn.entity {Object}
  @param noTrackingFn.entityType {EntityType} The entityType that the 'entity' parameter would be if we were tracking
  **/
  proto.registerEntityTypeCtor = function (structuralTypeName, aCtor, initFn, noTrackingFn) {
    assertParam(structuralTypeName, "structuralTypeName").isString().check();
    assertParam(aCtor, "aCtor").isFunction().isOptional().check();
    assertParam(initFn, "initFn").isOptional().isFunction().or().isString().check();
    assertParam(noTrackingFn, "noTrackingFn").isOptional().isFunction().check();

    var qualifiedTypeName = getQualifiedTypeName(this, structuralTypeName, false);
    var typeName = qualifiedTypeName || structuralTypeName;

    if (aCtor) {
      if (aCtor._$typeName && aCtor._$typeName != typeName) {
        console.warn("Registering a constructor for " + typeName + " that is already used for " + aCtor._$typeName + ".");
      }
      aCtor._$typeName = typeName;
    }

    this._ctorRegistry[typeName] = { ctor: aCtor, initFn: initFn, noTrackingFn: noTrackingFn };
    if (qualifiedTypeName) {
      var stype = this._structuralTypeMap[qualifiedTypeName];
      stype && stype.getCtor(true); // this will complete the registration if avail now.
    }

  };

  /**
  Returns whether this MetadataStore contains any metadata yet.
  @example
      // assume em1 is a preexisting EntityManager;
      if (em1.metadataStore.isEmpty()) {
          // do something interesting
      }
  @method isEmpty
  @return {Boolean}
  **/
  proto.isEmpty = function () {
    return __isEmpty(this._structuralTypeMap);
  };

  /**
  Returns an  {{#crossLink "EntityType"}}{{/crossLink}} or a {{#crossLink "ComplexType"}}{{/crossLink}} given its name.
  @example
      // assume em1 is a preexisting EntityManager
      var odType = em1.metadataStore.getEntityType("OrderDetail");
  or to throw an error if the type is not found
  @example
      var badType = em1.metadataStore.getEntityType("Foo", false);
      // badType will not get set and an exception will be thrown.
  @method getEntityType
  @param structuralTypeName {String}  Either the fully qualified name or a short name may be used. If a short name is specified and multiple types share
  that same short name an exception will be thrown.
  @param [okIfNotFound=false] {Boolean} Whether to throw an error if the specified EntityType is not found.
  @return {EntityType|ComplexType} The EntityType. ComplexType or 'undefined' if not not found.
  **/
  proto.getEntityType = function (structuralTypeName, okIfNotFound) {
    assertParam(structuralTypeName, "structuralTypeName").isString().check();
    assertParam(okIfNotFound, "okIfNotFound").isBoolean().isOptional().check(false);
    return this._getEntityType(structuralTypeName, okIfNotFound);
  };

  proto._getEntityType = function (typeName, okIfNotFound) {
    var qualTypeName = getQualifiedTypeName(this, typeName, false);
    var type = this._structuralTypeMap[qualTypeName];
    if (!type) {
      if (okIfNotFound) return null;
      var msg = __formatString("Unable to locate a 'Type' by the name: '%1'. Be sure to execute a query or call fetchMetadata first.", typeName);
      throw new Error(msg);

    }
    if (type.length) {
      var typeNames = type.join(",");
      throw new Error("There are multiple types with this 'shortName': " + typeNames);
    }
    return type;
  };

  /**
  Returns an array containing all of the  {{#crossLink "EntityType"}}{{/crossLink}}s or {{#crossLink "ComplexType"}}{{/crossLink}}s in this MetadataStore.
  @example
      // assume em1 is a preexisting EntityManager
      var allTypes = em1.metadataStore.getEntityTypes();
  @method getEntityTypes
  @return {Array of EntityType|ComplexType}
  **/
  proto.getEntityTypes = function () {
    return getTypesFromMap(this._structuralTypeMap);
  };

  proto.getIncompleteNavigationProperties = function () {
    return __objectMap(this._incompleteTypeMap, function (key, value) {
      return value;
    });
  };

  /**
  Returns a fully qualified entityTypeName for a specified resource name.  The reverse of this operation
  can be obtained via the  {{#crossLink "EntityType"}}{{/crossLink}} 'defaultResourceName' property
  @method getEntityTypeNameForResourceName
  @param resourceName {String}
  **/
  proto.getEntityTypeNameForResourceName = function (resourceName) {
    assertParam(resourceName, "resourceName").isString().check();
    return this._resourceEntityTypeMap[resourceName];
  };

  /**
  Associates a resourceName with an entityType.

  This method is only needed in those cases where multiple resources return the same
  entityType.  In this case Metadata discovery will only determine a single resource name for
  each entityType.
  @method setEntityTypeForResourceName
  @param resourceName {String}
  @param entityTypeOrName {EntityType|String} If passing a string either the fully qualified name or a short name may be used. If a short name is specified and multiple types share
  that same short name an exception will be thrown. If the entityType has not yet been discovered then a fully qualified name must be used.
  **/
  proto.setEntityTypeForResourceName = function (resourceName, entityTypeOrName) {
    assertParam(resourceName, "resourceName").isString().check();
    assertParam(entityTypeOrName, "entityTypeOrName").isInstanceOf(EntityType).or().isString().check();

    var entityTypeName;
    if (entityTypeOrName instanceof EntityType) {
      entityTypeName = entityTypeOrName.name;
    } else {
      entityTypeName = getQualifiedTypeName(this, entityTypeOrName, true);
    }

    this._resourceEntityTypeMap[resourceName] = entityTypeName;
    var entityType = this._getEntityType(entityTypeName, true);
    if (entityType && !entityType.defaultResourceName) {
      entityType.defaultResourceName = resourceName;
    }
  };


  // protected methods

  proto._checkEntityType = function (entity) {
    if (entity.entityType) return;
    var typeName = entity.prototype._$typeName;
    if (!typeName) {
      throw new Error("This entity has not been registered. See the MetadataStore.registerEntityTypeCtor method");
    }
    var entityType = this._getEntityType(typeName);
    if (entityType) {
      entity.entityType = entityType;
    }
  };

  function getTypesFromMap(typeMap) {
    var types = [];
    for (var key in typeMap) {
      var value = typeMap[key];
      // skip 'shortName' entries
      if (key === value.name) {
        types.push(typeMap[key]);
      }
    }
    return types;
  }

  function structuralTypeFromJson(metadataStore, json, allowMerge) {
    var typeName = qualifyTypeName(json.shortName, json.namespace);
    var stype = metadataStore._getEntityType(typeName, true);
    if (stype) {
      if (allowMerge) {
        return mergeStructuralType(stype, json);
      } else {
        // allow it but don't replace anything.
        return stype;
      }
    }
    var config = {
      shortName: json.shortName,
      namespace: json.namespace,
      isAbstract: json.isAbstract,
      autoGeneratedKeyType: AutoGeneratedKeyType.fromName(json.autoGeneratedKeyType),
      defaultResourceName: json.defaultResourceName,
      custom: json.custom
    };

    stype = json.isComplexType ? new ComplexType(config) : new EntityType(config);

    // baseType may not have been imported yet so we need to defer handling this type until later.
    if (json.baseTypeName) {
      stype.baseTypeName = json.baseTypeName;
      var baseEntityType = metadataStore._getEntityType(json.baseTypeName, true);
      if (baseEntityType) {
        completeStructuralTypeFromJson(metadataStore, json, stype, baseEntityType);
      } else {
        __getArray(metadataStore._deferredTypes, json.baseTypeName).push({ json: json, stype: stype });

      }
    } else {
      completeStructuralTypeFromJson(metadataStore, json, stype);
    }

    // stype may or may not have been added to the metadataStore at this point.
    return stype;
  }

  function mergeStructuralType(stype, json) {
    if (json.custom) {
      stype.custom = json.custom;
    }

    mergeProps(stype, json.dataProperties);
    mergeProps(stype, json.navigationProperties);
    return stype;
  }

  function mergeProps(stype, jsonProps) {
    if (!jsonProps) return;
    jsonProps.forEach(function (jsonProp) {
      var propName = jsonProp.name;
      if (!propName) {
        if (jsonProp.nameOnServer) {
          propName = stype.metadataStore.namingConvention.serverPropertyNameToClient(jsonProp.nameOnServer, {});
        } else {
          throw new Error("Unable to complete 'importMetadata' - cannot locate a 'name' or 'nameOnServer' for one of the imported property nodes");
        }
      }
      if (jsonProp.custom) {
        var prop = stype.getProperty(propName, true);
        prop.custom = jsonProp.custom;
      }
    });
  }

  function completeStructuralTypeFromJson(metadataStore, json, stype) {

    // validators from baseType work because validation walks thru base types
    // so no need to copy down.
    if (json.validators) {
      stype.validators = json.validators.map(Validator.fromJSON);
    }


    json.dataProperties.forEach(function (dp) {
      stype._addPropertyCore(DataProperty.fromJSON(dp));
    });


    var isEntityType = !json.isComplexType;
    if (isEntityType) {
      //noinspection JSHint
      json.navigationProperties && json.navigationProperties.forEach(function (np) {
        stype._addPropertyCore(NavigationProperty.fromJSON(np));
      });
    }

    metadataStore.addEntityType(stype);

    var deferredTypes = metadataStore._deferredTypes;
    var deferrals = deferredTypes[stype.name];
    if (deferrals) {
      deferrals.forEach(function (d) {
        completeStructuralTypeFromJson(metadataStore, d.json, d.stype);
      });
      delete deferredTypes[stype.name];
    }
  }

  function getQualifiedTypeName(metadataStore, structTypeName, throwIfNotFound) {
    if (isQualifiedTypeName(structTypeName)) return structTypeName;
    var result = metadataStore._shortNameMap[structTypeName];
    if (!result && throwIfNotFound) {
      throw new Error("Unable to locate 'entityTypeName' of: " + structTypeName);
    }
    return result;
  }

  return ctor;
})();

var CsdlMetadataParser = (function () {

  function parse(metadataStore, schemas, altMetadata) {

    metadataStore._entityTypeResourceMap = {};
    schemas = __toArray(schemas);
    schemas.forEach(function (schema) {
      if (schema.cSpaceOSpaceMapping) {
        // Web api only - not avail in OData.
        var mappings = JSON.parse(schema.cSpaceOSpaceMapping);
        var newMap = {};
        mappings.forEach(function (mapping) {
          newMap[mapping[0]] = mapping[1];
        });
        schema.cSpaceOSpaceMapping = newMap;
      }

      if (schema.entityContainer) {
        __toArray(schema.entityContainer).forEach(function (container) {
          __toArray(container.entitySet).forEach(function (entitySet) {
            var entityTypeName = parseTypeNameWithSchema(entitySet.entityType, schema).typeName;
            metadataStore.setEntityTypeForResourceName(entitySet.name, entityTypeName);
            metadataStore._entityTypeResourceMap[entityTypeName] = entitySet.name;
          });
        });
      }

      // process complextypes before entity types.
      if (schema.complexType) {
        __toArray(schema.complexType).forEach(function (ct) {
          var complexType = parseCsdlComplexType(ct, schema, metadataStore);
        });
      }
      if (schema.entityType) {
        __toArray(schema.entityType).forEach(function (et) {
          var entityType = parseCsdlEntityType(et, schema, schemas, metadataStore);

        });
      }

    });
    var badNavProps = metadataStore.getIncompleteNavigationProperties();
    if (badNavProps.length > 0) {
      var msg = badNavProps.map(function(npa) {
        if (Array.isArray(npa)) {
          return npa.map(function(np) {
            return np.parentType.name + ":" + np.name;
          }).join(', ');
        }
        return npa.parentType.name + ":" + npa.name;
      }).join(', ');
      throw new Error("Incomplete navigation properties: " + msg);
    }
    if (altMetadata) {
      metadataStore.importMetadata(altMetadata, true);
    }
    return metadataStore;
  }

  function parseCsdlEntityType(csdlEntityType, schema, schemas, metadataStore) {
    var shortName = csdlEntityType.name;
    var ns = getNamespaceFor(shortName, schema);
    var entityType = new EntityType({
      shortName: shortName,
      namespace: ns,
      isAbstract: csdlEntityType.abstract && csdlEntityType.abstract === 'true'
    });
    if (csdlEntityType.baseType) {
      var baseTypeName = parseTypeNameWithSchema(csdlEntityType.baseType, schema).typeName;
      entityType.baseTypeName = baseTypeName;
      var baseEntityType = metadataStore._getEntityType(baseTypeName, true);
      if (baseEntityType) {
        completeParseCsdlEntityType(entityType, csdlEntityType, schema, schemas, metadataStore);
      } else {
        var deferrals = metadataStore._deferredTypes[baseTypeName];
        if (!deferrals) {
          deferrals = [];
          metadataStore._deferredTypes[baseTypeName] = deferrals;
        }
        deferrals.push({ entityType: entityType, csdlEntityType: csdlEntityType });
      }
    } else {
      completeParseCsdlEntityType(entityType, csdlEntityType, schema, schemas, metadataStore);
    }
    // entityType may or may not have been added to the metadataStore at this point.
    return entityType;

  }

  function completeParseCsdlEntityType(entityType, csdlEntityType, schema, schemas, metadataStore) {
    var keyNamesOnServer = csdlEntityType.key ? __toArray(csdlEntityType.key.propertyRef).map(__pluck("name")) : [];

    __toArray(csdlEntityType.property).forEach(function (prop) {
      parseCsdlDataProperty(entityType, prop, schema, keyNamesOnServer);
    });

    __toArray(csdlEntityType.navigationProperty).forEach(function (prop) {
      parseCsdlNavProperty(entityType, prop, schema, schemas);
    });

    metadataStore.addEntityType(entityType);
    entityType.defaultResourceName = metadataStore._entityTypeResourceMap[entityType.name];

    var deferredTypes = metadataStore._deferredTypes;
    var deferrals = deferredTypes[entityType.name];
    if (deferrals) {
      deferrals.forEach(function (d) {
        completeParseCsdlEntityType(d.entityType, d.csdlEntityType, schema, schemas, metadataStore);
      });
      delete deferredTypes[entityType.name];
    }

  }

  function parseCsdlComplexType(csdlComplexType, schema, metadataStore) {
    var shortName = csdlComplexType.name;
    var ns = getNamespaceFor(shortName, schema);
    var complexType = new ComplexType({
      shortName: shortName,
      namespace: ns
    });

    __toArray(csdlComplexType.property).forEach(function (prop) {
      parseCsdlDataProperty(complexType, prop, schema);
    });

    metadataStore.addEntityType(complexType);
    return complexType;
  }

  function parseCsdlDataProperty(parentType, csdlProperty, schema, keyNamesOnServer) {
    var dp;
    var typeParts = csdlProperty.type.split(".");
    // Both tests on typeParts are necessary because of differing metadata conventions for OData and Edmx feeds.
    if (typeParts[0] === "Edm" && typeParts.length === 2) {
      dp = parseCsdlSimpleProperty(parentType, csdlProperty, keyNamesOnServer);
    } else {
      if (isEnumType(csdlProperty, schema)) {
        dp = parseCsdlSimpleProperty(parentType, csdlProperty, keyNamesOnServer);
        if (dp) {
          dp.enumType = csdlProperty.type;
        }
      } else {
        dp = parseCsdlComplexProperty(parentType, csdlProperty, schema);
      }
    }
    if (dp) {
      parentType._addPropertyCore(dp);
      addValidators(dp);
    }
    return dp;
  }

  function parseCsdlSimpleProperty(parentType, csdlProperty, keyNamesOnServer) {
    var dataType = DataType.fromEdmDataType(csdlProperty.type);
    if (dataType == null) {
      parentType.warnings.push("Unable to recognize DataType for property: " + csdlProperty.name + " DateType: " + csdlProperty.type);
      return null;
    }
    var isNullable = csdlProperty.nullable === 'true' || csdlProperty.nullable == null;
    // var fixedLength = csdlProperty.fixedLength ? csdlProperty.fixedLength === true : undefined;
    var isPartOfKey = keyNamesOnServer != null && keyNamesOnServer.indexOf(csdlProperty.name) >= 0;
    if (isPartOfKey && parentType.autoGeneratedKeyType === AutoGeneratedKeyType.None) {
      if (isIdentityProperty(csdlProperty)) {
        parentType.autoGeneratedKeyType = AutoGeneratedKeyType.Identity;
      }
    }
    // TODO: nit - don't set maxLength if null;
    var maxLength = csdlProperty.maxLength;
    maxLength = (maxLength == null || maxLength === "Max") ? null : parseInt(maxLength, 10);
    // can't set the name until we go thru namingConventions and these need the dp.


    var dp = new DataProperty({
      nameOnServer: csdlProperty.name,
      dataType: dataType,
      isNullable: isNullable,
      isPartOfKey: isPartOfKey,
      maxLength: maxLength,
      defaultValue: csdlProperty.defaultValue,
      // fixedLength: fixedLength,
      concurrencyMode: csdlProperty.concurrencyMode
    });

    if (dataType === DataType.Undefined) {
      dp.rawTypeName = csdlProperty.type;
    }
    return dp;
  }

  function parseCsdlComplexProperty(parentType, csdlProperty, schema) {

    // Complex properties are never nullable ( per EF specs)
    // var isNullable = csdlProperty.nullable === 'true' || csdlProperty.nullable == null;
    // var complexTypeName = csdlProperty.type.split("Edm.")[1];
    var complexTypeName = parseTypeNameWithSchema(csdlProperty.type, schema).typeName;
    // can't set the name until we go thru namingConventions and these need the dp.
    var dp = new DataProperty({
      nameOnServer: csdlProperty.name,
      complexTypeName: complexTypeName,
      isNullable: false
    });

    return dp;
  }

  function parseCsdlNavProperty(entityType, csdlProperty, schema, schemas) {
    var association = getAssociation(csdlProperty, schema, schemas);
    if (!association) {
      throw new Error("Unable to resolve Foreign Key Association: " + csdlProperty.relationship);
    }
    var toEnd = __arrayFirst(association.end, function (assocEnd) {
      return assocEnd.role === csdlProperty.toRole;
    });

    var isScalar = toEnd.multiplicity !== "*";
    var dataType = parseTypeNameWithSchema(toEnd.type, schema).typeName;

    var constraint = association.referentialConstraint;
    if (!constraint) {
      // TODO: Revisit this later - right now we just ignore many-many and assocs with missing constraints.

      // Think about adding this back later.
      if (association.end[0].multiplicity == "*" && association.end[1].multiplicity == "*") {
        // ignore many to many relations for now
        return;
      } else {
        // For now assume it will be set later directly on the client.
        // other alternative is to throw an error:
        // throw new Error("Foreign Key Associations must be turned on for this model");
      }
    }

    var cfg = {
      nameOnServer: csdlProperty.name,
      entityTypeName: dataType,
      isScalar: isScalar,
      associationName: association.name
    };

    if (constraint) {
      var principal = constraint.principal;
      var dependent = constraint.dependent;

      var propRefs = __toArray(dependent.propertyRef);
      var fkNames = propRefs.map(__pluck("name"));
      if (csdlProperty.fromRole === principal.role) {
        cfg.invForeignKeyNamesOnServer = fkNames;
      } else {
        // will be used later by np._update
        cfg.foreignKeyNamesOnServer = fkNames;
      }
    }

    var np = new NavigationProperty(cfg);
    entityType._addPropertyCore(np);
    return np;
  }

  function isEnumType(csdlProperty, schema) {
    if (schema.enumType) return isEdmxEnumType(csdlProperty, schema);
    else if (schema.extensions) return isODataEnumType(csdlProperty, schema);
    else return false;
  }

  function isEdmxEnumType(csdlProperty, schema) {
    var enumTypes = __toArray(schema.enumType);
    var typeParts = csdlProperty.type.split(".");
    var baseTypeName = typeParts[typeParts.length - 1];
    return enumTypes.some(function (enumType) {
      return enumType.name === baseTypeName;
    });
  }

  function isODataEnumType(csdlProperty, schema) {
    var enumTypes = schema.extensions.filter(function (ext) {
      return ext.name === "EnumType";
    });
    var typeParts = csdlProperty.type.split(".");
    var baseTypeName = typeParts[typeParts.length - 1];
    return enumTypes.some(function (enumType) {
      return enumType.attributes.some(function (attr) {
        return attr.name === "Name" && attr.value === baseTypeName;
      });
    });
  }

  function addValidators(dataProperty) {
    var typeValidator;
    if (!dataProperty.isNullable) {
      dataProperty.validators.push(Validator.required());
    }

    if (dataProperty.isComplexProperty) return;

    if (dataProperty.dataType === DataType.String) {
      if (dataProperty.maxLength) {
        var validatorArgs = { maxLength: dataProperty.maxLength };
        typeValidator = Validator.maxLength(validatorArgs);
      } else {
        typeValidator = Validator.string();
      }
    } else {
      typeValidator = dataProperty.dataType.validatorCtor();
    }

    dataProperty.validators.push(typeValidator);

  }

  function isIdentityProperty(csdlProperty) {
    // see if web api feed
    var propName = __arrayFirst(Object.keys(csdlProperty), function (pn) {
      return pn.indexOf("StoreGeneratedPattern") >= 0;
    });
    if (propName) {
      return (csdlProperty[propName] === "Identity");
    } else {
      // see if Odata feed
      var extensions = csdlProperty.extensions;
      if (!extensions) {
        return false;
      }
      var identityExtn = __arrayFirst(extensions, function (extension) {
        return extension.name === "StoreGeneratedPattern" && extension.value === "Identity";
      });
      return !!identityExtn;
    }
  }

  // Fast version
  // np: schema.entityType[].navigationProperty.relationship -> schema.association
  //   match( shortName(np.relationship) == schema.association[].name
  //      --> association__

  // Correct version
  // np: schema.entityType[].navigationProperty.relationship -> schema.association
  //   match( np.relationship == schema.entityContainer[0].associationSet[].association )
  //      -> associationSet.name
  //   match ( associationSet.name == schema.association[].name )
  //      -> association

  function getAssociation(csdlNavProperty, containingSchema, schemas) {
    var assocFullName = parseTypeNameWithSchema(csdlNavProperty.relationship, containingSchema);
    var assocNamespace = assocFullName.namespace;
    var assocSchema = __arrayFirst(schemas, function (schema) {
      return schema.namespace === assocNamespace;
    });
    if (!assocSchema) return null;
    
    var assocName = assocFullName.shortTypeName;
    var assocs = assocSchema.association;
    if (!assocs) return null;
    if (!Array.isArray(assocs)) {
      assocs = [assocs];
    }
    var association = __arrayFirst(assocs, function (assoc) {
      return assoc.name === assocName;
    });
    return association;
  }

  // schema is only needed for navProperty type name
  function parseTypeNameWithSchema(entityTypeName, schema) {
    var result = parseTypeName(entityTypeName);
    if (schema && schema.cSpaceOSpaceMapping) {
      var ns = getNamespaceFor(result.shortTypeName, schema);
      if (ns) {
        result = makeTypeHash(result.shortTypeName, ns);
      }
    }
    return result;
  }

  function getNamespaceFor(shortName, schema) {
    var ns;
    var mapping = schema.cSpaceOSpaceMapping;
    if (mapping) {
      var fullName = mapping[schema.namespace + "." + shortName];
      ns = fullName && fullName.substr(0, fullName.length - (shortName.length + 1));
      if (ns) return ns;
    }
    // if schema does not also have an entityType node then
    // this is an WebApi2 OData schema which is usually equal to 'Default'; which is useless.
    if (schema.entityType || schema.namespace != 'Default') {
      return schema.namespace;
    }
    return null;
  }

  return {
    parse: parse
  };

})();

var EntityType = (function () {
  /**
  Container for all of the metadata about a specific type of Entity.
  @class EntityType
  **/
  var __nextAnonIx = 0;


  /**
  @example
      var entityType = new EntityType( {
          shortName: "person",
          namespace: "myAppNamespace"
      });
  @method <ctor> EntityType
  @param config {Object|MetadataStore} Configuration settings or a MetadataStore.  If this parameter is just a MetadataStore
  then what will be created is an 'anonymous' type that will never be communicated to or from the server. It is purely for
  client side use and will be given an automatically generated name. Normally, however, you will use a configuration object.
  @param config.shortName {String}
  @param [config.namespace=""] {String}
  @param [config.baseTypeName] {String}
  @param [config.isAbstract=false] {Boolean}
  @param [config.autoGeneratedKeyType] {AutoGeneratedKeyType}
  @param [config.defaultResourceName] {String}
  @param [config.dataProperties] {Array of DataProperties}
  @param [config.navigationProperties] {Array of NavigationProperties}
  @param [config.serializerFn] A function that is used to mediate the serialization of instances of this type.
  @param [config.custom] {Object}
  **/
  var ctor = function EntityType(config) {
    if (arguments.length > 1) {
      throw new Error("The EntityType ctor has a single argument that is either a 'MetadataStore' or a configuration object.");
    }
    if (config._$typeName === "MetadataStore") {
      this.metadataStore = config;
      this.shortName = "Anon_" + (++__nextAnonIx);
      this.namespace = "";
      this.isAnonymous = true;
    } else {
      assertConfig(config)
          .whereParam("shortName").isNonEmptyString()
          .whereParam("namespace").isString().isOptional().withDefault("")
          .whereParam("baseTypeName").isString().isOptional()
          .whereParam("isAbstract").isBoolean().isOptional().withDefault(false)
          .whereParam("autoGeneratedKeyType").isEnumOf(AutoGeneratedKeyType).isOptional().withDefault(AutoGeneratedKeyType.None)
          .whereParam("defaultResourceName").isNonEmptyString().isOptional().withDefault(null)
          .whereParam("dataProperties").isOptional()
          .whereParam("navigationProperties").isOptional()
          .whereParam("serializerFn").isOptional().isFunction()
          .whereParam("custom").isOptional()
          .applyAll(this);
    }

    this.name = qualifyTypeName(this.shortName, this.namespace);

    // the defaultResourceName may also be set up either via metadata lookup or first query or via the 'setProperties' method
    this.dataProperties = [];
    this.navigationProperties = [];
    this.complexProperties = [];
    this.keyProperties = [];
    this.foreignKeyProperties = [];
    this.inverseForeignKeyProperties = [];
    this.concurrencyProperties = [];
    this.unmappedProperties = []; // will be updated later.
    this.validators = [];
    this.warnings = [];
    this._mappedPropertiesCount = 0;
    this.subtypes = [];
    // now process any data/nav props
    addProperties(this, config.dataProperties, DataProperty);
    addProperties(this, config.navigationProperties, NavigationProperty);
  };
  var proto = ctor.prototype;
  var parseRawValue = DataType.parseRawValue;
  proto._$typeName = "EntityType";
  ctor.qualifyTypeName = qualifyTypeName;

  /**
  The {{#crossLink "MetadataStore"}}{{/crossLink}} that contains this EntityType

  __readOnly__
  @property metadataStore {MetadataStore}
  **/

  /**
  The DataProperties (see {{#crossLink "DataProperty"}}{{/crossLink}}) associated with this EntityType.

  __readOnly__
  @property dataProperties {Array of DataProperty}
  **/

  /**
  The NavigationProperties  (see {{#crossLink "NavigationProperty"}}{{/crossLink}}) associated with this EntityType.

  __readOnly__
  @property navigationProperties {Array of NavigationProperty}
  **/

  /**
  The DataProperties for this EntityType that contain instances of a ComplexType (see {{#crossLink "ComplexType"}}{{/crossLink}}).

  __readOnly__
  @property complexProperties {Array of DataProperty}
  **/

  /**
  The DataProperties associated with this EntityType that make up it's {{#crossLink "EntityKey"}}{{/crossLink}}.

  __readOnly__
  @property keyProperties {Array of DataProperty}
  **/

  /**
  The DataProperties associated with this EntityType that are foreign key properties.

  __readOnly__
  @property foreignKeyProperties {Array of DataProperty}
  **/

  /**
  The DataProperties associated with this EntityType that are concurrency properties.

  __readOnly__
  @property concurrencyProperties {Array of DataProperty}
  **/

  /**
  The DataProperties associated with this EntityType that are not mapped to any backend datastore. These are effectively free standing
  properties.

  __readOnly__
  @property unmappedProperties {Array of DataProperty}
  **/

  /**
  The default resource name associated with this EntityType.  An EntityType may be queried via a variety of 'resource names' but this one
  is used as the default when no resource name is provided.  This will occur when calling {{#crossLink "EntityAspect/loadNavigationProperty"}}{{/crossLink}}
  or when executing any {{#crossLink "EntityQuery"}}{{/crossLink}} that was created via an {{#crossLink "EntityKey"}}{{/crossLink}}.

  __readOnly__
  @property defaultResourceName {String}
  **/

  /**
  The fully qualified name of this EntityType.

  __readOnly__
  @property name {String}
  **/

  /**
  The short, unqualified, name for this EntityType.

  __readOnly__
  @property shortName {String}
  **/

  /**
  The namespace for this EntityType.

  __readOnly__
  @property namespace {String}
  **/

  /**
  The base EntityType (if any) for this EntityType.

  __readOnly__
  @property baseEntityType {EntityType}
  **/

  /**
  Whether this EntityType is abstract.

  __readOnly__
  @property isAbstract {boolean}
  **/

  /**
  The {{#crossLink "AutoGeneratedKeyType"}}{{/crossLink}} for this EntityType.

  __readOnly__
  @property autoGeneratedKeyType {AutoGeneratedKeyType}
  @default AutoGeneratedKeyType.None
  **/

  /**
  The entity level validators associated with this EntityType. Validators can be added and
  removed from this collection.

  __readOnly__
  @property validators {Array of Validator}
  **/

  /**
  A free form object that can be used to define any custom metadata for this EntityType.

  __readOnly__
  @property custom {Object}
  **/

  /**
  General purpose property set method
  @example
      // assume em1 is an EntityManager containing a number of existing entities.
      var custType = em1.metadataStore.getEntityType("Customer");
      custType.setProperties( {
          autoGeneratedKeyType: AutoGeneratedKeyType.Identity;
          defaultResourceName: "CustomersAndIncludedOrders"
      )};
  @method setProperties
  @param config [object]
  @param [config.autogeneratedKeyType] {AutoGeneratedKeyType}
  @param [config.defaultResourceName] {String}
  @param [config.serializerFn] A function that is used to mediate the serialization of instances of this type.
  @param [config.custom] {Object}
  **/
  proto.setProperties = function (config) {
    assertConfig(config)
        .whereParam("autoGeneratedKeyType").isEnumOf(AutoGeneratedKeyType).isOptional()
        .whereParam("defaultResourceName").isString().isOptional()
        .whereParam("serializerFn").isFunction().isOptional()
        .whereParam("custom").isOptional()
        .applyAll(this);
    if (config.defaultResourceName) {
      this.defaultResourceName = config.defaultResourceName;
    }
  };

  /**
  Returns whether this type is a subtype of a specified type.

  @method isSubtypeOf
  @param entityType [EntityType]
  **/
  proto.isSubtypeOf = function (entityType) {
    assertParam(entityType, "entityType").isInstanceOf(EntityType).check();
    var baseType = this;
    do {
      if (baseType === entityType) return true;
      baseType = baseType.baseEntityType;
    } while (baseType);
    return false;
  };

  /**
  Returns an array containing this type and any/all subtypes of this type down thru the hierarchy.

  @method getSelfAndSubtypes
  **/
  proto.getSelfAndSubtypes = function () {
    var result = [this];
    this.subtypes.forEach(function (st) {
      var subtypes = st.getSelfAndSubtypes();
      result.push.apply(result, subtypes);
    });
    return result;
  };

  proto.getAllValidators = function () {
    var result = this.validators.slice(0);
    var bt = this.baseEntityType;
    while (bt) {
      result.push.apply(result, bt.validators);
      bt = bt.baseEntityType;
    }
    ;
    return result;
  }

  /**
  Adds a  {{#crossLink "DataProperty"}}{{/crossLink}} or a {{#crossLink "NavigationProperty"}}{{/crossLink}} to this EntityType.
  @example
      // assume myEntityType is a newly constructed EntityType.
      myEntityType.addProperty(dataProperty1);
      myEntityType.addProperty(dataProperty2);
      myEntityType.addProperty(navigationProperty1);
  @method addProperty
  @param property {DataProperty|NavigationProperty}
  **/
  proto.addProperty = function (property) {
    assertParam(property, "property").isInstanceOf(DataProperty).or().isInstanceOf(NavigationProperty).check();

    // true is 2nd arg to force resolve of any navigation properties.
    var newprop = this._addPropertyCore(property, true);

    if (this.subtypes && this.subtypes.length) {
      var stype = this;
      stype.getSelfAndSubtypes().forEach(function (st) {
        if (st !== stype) {
          if (property.isNavigationProperty) {
            st._addPropertyCore(new NavigationProperty(property), true);
          } else {
            st._addPropertyCore(new DataProperty(property), true);
          }
        }
      });
    }
    return newprop;
  };

  proto._updateFromBase = function (baseEntityType) {
    this.baseEntityType = baseEntityType;
    if (this.autoGeneratedKeyType === AutoGeneratedKeyType.None) {
      this.autoGeneratedKeyType = baseEntityType.autoGeneratedKeyType;
    }

    baseEntityType.dataProperties.forEach(function (dp) {
      var newDp = new DataProperty(dp);
      // don't need to copy validators becaue we will walk the hierarchy to find them
      newDp.validators = [];
      newDp.baseProperty = dp;
      this._addPropertyCore(newDp);
    }, this);
    baseEntityType.navigationProperties.forEach(function (np) {
      var newNp = new NavigationProperty(np);
      // don't need to copy validators becaue we will walk the hierarchy to find them
      newNp.validators = [];
      newNp.baseProperty = np;
      this._addPropertyCore(newNp);
    }, this);
    baseEntityType.subtypes.push(this);
  }

  proto._addPropertyCore = function (property, shouldResolve) {
    if (this.isFrozen) {
      throw new Error("The '" + this.name + "' EntityType/ComplexType has been frozen. You can only add properties to an EntityType/ComplexType before any instances of that type have been created and attached to an entityManager.");
    }
    var parentType = property.parentType;
    if (parentType) {
      if (parentType !== this) {
        throw new Error("This property: " + property.name + " has already been added to " + property.parentType.name);
      } else {
        // adding the same property more than once to the same entityType is just ignored.
        return this;
      }
    }
    property.parentType = this;
    var ms = this.metadataStore;
    if (property.isDataProperty) {
      this._addDataProperty(property);
    } else {
      this._addNavigationProperty(property);
      // metadataStore can be undefined if this entityType has not yet been added to a MetadataStore.
      if (shouldResolve && ms) {
        tryResolveNp(property, ms);
      }
    }
    // unmapped properties can be added AFTER entityType has already resolved all property names.
    if (ms && !(property.name && property.nameOnServer)) {
      updateClientServerNames(ms.namingConvention, property, "name");
    }
    // props can be added after entity prototype has already been wrapped.
    if (ms && this._extra) {
      if (this._extra.alreadyWrappedProps) {
        var proto = this._ctor.prototype;
        __modelLibraryDef.getDefaultInstance().initializeEntityPrototype(proto);
      }
    }
    return this;
  };

  /**
  Create a new entity of this type.
  @example
      // assume em1 is an EntityManager containing a number of existing entities.
      var custType = em1.metadataStore.getEntityType("Customer");
      var cust1 = custType.createEntity();
      em1.addEntity(cust1);
  @method createEntity
  @param [initialValues] {Config object} - Configuration object of the properties to set immediately after creation.
  @return {Entity} The new entity.
  **/
  proto.createEntity = function (initialValues) {
    // ignore the _$eref once the entity is attached to an entityManager.
    if (initialValues && initialValues._$eref && !initialValues._$eref.entityAspect.entityManager) return initialValues._$eref;

    var instance = this._createInstanceCore();

    if (initialValues) {
      // only assign an _eref if the object is fully "keyed"
      if (this.keyProperties.every(function (kp) {
        return initialValues[kp.name] != null;
      })) {
        initialValues._$eref = instance;
      }
      ;

      this._updateTargetFromRaw(instance, initialValues, getRawValueFromConfig);

      this.navigationProperties.forEach(function (np) {
        var relatedEntity;
        var val = initialValues[np.name];
        if (val != undefined) {
          var navEntityType = np.entityType;
          if (np.isScalar) {
            relatedEntity = val.entityAspect ? val : navEntityType.createEntity(val);
            instance.setProperty(np.name, relatedEntity);
          } else {
            var relatedEntities = instance.getProperty(np.name);
            val.forEach(function (v) {
              relatedEntity = v.entityAspect ? v : navEntityType.createEntity(v);
              relatedEntities.push(relatedEntity);
            });
          }
        }
      });
    }

    this._initializeInstance(instance);
    return instance;
  };

  function getRawValueFromConfig(rawEntity, dp) {
    // 'true' fork can happen if an initializer contains an actaul instance of an already created complex object.
    return (rawEntity.entityAspect || rawEntity.complexAspect) ? rawEntity.getProperty(dp.name) : rawEntity[dp.name];
  }

  proto._createInstanceCore = function () {
    var aCtor = this.getEntityCtor();
    var instance = new aCtor();
    new EntityAspect(instance);
    return instance;
  };

  proto._initializeInstance = function (instance) {
    if (this.baseEntityType) {
      this.baseEntityType._initializeInstance(instance);
    }
    var initFn = this.initFn;
    if (initFn) {
      if (typeof initFn === "string") {
        initFn = instance[initFn];
      }
      initFn(instance);
    }
    this.complexProperties && this.complexProperties.forEach(function (cp) {
      var ctInstance = instance.getProperty(cp.name);
      if (Array.isArray(ctInstance)) {
        ctInstance.forEach(function (ctInst) {
          cp.dataType._initializeInstance(ctInst);
        });
      } else {
        cp.dataType._initializeInstance(ctInstance);
      }
    });
    // not needed for complexObjects
    if (instance.entityAspect) {
      instance.entityAspect._initialized = true;
    }
  };

  /**
  Returns the constructor for this EntityType.
  @method getCtor ( or obsolete getEntityCtor)
  @return {Function} The constructor for this EntityType.
  **/
  proto.getCtor = proto.getEntityCtor = function (forceRefresh) {
    if (this._ctor && !forceRefresh) return this._ctor;

    var ctorRegistry = this.metadataStore._ctorRegistry;
    var r = ctorRegistry[this.name] || ctorRegistry[this.shortName] || {};
    var aCtor = r.ctor || this._ctor;

    var ctorType = aCtor && aCtor.prototype && (aCtor.prototype.entityType || aCtor.prototype.complexType);
    if (ctorType && ctorType.metadataStore !== this.metadataStore) {
      // We can't risk a mismatch between the ctor and the type info in a specific metadatastore
      // because modelLibraries rely on type info to intercept ctor properties
      throw new Error("Cannot register the same constructor for " + this.name + " in different metadata stores.  Please define a separate constructor for each metadata store.");
    }


    if (r.ctor && forceRefresh) {
      this._extra = undefined;
    }

    if (!aCtor) {
      var createCtor = __modelLibraryDef.getDefaultInstance().createCtor;
      aCtor = createCtor ? createCtor(this) : createEmptyCtor(this);
    }

    this.initFn = r.initFn;
    this.noTrackingFn = r.noTrackingFn;

    aCtor.prototype._$typeName = this.name;
    this._setCtor(aCtor);
    return aCtor;
  };

  function createEmptyCtor(type) {
    var name = type.name.replace(/\W/g, '_');
    return Function('return function '+name+'(){}')();
  }

  // May make public later.
  proto._setCtor = function (aCtor, interceptor) {

    var instanceProto = aCtor.prototype;

    // place for extra breeze related data
    this._extra = this._extra || {};

    var instance = new aCtor();
    calcUnmappedProperties(this, instance);

    if (this._$typeName === "EntityType") {
      // insure that all of the properties are on the 'template' instance before watching the class.
      instanceProto.entityType = this;
    } else {
      instanceProto.complexType = this;
    }

    // defaultPropertyInterceptor is a 'global' (but internal to breeze) function;
    instanceProto._$interceptor = interceptor || defaultPropertyInterceptor;
    __modelLibraryDef.getDefaultInstance().initializeEntityPrototype(instanceProto);
    this._ctor = aCtor;
  };

  /**
  Adds either an entity or property level validator to this EntityType.
  @example
      // assume em1 is an EntityManager containing a number of existing entities.
      var custType = em1.metadataStore.getEntityType("Customer");
      var countryProp = custType.getProperty("Country");
      var valFn = function (v) {
              if (v == null) return true;
              return (core.stringStartsWith(v, "US"));
          };
      var countryValidator = new Validator("countryIsUS", valFn,
      { displayName: "Country", messageTemplate: "'%displayName%' must start with 'US'" });
      custType.addValidator(countryValidator, countryProp);
  This is the same as adding an entity level validator via the 'validators' property of DataProperty or NavigationProperty
  @example
      countryProp.validators.push(countryValidator);
  Entity level validators can also be added by omitting the 'property' parameter.
  @example
      custType.addValidator(someEntityLevelValidator);
  or
  @example
      custType.validators.push(someEntityLevelValidator);
  @method addValidator
  @param validator {Validator} Validator to add.
  @param [property] Property to add this validator to.  If omitted, the validator is assumed to be an
  entity level validator and is added to the EntityType's 'validators'.
  **/
  proto.addValidator = function (validator, property) {
    assertParam(validator, "validator").isInstanceOf(Validator).check();
    assertParam(property, "property").isOptional().isString().or().isEntityProperty().check();
    if (property) {
      if (typeof (property) === 'string') {
        property = this.getProperty(property, true);
      }
      property.validators.push(validator);
    } else {
      this.validators.push(validator);
    }
  };

  /**
  Returns all of the properties ( dataProperties and navigationProperties) for this EntityType.
  @example
      // assume em1 is an EntityManager containing a number of existing entities.
      var custType = em1.metadataStore.getEntityType("Customer");
      var arrayOfProps = custType.getProperties();
  @method getProperties
  @return {Array of DataProperty|NavigationProperty} Array of Data and Navigation properties.
  **/
  proto.getProperties = function () {
    return this.dataProperties.concat(this.navigationProperties);
  };

  /**
  Returns all of the property names ( for both dataProperties and navigationProperties) for this EntityType.
  @example
      // assume em1 is an EntityManager containing a number of existing entities.
      var custType = em1.metadataStore.getEntityType("Customer");
      var arrayOfPropNames = custType.getPropertyNames();
  @method getPropertyNames
  @return {Array of String}
  **/
  proto.getPropertyNames = function () {
    return this.getProperties().map(__pluck('name'));
  };

  /**
  Returns a data property with the specified name or null.
  @example
      // assume em1 is an EntityManager containing a number of existing entities.
      var custType = em1.metadataStore.getEntityType("Customer");
      var customerNameDataProp = custType.getDataProperty("CustomerName");
  @method getDataProperty
  @param propertyName {String}
  @return {DataProperty} Will be null if not found.
  **/
  proto.getDataProperty = function (propertyName) {
    return __arrayFirst(this.dataProperties, __propEq('name', propertyName));
  };

  /**
  Returns a navigation property with the specified name or null.
  @example
      // assume em1 is an EntityManager containing a number of existing entities.
      var custType = em1.metadataStore.getEntityType("Customer");
      var customerOrdersNavProp = custType.getDataProperty("Orders");
  @method getNavigationProperty
  @param propertyName {String}
  @return {NavigationProperty} Will be null if not found.
  **/
  proto.getNavigationProperty = function (propertyName) {
    return __arrayFirst(this.navigationProperties, __propEq('name', propertyName));
  };

  /**
  Returns either a DataProperty or a NavigationProperty with the specified name or null.

  This method also accepts a '.' delimited property path and will return the 'property' at the
  end of the path.
  @example
      var custType = em1.metadataStore.getEntityType("Customer");
      var companyNameProp = custType.getProperty("CompanyName");
  This method can also walk a property path to return a property
  @example
      var orderDetailType = em1.metadataStore.getEntityType("OrderDetail");
      var companyNameProp2 = orderDetailType.getProperty("Order.Customer.CompanyName");
      // companyNameProp === companyNameProp2
  @method getProperty
  @param propertyPath {String}
  @param [throwIfNotFound=false] {Boolean} Whether to throw an exception if not found.
  @return {DataProperty|NavigationProperty} Will be null if not found.
  **/
  proto.getProperty = function (propertyPath, throwIfNotFound) {
    var props = this.getPropertiesOnPath(propertyPath, false, throwIfNotFound);
    return props ? props[props.length - 1] : null;
  };

  proto.getPropertiesOnPath = function(propertyPath, useServerName, throwIfNotFound) {
    throwIfNotFound = throwIfNotFound || false;
    var propertyNames = (Array.isArray(propertyPath)) ? propertyPath : propertyPath.trim().split('.');

    var ok = true;
    var parentType = this;
    var key = useServerName ? "nameOnServer" : "name";
    var props = propertyNames.map(function (propName) {
      var prop = __arrayFirst(parentType.getProperties(), __propEq(key, propName));
      if (prop) {
        parentType = prop.isNavigationProperty ? prop.entityType : prop.dataType;
      } else if (throwIfNotFound) {
        throw new Error("unable to locate property: " + propName + " on entityType: " + parentType.name);
      } else {
        ok = false;
      }
      return prop;
    });
    return ok ? props : null;
  }

  proto.clientPropertyPathToServer = function(propertyPath, delimiter) {
    var delimiter = delimiter || '.';
    var propNames;
    if (this.isAnonymous) {
      var fn = this.metadataStore.namingConvention.clientPropertyNameToServer;
      propNames = propertyPath.split(".").map(function (propName) {
        return fn(propName);
      });
    } else {
      propNames = this.getPropertiesOnPath(propertyPath, false, true).map(function(prop) {
        return prop.nameOnServer;
      });
    }
    return propNames.join(delimiter);
  }

  proto.getEntityKeyFromRawEntity = function (rawEntity, rawValueFn) {
    var keyValues = this.keyProperties.map(function (dp) {
      var val = rawValueFn(rawEntity, dp);
      return parseRawValue(val, dp.dataType);
    });
    return new EntityKey(this, keyValues);
  };

  proto._updateTargetFromRaw = function (target, raw, rawValueFn) {
    // called recursively for complex properties
    this.dataProperties.forEach(function (dp) {
      if (!dp.isSettable) return;
      var rawVal = rawValueFn(raw, dp);
      if (rawVal === undefined) return;
      var dataType = dp.dataType; // this will be a complexType when dp is a complexProperty
      var oldVal;
      if (dp.isComplexProperty) {
        if (rawVal === null) return; // rawVal may be null in nosql dbs where it was never defined for the given row.
        oldVal = target.getProperty(dp.name);
        if (dp.isScalar) {
          dataType._updateTargetFromRaw(oldVal, rawVal, rawValueFn);
        } else {
          if (Array.isArray(rawVal)) {
            var newVal = rawVal.map(function (rawCo) {
              var newCo = dataType._createInstanceCore(target, dp);
              dataType._updateTargetFromRaw(newCo, rawCo, rawValueFn);
              dataType._initializeInstance(newCo);
              return newCo;
            });
            if (!__arrayEquals(oldVal, newVal, coEquals)) {
              // clear the old array and push new objects into it.
              oldVal.length = 0;
              newVal.forEach(function (nv) {
                oldVal.push(nv);
              });
            }
          } else {
            oldVal.length = 0;
          }
        }
      } else {
        var val;
        if (dp.isScalar) {
          var newVal = parseRawValue(rawVal, dataType);
          target.setProperty(dp.name, newVal);
        } else {
          oldVal = target.getProperty(dp.name);
          if (Array.isArray(rawVal)) {
            // need to compare values
            var newVal = rawVal.map(function (rv) {
              return parseRawValue(rv, dataType);
            });
            if (!__arrayEquals(oldVal, newVal)) {
              // clear the old array and push new objects into it.
              oldVal.length = 0;
              newVal.forEach(function (nv) {
                oldVal.push(nv);
              });
            }
          } else {
            oldVal.length = 0;
          }

        }
      }
    });

    // if merging from an import then raw will have an entityAspect or a complexAspect
    var rawAspect = raw.entityAspect || raw.complexAspect;
    if (rawAspect) {
      var targetAspect = target.entityAspect || target.complexAspect;
      if (rawAspect.originalValuesMap) {
        targetAspect.originalValues = rawAspect.originalValuesMap;
      }
      if (rawAspect.extraMetadata) {
        targetAspect.extraMetadata = rawAspect.extraMetadata;
      }
    }
  }

  function coEquals(co1, co2) {
    var dataProps = co1.complexAspect.parentProperty.dataType.dataProperties;
    var areEqual = dataProps.every(function (dp) {
      if (!dp.isSettable) return true;
      var v1 = co1.getProperty(dp.name);
      var v2 = co2.getProperty(dp.name);
      if (dp.isComplexProperty && dp.isScalar) {
        return coEquals(v1, v2);
      }
      else if(dp.isComplexProperty && !dp.isScalar) {
        return __arrayEquals(v1, v2, coEquals)
      } else {
        var dataType = dp.dataType; // this will be a complexType when dp is a complexProperty
        return (v1 === v2 || (dataType && dataType.normalize && v1 && v2 && dataType.normalize(v1) === dataType.normalize(v2)));
      }
    });
    return areEqual;
  }

  /**
  Returns a string representation of this EntityType.
  @method toString
  @return {String}
  **/
  proto.toString = function () {
    return this.name;
  };

  proto.toJSON = function () {
    return __toJson(this, {
      shortName: null,
      namespace: null,
      baseTypeName: null,
      isAbstract: false,
      autoGeneratedKeyType: null, // do not suppress default value
      defaultResourceName: null,
      dataProperties: localPropsOnly,
      navigationProperties: localPropsOnly,
      validators: null,
      custom: null
    });
  };

  function localPropsOnly(props) {
    return props.filter(function (prop) {
      return prop.baseProperty == null;
    });
  }



  proto._updateNames = function (property) {
    var nc = this.metadataStore.namingConvention;
    updateClientServerNames(nc, property, "name");

    if (property.isNavigationProperty) {
      updateClientServerNames(nc, property, "foreignKeyNames");
      updateClientServerNames(nc, property, "invForeignKeyNames");

      // these will get set later via _updateNps
      // this.inverse
      // this.entityType
      // this.relatedDataProperties
      //    dataProperty.relatedNavigationProperty
      //    dataProperty.inverseNavigationProperty
    }
  };



  function updateClientServerNames(nc, parent, clientPropName) {
    var serverPropName = clientPropName + "OnServer";
    var clientName = parent[clientPropName];
    if (clientName && clientName.length) {
      // if (parent.isUnmapped) return;
      var serverNames = __toArray(clientName).map(function (cName) {
        var sName = nc.clientPropertyNameToServer(cName, parent);
        var testName = nc.serverPropertyNameToClient(sName, parent);
        if (cName !== testName) {
          throw new Error("NamingConvention for this client property name does not roundtrip properly:" + cName + "-->" + testName);
        }
        return sName;
      });
      parent[serverPropName] = Array.isArray(clientName) ? serverNames : serverNames[0];
    } else {
      var serverName = parent[serverPropName];
      if ((!serverName) || serverName.length === 0) return;
      var clientNames = __toArray(serverName).map(function (sName) {
        var cName = nc.serverPropertyNameToClient(sName, parent);
        var testName = nc.clientPropertyNameToServer(cName, parent);
        if (sName !== testName) {
          throw new Error("NamingConvention for this server property name does not roundtrip properly:" + sName + "-->" + testName);
        }
        return cName;
      });
      parent[clientPropName] = Array.isArray(serverName) ? clientNames : clientNames[0];
    }
  }

  proto._checkNavProperty = function (navigationProperty) {
    if (navigationProperty.isNavigationProperty) {
      if (navigationProperty.parentType !== this) {
        throw new Error(__formatString("The navigationProperty '%1' is not a property of entity type '%2'",
            navigationProperty.name, this.name));
      }
      return navigationProperty;
    }

    if (typeof (navigationProperty) === 'string') {
      var np = this.getProperty(navigationProperty);
      if (np && np.isNavigationProperty) return np;
    }
    throw new Error("The 'navigationProperty' parameter must either be a NavigationProperty or the name of a NavigationProperty");
  };

  proto._addDataProperty = function (dp) {

    this.dataProperties.push(dp);

    if (dp.isPartOfKey) {
      this.keyProperties.push(dp);
    }

    if (dp.isComplexProperty) {
      this.complexProperties.push(dp);
    }

    if (dp.concurrencyMode && dp.concurrencyMode !== "None") {
      this.concurrencyProperties.push(dp);
    }

    if (dp.isUnmapped) {
      this.unmappedProperties.push(dp);
    }

  };

  proto._addNavigationProperty = function (np) {

    this.navigationProperties.push(np);

    if (!isQualifiedTypeName(np.entityTypeName)) {
      np.entityTypeName = qualifyTypeName(np.entityTypeName, this.namespace);
    }
  };

  proto._updateCps = function () {
    var metadataStore = this.metadataStore;
    var incompleteTypeMap = metadataStore._incompleteComplexTypeMap;
    this.complexProperties.forEach(function (cp) {
      if (cp.complexType) return;
      if (!resolveCp(cp, metadataStore)) {
        __getArray(incompleteTypeMap, cp.complexTypeName).push(cp);
      }
    });

    if (this.isComplexType) {
      (incompleteTypeMap[this.name] || []).forEach(function (cp) {
        resolveCp(cp, metadataStore);
      });
      delete incompleteTypeMap[this.name];
    }
  };

  function resolveCp(cp, metadataStore) {
    var complexType = metadataStore._getEntityType(cp.complexTypeName, true);
    if (!complexType) return false;
    if (!(complexType instanceof ComplexType)) {
      throw new Error("Unable to resolve ComplexType with the name: " + cp.complexTypeName + " for the property: " + property.name);
    }
    cp.dataType = complexType;
    cp.defaultValue = null;
    return true;
  }

  proto._updateNps = function () {
    var metadataStore = this.metadataStore;

    // resolve all navProps for this entityType
    this.navigationProperties.forEach(function (np) {
      tryResolveNp(np, metadataStore);
    });
    var incompleteTypeMap = metadataStore._incompleteTypeMap;
    // next resolve all navProp that point to this entityType.
    (incompleteTypeMap[this.name] || []).forEach(function (np) {
      tryResolveNp(np, metadataStore);
    });
    // every navProp that pointed to this type should now be resolved
    delete incompleteTypeMap[this.name];
  };

  function tryResolveNp(np, metadataStore) {
    if (np.entityType) return true;

    var entityType = metadataStore._getEntityType(np.entityTypeName, true);
    if (entityType) {
      np.entityType = entityType;
      np._resolveNp();
      // don't bother removing - _updateNps will do it later.
      // __arrayRemoveItem(incompleteNps, np, false);
    } else {
      var incompleteNps = __getArray(metadataStore._incompleteTypeMap, np.entityTypeName);
      __arrayAddItemUnique(incompleteNps, np);
    }
    return !!entityType;
  }

  function calcUnmappedProperties(stype, instance) {
    var metadataPropNames = stype.getPropertyNames();
    var modelLib = __modelLibraryDef.getDefaultInstance();
    var trackablePropNames = modelLib.getTrackablePropertyNames(instance);
    trackablePropNames.forEach(function (pn) {
      if (metadataPropNames.indexOf(pn) === -1) {
        var val = instance[pn];
        try {
          if (typeof val == "function") val = val();
        } catch (e) {
        }
        var dt = DataType.fromValue(val);
        var newProp = new DataProperty({
          name: pn,
          dataType: dt,
          isNullable: true,
          isUnmapped: true
        });
        newProp.isSettable = __isSettable(instance, pn);
        if (stype.subtypes && stype.subtypes.length) {
          stype.getSelfAndSubtypes().forEach(function (st) {
            st._addPropertyCore(new DataProperty(newProp));
          });
        } else {
          stype._addPropertyCore(newProp);
        }
      }
    });
  }

  return ctor;
})();

var ComplexType = (function () {
  /**
  Container for all of the metadata about a specific type of Complex object.
  @class ComplexType
  **/

  /**
  @example
      var complexType = new ComplexType( {
          shortName: "address",
          namespace: "myAppNamespace"
      });
  @method <ctor> ComplexType
  @param config {Object} Configuration settings
  @param config.shortName {String}
  @param [config.namespace=""] {String}
  @param [config.dataProperties] {Array of DataProperties}
  @param [config.custom] {Object}
  **/
  var ctor = function ComplexType(config) {
    if (arguments.length > 1) {
      throw new Error("The ComplexType ctor has a single argument that is a configuration object.");
    }

    assertConfig(config)
        .whereParam("shortName").isNonEmptyString()
        .whereParam("namespace").isString().isOptional().withDefault("")
        .whereParam("dataProperties").isOptional()
        .whereParam("isComplexType").isOptional().isBoolean()   // needed because this ctor can get called from the addEntityType method which needs the isComplexType prop
        .whereParam("custom").isOptional()
        .applyAll(this);

    this.name = qualifyTypeName(this.shortName, this.namespace);
    this.isComplexType = true;
    this.dataProperties = [];
    this.complexProperties = [];
    this.validators = [];
    this.concurrencyProperties = [];
    this.unmappedProperties = [];
    this.navigationProperties = []; // not yet supported
    this.keyProperties = []; // may be used later to enforce uniqueness on arrays of complextypes.

    addProperties(this, config.dataProperties, DataProperty);
  };
  var proto = ctor.prototype;
  /**
  The DataProperties (see {{#crossLink "DataProperty"}}{{/crossLink}}) associated with this ComplexType.

  __readOnly__
  @property dataProperties {Array of DataProperty}
  **/

  /**
  The DataProperties for this ComplexType that contain instances of a ComplexType (see {{#crossLink "ComplexType"}}{{/crossLink}}).

  __readOnly__
  @property complexProperties {Array of DataProperty}
  **/

  /**
  The DataProperties associated with this ComplexType that are not mapped to any backend datastore. These are effectively free standing
  properties.

  __readOnly__
  @property unmappedProperties {Array of DataProperty}
  **/

  /**
  The fully qualifed name of this ComplexType.

  __readOnly__
  @property name {String}
  **/

  /**
  The short, unqualified, name for this ComplexType.

  __readOnly__
  @property shortName {String}
  **/

  /**
  The namespace for this ComplexType.

  __readOnly__
  @property namespace {String}
  **/

  /**
  The entity level validators associated with this ComplexType. Validators can be added and
  removed from this collection.

  __readOnly__
  @property validators {Array of Validator}
  **/

  /**
  A free form object that can be used to define any custom metadata for this ComplexType.

  __readOnly__
  @property custom {Object}
  **/

  /**
  General purpose property set method
  @example
      // assume em1 is an EntityManager
      var addresstType = em1.metadataStore.getEntityType("Address");
      addressType.setProperties( {
          custom: { foo: 7, bar: "test" }
      });
  @method setProperties
  @param config [object]
  @param [config.custom] {Object}
  **/
  proto.setProperties = function (config) {
    assertConfig(config)
        .whereParam("custom").isOptional()
        .applyAll(this);
  };

  proto.getAllValidators = function () {
    // ComplexType inheritance is not YET supported.
    return this.validators;
  }

  /**
  Creates a new non-attached instance of this ComplexType.
  @method createInstance
  @param initialValues {Object} Configuration object containing initial values for the instance.
  **/
  // This method is actually the EntityType.createEntity method renamed 
  proto._createInstanceCore = function (parent, parentProperty) {
    var aCtor = this.getCtor();
    var instance = new aCtor();
    new ComplexAspect(instance, parent, parentProperty);
    // initialization occurs during either attach or in createInstance call.
    return instance;
  };


  proto.addProperty = function (dataProperty) {
    assertParam(dataProperty, "dataProperty").isInstanceOf(DataProperty).check();
    return this._addPropertyCore(dataProperty);
  };

  proto.getProperties = function () {
    return this.dataProperties;
  };

  /**
  See  {{#crossLink "EntityType.addValidator"}}{{/crossLink}}
  @method addValidator
  @param validator {Validator} Validator to add.
  @param [property] Property to add this validator to.  If omitted, the validator is assumed to be an
  entity level validator and is added to the EntityType's 'validators'.
  **/

  /**
  See  {{#crossLink "EntityType.getProperty"}}{{/crossLink}}
  @method getProperty
  **/

  /**
  See  {{#crossLink "EntityType.getPropertyNames"}}{{/crossLink}}
  @method getPropertyNames
  **/

  /**
  See  {{#crossLink "EntityType.getEntityCtor"}}{{/crossLink}}
  @method getCtor
  **/

  // copy entityType methods onto complexType
  proto = __extend(proto, EntityType.prototype, [
    "addValidator",
    "getProperty",
    "getPropertiesOnPath",
    "getPropertyNames",
    "_addPropertyCore",
    "_addDataProperty",
    "_updateNames",
    "_updateCps",
    "_initializeInstance",
    "_updateTargetFromRaw",
    "_setCtor"
  ]);

  // note the name change.
  proto.createInstance = EntityType.prototype.createEntity;  // name change
  proto.getCtor = EntityType.prototype.getEntityCtor;


  proto.toJSON = function () {
    return __toJson(this, {
      shortName: null,
      namespace: null,
      isComplexType: null,
      dataProperties: null,
      validators: null,
      custom: null
    });
  };


  proto._$typeName = "ComplexType";

  return ctor;
})();

var DataProperty = (function () {

  /**
  A DataProperty describes the metadata for a single property of an  {{#crossLink "EntityType"}}{{/crossLink}} that contains simple data.

  Instances of the DataProperty class are constructed automatically during Metadata retrieval. However it is also possible to construct them
  directly via the constructor.
  @class DataProperty
  **/

  /**
  @example
      var lastNameProp = new DataProperty( {
          name: "lastName",
          dataType: DataType.String,
          isNullable: true,
          maxLength: 20
      });
      // assuming personEntityType is a newly constructed EntityType
      personEntityType.addProperty(lastNameProperty);
  @method <ctor> DataProperty
  @param config {configuration Object}
  @param [config.name] {String}  The name of this property.
  @param [config.nameOnServer] {String} Same as above but the name is that defined on the server.
  Either this or the 'name' above must be specified. Whichever one is specified the other will be computed using
  the NamingConvention on the MetadataStore associated with the EntityType to which this will be added.
  @param [config.dataType=DataType.String] {DataType}
  @param [config.complexTypeName] {String}
  @param [config.isNullable=true] {Boolean}
  @param [config.isScalar=true] {Boolean}
  @param [config.defaultValue] {Any}
  @param [config.isPartOfKey=false] {Boolean}
  @param [config.isUnmapped=false] {Boolean}
  @param [config.concurrencyMode] {String}
  @param [config.maxLength] {Integer} Only meaningfull for DataType.String
  @param [config.validators] {Array of Validator}
  @param [config.custom] {Object}
  **/
  var ctor = function DataProperty(config) {
    assertConfig(config)
        .whereParam("name").isString().isOptional()
        .whereParam("nameOnServer").isString().isOptional()
        .whereParam("dataType").isEnumOf(DataType).isOptional().or().isString().or().isInstanceOf(ComplexType)
        .whereParam("complexTypeName").isOptional()
        .whereParam("isNullable").isBoolean().isOptional().withDefault(true)
        .whereParam("isScalar").isOptional().withDefault(true)// will be false for some NoSQL databases.
        .whereParam("defaultValue").isOptional()
        .whereParam("isPartOfKey").isBoolean().isOptional()
        .whereParam("isUnmapped").isBoolean().isOptional()
        .whereParam("isSettable").isBoolean().isOptional().withDefault(true)
        .whereParam("concurrencyMode").isString().isOptional()
        .whereParam("maxLength").isNumber().isOptional()
        .whereParam("validators").isInstanceOf(Validator).isArray().isOptional().withDefault([])
        .whereParam("displayName").isOptional()
        .whereParam("enumType").isOptional()
        .whereParam("rawTypeName").isOptional() // occurs with undefined datatypes
        .whereParam("custom").isOptional()
        .applyAll(this);
    var hasName = !!(this.name || this.nameOnServer);
    if (!hasName) {
      throw new Error("A DataProperty must be instantiated with either a 'name' or a 'nameOnServer' property");
    }
    // name/nameOnServer is resolved later when a metadataStore is available.

    if (this.complexTypeName) {
      this.isComplexProperty = true;
      this.dataType = null;
    } else if (typeof(this.dataType) === "string") {
      var dt = DataType.fromName(this.dataType);
      if (!dt) {
        throw new Error("Unable to find a DataType enumeration by the name of: " + this.dataType);
      }
      this.dataType = dt;
    } else if (!this.dataType) {
      this.dataType = DataType.String;
    }

    // == as opposed to === is deliberate here.
    if (this.defaultValue == null) {
      if (this.isNullable) {
        this.defaultValue = null;
      } else {
        if (this.isComplexProperty) {
          // what to do? - shouldn't happen from EF - but otherwise ???
        } else if (this.dataType === DataType.Binary) {
          this.defaultValue = "AAAAAAAAJ3U="; // hack for all binary fields but value is specifically valid for timestamp fields - arbitrary valid 8 byte base64 value.
        } else {
          this.defaultValue = this.dataType.defaultValue;
          if (this.defaultValue == null) {
            throw new Error("A nonnullable DataProperty cannot have a null defaultValue. Name: " + (this.name || this.nameOnServer));
          }
        }
      }
    } else if (this.dataType.isNumeric) {
      // in case the defaultValue comes in as a string ( which it does in EF6).
      if (typeof (this.defaultValue) === "string") {
        this.defaultValue = parseFloat(this.defaultValue);
      }
    }

    if (this.isComplexProperty) {
      this.isScalar = this.isScalar == null || this.isScalar === true;
    }

  };
  var proto = ctor.prototype;
  proto._$typeName = "DataProperty";

  ctor.getRawValueFromServer = function (rawEntity, dp) {
    if (dp.isUnmapped) {
      return rawEntity[dp.nameOnServer || dp.name];
    } else {
      var val = rawEntity[dp.nameOnServer];
      return val !== undefined ? val : dp.defaultValue;
    }
  }

  ctor.getRawValueFromClient = function (rawEntity, dp) {
    var val = rawEntity[dp.name];
    return val !== undefined ? val : dp.defaultValue;
  }


  /**
  The name of this property

  __readOnly__
  @property name {String}
  **/

  /**
  The display name of this property

  __readOnly__
  @property displayName {String} 
  **/
  
  /**
  The name of this property on the server

  __readOnly__
  @property nameOnServer {String} 
  **/
  
  /**
  The parent type that this property belongs to - will be either a {{#crossLink "EntityType"}}{{/crossLink}} or a {{#crossLink "ComplexType"}}{{/crossLink}}.

  __readOnly__
  @property parentType {EntityType|ComplexType}
  **/

  /**
  The {{#crossLink "DataType"}}{{/crossLink}} of this property.

  __readOnly__
  @property dataType {DataType}
  **/

  /**
  The name of the {{#crossLink "ComplexType"}}{{/crossLink}} associated with this property; may be null.

  __readOnly__
  @property complexTypeName {String}
  **/

  /**
  Whether the contents of this property is an instance of a {{#crossLink "ComplexType"}}{{/crossLink}}.

  __readOnly__
  @property isComplexProperty {bool}
  **/

  /**
  Whether this property is nullable.

  __readOnly__
  @property isNullable {Boolean}
  **/

  /**
  Whether this property is scalar (i.e., returns a single value).

  __readOnly__
  @property isScalar {Boolean}
  **/

  /**
  Property on the base type that this property is inherited from. Will be null if the property is not on the base type.

  __readOnly__
  @property baseProperty {DataProperty}
  **/

  /**
  Whether this property is a 'key' property.

  __readOnly__
  @property isPartOfKey {Boolean}
  **/

  /**
  Whether this property is an 'unmapped' property.

  __readOnly__
  @property isUnmapped {Boolean}
  **/

  /**
  __Describe this__

  __readOnly__
  @property concurrencyMode {String}
  **/

  /**
  The maximum length for the value of this property.

  __readOnly__
  @property maxLength {Number}
  **/

  /**
  The {{#crossLink "Validator"}}{{/crossLink}}s that are associated with this property. Validators can be added and
  removed from this collection.

  __readOnly__
  @property validators {Array of Validator}
  **/

  /**
  The default value for this property.

  __readOnly__
  @property defaultValue {any}
  **/

  /**
  The navigation property related to this property.  Will only be set if this is a foreign key property.

  __readOnly__
  @property relatedNavigationProperty {NavigationProperty}
  **/

  /**
  A free form object that can be used to define any custom metadata for this DataProperty.

  __readOnly__
  @property custom {Object}
  **/

  /**
  Is this a DataProperty? - always true here
  Allows polymorphic treatment of DataProperties and NavigationProperties.

  __readOnly__
  @property isDataProperty {Boolean}
  **/

  /**
  Is this a NavigationProperty? - always false here
  Allows polymorphic treatment of DataProperties and NavigationProperties.

  __readOnly__
  @property isNavigationProperty {Boolean}
  **/

  proto.isDataProperty = true;
  proto.isNavigationProperty = false;

  proto.resolveProperty = function (propName) {
    var result = this[propName];
    var baseProp = this.baseProperty;
    while (result == undefined && baseProp != null) {
      result = baseProp[propName];
      baseProp = baseProp.baseProperty;
    }
    return result;
  }

  proto.formatName = function () {
    return this.parentType.name + "--" + this.name;
  }


  /**
  General purpose property set method
  @example
      // assume em1 is an EntityManager
      var prop = myEntityType.getProperty("myProperty");
      prop.setProperties( {
          custom: { foo: 7, bar: "test" }
      });
  @method setProperties
  @param config [object]
  @param [config.custom] {Object}
  **/
  proto.setProperties = function (config) {
    assertConfig(config)
        .whereParam("displayName").isOptional()
        .whereParam("custom").isOptional()
        .applyAll(this);
  };

  proto.getAllValidators = function () {
    var validators = this.validators.slice(0);
    var baseProp = this.baseProperty;
    while (baseProp) {
      validators.push.apply(validators, baseProp.validators);
      baseProp = baseProp.baseProperty;
    }
    return validators;
  }

  proto.toJSON = function () {
    // do not serialize dataTypes that are complexTypes
    return __toJson(this, {
      name: null,
      dataType: function (v) {
        return (v && v.parentEnum) ? v.name : undefined;
      }, // do not serialize dataTypes that are complexTypes
      complexTypeName: null,
      isNullable: true,
      defaultValue: null,
      isPartOfKey: false,
      isUnmapped: false,
      isSettable: true,
      concurrencyMode: null,
      maxLength: null,
      validators: null,
      displayName: null,
      enumType: null,
      rawTypeName: null,
      isScalar: true,
      custom: null
    });
  };

  ctor.fromJSON = function (json) {
    json.dataType = DataType.fromName(json.dataType);
    // Parse default value into correct data type. (dateTime instances require extra work to deserialize properly.)
    if (json.defaultValue && json.dataType && json.dataType.parse) {
      json.defaultValue = json.dataType.parse(json.defaultValue, typeof json.defaultValue);
    }

    if (json.validators) {
      json.validators = json.validators.map(Validator.fromJSON);
    }

    return new DataProperty(json);
  };

  return ctor;
})();

var NavigationProperty = (function () {

  /**
  A NavigationProperty describes the metadata for a single property of an  {{#crossLink "EntityType"}}{{/crossLink}} that return instances of other EntityTypes.

  Instances of the NavigationProperty class are constructed automatically during Metadata retrieval.   However it is also possible to construct them
  directly via the constructor.
  @class NavigationProperty
  **/

  /**
  @example
      var homeAddressProp = new NavigationProperty( {
          name: "homeAddress",
          entityTypeName: "Address:#myNamespace",
          isScalar: true,
          associationName: "address_person",
          foreignKeyNames: ["homeAddressId"]
      });
      var homeAddressIdProp = new DataProperty( {
          name: "homeAddressId"
          dataType: DataType.Integer
      });
      // assuming personEntityType is a newly constructed EntityType
      personEntityType.addProperty(homeAddressProp);
      personEntityType.addProperty(homeAddressIdProp);
  @method <ctor> NavigationProperty
  @param config {configuration Object}
  @param [config.name] {String}  The name of this property.
  @param [config.nameOnServer] {String} Same as above but the name is that defined on the server.
  Either this or the 'name' above must be specified. Whichever one is specified the other will be computed using
  the NamingConvention on the MetadataStore associated with the EntityType to which this will be added.
  @param config.entityTypeName {String} The fully qualified name of the type of entity that this property will return.  This type
  need not yet have been created, but it will need to get added to the relevant MetadataStore before this EntityType will be 'complete'.
  The entityType name is constructed as: {shortName} + ":#" + {namespace}
  @param [config.isScalar=true] {Boolean}
  @param [config.associationName] {String} A name that will be used to connect the two sides of a navigation. May be omitted for unidirectional navigations.
  @param [config.foreignKeyNames] {Array of String} An array of foreign key names. The array is needed to support the possibility of multipart foreign keys.
  Most of the time this will be a single foreignKeyName in an array.
  @param [config.foreignKeyNamesOnServer] {Array of String} Same as above but the names are those defined on the server. Either this or 'foreignKeyNames' must
  be specified, if there are foreignKeys. Whichever one is specified the other will be computed using
  the NamingConvention on the MetadataStore associated with the EntityType to which this will be added.
  @param [config.validators] {Array of Validator}
  **/
  var ctor = function NavigationProperty(config) {
    assertConfig(config)
        .whereParam("name").isString().isOptional()
        .whereParam("nameOnServer").isString().isOptional()
        .whereParam("entityTypeName").isString()
        .whereParam("isScalar").isBoolean().isOptional().withDefault(true)
        .whereParam("associationName").isString().isOptional()
        .whereParam("foreignKeyNames").isArray().isString().isOptional().withDefault([])
        .whereParam("foreignKeyNamesOnServer").isArray().isString().isOptional().withDefault([])
        .whereParam("invForeignKeyNames").isArray().isString().isOptional().withDefault([])
        .whereParam("invForeignKeyNamesOnServer").isArray().isString().isOptional().withDefault([])
        .whereParam("validators").isInstanceOf(Validator).isArray().isOptional().withDefault([])
        .whereParam("displayName").isOptional()
        .whereParam("custom").isOptional()
        .applyAll(this);
    var hasName = !!(this.name || this.nameOnServer);

    if (!hasName) {
      throw new Error("A Navigation property must be instantiated with either a 'name' or a 'nameOnServer' property");
    }
  };
  var proto = ctor.prototype;
  proto._$typeName = "NavigationProperty";

  /**
  The {{#crossLink "EntityType"}}{{/crossLink}} that this property belongs to. ( same as parentEntityType).
  __readOnly__
  @property parentType {EntityType}
  **/

  /**
  The {{#crossLink "EntityType"}}{{/crossLink}} that this property belongs to.
  __readOnly__
  @property parentEntityType {EntityType}
  **/

  /**
  The name of this property

  __readOnly__
  @property name {String}
  **/

  /**
  The display name of this property

  __readOnly__
  @property displayName {String} 
  **/
  
  /**
  The name of this property on the server

  __readOnly__
  @property nameOnServer {String} 
  **/
  
  /**
  The {{#crossLink "EntityType"}}{{/crossLink}} returned by this property.

  __readOnly__
  @property entityType {EntityType}
  **/

  /**
  Whether this property returns a single entity or an array of entities.

  __readOnly__
  @property isScalar {Boolean}
  **/

  /**
  Property on the base type that this property is inherited from. Will be null if the property is not on the base type.

  __readOnly__
  @property baseProperty {NavigationProperty}
  **/

  /**
  The name of the association to which that this property belongs.  This associationName will be shared with this
  properties 'inverse'.

  __readOnly__
  @property associationName {String}
  **/

  /**
  The names of the foreign key DataProperties associated with this NavigationProperty. There will usually only be a single DataProperty associated
  with a Navigation property except in the case of entities with multipart keys.

  __readOnly__
  @property foreignKeyNames {Array of String}
  **/

  /**
  The 'foreign key' DataProperties associated with this NavigationProperty. There will usually only be a single DataProperty associated
  with a Navigation property except in the case of entities with multipart keys.

  __readOnly__
  @property relatedDataProperties {Array of DataProperty}
  **/

  /**
  The inverse of this NavigationProperty.  The NavigationProperty that represents a navigation in the opposite direction
  to this NavigationProperty.

  __readOnly__
  @property inverse {NavigationProperty}
  **/

  /**
  The {{#crossLink "Validator"}}{{/crossLink}}s that are associated with this property. Validators can be added and
  removed from this collection.

  __readOnly__
  @property validators {Array of Validator}
  **/

  /**
  A free form object that can be used to define any custom metadata for this NavigationProperty.

  __readOnly__
  @property custom {Object}
  **/

  /**
  Is this a DataProperty? - always false here
  Allows polymorphic treatment of DataProperties and NavigationProperties.

  __readOnly__
  @property isDataProperty {Boolean}
  **/

  /**
  Is this a NavigationProperty? - always true here
  Allows polymorphic treatment of DataProperties and NavigationProperties.

  __readOnly__
  @property isNavigationProperty {Boolean}
  **/

  proto.isDataProperty = false;
  proto.isNavigationProperty = true;

  __extend(proto, DataProperty.prototype, [
    "formatName", "getAllValidators", "resolveProperty"
  ]);

  /**
  General purpose property set method
  @example
      // assume myEntityType is an EntityType
      var prop = myEntityType.getProperty("myProperty");
      prop.setProperties( {
          custom: { foo: 7, bar: "test" }
      });
  @method setProperties
  @param config [object]
  @param [config.inverse] {String}
  @param [config.custom] {Object}
  **/
  proto.setProperties = function (config) {
    if (!this.parentType) {
      throw new Error("Cannot call NavigationProperty.setProperties until the parent EntityType of the NavigationProperty has been set.");
    }
    var inverse = config.inverse;
    if (inverse) delete config.inverse;
    assertConfig(config)
        .whereParam("displayName").isOptional()
        .whereParam("foreignKeyNames").isArray().isString().isOptional().withDefault([])
        .whereParam("invForeignKeyNames").isArray().isString().isOptional().withDefault([])
        .whereParam("custom").isOptional()
        .applyAll(this);
    this.parentType._updateNames(this);

    this._resolveNp();
    if (inverse) {
      this.setInverse(inverse);
    }

  };

  proto.getInverse = function() {
    var np = this;
    while(!np.inverse && np.baseProperty) {
      np = np.baseProperty;
    }
    return np.inverse;
  }

  proto.setInverse = function (inverseNp) {
    var invNp;
    if (typeof (inverseNp) === "string") {
      invNp = this.entityType.getNavigationProperty(inverseNp);
    } else {
      invNp = inverseNp;
    }

    if (!invNp) {
      throw throwSetInverseError(this, "Unable to find inverse property: " + invNpName);
    }
    if (this.inverse || invNp.inverse) {
      throwSetInverseError(this, "It has already been set on one side or the other.");
    }
    if (invNp.entityType != this.parentType) {
      throwSetInverseError(this, invNp.formatName + " is not a valid inverse property for this.");
    }
    if (this.associationName) {
      invNp.associationName = this.associationName;
    } else {
      if (!invNp.associationName) {
        invNp.associationName = this.formatName() + "_" + invNp.formatName();
      }
      this.associationName = invNp.associationName;
    }
    this._resolveNp();
    invNp._resolveNp();
  };

  // In progress - will be used for manual metadata config
  proto.createInverse = function (config) {

    if (!this.entityType) {
      throwCreateInverseError(this, "has not yet been defined.");
    }
    if (this.entityType.isFrozen) {
      throwCreateInverseError(this, "is frozen.");
    }
    var metadataStore = this.entityType.metadataStore;
    if (metadataStore == null) {
      throwCreateInverseError(this, "has not yet been added to the metadataStore.");
    }

    config.entityTypeName = this.parentEntityType.name;
    config.associationName = this.associationName;
    var invNp = new NavigationProperty(config);
    this.parentEntityType.addNavigationProperty(invNp);
    return invNp;
  };

  function throwSetInverseError(np, message) {
    throw new Error("Cannot set the inverse property for: " + np.formatName() + ". " + message);
  }

  function throwCreateInverseError(np, message) {
    throw new Error("Cannot create inverse for: " + np.formatName() + ". The entityType for this navigation property " + message);
  }

  proto.toJSON = function () {
    return __toJson(this, {
      name: null,
      entityTypeName: null,
      isScalar: null,
      associationName: null,
      validators: null,
      displayName: null,
      foreignKeyNames: null,
      invForeignKeyNames: null,
      custom: null
    });
  };

  ctor.fromJSON = function (json) {
    if (json.validators) {
      json.validators = json.validators.map(Validator.fromJSON);
    }
    return new NavigationProperty(json);
  };

  proto._resolveNp = function () {
    var np = this;
    var entityType = np.entityType;
    var invNp = __arrayFirst(entityType.navigationProperties, function (altNp) {
      // Can't do this because of possibility of comparing a base class np with a subclass altNp.
      // return altNp.associationName === np.associationName
      //    && altNp !== np;
      // So use this instead.
      return altNp.associationName === np.associationName &&
          (altNp.name !== np.name || altNp.entityTypeName !== np.entityTypeName);
    });
    np.inverse = invNp;
    //if (invNp && invNp.inverse == null) {
    //    invNp._resolveNp();
    //}
    if (!invNp) {
      // unidirectional 1-n relationship
      np.invForeignKeyNames.forEach(function (invFkName) {
        var fkProp = entityType.getDataProperty(invFkName);
        if (!fkProp) {
          throw new Error("EntityType '" + np.entityTypeName + "' has no foreign key matching '" + invFkName + "'");
        }
        var invEntityType = np.parentType;
        fkProp.inverseNavigationProperty = __arrayFirst(invEntityType.navigationProperties, function (np2) {
          return np2.invForeignKeyNames && np2.invForeignKeyNames.indexOf(fkProp.name) >= 0 && np2.entityType === fkProp.parentType;
        });
        __arrayAddItemUnique(entityType.foreignKeyProperties, fkProp);
      });
    }

    resolveRelated(np);
  }

  // sets navigation property: relatedDataProperties and dataProperty: relatedNavigationProperty
  function resolveRelated(np) {

    var fkNames = np.foreignKeyNames;
    if (fkNames.length === 0) return;

    var parentEntityType = np.parentType;
    var fkProps = fkNames.map(function (fkName) {
      return parentEntityType.getDataProperty(fkName);
    });
    var fkPropCollection = parentEntityType.foreignKeyProperties;

    fkProps.forEach(function (dp) {
      __arrayAddItemUnique(fkPropCollection, dp);
      dp.relatedNavigationProperty = np;
      // now update the inverse
      __arrayAddItemUnique(np.entityType.inverseForeignKeyProperties, dp);
      if (np.relatedDataProperties) {
        __arrayAddItemUnique(np.relatedDataProperties, dp);
      } else {
        np.relatedDataProperties = [dp];
      }
    });
  }

  return ctor;
})();

var AutoGeneratedKeyType = (function () {
  /**
  AutoGeneratedKeyType is an 'Enum' containing all of the valid states for an automatically generated key.
  @class AutoGeneratedKeyType
  @static
  @final
  **/
  var ctor = new Enum("AutoGeneratedKeyType");
  /**
  This entity does not have an autogenerated key.
  The client must set the key before adding the entity to the EntityManager
  @property None {AutoGeneratedKeyType}
  @final
  @static
  **/
  ctor.None = ctor.addSymbol();
  /**
  This entity's key is an Identity column and is set by the backend database.
  Keys for new entities will be temporary until the entities are saved at which point the keys will
  be converted to their 'real' versions.
  @property Identity {AutoGeneratedKeyType}
  @final
  @static
  **/
  ctor.Identity = ctor.addSymbol();
  /**
  This entity's key is generated by a KeyGenerator and is set by the backend database.
  Keys for new entities will be temporary until the entities are saved at which point the keys will
  be converted to their 'real' versions.
  @property KeyGenerator {AutoGeneratedKeyType}
  @final
  @static
  **/
  ctor.KeyGenerator = ctor.addSymbol();
  ctor.resolveSymbols();

  return ctor;
})();

// mixin methods
(function () {

  var proto = Param.prototype;

  proto.isEntity = function () {
    return this._addContext({
      fn: isEntity,
      msg: " must be an entity"
    });
  };

  function isEntity(context, v) {
    if (v == null) return false;
    return (v.entityType !== undefined);
  }

  proto.isEntityProperty = function () {
    return this._addContext({
      fn: isEntityProperty,
      msg: " must be either a DataProperty or a NavigationProperty"
    });
  };

  function isEntityProperty(context, v) {
    if (v == null) return false;
    return (v.isDataProperty || v.isNavigationProperty);
  }
})();

// functions shared between classes related to Metadata

function parseTypeName(entityTypeName) {
  if (!entityTypeName) {
    return null;
  }

  var typeParts = entityTypeName.split(":#");
  if (typeParts.length > 1) {
    return makeTypeHash(typeParts[0], typeParts[1]);
  }

  if (__stringStartsWith(entityTypeName, MetadataStore.ANONTYPE_PREFIX)) {
    var typeHash = makeTypeHash(entityTypeName);
    typeHash.isAnonymous = true
    return typeHash;
  }
  var entityTypeNameNoAssembly = entityTypeName.split(",")[0];
  var typeParts = entityTypeNameNoAssembly.split(".");
  if (typeParts.length > 1) {
    var shortName = typeParts[typeParts.length - 1];
    var namespaceParts = typeParts.slice(0, typeParts.length - 1);
    var ns = namespaceParts.join(".");
    return makeTypeHash(shortName, ns);
  } else {
    return makeTypeHash(entityTypeName);
  }
}

function makeTypeHash(shortName, namespace) {
  return {
    shortTypeName: shortName,
    namespace: namespace,
    typeName: qualifyTypeName(shortName, namespace)
  };
}

function isQualifiedTypeName(entityTypeName) {
  return entityTypeName.indexOf(":#") >= 0;
}

function qualifyTypeName(shortName, namespace) {
  if (namespace && namespace.length > 0) {
    return shortName + ":#" + namespace;
  } else {
    return shortName;
  }
}

// Used by both ComplexType and EntityType
function addProperties(entityType, propObj, ctor) {

  if (!propObj) return;
  if (Array.isArray(propObj)) {
    propObj.forEach(entityType._addPropertyCore.bind(entityType));
  } else if (typeof (propObj) === 'object') {
    for (var key in propObj) {
      if (__hasOwnProperty(propObj, key)) {
        var value = propObj[key];
        value.name = key;
        var prop = new ctor(value);
        entityType._addPropertyCore(prop);
      }
    }
  } else {
    throw new Error("The 'dataProperties' or 'navigationProperties' values must be either an array of data/nav properties or an object where each property defines a data/nav property");
  }
}

breeze.MetadataStore = MetadataStore;
breeze.EntityType = EntityType;
breeze.ComplexType = ComplexType;
breeze.DataProperty = DataProperty;
breeze.NavigationProperty = NavigationProperty;
breeze.AutoGeneratedKeyType = AutoGeneratedKeyType;



;/**
@module breeze
**/

var KeyGenerator = (function () {

  /*
  @class KeyGenerator
  */
  var ctor = function KeyGenerator() {
    // key is dataProperty.name + || + entityType.name, value is propEntry
    // propEntry = { entityType, propertyName, keyMap }
    // keyMap has key of the actual value ( as a string) and a value of null or the real id.
    this._tempIdMap = {};
  };
  var proto = ctor.prototype;

  /*
  Returns a unique 'temporary' id for the specified {{#crossLink "EntityType"}}{{/crossLink}}.
  Uniqueness is defined for this purpose as being unique within each instance of a KeyGenerator. This is sufficient
  because each EntityManager will have its own instance of a KeyGenerator and any entities imported into
  the EntityManager with temporary keys will have them regenerated and remapped on import.

  The return value of this method must be of the correct type as determined by the keyProperties of the
  specified EntityType
  @example
      // Assume em1 is a preexisting EntityManager
      var custType = em1.metadataStore.getEntityType("Customer");
      var cust1 = custType.createEntity();
      // next line both sets cust1's 'CustomerId' property but also returns the value
      var cid1 = em1.generateTempKeyValue(cust1);
      em1.saveChanges().then( function( data) {
        var sameCust1 = data.results[0];
        // cust1 === sameCust1;
        // but cust1.getProperty("CustomerId") != cid1
        // because the server will have generated a new id
        // and the client will have been updated with this
        // new id.
      });
  @method generateTempKeyValue
  @param entityType {EntityType}
  */
  proto.generateTempKeyValue = function (entityType, valueIfAvail) {
    var keyProps = entityType.keyProperties;
    if (keyProps.length > 1) {
      throw new Error("Ids can not be autogenerated for entities with multipart keys");
    }
    var keyProp = keyProps[0];
    var propEntry = getPropEntry(this, keyProp, true);
    var nextId;
    if (valueIfAvail != null) {
      if (!propEntry.keyMap[valueIfAvail.toString()]) {
        nextId = valueIfAvail;
      }
    }

    if (nextId === undefined) {
      var dataType = keyProp.dataType;
      if (dataType.getNext) {
        nextId = dataType.getNext(this);
        // need to watch out for collision with previously imported ids that might also get generated.
        while (propEntry.keyMap[nextId.toString()] != null) {
          nextId = dataType.getNext(this);
        }
      } else {
        throw new Error("Cannot use a property with a dataType of: " + dataType.toString() + " for id generation");
      }
    }

    propEntry.keyMap[nextId.toString()] = true;
    return nextId;
  };

  proto.getTempKeys = function () {
    var results = [];
    //noinspection JSHint
    for (var key in this._tempIdMap) {
      var propEntry = this._tempIdMap[key];
      var entityType = propEntry.entityType;
      // var propName = propEntry.propertyName;
      //noinspection JSHint
      for (var keyValue in propEntry.keyMap) {
        results.push(new EntityKey(entityType, [keyValue]));
      }
    }
    return results;
  };


  // proto methods below are not part of the KeyGenerator interface.

  proto.isTempKey = function (entityKey) {
    var keyProps = entityKey.entityType.keyProperties;
    if (keyProps.length > 1) return false;
    var keyProp = keyProps[0];
    var propEntry = getPropEntry(this, keyProp);
    if (!propEntry) {
      return false;
    }
    return (propEntry.keyMap[entityKey.values[0].toString()] !== undefined);
  };

  function getPropEntry(that, keyProp, createIfMissing) {
    var key = keyProp.name + ".." + keyProp.parentType.name;
    var propEntry = that._tempIdMap[key];
    if (!propEntry) {
      if (createIfMissing) {
        propEntry = { entityType: keyProp.parentType, propertyName: keyProp.name, keyMap: {} };
        that._tempIdMap[key] = propEntry;
      }
    }
    return propEntry;
  }

  __config.registerType(ctor, "KeyGenerator");

  return ctor;
})();

breeze.KeyGenerator = KeyGenerator;;/**
@module breeze
**/

var LocalQueryComparisonOptions = (function () {

  /**
  A LocalQueryComparisonOptions instance is used to specify the "comparison rules" used when performing "local queries" in order
  to match the semantics of these same queries when executed against a remote service.  These options should be set based on the
  manner in which your remote service interprets certain comparison operations.

  The default LocalQueryComparisonOptions stipulates 'caseInsensitive" queries with ANSI SQL rules regarding comparisons of unequal
  length strings.

  @class LocalQueryComparisonOptions
  **/

  /**
  LocalQueryComparisonOptions constructor
  @example
      // create a 'caseSensitive - non SQL' instance.
      var lqco = new LocalQueryComparisonOptions({
              name: "caseSensitive-nonSQL"
              isCaseSensitive: true;
              usesSql92CompliantStringComparison: false;
          });
      // either apply it globally
      lqco.setAsDefault();
      // or to a specific MetadataStore
      var ms = new MetadataStore({ localQueryComparisonOptions: lqco });
      var em = new EntityManager( { metadataStore: ms });

  @method <ctor> LocalQueryComparisonOptions
  @param config {Object}
  @param [config.name] {String}
  @param [config.isCaseSensitive] {Boolean} Whether predicates that involve strings will be interpreted in a "caseSensitive" manner. Default is 'false'
  @param [config.usesSql92CompliantStringComparison] {Boolean} Whether of not to enforce the ANSI SQL standard
  of padding strings of unequal lengths before comparison with spaces. Note that per the standard, padding only occurs with equality and
  inequality predicates, and not with operations like 'startsWith', 'endsWith' or 'contains'.  Default is true.
  **/

  var ctor = function LocalQueryComparisonOptions(config) {
    assertConfig(config || {})
        .whereParam("name").isOptional().isString()
        .whereParam("isCaseSensitive").isOptional().isBoolean()
        .whereParam("usesSql92CompliantStringComparison").isBoolean()
        .applyAll(this);
    if (!this.name) {
      this.name = __getUuid();
    }
    __config._storeObject(this, proto._$typeName, this.name);
  };
  var proto = ctor.prototype;
  proto._$typeName = "LocalQueryComparisonOptions";

  
  /**
  Case insensitive SQL compliant options - this is also the default unless otherwise changed.
  @property caseInsensitiveSQL {LocalQueryComparisonOptions}
  @static
  **/
  ctor.caseInsensitiveSQL = new ctor({
  name: "caseInsensitiveSQL",
  isCaseSensitive: false,
  usesSql92CompliantStringComparison: true
  });

  /**
  The default value whenever LocalQueryComparisonOptions are not specified. By default this is 'caseInsensitiveSQL'.
  @property defaultInstance {LocalQueryComparisonOptions}
  @static
  **/
  ctor.defaultInstance = new ctor(ctor.caseInsensitiveSQL);

  /**
  Sets the 'defaultInstance' by creating a copy of the current 'defaultInstance' and then applying all of the properties of the current instance.
  The current instance is returned unchanged.
  @method setAsDefault
  @example
      var lqco = new LocalQueryComparisonOptions({
          isCaseSensitive: false;
          usesSql92CompliantStringComparison: true;
      });
  lqco.setAsDefault();
  @chainable
  **/
  proto.setAsDefault = function () {
  return __setAsDefault(this, ctor);
  };


  return ctor;
})();

breeze.LocalQueryComparisonOptions = LocalQueryComparisonOptions;


;/**
@module breeze
**/

var NamingConvention = (function () {
  /**
  A NamingConvention instance is used to specify the naming conventions under which a MetadataStore
  will translate property names between the server and the javascript client.

  The default NamingConvention does not perform any translation, it simply passes property names thru unchanged.

  @class NamingConvention
  **/

  /**
  NamingConvention constructor

  @example
      // A naming convention that converts the first character of every property name to uppercase on the server
      // and lowercase on the client.
      var namingConv = new NamingConvention({
          serverPropertyNameToClient: function(serverPropertyName) {
              return serverPropertyName.substr(0, 1).toLowerCase() + serverPropertyName.substr(1);
          },
          clientPropertyNameToServer: function(clientPropertyName) {
              return clientPropertyName.substr(0, 1).toUpperCase() + clientPropertyName.substr(1);
          }            
      });
      var ms = new MetadataStore({ namingConvention: namingConv });
      var em = new EntityManager( { metadataStore: ms });
  @method <ctor> NamingConvention
  @param config {Object}
  @param config.serverPropertyNameToClient {Function} Function that takes a server property name add converts it into a client side property name.
  @param config.clientPropertyNameToServer {Function} Function that takes a client property name add converts it into a server side property name.
  **/
  var ctor = function NamingConvention(config) {
    assertConfig(config || {})
        .whereParam("name").isOptional().isString()
        .whereParam("serverPropertyNameToClient").isFunction()
        .whereParam("clientPropertyNameToServer").isFunction()
        .applyAll(this);
    if (!this.name) {
      this.name = __getUuid();
    }
    __config._storeObject(this, proto._$typeName, this.name);
  };
  var proto = ctor.prototype;
  proto._$typeName = "NamingConvention";

  /**
  The function used to convert server side property names to client side property names.

  @method serverPropertyNameToClient
  @param serverPropertyName {String}
  @param [property] {DataProperty|NavigationProperty} The actual DataProperty or NavigationProperty corresponding to the property name.
  @return {String} The client side property name.
  **/

  /**
  The function used to convert client side property names to server side property names.

  @method clientPropertyNameToServer
  @param clientPropertyName {String}
  @param [property] {DataProperty|NavigationProperty} The actual DataProperty or NavigationProperty corresponding to the property name.
  @return {String} The server side property name.
  **/

  /**
  A noop naming convention - This is the default unless another is specified.
  @property none {NamingConvention}
  @static
  **/
  ctor.none = new ctor({
    name: "noChange",
    serverPropertyNameToClient: function (serverPropertyName) {
      return serverPropertyName;
    },
    clientPropertyNameToServer: function (clientPropertyName) {
      return clientPropertyName;
    }
  });

  /**
  The "camelCase" naming convention - This implementation only lowercases the first character of the server property name
  but leaves the rest of the property name intact.  If a more complicated version is needed then one should be created via the ctor.
  @property camelCase {NamingConvention}
  @static
  **/
  ctor.camelCase = new ctor({
    name: "camelCase",
    serverPropertyNameToClient: function (serverPropertyName) {
      return serverPropertyName.substr(0, 1).toLowerCase() + serverPropertyName.substr(1);
    },
    clientPropertyNameToServer: function (clientPropertyName) {
      return clientPropertyName.substr(0, 1).toUpperCase() + clientPropertyName.substr(1);
    }
  });

  /**
  The default value whenever NamingConventions are not specified.
  @property defaultInstance {NamingConvention}
  @static
  **/
  ctor.defaultInstance = new ctor(ctor.none);

  /**
  Sets the 'defaultInstance' by creating a copy of the current 'defaultInstance' and then applying all of the properties of the current instance.
  The current instance is returned unchanged.
  @method setAsDefault
  @example
      var namingConv = new NamingConvention({
          serverPropertyNameToClient: function(serverPropertyName) {
              return serverPropertyName.substr(0, 1).toLowerCase() + serverPropertyName.substr(1);
          },
          clientPropertyNameToServer: function(clientPropertyName) {
              return clientPropertyName.substr(0, 1).toUpperCase() + clientPropertyName.substr(1);
          }            
      });
      namingConv.setAsDefault();
  @chainable
  **/
  proto.setAsDefault = function () {
    return __setAsDefault(this, ctor);
  };

  return ctor;
})();

breeze.NamingConvention = NamingConvention;


;var Predicate = (function () {
  
  var Predicate = (function () {
    /**
    Used to define a 'where' predicate for an EntityQuery.  Predicates are immutable, which means that any
    method that would modify a Predicate actually returns a new Predicate.
    @class Predicate
    **/

    /**
    Predicate constructor
    @example
        var p1 = new Predicate("CompanyName", "StartsWith", "B");
        var query = new EntityQuery("Customers").where(p1); 
    or
    @example
        var p2 = new Predicate("Region", FilterQueryOp.Equals, null);
        var query = new EntityQuery("Customers").where(p2);
    @method <ctor> Predicate
    @param property {String} A property name, a nested property name or an expression involving a property name.
    @param operator {FilterQueryOp|String}
    @param value {Object} - This will be treated as either a property expression or a literal depending on context.  In general,
    if the value can be interpreted as a property expression it will be, otherwise it will be treated as a literal.
    In most cases this works well, but you can also force the interpretation by making the value argument itself an object with a 'value'
    property and an 'isLiteral' property set to either true or false.  Breeze also tries to infer the dataType of any
    literal based on context, if this fails you can force this inference by making the value argument an object with a
    'value' property and a 'dataType' property set to one of the breeze.DataType enumeration instances.
    **/

    var ctor = function () {
      // empty ctor is used by all subclasses.
      if (arguments.length === 0) return;
      if (arguments.length === 1) {
        // 3 possibilities:
        //      Predicate(aPredicate)
        //      Predicate([ aPredicate ])
        //      Predicate(["freight", ">", 100"])
        //      Predicate( "freight gt 100" }  // passthru ( i.e. maybe an odata string)
        //      Predicate( { freight: { ">": 100 } })
        var arg = arguments[0];
        if (Array.isArray(arg)) {
          if (arg.length === 1) {
            // recurse
            return Predicate(arg[0]);
          } else {
            return createPredicateFromArray(arg);
          }
        } else if (arg instanceof Predicate) {
          return arg;
        } else if (typeof arg == 'string') {
          return new PassthruPredicate(arg);
        } else {
          return createPredicateFromObject(arg);
        }
      } else {
        // 2 possibilities
        //      Predicate("freight", ">", 100");
        //      Predicate("orders", "any", "freight",  ">", 950);
        return createPredicateFromArray(Array.prototype.slice.call(arguments, 0));
      }
    };
    var proto = ctor.prototype;
    
    /**
    Same as using the ctor.
    @example
        // so 
        var p = Predicate.create(a, b, c);
        // is the same as 
        var p = new Predicate(a, b, c); 
    
    @method create
    @param property {String} A property name, a nested property name or an expression involving a property name.
    @param operator {FilterQueryOp|String}
    @param value {Object} - This will be treated as either a property expression or a literal depending on context.  In general,
    if the value can be interpreted as a property expression it will be, otherwise it will be treated as a literal.
    In most cases this works well, but you can also force the interpretation by making the value argument itself an object with a 'value'
    property and an 'isLiteral' property set to either true or false.  Breeze also tries to infer the dataType of any
    literal based on context, if this fails you can force this inference by making the value argument an object with a
    'value' property and a 'dataType' property set to one of the breeze.DataType enumeration instances.

    @static
    **/
    ctor.create = ctor;
    
    /**
    Creates a 'composite' Predicate by 'and'ing a set of specified Predicates together.
    @example
        var dt = new Date(88, 9, 12);
        var p1 = Predicate.create("OrderDate", "ne", dt);
        var p2 = Predicate.create("ShipCity", "startsWith", "C");
        var p3 = Predicate.create("Freight", ">", 100);
        var newPred = Predicate.and(p1, p2, p3);
    or
    @example
        var preds = [p1, p2, p3];
        var newPred = Predicate.and(preds);
    @method and
    @param predicates* {multiple Predicates|Array of Predicate} Any null or undefined values passed in will be automatically filtered out before constructing the composite predicate.
    @static
    **/
    ctor.and = function () {
      var pred = new AndOrPredicate("and", __arraySlice(arguments));
      // return undefined if empty
      return pred.op && pred;
    };
    
    /**
    Creates a 'composite' Predicate by 'or'ing a set of specified Predicates together.
    @example
        var dt = new Date(88, 9, 12);
        var p1 = Predicate.create("OrderDate", "ne", dt);
        var p2 = Predicate.create("ShipCity", "startsWith", "C");
        var p3 = Predicate.create("Freight", ">", 100);
        var newPred = Predicate.or(p1, p2, p3);
    or
    @example
        var preds = [p1, p2, p3];
        var newPred = Predicate.or(preds);
    @method or
    @param predicates* {multiple Predicates|Array of Predicate} Any null or undefined values passed in will be automatically filtered out before constructing the composite predicate.
    @static
    **/
    ctor.or = function () {
      var pred = new AndOrPredicate("or", __arraySlice(arguments));
      return pred.op && pred;
    };
    
    /**
    Creates a 'composite' Predicate by 'negating' a specified predicate.
    @example
        var p1 = Predicate.create("Freight", "gt", 100);
        var not_p1 = Predicate.not(p1);
    This can also be accomplished using the 'instance' version of the 'not' method
    @example
        var not_p1 = p1.not();
    Both of which would be the same as
    @example
        var not_p1 = Predicate.create("Freight", "le", 100);
    @method not
    @param predicate {Predicate}
    @static
    **/
    ctor.not = function (pred) {
      return pred.not();
    };

    ctor.extendBinaryPredicateFn = function(opMap, visitorFn ) {
      var baseVisitorFn = toFunctionVisitor.binaryPredicate;
      for (var op in (opMap || {})) {
        var config = opMap[op];
        config.visitorFn = visitorFn;
        updateAliasMap(BinaryPredicate.prototype.aliasMap, op, opMap[op])
      }
      if (!toFunctionVisitor.isExtended) {
        toFunctionVisitor.binaryPredicate = function (context, expr1Val, expr2Val) {
          var visitorFn = this.aliasMap[this.op.key].visitorFn;
          if (visitorFn) {
            return visitorFn(context, expr1Val, expr2Val);
          } else {
            return baseVisitorFn(context, expr1Val, expr2Val);
          }
        }
        toFunctionVisitor.isExtended = true;
      }
    };


    /**
    'And's this Predicate with one or more other Predicates and returns a new 'composite' Predicate
    @example
        var dt = new Date(88, 9, 12);
        var p1 = Predicate.create("OrderDate", "ne", dt);
        var p2 = Predicate.create("ShipCity", "startsWith", "C");
        var p3 = Predicate.create("Freight", ">", 100);
        var newPred = p1.and(p2, p3);
    or
    @example
        var preds = [p2, p3];
        var newPred = p1.and(preds);
    The 'and' method is also used to write "fluent" expressions
    @example
        var p4 = Predicate.create("ShipCity", "startswith", "F")
          .and("Size", "gt", 2000);
    @method and
    @param predicates* {multiple Predicates|Array of Predicate} Any null or undefined values passed in will be automatically filtered out before constructing the composite predicate.
    **/
    proto.and = function () {
      return new AndOrPredicate("and", argsForAndOrPredicates(this, arguments));
    };
    
    /**
    'Or's this Predicate with one or more other Predicates and returns a new 'composite' Predicate
    @example
        var dt = new Date(88, 9, 12);
        var p1 = Predicate.create("OrderDate", "ne", dt);
        var p2 = Predicate.create("ShipCity", "startsWith", "C");
        var p3 = Predicate.create("Freight", ">", 100);
        var newPred = p1.or(p2, p3);
    or
    @example
        var preds = [p2, p3];
        var newPred = p1.or(preds);
    The 'or' method is also used to write "fluent" expressions
    @example
        var p4 = Predicate.create("ShipCity", "startswith", "F")
          .or("Size", "gt", 2000);
    @method or
    @param predicates* {multiple Predicates|Array of Predicate} Any null or undefined values passed in will be automatically filtered out before constructing the composite predicate.
    **/
    proto.or = function () {
      return new AndOrPredicate("or", argsForAndOrPredicates(this, arguments));
    };
    
    /**
    Returns the 'negated' version of this Predicate
    @example
        var p1 = Predicate.create("Freight", "gt", 100);
        var not_p1 = p1.not();
    This can also be accomplished using the 'static' version of the 'not' method
    @example
        var p1 = Predicate.create("Freight", "gt", 100);
        var not_p1 = Predicate.not(p1);
    which would be the same as
    @example
        var not_p1 = Predicate.create("Freight", "le", 100);
    @method not
    **/
    proto.not = function () {
      return new UnaryPredicate("not", this);
    };
    
    //
    proto.toJSON = function () {
      // toJSON ( part of js standard - takes a single parameter
      // that is either "" or the name of the property being serialized.
      return this.toJSONExt({ entityType: this._entityType });
    }

    proto.toJSONExt = function(context) {
      return this.visit(context, toJSONVisitor);
    }

    proto.toFunction = function(context) {
      return this.visit(context, toFunctionVisitor);
    }

    proto.toString = function () {
      return JSON.stringify(this);
    };

    proto.visit = function(context, visitor) {
      if (__isEmpty(context)) {
        context = { entityType: null };
      } else if (context instanceof EntityType) {
        context = { entityType: context };
      } else if (!__hasOwnProperty(context, "entityType")) {
        throw new Error("All visitor methods must be called with a context object containing at least an 'entityType' property");
      }

      if (visitor) {
        context.visitor = visitor;
      } else {
        visitor = context.visitor;
      }
      var fn = visitor[this.visitorMethodName];
      if (fn == null) {
        throw new Error("Unable to locate method: " + this.visitorMethodName + " on visitor");
      }


      var entityType = context.entityType;
      // don't both validating if already done so ( or if no _validate method
      if (this._validate && entityType == null || this._entityType !== entityType) {
        // don't need to capture return value because validation fn doesn't have one.
        this._validate(entityType, context.usesNameOnServer);
        this._entityType = entityType;
      }

      // args = context, arg1, args2, ...
      var args = Array.prototype.slice.call(arguments, 1);
      return fn.call(this, context);
    }

    proto._initialize = function (visitorMethodName,  opMap) {
      this.visitorMethodName = visitorMethodName;
      var aliasMap = this.aliasMap = {};
      for (var op in (opMap || {})) {
        updateAliasMap(aliasMap, op, opMap[op])
      }
    };

    function argsForAndOrPredicates(obj, args) {
      var preds = args[0];
      if (preds instanceof Predicate) {
        preds = __arraySlice(args);
      } else if (!Array.isArray(preds)) {
        preds = [Predicate(__arraySlice(args))];
      }
      return [obj].concat(preds);
    }
    
    function updateAliasMap(aliasMap, op, config) {
      var key = op.toLowerCase();
      config.key = key;
      aliasMap[key] = config;

      config.aliases && config.aliases.forEach(function (alias) {
        aliasMap[alias.toLowerCase()] = config;
      });
    }
    
    proto._resolveOp = function (op, okIfNotFound) {
      op = op.operator || op;
      var result = this.aliasMap[op.toLowerCase()];
      if (!result && !okIfNotFound) {
        throw new Error("Unable to resolve operator: " + op);
      }
      return result;
    };
    
    function createPredicateFromArray(arr) {
      // TODO: assert that length of the array should be > 3
      // Needs to handle:
      //      [ "freight", ">", 100"];
      //      [ "orders", "any", "freight",  ">", 950 ]
      //      [ "orders", "and", anotherPred ]
      //      [ "orders", "and", [ "freight, ">", 950 ]
      var json = {};
      var value = {};
      json[arr[0]] = value;
      var op = arr[1];
      op = op.operator || op;  // incoming op will be either a string or a FilterQueryOp
      if (arr.length == 3) {
        value[op] = arr[2];
      } else {
        value[op] = createPredicateFromArray(arr.splice(2));
      }
      return createPredicateFromObject(json);
    };
    
    function createPredicateFromObject(obj) {
      if (obj instanceof Predicate) return obj;
      
      if (typeof obj != 'object') {
        throw new Error("Unable to convert to a Predicate: " + obj);
      }
      var keys = Object.keys(obj);
      var preds = keys.map(function (key) {
        return createPredicateFromKeyValue(key, obj[key]);
      });
      return (preds.length === 1) ? preds[0] : new AndOrPredicate("and", preds);
    }
    
    function createPredicateFromKeyValue(key, value) {
      // { and: [a,b] } key='and', value = [a,b]
      if (AndOrPredicate.prototype._resolveOp(key, true)) {
        return new AndOrPredicate(key, value);
      }
      
      // { not: a }  key= 'not', value = a
      if (UnaryPredicate.prototype._resolveOp(key, true)) {
        return new UnaryPredicate(key, value);
      }

      if ((typeof value !== 'object') || value == null || __isDate(value)) {
        // { foo: bar } key='foo', value = bar ( where bar is a literal i.e. a string, a number, a boolean or a date.
        return new BinaryPredicate("eq", key, value);
      } else if (__hasOwnProperty(value, 'value')) {
        // { foo: { value: bar, dataType: xxx} } key='foo', value = bar ( where bar is an object representing a literal
        return new BinaryPredicate("eq", key, value);
      }
      
      if (Array.isArray(value)) {
        throw new Error("Unable to resolve predicate after the phrase: " + key);
      }
      
      var expr = key;
      var keys = Object.keys(value);
      var preds = keys.map(function (op) {
        
        // { a: { any: b } op = 'any', expr=a, value[op] = b
        if (AnyAllPredicate.prototype._resolveOp(op, true)) {
          return new AnyAllPredicate(op, expr, value[op]);
        }
        
        if (BinaryPredicate.prototype._resolveOp(op, true)) {
          // { a: { ">": b }} op = ">", expr=a, value[op] = b
          return new BinaryPredicate(op, expr, value[op]);
        } else if (__hasOwnProperty(value[op], 'value')) {
          // { a: { ">": { value: b, dataType: 'Int32' }} expr = a value[op] = { value: b, dataType: 'Int32' }
          return new BinaryPredicate("eq", expr, value[op]);
        }
        
        var msg = __formatString("Unable to resolve predicate after the phrase: '%1' for operator: '%2'  and value: '%3'", expr, op, value[op]);
        throw new Error(msg);

      });
      
      return (preds.length === 1) ? preds[0] : new AndOrPredicate("and", preds);
    }

    return ctor;
  })();
  
  var PassthruPredicate = (function () {
    var ctor = function PassthruPredicate(value) {
      this.value = value;
    };
    var proto = ctor.prototype = new Predicate();
    proto._initialize('passthruPredicate');

    proto._validate = __noop;

    return ctor;
  })();
  
  var UnaryPredicate = (function () {
    var ctor = function UnaryPredicate(op, pred) {
      this.op = this._resolveOp(op);
      this.pred = Predicate(pred);
    };
    
    var proto = ctor.prototype = new Predicate();
    proto._initialize('unaryPredicate', {
      'not': { aliases: [ '!', '~' ] }
    });

    proto._validate = function(entityType, usesNameOnServer) {
      this.pred._validate(entityType, usesNameOnServer);
    };

    return ctor;
  })();
  
  var BinaryPredicate = (function () {
    var ctor = function BinaryPredicate(op, expr1, expr2) {
      // 5 public props op, expr1Source, expr2Source, expr1, expr2
      this.op = this._resolveOp(op);
      this.expr1Source = expr1;
      this.expr2Source = expr2;
      // this.expr1 and this.expr2 won't be
      // determined until validate is run
    };
    
    var proto = ctor.prototype = new Predicate();
    proto._initialize('binaryPredicate', {
      'eq': {
        aliases: ["==", "equals" ]
      },
      'ne': {
        aliases: ["!=", "~=", "notequals" ]
      },
      'lt': {
        aliases: ["<", "lessthan" ]
      },
      'le': {
        aliases: ["<=", "lessthanorequal" ]
      },
      'gt': {
        aliases: [">", "greaterthan"]
      },
      'ge': {
        aliases: [">=", "greaterthanorequal" ]
      },
      'startswith': {
        isFunction: true
      },
      'endswith': {
        isFunction: true
      },
      'contains': {
        aliases: ["substringof"],
        isFunction: true
      },
      'in': {

      }
    });


    proto._validate = function(entityType, usesNameOnServer) {
      var expr1Context = { entityType: entityType, usesNameOnServer: usesNameOnServer };
      this.expr1 = createExpr(this.expr1Source, expr1Context);
      if (this.expr1 == null) {
        throw new Error("Unable to validate 1st expression: " + this.expr1Source);
      }
      if (this.expr1 instanceof LitExpr) {
        // lhs must be either a property or a function.
        throw new Error("The left hand side of a binary predicate cannot be a literal expression, it must be a valid property or functional predicate expression: " + this.expr1Source);
      }

      if (this.op.key == 'in' && !Array.isArray(this.expr2Source)) {
        throw new Error("The 'in' operator requires that its right hand argument be an array");
      }
      var expr2Context = __extend(expr1Context, { isRHS: true, dataType: this.expr1.dataType });
      this.expr2 = createExpr(this.expr2Source, expr2Context );
      if (this.expr2 == null) {
        throw new Error("Unable to validate 2nd expression: " + this.expr2Source);
      }

      if (this.expr1.dataType == null) {
        this.expr1.dataType = this.expr2.dataType;
      }
    }

    return ctor;
  })();
  
  var AndOrPredicate = (function () {
    // two public props: op, preds
    var ctor = function AndOrPredicate(op, preds) {
      this.op = this._resolveOp(op);
      if (preds.length == 1 && Array.isArray(preds[0])) {
        preds = preds[0];
      }
      this.preds = preds.filter(function (pred) {
        return pred != null;
      }).map(function (pred) {
        return Predicate(pred);
      });
      if (this.preds.length == 0) {
        // marker for an empty predicate
        this.op = null;
      }
      if (this.preds.length == 1) {
        return this.preds[0];
      }
    };
    
    var proto = ctor.prototype = new Predicate();
    proto._initialize("andOrPredicate", {
      'and': { aliases: [ '&&' ] },
      'or': { aliases: [ '||' ] }
    });

    proto._validate = function(entityType, usesNameOnServer) {
      this.preds.every(function (pred) {
        pred._validate(entityType, usesNameOnServer);
      });
    }

    return ctor;
  })();
  
  var AnyAllPredicate = (function () {
    // 4 public props: op, exprSource, expr, pred
    var ctor = function AnyAllPredicate(op, expr, pred) {
      this.op = this._resolveOp(op);
      this.exprSource = expr;
      // this.expr will not be resolved until validate is called
      this.pred = Predicate(pred);
    };
    
    var proto = ctor.prototype = new Predicate();
    proto._initialize("anyAllPredicate", {
      'any': { aliases: ['some'] },
      'all': { aliases: ["every"] }
    });

    proto._validate = function(entityType, usesNameOnServer) {
      this.expr = createExpr(this.exprSource, { entityType: entityType, usesNameOnServer: usesNameOnServer });
      // can't really know the predicateEntityType unless the original entity type was known.
      if (entityType == null || entityType.isAnonymous) {
        this.expr.dataType = null;
      }
      this.pred._validate(this.expr.dataType, usesNameOnServer);
    }

    return ctor;
  })();

  var PredicateExpression = function (visitorMethodName) {
    this.visitorMethodName = visitorMethodName;
    // give expressions the Predicate prototype method
    this.visit = Predicate.prototype.visit;
    // default impls - may be overridden
    this._validate = __noop;
  }

  var LitExpr = (function () {
    // 2 public props: value, dataType
    var ctor = function LitExpr(value, dataType, hasExplicitDataType) {
      // dataType may come is an a string
      dataType = resolveDataType(dataType);
      // if the DataType comes in as Undefined this means
      // that we should NOT attempt to parse it but just leave it alone
      // for now - this is usually because it is part of a Func expr.
      dataType = dataType || DataType.fromValue(value);

      if (dataType && dataType.parse) {
        if (Array.isArray(value)) {
          this.value = value.map(function(v) { return dataType.parse(v, typeof v) });
        } else {
          this.value = dataType.parse(value, typeof value);
        }
      } else {
        this.value = value;
      }
      this.dataType = dataType;
      this.hasExplicitDataType = hasExplicitDataType;
    };
    var proto = ctor.prototype = new PredicateExpression('litExpr');
    proto.toString = function() {
      return " LitExpr - value: " + this.value.toString() + " dataType: " + this.dataType.toString();
    };

    function resolveDataType(dataType) {
      if (dataType == null) return dataType;
      if (DataType.contains(dataType)) {
        return dataType;
      }
      if (__isString(dataType)) {
        var dt = DataType.fromName(dataType);
        if (dt) return dt;
        throw new Error("Unable to resolve a dataType named: " + dataType);
      }
      
      throw new Error("The dataType parameter passed into this literal expression is not a 'DataType'" + dataType);
    }
    
    return ctor;
  })();
  
  var PropExpr = (function () {
    // two public props: propertyPath, dateType
    var ctor = function PropExpr(propertyPath) {
      this.propertyPath = propertyPath;
      //this.dataType = DataType.Undefined;
      // this.dataType resolved after validate ( if not on an anon type }
    };
    var proto = ctor.prototype = new PredicateExpression('propExpr');
    proto.toString = function() {
      return " PropExpr - " + this.propertyPath;
    };

    proto._validate = function(entityType, usesNameOnServer) {

      if (entityType == null || entityType.isAnonymous) return;
      var props = entityType.getPropertiesOnPath(this.propertyPath, usesNameOnServer, false);

      if (!props) {
        var msg = __formatString("Unable to resolve propertyPath.  EntityType: '%1'   PropertyPath: '%2'", entityType.name, this.propertyPath);
        throw new Error(msg);
      }
      // get the last property
      var prop = props[props.length - 1];
      if (prop.isDataProperty) {
        this.dataType = prop.dataType;
      } else {
        this.dataType = prop.entityType;
      }
    }

    return ctor;
  })();
  
  var FnExpr = (function () {
    
    var ctor = function FnExpr(fnName, exprs) {
      // 4 public props: fnName, exprs, localFn, dataType
      this.fnName = fnName;
      this.exprs = exprs;
      var qf = _funcMap[fnName];
      if (qf == null) {
        throw new Error("Unknown function: " + fnName);
      }
      this.localFn = qf.fn;
      this.dataType = qf.dataType;
    };
    var proto = ctor.prototype = new PredicateExpression('fnExpr');

    proto.toString = function() {
      var exprStr = this.exprs.map(function(expr) {
        expr.toString();
      }).toString();
      return "FnExpr - " + this.fnName + "(" + exprStr + ")";
    };

    proto._validate = function(entityType, usesNameOnServer) {
      this.exprs.forEach(function (expr) {
        expr._validate(entityType, usesNameOnServer);
      });
    };

    // TODO: add dataTypes for the args next - will help to infer other dataTypes.
    var _funcMap = ctor.funcMap = {
      toupper: {
        fn: function (source) {
          return source.toUpperCase();
        }, dataType: DataType.String
      },
      tolower: {
        fn: function (source) {
          return source.toLowerCase();
        }, dataType: DataType.String
      },
      substring: {
        fn: function (source, pos, length) {
          return source.substring(pos, length);
        }, dataType: DataType.String
      },
      substringof: {
        fn: function (find, source) {
          return source.indexOf(find) >= 0;
        }, dataType: DataType.Boolean
      },
      length: {
        fn: function (source) {
          return source.length;
        }, dataType: DataType.Int32
      },
      trim: {
        fn: function (source) {
          return source.trim();
        }, dataType: DataType.String
      },
      concat: {
        fn: function (s1, s2) {
          return s1.concat(s2);
        }, dataType: DataType.String
      },
      replace: {
        fn: function (source, find, replace) {
          return source.replace(find, replace);
        }, dataType: DataType.String
      },
      startswith: {
        fn: function (source, find) {
          return __stringStartsWith(source, find);
        }, dataType: DataType.Boolean
      },
      endswith: {
        fn: function (source, find) {
          return __stringEndsWith(source, find);
        }, dataType: DataType.Boolean
      },
      indexof: {
        fn: function (source, find) {
          return source.indexOf(find);
        }, dataType: DataType.Int32
      },
      round: {
        fn: function (source) {
          return Math.round(source);
        }, dataType: DataType.Int32
      },
      ceiling: {
        fn: function (source) {
          return Math.ceil(source);
        }, dataType: DataType.Int32
      },
      floor: {
        fn: function (source) {
          return Math.floor(source);
        }, dataType: DataType.Int32
      },
      second: {
        fn: function (source) {
          return source.getSeconds();
        }, dataType: DataType.Int32
      },
      minute: {
        fn: function (source) {
          return source.getMinutes();
        }, dataType: DataType.Int32
      },
      day: {
        fn: function (source) {
          return source.getDate();
        }, dataType: DataType.Int32
      },
      month: {
        fn: function (source) {
          return source.getMonth() + 1;
        }, dataType: DataType.Int32
      },
      year: {
        fn: function (source) {
          return source.getFullYear();
        }, dataType: DataType.Int32
      }
    };
    
    return ctor;
  })();

  var RX_IDENTIFIER = /^[a-z_][\w.$]*$/i;
  // comma delimited expressions ignoring commas inside of both single and double quotes.
  var RX_COMMA_DELIM1 = /('[^']*'|[^,]+)/g;
  var RX_COMMA_DELIM2 = /("[^"]*"|[^,]+)/g;
  var DELIM = String.fromCharCode(191);

  function createExpr(source, exprContext) {
    var entityType = exprContext.entityType;

    // the right hand side of an 'in' clause
    if (Array.isArray(source)) {
      if (!exprContext.isRHS) {
        throw new Error("Array expressions are only permitted on the right hand side of a BinaryPredicate");
      }
      return new LitExpr(source, exprContext.dataType);
    }

    if (!__isString(source)) {
      if (source != null && __isObject(source) && !source.toISOString) { 
        // source is an object but not a Date-like thing such as a JS or MomentJS Date
        if (source.value === undefined) {
          throw new Error("Unable to resolve an expression for: " + source + " on entityType: " + entityType.name);
        }
        if (source.isProperty) {
          return new PropExpr(source.value);
        } else {
          // we want to insure that any LitExpr created this way is tagged with 'hasExplicitDataType: true'
          // because we want to insure that if we roundtrip thru toJSON that we don't
          // accidentally reinterpret this node as a PropExpr.
          // return new LitExpr(source.value, source.dataType || context.dataType, !!source.dataType);
          return new LitExpr(source.value, source.dataType || exprContext.dataType, true);
        }
      } else {
        return new LitExpr(source, exprContext.dataType);
      }
    }

    if (exprContext.isRHS) {
      if (entityType == null || entityType.isAnonymous) {
        // if entityType is unknown then assume that the rhs is a literal
        return new LitExpr(source, exprContext.dataType);
      } else {
        return parseLitOrPropExpr(source, exprContext);
      }
    } else {
      var regex = /\([^()]*\)/;
      var m;
      var tokens = [];
      var i = 0;
      while (m = regex.exec(source)) {
        var token = m[0];
        tokens.push(token);
        var repl = DELIM + i++;
        source = source.replace(token, repl);
      }

      var expr = parseExpr(source, tokens, exprContext);
      expr._validate(entityType, exprContext.usesNameOnServer);
      return expr;
    }
  }

  function parseExpr(source, tokens, exprContext) {
    var parts = source.split(DELIM);
    if (parts.length === 1) {
      return parseLitOrPropExpr(parts[0], exprContext);
    } else {
      return parseFnExpr(source, parts, tokens, exprContext);
    }
  }

  function parseLitOrPropExpr(value, exprContext) {
    value = value.trim();
    // value is either a string, a quoted string, a number, a bool value, or a date
    // if a string ( not a quoted string) then this represents a property name ( 1st ) or a lit string ( 2nd)
    var firstChar = value.substr(0, 1);
    var isQuoted = (firstChar === "'" || firstChar === '"') && value.length > 1 && value.substr(value.length - 1) === firstChar;
    if (isQuoted) {
      var unquotedValue = value.substr(1, value.length - 2);
      return new LitExpr(unquotedValue, exprContext.dataType || DataType.String);
    } else {
      var entityType = exprContext.entityType;
      // TODO: get rid of isAnonymous below when we get the chance.
      if (entityType == null || entityType.isAnonymous) {
        // this fork will only be reached on the LHS of an BinaryPredicate -
        // a RHS expr cannot get here with an anon type
        return new PropExpr(value);
      } else {
        var mayBeIdentifier = RX_IDENTIFIER.test(value);
        if (mayBeIdentifier) {
          // if (entityType.getProperty(value, false) != null) {
          if (entityType.getPropertiesOnPath(value, exprContext.usesNameOnServer, false) != null) {
            return new PropExpr(value);
          }
        }
      }
      // we don't really know the datatype here because even though it comes in as a string
      // its usually a string BUT it might be a number  i.e. the "1" or the "2" from an expr
      // like "toUpper(substring(companyName, 1, 2))"
      return new LitExpr(value, exprContext.dataType);
    }
  }

  function parseFnExpr(source, parts, tokens, exprContext) {
    try {
      var fnName = parts[0].trim().toLowerCase();

      var argSource = tokens[parts[1]].trim();
      if (argSource.substr(0, 1) === "(") {
        argSource = argSource.substr(1, argSource.length - 2);
      }
      var commaMatchStr = source.indexOf("'") >= 0 ? RX_COMMA_DELIM1 : RX_COMMA_DELIM2;
      var args = argSource.match(commaMatchStr);
      var newContext = __extend({}, exprContext);
      // a dataType of Undefined on a context basically means not to try parsing
      // the value if the expr is a literal
      newContext.dataType = DataType.Undefined;
      newContext.isFnArg = true;
      var exprs = args.map(function (a) {
        return parseExpr(a, tokens, newContext);
      });
      return new FnExpr(fnName, exprs);
    } catch (e) {
      return null;
    }
  }

  var toFunctionVisitor =  (function () {
    var visitor = {

      passthruPredicate: function () {
        throw new Error("Cannot execute an PassthruPredicate expression against the local cache: " + this.value);
      },
      
      unaryPredicate: function (context) {
        var predFn = this.pred.visit(context);
        switch (this.op.key) {
          case "not":
            return function (entity) {
              return !predFn(entity);
            };
          default:
            throw new Error("Invalid unary operator:" + this.op.key);
        }
      },
      
      binaryPredicate: function (context) {
        var expr1Fn = this.expr1.visit(context);
        var expr2Fn = this.expr2.visit(context);
        var dataType = this.expr1.dataType || this.expr2.dataType;
        var lqco = context.entityType.metadataStore.localQueryComparisonOptions;
        var predFn = getBinaryPredicateFn(this, dataType, lqco);
        if (predFn == null) {
          throw new Error("Invalid binaryPredicate operator:" + this.op.key);
        }
        return function (entity) {
          return predFn(expr1Fn(entity), expr2Fn(entity));
        };
      },
      
      andOrPredicate: function (context) {
        var predFns = this.preds.map(function(pred) {
          return pred.visit(context);
        });
        switch (this.op.key) {
          case "and":
            return function (entity) {
              var result = predFns.reduce(function (prev, cur) {
                return prev && cur(entity);
              }, true);
              return result;
            };
          case "or":
            return function (entity) {
              var result = predFns.reduce(function (prev, cur) {
                return prev || cur(entity);
              }, false);
              return result;
            };
          default:
            throw new Error("Invalid boolean operator:" + op.key);
        }
      },
      
      anyAllPredicate: function (context) {
        var exprFn = this.expr.visit(context);
        var newContext = __extend({}, context);
        newContext.entityType = this.expr.dataType;
        var predFn = this.pred.visit(newContext);
        var anyAllPredFn = getAnyAllPredicateFn(this.op);
        return function (entity) {
          return anyAllPredFn(exprFn(entity), predFn);
        };
      },
      
      litExpr: function () {
        var value = this.value;
        return function (entity) {
          return value;
        };
      },
      
      propExpr: function () {
        var propertyPath = this.propertyPath;
        var properties = propertyPath.split('.');
        if (properties.length === 1) {
          return function (entity) {
            return entity.getProperty(propertyPath);
          };
        } else {
          return function (entity) {
            return getPropertyPathValue(entity, properties);
          };
        }
      },
      
      fnExpr: function (context) {
        var exprFns = this.exprs.map(function(expr) {
          return expr.visit(context);
        });
        var that = this;
        return function (entity) {
          var values = exprFns.map(function (exprFn) {
            var value = exprFn(entity);
            return value;
          });
          var result = that.localFn.apply(null, values);
          return result;
        }
      }

    };

    function getAnyAllPredicateFn(op) {
      switch (op.key) {
        case "any":
          return function (v1, v2) {
            return v1.some(function (v) {
              return v2(v);
            });
          };
        case "all":
          return function (v1, v2) {
            return v1.every(function (v) {
              return v2(v);
            });
          };
        default:
          throw new Error("Unknown operator: " + op.key);
      }
    }

    function getBinaryPredicateFn(binaryPredicate, dataType, lqco) {
      var op = binaryPredicate.op;
      var mc = DataType.getComparableFn(dataType);
      var predFn;
      switch (op.key) {
        case 'eq':
          predFn = function (v1, v2) {
            if (v1 && typeof v1 === 'string') {
              return stringEquals(v1, v2, lqco);
            } else {
              return mc(v1) == mc(v2);
            }
          };
          break;
        case 'ne':
          predFn = function (v1, v2) {
            if (v1 && typeof v1 === 'string') {
              return !stringEquals(v1, v2, lqco);
            } else {
              return mc(v1) != mc(v2);
            }
          };
          break;
        case 'gt':
          predFn = function (v1, v2) {
            return mc(v1) > mc(v2);
          };
          break;
        case 'ge':
          predFn = function (v1, v2) {
            return mc(v1) >= mc(v2);
          };
          break;
        case 'lt':
          predFn = function (v1, v2) {
            return mc(v1) < mc(v2);
          };
          break;
        case 'le':
          predFn = function (v1, v2) {
            return mc(v1) <= mc(v2);
          };
          break;
        case 'startswith':
          predFn = function (v1, v2) {
            return stringStartsWith(v1, v2, lqco);
          };
          break;
        case 'endswith':
          predFn = function (v1, v2) {
            return stringEndsWith(v1, v2, lqco);
          };
          break;
        case 'contains':
          predFn = function (v1, v2) {
            return stringContains(v1, v2, lqco);
          };
          break;
        case 'in':
          predFn = function (v1, v2) {
            v1 = mc(v1);
            v2 = v2.map(function(v) { return mc(v) });
            return v2.indexOf(v1) >= 0;
          };
          break;
        default:
          return null;
      }
      return predFn;
    }

    function stringEquals(a, b, lqco) {
      if (b == null) return false;
      if (typeof b !== 'string') {
        b = b.toString();
      }
      if (lqco.usesSql92CompliantStringComparison) {
        a = (a || "").trim();
        b = (b || "").trim();
      }
      if (!lqco.isCaseSensitive) {
        a = (a || "").toLowerCase();
        b = (b || "").toLowerCase();
      }
      return a === b;
    }
    
    function stringStartsWith(a, b, lqco) {
      if (!lqco.isCaseSensitive) {
        a = (a || "").toLowerCase();
        b = (b || "").toLowerCase();
      }
      return __stringStartsWith(a, b);
    }
    
    function stringEndsWith(a, b, lqco) {
      if (!lqco.isCaseSensitive) {
        a = (a || "").toLowerCase();
        b = (b || "").toLowerCase();
      }
      return __stringEndsWith(a, b);
    }
    
    function stringContains(a, b, lqco) {
      if (!lqco.isCaseSensitive) {
        a = (a || "").toLowerCase();
        b = (b || "").toLowerCase();
      }
      return a.indexOf(b) >= 0;
    }
    
    return visitor;
  }());

  var toJSONVisitor = (function () {
    var visitor = {

      passthruPredicate: function () {
        return this.value;
      },
      
      unaryPredicate: function (context) {
        var predVal = this.pred.visit(context);
        var json = {};
        json[this.op.key] = predVal;
        return json;
      },
      
      binaryPredicate: function (context) {
        var expr1Val = this.expr1.visit(context);
        var expr2Val = this.expr2.visit(context);
        var json = {};
        if (this.expr2 instanceof PropExpr) {
          expr2Val = { value: expr2Val, isProperty: true };
        }
        if (this.op.key === "eq") {
          json[expr1Val] = expr2Val;
        } else {
          var value = {};
          json[expr1Val] = value;
          value[this.op.key] = expr2Val;
        }
        return json;
      },
      
      andOrPredicate: function (context) {
        var predVals = this.preds.map(function(pred) {
          return pred.visit(context);
        });
        if (!predVals || !predVals.length) {
          return {};
        }
        var json;
        // normalizeAnd clauses if possible.
        // passthru predicate will appear as string and their 'ands' can't be 'normalized'
        if (this.op.key === 'and' && predVals.length === 2 && !predVals.some(__isString)) {
          // normalize 'and' clauses - will return null if can't be combined.
          json = predVals.reduce(combine);
        }
        if (json == null) {
          json = {};
          json[this.op.key] = predVals;
        }
        return json;
      },
      
      anyAllPredicate: function (context) {
        var exprVal = this.expr.visit(context);
        var newContext = __extend({}, context);
        newContext.entityType = this.expr.dataType;
        var predVal = this.pred.visit(newContext);
        var json = {};
        var value = {};
        value[this.op.key] = predVal;
        json[exprVal] = value;
        return json;
      },
      
      litExpr: function (context) {
        if (this.hasExplicitDataType || context.useExplicitDataType) {
          return { value: this.value, dataType: this.dataType.name }
        } else {
          return this.value;
        }
      },
      
      propExpr: function (context) {
        if (context.toNameOnServer) {
          return context.entityType.clientPropertyPathToServer(this.propertyPath);
        } else {
          return this.propertyPath;
        }
      },
      
      fnExpr: function (context) {
        var exprVals = this.exprs.map(function(expr) {
          return expr.visit(context);
        });
        return this.fnName + "(" + exprVals.join(",") + ")";
      }
    };
    
    function combine(j1, j2) {
      var ok = Object.keys(j2).every(function (key) {
        if (j1.hasOwnProperty(key)) {
          if (typeof (j2[key]) != 'object') {
            // exit and indicate that we can't combine
            return false;
          }
          if (combine(j1[key], j2[key]) == null) {
            return false;
          }
        } else {
          j1[key] = j2[key];
        }
        return true;
      });
      return ok ? j1 : null;
    }
    
    return visitor;
  }());

  
  return Predicate;

})();

breeze.Predicate = Predicate;

;var EntityQuery = (function () {
  /**
  An EntityQuery instance is used to query entities either from a remote datasource or from a local {{#crossLink "EntityManager"}}{{/crossLink}}.

  EntityQueries are immutable - this means that all EntityQuery methods that return an EntityQuery actually create a new EntityQuery.  This means that
  EntityQueries can be 'modified' without affecting any current instances.

  @class EntityQuery
  **/

  /**
  @example
      var query = new EntityQuery("Customers")

  Usually this constructor will be followed by calls to filtering, ordering or selection methods
  @example
      var query = new EntityQuery("Customers")
          .where("CompanyName", "startsWith", "C")
          .orderBy("Region");

  @method <ctor> EntityQuery
  @param [resourceName] {String}
  **/
  var ctor = function EntityQuery(resourceName) {
    if (resourceName != null && !__isString(resourceName)) {
      return fromJSON(this, resourceName);
    }
    
    this.resourceName = resourceName;
    this.fromEntityType = null;
    this.wherePredicate = null;
    this.orderByClause = null;
    this.selectClause = null;
    this.skipCount = null;
    this.takeCount = null;
    this.expandClause = null;
    this.parameters = {};
    this.inlineCountEnabled = false;
    this.noTrackingEnabled = false;
    // default is to get queryOptions and dataService from the entityManager.
    // this.queryOptions = new QueryOptions();
    // this.dataService = new DataService();
    this.entityManager = null;

  };
  var proto = ctor.prototype;
  proto._$typeName = "EntityQuery";
  
  
  /**
  The resource name used by this query.

  __readOnly__
  @property resourceName {String}
  **/

  /**
  The entityType that is associated with the 'from' clause ( resourceName) of the query.  This is only guaranteed to be be set AFTER the query
  has been executed because it depends on the MetadataStore associated with the EntityManager that the query was executed against.
  This value may be null if the entityType cannot be associated with a resourceName.

  __readOnly__
  @property fromEntityType {EntityType}
  **/

  /**
  The entityType that will be returned by this query. This property will only be set if the 'toType' method was called.

  __readOnly__
  @property resultEntityType {EntityType}
  **/

  /**
  The 'where' predicate used by this query.

  __readOnly__
  @property wherePredicate {Predicate}
  **/

  /**
  The {{#crossLink "OrderByClause"}}{{/crossLink}} used by this query.

  __readOnly__
  @property orderByClause {OrderByClause}
  **/

  /**
  The number of entities to 'skip' for this query.

  __readOnly__
  @property skipCount {Integer}
  **/

  /**
  The number of entities to 'take' for this query.

  __readOnly__
  @property takeCount {Integer}
  **/

  /**
  Any additional parameters that were added to the query via the 'withParameters' method.

  __readOnly__
  @property parameters {Object}
  **/

  /**
  The {{#crossLink "QueryOptions"}}{{/crossLink}} for this query.

  __readOnly__
  @property queryOptions {QueryOptions}
  **/

  /**
  The {{#crossLink "EntityManager"}}{{/crossLink}} for this query. This may be null and can be set via the 'using' method.

  __readOnly__
  @property entityManager {EntityManager}
  **/

  /**
  Specifies the resource to query for this EntityQuery.
  @example
      var query = new EntityQuery()
          .from("Customers");
  is the same as
  @example
      var query = new EntityQuery("Customers");
  @method from
  @param resourceName {String} The resource to query.
  @return {EntityQuery}
  @chainable
  **/
  proto.from = function (resourceName) {
    // TODO: think about allowing entityType as well
    assertParam(resourceName, "resourceName").isString().check();
    return clone(this, "resourceName", resourceName);
  };
  
  /**
  This is a static version of the "from" method and it creates a 'base' entityQuery for the specified resource name.
  @example
      var query = EntityQuery.from("Customers");
  is the same as
  @example
      var query = new EntityQuery("Customers");
  @method from
  @static
  @param resourceName {String} The resource to query.
  @return {EntityQuery}
  @chainable
  **/
  ctor.from = function (resourceName) {
    assertParam(resourceName, "resourceName").isString().check();
    return new EntityQuery(resourceName);
  };
  
  /**
  Specifies the top level EntityType that this query will return.  Only needed when a query returns a json result that does not include type information.
  @example
      var query = new EntityQuery()
        .from("MyCustomMethod")
        .toType("Customer")

  @method toType
  @param entityType {String|EntityType} The top level entityType that this query will return.  This method is only needed when a query returns a json result that
  does not include type information.  If the json result consists of more than a simple entity or array of entities, consider using a JsonResultsAdapter instead.
  @return {EntityQuery}
  @chainable
  **/
  proto.toType = function (entityType) {
    assertParam(entityType, "entityType").isString().or().isInstanceOf(EntityType).check();
    return clone(this, "resultEntityType", entityType);
  };
  
  
  /**
  Returns a new query with an added filter criteria; Can be called multiple times which means to 'and' with any existing
  Predicate or can be called with null to clear all predicates.
  @example
      var query = new EntityQuery("Customers")
                .where("CompanyName", "startsWith", "C");
  This can also be expressed using an explicit {{#crossLink "FilterQueryOp"}}{{/crossLink}} as
  @example
      var query = new EntityQuery("Customers")
          .where("CompanyName", FilterQueryOp.StartsWith, "C");
  or a preconstructed {{#crossLink "Predicate"}}{{/crossLink}} may be used
  @example
      var pred = new Predicate("CompanyName", FilterQueryOp.StartsWith, "C");
      var query = new EntityQuery("Customers").where(pred);
  Predicates are often useful when you want to combine multiple conditions in a single filter, such as
  @example
      var pred = Predicate.create("CompanyName", "startswith", "C").and("Region", FilterQueryOp.Equals, null);
      var query = new EntityQuery("Customers")
        .where(pred);
  @example
  More complicated queries can make use of nested property paths
  @example
      var query = new EntityQuery("Products")
        .where("Category.CategoryName", "startswith", "S");
  or OData functions - A list of valid OData functions can be found within the {{#crossLink "Predicate"}}{{/crossLink}} documentation.
  @example
      var query = new EntityQuery("Customers")
        .where("toLower(CompanyName)", "startsWith", "c");
  or to be even more baroque
  @example
      var query = new EntityQuery("Customers")
        .where("toUpper(substring(CompanyName, 1, 2))", FilterQueryOp.Equals, "OM");
  @method where
  @param predicate {Predicate|property|property path, operator, value} Can be either

    - a single {{#crossLink "Predicate"}}{{/crossLink}}

    - or the parameters to create a 'simple' Predicate

    - a property name, a property path with '.' as path seperators or a property expression {String}
    - an operator {FilterQueryOp|String} Either a  {{#crossLink "FilterQueryOp"}}{{/crossLink}} or it's string representation. Case is ignored
    when if a string is provided and any string that matches one of the FilterQueryOp aliases will be accepted.
    - a value {Object} - This will be treated as either a property expression or a literal depending on context.  In general,
    if the value can be interpreted as a property expression it will be, otherwise it will be treated as a literal.
    In most cases this works well, but you can also force the interpretation by making the value argument itself an object with a 'value' property and an 'isLiteral' property set to either true or false.
    Breeze also tries to infer the dataType of any literal based on context, if this fails you can force this inference by making the value argument an object with a 'value' property and a 'dataType'property set
    to one of the breeze.DataType enumeration instances.
    - or a null or undefined ( this causes any existing where clause to be removed)

  @return {EntityQuery}
  @chainable
  **/
  proto.where = function (wherePredicate) {
    if (wherePredicate != null) {
      wherePredicate = Predicate.create(__arraySlice(arguments));
      if (this.fromEntityType) wherePredicate._validate(this.fromEntityType);
      if (this.wherePredicate) {
        wherePredicate = this.wherePredicate.and(wherePredicate);
      }
    }
    return clone(this, "wherePredicate", wherePredicate);
  };

  /**
  Returns a new query that orders the results of the query by property name.  By default sorting occurs is ascending order, but sorting in descending order is supported as well.
  OrderBy clauses may be chained.
  @example
      var query = new EntityQuery("Customers")
        .orderBy("CompanyName");

  or to sort across multiple properties
  @example
      var query = new EntityQuery("Customers")
        .orderBy("Region, CompanyName");

  Nested property paths are also supported
  @example
      var query = new EntityQuery("Products")
        .orderBy("Category.CategoryName");

  Sorting in descending order is supported via the addition of ' desc' to the end of any property path.
  @example
      var query = new EntityQuery("Customers")
        .orderBy("CompanyName desc");

  or
  @example
      var query = new EntityQuery("Customers")
        .orderBy("Region desc, CompanyName desc");
  @method orderBy
  @param propertyPaths {String|Array of String} A comma-separated (',') string of property paths or an array of property paths.
  Each property path can optionally end with " desc" to force a descending sort order. If 'propertyPaths' is either null or omitted then all ordering is removed.
  @param isDescending {Boolean} - If specified, overrides all of the embedded 'desc' tags in the previously specified property paths.
  @return {EntityQuery}
  @chainable
  **/
  proto.orderBy = function (propertyPaths, isDescending) {
    // propertyPaths: can pass in create("A.X,B") or create("A.X desc, B") or create("A.X desc,B", true])
    // isDesc parameter trumps isDesc in propertyName.

    var orderByClause = propertyPaths == null ? null : new OrderByClause(normalizePropertyPaths(propertyPaths), isDescending);
    if (this.orderByClause && orderByClause) {
      orderByClause = new OrderByClause([this.orderByClause, orderByClause]);
    }
    return clone(this, "orderByClause", orderByClause);
  }
  
  /**
  Returns a new query that orders the results of the query by property name in descending order.
  @example
      var query = new EntityQuery("Customers")
        .orderByDesc("CompanyName");

  or to sort across multiple properties
  @example
      var query = new EntityQuery("Customers")
        .orderByDesc("Region, CompanyName");

  Nested property paths are also supported
  @example
      var query = new EntityQuery("Products")
        .orderByDesc("Category.CategoryName");

  @method orderByDesc
  @param propertyPaths {String|Array of String} A comma-separated (',') string of property paths or an array of property paths.
  If 'propertyPaths' is either null or omitted then all ordering is removed.
  @return {EntityQuery}
  @chainable
  **/
  proto.orderByDesc = function (propertyPaths) {
    return this.orderBy(propertyPaths, true);
  };
  
  /**
  Returns a new query that selects a list of properties from the results of the original query and returns the values of just these properties. This
  will be referred to as a projection.
  If the result of this selection "projection" contains entities, these entities will automatically be added to EntityManager's cache and will
  be made 'observable'.
  Any simple properties, i.e. strings, numbers or dates within a projection will not be cached are will NOT be made 'observable'.

  @example
  Simple data properties can be projected
  @example
      var query = new EntityQuery("Customers")
        .where("CompanyName", "startsWith", "C")
        .select("CompanyName");
  This will return an array of objects each with a single "CompanyName" property of type string.
  A similar query could return a navigation property instead
  @example
      var query = new EntityQuery("Customers")
        .where("CompanyName", "startsWith", "C")
        .select("Orders");
  where the result would be an array of objects each with a single "Orders" property that would itself be an array of "Order" entities.
  Composite projections are also possible:
  @example
      var query = new EntityQuery("Customers")
        .where("CompanyName", "startsWith", "C")
        .select("CompanyName, Orders");
  As well as projections involving nested property paths
  @example
      var query = EntityQuery("Orders")
        .where("Customer.CompanyName", "startsWith", "C")
        .select("Customer.CompanyName, Customer, OrderDate");
  @method select
  @param propertyPaths {String|Array of String} A comma-separated (',') string of property paths or an array of property paths.
  If 'propertyPaths' is either null or omitted then any existing projection on the query is removed.
  @return {EntityQuery}
  @chainable
  **/
  proto.select = function (propertyPaths) {
    var selectClause = propertyPaths == null ? null : new SelectClause(normalizePropertyPaths(propertyPaths));
    return clone(this, "selectClause", selectClause);
  };
  
  /**
  Returns a new query that skips the specified number of entities when returning results.
  Any existing 'skip' can be cleared by calling 'skip' with no arguments.
  @example
      var query = new EntityQuery("Customers")
        .where("CompanyName", "startsWith", "C")
        .skip(5);
  @method skip
  @param count {Number} The number of entities to return. If omitted or null any existing skip count on the query is removed.
  @return {EntityQuery}
  @chainable
  **/
  proto.skip = function (count) {
    assertParam(count, "count").isOptional().isNumber().check();
    return clone(this, "skipCount", (count == null) ? null : count);
  };
  
  /**
  Returns a new query that returns only the specified number of entities when returning results. - Same as 'take'.
  Any existing 'top' can be cleared by calling 'top' with no arguments.
  @example
      var query = new EntityQuery("Customers")
        .top(5);
  @method top
  @param count {Number} The number of entities to return.
  If 'count' is either null or omitted then any existing 'top' count on the query is removed.
  @return {EntityQuery}
  @chainable
  **/
  proto.top = function (count) {
    return this.take(count);
  };
  
  /**
  Returns a new query that returns only the specified number of entities when returning results - Same as 'top'.
  Any existing take can be cleared by calling take with no arguments.
  @example
      var query = new EntityQuery("Customers")
        .take(5);
  @method take
  @param count {Number} The number of entities to return.
  If 'count' is either null or omitted then any existing 'take' count on the query is removed.
  @return {EntityQuery}
  @chainable
  **/
  proto.take = function (count) {
    assertParam(count, "count").isOptional().isNumber().check();
    return clone(this, "takeCount", (count == null) ? null : count);
  };
  
  /**
  Returns a new query that will return related entities nested within its results. The expand method allows you to identify related entities, via navigation property
  names such that a graph of entities may be retrieved with a single request. Any filtering occurs before the results are 'expanded'.
  @example
      var query = new EntityQuery("Customers")
        .where("CompanyName", "startsWith", "C")
        .expand("Orders");
  will return the filtered customers each with its "Orders" properties fully resolved.
  Multiple paths may be specified by separating the paths by a ','
  @example
      var query = new EntityQuery("Orders")
        .expand("Customer, Employee")
  and nested property paths my be specified as well
  @example
      var query = new EntityQuery("Orders")
        .expand("Customer, OrderDetails, OrderDetails.Product")
  @method expand
  @param propertyPaths {String|Array of String} A comma-separated list of navigation property names or an array of navigation property names. Each Navigation Property name can be followed
  by a '.' and another navigation property name to enable identifying a multi-level relationship.
  If 'propertyPaths' is either null or omitted then any existing 'expand' clause on the query is removed.
  @return {EntityQuery}
  @chainable
  **/
  proto.expand = function (propertyPaths) {
    var expandClause = propertyPaths == null ? null : new ExpandClause(normalizePropertyPaths(propertyPaths));
    return clone(this, "expandClause", expandClause);
  };
  
  /**
  Returns a new query that includes a collection of parameters to pass to the server.
  @example
      var query = EntityQuery.from("EmployeesFilteredByCountryAndBirthdate")
        .withParameters({ BirthDate: "1/1/1960", Country: "USA" });
   
  will call the 'EmployeesFilteredByCountryAndBirthdate' method on the server and pass in 2 parameters. This
  query will be uri encoded as
  @example
      {serviceApi}/EmployeesFilteredByCountryAndBirthdate?birthDate=1%2F1%2F1960&country=USA

  Parameters may also be mixed in with other query criteria.
  @example
      var query = EntityQuery.from("EmployeesFilteredByCountryAndBirthdate")
        .withParameters({ BirthDate: "1/1/1960", Country: "USA" })
        .where("LastName", "startsWith", "S")
        .orderBy("BirthDate");

  @method withParameters
  @param parameters {Object} A parameters object where the keys are the parameter names and the values are the parameter values.
  @return {EntityQuery}
  @chainable
  **/
  proto.withParameters = function (parameters) {
    assertParam(parameters, "parameters").isObject().check();
    return clone(this, "parameters", parameters);
  };
  
  /**
  Returns a query with the 'inlineCount' capability either enabled or disabled.  With 'inlineCount' enabled, an additional 'inlineCount' property
  will be returned with the query results that will contain the number of entities that would have been returned by this
  query with only the 'where'/'filter' clauses applied, i.e. without any 'skip'/'take' operators applied. For local queries this clause is ignored.

  @example
      var query = new EntityQuery("Customers")
        .take(20)
        .orderBy("CompanyName")
        .inlineCount(true);
  will return the first 20 customers as well as a count of all of the customers in the remote store.

  @method inlineCount
  @param enabled {Boolean=true} Whether or not inlineCount capability should be enabled. If this parameter is omitted, true is assumed.
  @return {EntityQuery}
  @chainable
  **/
  proto.inlineCount = function (enabled) {
    assertParam(enabled, "enabled").isBoolean().isOptional().check();
    enabled = (enabled === undefined) ? true : !!enabled;
    return clone(this, "inlineCountEnabled", enabled);
  };

  proto.useNameOnServer = function(usesNameOnServer) {
    assertParam(usesNameOnServer, "usesNameOnServer").isBoolean().isOptional().check();
    usesNameOnServer = (usesNameOnServer === undefined) ? true : !!usesNameOnServer;
    return clone(this, "usesNameOnServer", usesNameOnServer);
  }
  
  /**
  Returns a query with the 'noTracking' capability either enabled or disabled.  With 'noTracking' enabled, the results of this query
  will not be coerced into entities but will instead look like raw javascript projections. i.e. simple javascript objects.

  @example
      var query = new EntityQuery("Customers")
        .take(20)
        .orderBy("CompanyName")
        .noTracking(true);

  @method noTracking
  @param enabled {Boolean=true} Whether or not the noTracking capability should be enabled. If this parameter is omitted, true is assumed.
  @return {EntityQuery}
  @chainable
  **/
  proto.noTracking = function (enabled) {
    assertParam(enabled, "enabled").isBoolean().isOptional().check();
    enabled = (enabled === undefined) ? true : !!enabled;
    return clone(this, "noTrackingEnabled", enabled);
  };
  
  /**
  Returns a copy of this EntityQuery with the specified {{#crossLink "EntityManager"}}{{/crossLink}}, {{#crossLink "DataService"}}{{/crossLink}},
  {{#crossLink "JsonResultsAdapter"}}{{/crossLink}}, {{#crossLink "MergeStrategy"}}{{/crossLink}} or {{#crossLink "FetchStrategy"}}{{/crossLink}} applied.
  @example
      // 'using' can be used to return a new query with a specified EntityManager.
      var em = new EntityManager(serviceName);
      var query = new EntityQuery("Orders")
        .using(em);
  or with a specified {{#crossLink "MergeStrategy"}}{{/crossLink}}
  @example
      var em = new EntityManager(serviceName);
      var query = new EntityQuery("Orders")
        .using(MergeStrategy.PreserveChanges);
  or with a specified {{#crossLink "FetchStrategy"}}{{/crossLink}}
  @example
      var em = new EntityManager(serviceName);
      var query = new EntityQuery("Orders")
        .using(FetchStrategy.FromLocalCache);
  
  @method using
  @param obj {EntityManager|QueryOptions|DataService|MergeStrategy|FetchStrategy|JsonResultsAdapter|config object} The object to update in creating a new EntityQuery from an existing one.
  @return {EntityQuery}
  @chainable
  **/
  proto.using = function (obj) {
    if (!obj) return this;
    var eq = clone(this);
    processUsing(eq, {
      entityManager: null,
      dataService: null,
      queryOptions: null,
      fetchStrategy: function (eq, val) {
        eq.queryOptions = (eq.queryOptions || new QueryOptions()).using(val)
      },
      mergeStrategy: function (eq, val) {
        eq.queryOptions = (eq.queryOptions || new QueryOptions()).using(val)
      },
      jsonResultsAdapter: function (eq, val) {
        eq.dataService = (eq.dataService || new DataService()).using({ jsonResultsAdapter: val })
      }
    }, obj);
    return eq;
  };
  
  /**
  Executes this query.  This method requires that an EntityManager has been previously specified via the "using" method.
  @example
  This method can be called using a 'promises' syntax ( recommended)
  @example
      var em = new EntityManager(serviceName);
      var query = new EntityQuery("Orders").using(em);
      query.execute().then( function(data) {
          ... query results processed here
      }).fail( function(err) {
          ... query failure processed here
      });
  or with callbacks
  @example
      var em = new EntityManager(serviceName);
      var query = new EntityQuery("Orders").using(em);
      query.execute(
        function(data) {
                    var orders = data.results;
                    ... query results processed here
                },
        function(err) {
                    ... query failure processed here
                });
  Either way this method is the same as calling the EntityManager 'execute' method.
  @example
      var em = new EntityManager(serviceName);
      var query = new EntityQuery("Orders");
      em.executeQuery(query).then( function(data) {
         var orders = data.results;
          ... query results processed here
      }).fail( function(err) {
         ... query failure processed here
      });

  @method execute
  @async

  @param callback {Function} Function called on success.

  successFunction([data])
  @param [callback.data] {Object}
  @param callback.data.results {Array of Entity}
  @param callback.data.query {EntityQuery} The original query
  @param callback.data.httpResponse {HttpResponse} The HttpResponse returned from the server.
  @param callback.data.inlineCount {Integer} Only available if 'inlineCount(true)' was applied to the query.  Returns the count of
  items that would have been returned by the query before applying any skip or take operators, but after any filter/where predicates
  would have been applied.
  @param callback.data.retrievedEntities {Array of Entity} All entities returned by the query.  Differs from results when .expand() is used.

  @param errorCallback {Function} Function called on failure.

  failureFunction([error])
  @param [errorCallback.error] {Error} Any error that occured wrapped into an Error object.
  @param [errorCallback.error.query] The query that caused the error.
  @param [errorCallback.error.httpResponse] {HttpResponse} The raw XMLHttpRequest returned from the server.

  @return {Promise}
  **/
  proto.execute = function (callback, errorCallback) {
    if (!this.entityManager) {
      throw new Error("An EntityQuery must have its EntityManager property set before calling 'execute'");
    }
    return this.entityManager.executeQuery(this, callback, errorCallback);
  };
  
  /**
  Executes this query against the local cache.  This method requires that an EntityManager have been previously specified via the "using" method.
  @example
      // assume em is an entityManager already filled with order entities;
      var query = new EntityQuery("Orders").using(em);
      var orders = query.executeLocally();

  Note that calling this method is the same as calling {{#crossLink "EntityManager/executeQueryLocally"}}{{/crossLink}}.

  @method executeLocally
  **/
  proto.executeLocally = function () {
    if (!this.entityManager) {
      throw new Error("An EntityQuery must have its EntityManager property set before calling 'executeLocally'");
    }
    return this.entityManager.executeQueryLocally(this);
  };
  
  proto.toJSON = function () {
    return this.toJSONExt();
  }
  
  proto.toJSONExt = function (context) {
    context = context || {};
    context.entityType = context.entityType || this.fromEntityType;
    context.propertyPathFn = context.toNameOnServer ? context.entityType.clientPropertyPathToServer.bind(context.entityType) : __identity;
    
    var that = this;
    
    var toJSONExtFn = function (v) {
      return v ? v.toJSONExt(context) : undefined;
    };
    return __toJson(this, {
      "from,resourceName": null,
      "toType,resultEntityType": function (v) {
        // resultEntityType can be either a string or an entityType
        return v ? (__isString(v) ? v : v.name) : undefined;
      },
      "where,wherePredicate": toJSONExtFn,
      "orderBy,orderByClause": toJSONExtFn,
      "select,selectClause": toJSONExtFn,
      "expand,expandClause": toJSONExtFn,
      "skip,skipCount": null,
      "take,takeCount": null,
      parameters: function (v) {
        return __isEmpty(v) ? undefined : v;
      },
      "inlineCount,inlineCountEnabled": false,
      "noTracking,noTrackingEnabled": false,
      queryOptions: null
    });

  }
  
  function fromJSON(eq, json) {
    __toJson(json, {
      "resourceName,from": null,
      // just the name comes back and will be resolved later
      "resultEntityType,toType": null,
      "wherePredicate,where": function (v) {
        return v ? new Predicate(v) : undefined;
      },
      "orderByClause,orderBy": function (v) {
        return v ? new OrderByClause(v) : undefined;
      },
      "selectClause,select": function (v) {
        return v ? new SelectClause(v) : undefined;
      },
      "expandClause,expand": function (v) {
        return v ? new ExpandClause(v) : undefined;
      },
      "skipCount,skip": null,
      "takeCount,take": null,
      parameters: function (v) {
        return __isEmpty(v) ? undefined : v;
      },
      "inlineCountEnabled,inlineCount": false,
      "noTrackingEnabled,noTracking": false,
      queryOptions: function (v) {
        return v ? QueryOptions.fromJSON(v) : undefined;
      }
    }, eq);
    return eq;
  }
  
  /**
  Static method that creates an EntityQuery that will allow 'requerying' an entity or a collection of entities by primary key. This can be useful
  to force a requery of selected entities, or to restrict an existing collection of entities according to some filter.

  Works for a single entity or an array of entities of the SAME type.
  Does not work for an array of entities of different types.

  @example
      // assuming 'customers' is an array of 'Customer' entities retrieved earlier.
      var customersQuery = EntityQuery.fromEntities(customers);
  The resulting query can, of course, be extended
  @example
      // assuming 'customers' is an array of 'Customer' entities retrieved earlier.
      var customersQuery = EntityQuery.fromEntities(customers)
        .where("Region", FilterQueryOp.NotEquals, null);
  Single entities can requeried as well.
  @example
      // assuming 'customer' is a 'Customer' entity retrieved earlier.
      var customerQuery = EntityQuery.fromEntities(customer);
  will create a query that will return an array containing a single customer entity.
  @method fromEntities
  @static
  @param entities {Entity|Array of Entity} The entities for which we want to create an EntityQuery.
  @return {EntityQuery}
  @chainable
  **/
  ctor.fromEntities = function (entities) {
    assertParam(entities, "entities").isEntity().or().isNonEmptyArray().isEntity().check();
    if (!Array.isArray(entities)) {
      entities = __arraySlice(arguments);
    }
    var firstEntity = entities[0];
    var type = firstEntity.entityType;
    if (entities.some(function(e){
      return e.entityType !== type;
    })) {
      throw new Error("All 'fromEntities' must be the same type; at least one is not of type " +
        type.name);
    }
    var q = new EntityQuery(type.defaultResourceName);
    var preds = entities.map(function (entity) {
      return buildPredicate(entity);
    });
    var pred = Predicate.or(preds);
    q = q.where(pred);
    var em = firstEntity.entityAspect.entityManager;
    if (em) {
      q = q.using(em);
    }
    return q;
  };
  
  /**
  Creates an EntityQuery for the specified {{#crossLink "EntityKey"}}{{/crossLink}}.
  @example
      var empType = metadataStore.getEntityType("Employee");
      var entityKey = new EntityKey(empType, 1);
      var query = EntityQuery.fromEntityKey(entityKey);
  or
  @example
      // 'employee' is a previously queried employee
      var entityKey = employee.entityAspect.getKey();
      var query = EntityQuery.fromEntityKey(entityKey);
  @method fromEntityKey
  @static
  @param entityKey {EntityKey} The {{#crossLink "EntityKey"}}{{/crossLink}} for which a query will be created.
  @return {EntityQuery}
  @chainable
  **/
  ctor.fromEntityKey = function (entityKey) {
    assertParam(entityKey, "entityKey").isInstanceOf(EntityKey).check();
    var q = new EntityQuery(entityKey.entityType.defaultResourceName);
    var pred = buildKeyPredicate(entityKey);
    q = q.where(pred).toType(entityKey.entityType);
    return q;
  };
  
  /**
  Creates an EntityQuery for the specified entity and {{#crossLink "NavigationProperty"}}{{/crossLink}}.
  @example
      // 'employee' is a previously queried employee
      var ordersNavProp = employee.entityType.getProperty("Orders");
      var query = EntityQuery.fromEntityNavigation(employee, ordersNavProp);
  will return a query for the "Orders" of the specified 'employee'.
  @method fromEntityNavigation
  @static
  @param entity {Entity} The Entity whose navigation property will be queried.
  @param navigationProperty {NavigationProperty|String} The {{#crossLink "NavigationProperty"}}{{/crossLink}} or name of the NavigationProperty to be queried.
  @return {EntityQuery}
  @chainable
  **/
  ctor.fromEntityNavigation = function (entity, navigationProperty) {
    assertParam(entity, "entity").isEntity().check();
    var navProperty = entity.entityType._checkNavProperty(navigationProperty);
    var q = new EntityQuery(navProperty.entityType.defaultResourceName);
    var pred = buildNavigationPredicate(entity, navProperty);
    q = q.where(pred);
    var em = entity.entityAspect.entityManager;
    return em ? q.using(em) : q;
  };
  
  // protected methods
  
  proto._getFromEntityType = function (metadataStore, throwErrorIfNotFound) {
    // Uncomment next two lines if we make this method public.
    // assertParam(metadataStore, "metadataStore").isInstanceOf(MetadataStore).check();
    // assertParam(throwErrorIfNotFound, "throwErrorIfNotFound").isBoolean().isOptional().check();
    var entityType = this.fromEntityType;
    if (entityType) return entityType;
    
    var resourceName = this.resourceName;
    if (!resourceName) {
      throw new Error("There is no resourceName for this query");
    }
    
    if (metadataStore.isEmpty()) {
      if (throwErrorIfNotFound) {
        throw new Error("There is no metadata available for this query. " +
            "Are you querying the local cache before you've fetched metadata?");
      } else {
        return null;
      }
    }
    
    var entityTypeName = metadataStore.getEntityTypeNameForResourceName(resourceName);
    if (entityTypeName) {
      entityType = metadataStore._getEntityType(entityTypeName);
    } else {
      entityType = this._getToEntityType(metadataStore, true);
    }
    
    if (!entityType) {
      if (throwErrorIfNotFound) {
        throw new Error(__formatString("Cannot find an entityType for resourceName: '%1'. " 
            + " Consider adding an 'EntityQuery.toType' call to your query or " 
            + "calling the MetadataStore.setEntityTypeForResourceName method to register an entityType for this resourceName.", resourceName));
      } else {
        return null;
      }
    }
    
    this.fromEntityType = entityType;
    return entityType;

  };
  
  proto._getToEntityType = function (metadataStore, skipFromCheck) {
    // skipFromCheck is to avoid recursion if called from _getFromEntityType;
    if (this.resultEntityType instanceof EntityType) {
      return this.resultEntityType;
    } else if (this.resultEntityType) {
      // resultEntityType is a string
      this.resultEntityType = metadataStore._getEntityType(this.resultEntityType, false);
      return this.resultEntityType;
    } else {
      // resolve it, if possible, via the resourceName
      // do not cache this value in this case
      // cannot determine the resultEntityType if a selectClause is present.
      return skipFromCheck ? null : (!this.selectClause) && this._getFromEntityType(metadataStore, false);
    }
  };
  
  // for testing
  proto._toUri = function (em) {
    var ds = DataService.resolve([em.dataService]);
    return ds.uriBuilder.buildUri(this, em.metadataStore);
  }
  
  // private functions
  
  function clone(that, propName, value) {
    // immutable queries mean that we don't need to clone if no change in value.
    if (propName) {
      if (that[propName] === value) return that;
    }
    // copying QueryOptions is safe because they are are immutable;
    var copy = __extend(new EntityQuery(), that, [
      "resourceName",
      "fromEntityType",
      "wherePredicate",
      "orderByClause",
      "selectClause",
      "skipCount",
      "takeCount",
      "expandClause",
      "inlineCountEnabled",
      "noTrackingEnabled",
      "usesNameOnServer",
      "queryOptions",
      "entityManager",
      "dataService",
      "resultEntityType"
    ]);
    copy.parameters = __extend({}, that.parameters);
    if (propName) {
      copy[propName] = value;
    }
    return copy;
  }
  
  function processUsing(eq, map, value, propertyName) {
    var typeName = value._$typeName || (value.parentEnum && value.parentEnum.name);
    var key = typeName && typeName.substr(0, 1).toLowerCase() + typeName.substr(1);
    if (propertyName && key != propertyName) {
      throw new Error("Invalid value for property: " + propertyName);
    }
    if (key) {
      var fn = map[key];
      if (fn === undefined) {
        throw new Error("Invalid config property: " + key);
      } else if (fn === null) {
        eq[key] = value;
      } else {
        fn(eq, value);
      }
    } else {
      __objectForEach(value, function (propName, val) {
        processUsing(eq, map, val, propName)
      });
    }
  }
  
  function normalizePropertyPaths(propertyPaths) {
    assertParam(propertyPaths, "propertyPaths").isOptional().isString().or().isArray().isString().check();
    if (typeof propertyPaths === 'string') {
      propertyPaths = propertyPaths.split(",");
    }
    
    propertyPaths = propertyPaths.map(function (pp) {
      return pp.trim();
    });
    return propertyPaths;
  }
  
  function buildPredicate(entity) {
    var entityType = entity.entityType;
    var predParts = entityType.keyProperties.map(function (kp) {
      return Predicate.create(kp.name, FilterQueryOp.Equals, entity.getProperty(kp.name));
    });
    var pred = Predicate.and(predParts);
    return pred;
  }
  
  function buildKeyPredicate(entityKey) {
    var keyProps = entityKey.entityType.keyProperties;
    var preds = __arrayZip(keyProps, entityKey.values, function (kp, v) {
      return Predicate.create(kp.name, FilterQueryOp.Equals, v);
    });
    var pred = Predicate.and(preds);
    return pred;
  }
  
  function buildNavigationPredicate(entity, navigationProperty) {
    if (navigationProperty.isScalar) {
      if (navigationProperty.foreignKeyNames.length === 0) return null;
      var relatedKeyValues = navigationProperty.foreignKeyNames.map(function (fkName) {
        return entity.getProperty(fkName);
      });
      var entityKey = new EntityKey(navigationProperty.entityType, relatedKeyValues);
      return buildKeyPredicate(entityKey);
    } else {
      var inverseNp = navigationProperty.getInverse();
      var foreignKeyNames = inverseNp ? inverseNp.foreignKeyNames : navigationProperty.invForeignKeyNames;
      if (foreignKeyNames.length === 0) return null;
      var keyValues = entity.entityAspect.getKey().values;
      var predParts = __arrayZip(foreignKeyNames, keyValues, function (fkName, kv) {
        return Predicate.create(fkName, FilterQueryOp.Equals, kv);
      });
      return Predicate.and(predParts);
    }
  }
  
  return ctor;
})();

var FilterQueryOp = (function () {
  /**
   FilterQueryOp is an 'Enum' containing all of the valid  {{#crossLink "Predicate"}}{{/crossLink}}
   filter operators for an {{#crossLink "EntityQuery"}}{{/crossLink}}.

   @class FilterQueryOp
   @static
   **/
  var aEnum = new Enum("FilterQueryOp");
  /**
   Aliases: "eq", "=="
   @property Equals {FilterQueryOp}
   @final
   @static
   **/
  aEnum.Equals = aEnum.addSymbol({ operator: "eq" });
  /**
   Aliases: "ne", "!="
   @property NotEquals {FilterQueryOp}
   @final
   @static
   **/
  aEnum.NotEquals = aEnum.addSymbol({ operator: "ne" });
  /**
   Aliases: "gt", ">"
   @property GreaterThan {FilterQueryOp}
   @final
   @static
   **/
  aEnum.GreaterThan = aEnum.addSymbol({ operator: "gt" });
  /**
   Aliases: "lt", "<"
   @property LessThan {FilterQueryOp}
   @final
   @static
   **/
  aEnum.LessThan = aEnum.addSymbol({ operator: "lt" });
  /**
   Aliases: "ge", ">="
   @property GreaterThanOrEqual {FilterQueryOp}
   @final
   @static
   **/
  aEnum.GreaterThanOrEqual = aEnum.addSymbol({ operator: "ge" });
  /**
   Aliases: "le", "<="
   @property LessThanOrEqual {FilterQueryOp}
   @final
   @static
   **/
  aEnum.LessThanOrEqual = aEnum.addSymbol({ operator: "le" });
  /**
   String operation: Is a string a substring of another string.
   Aliases: "substringof"
   @property Contains {FilterQueryOp}
   @final
   @static
   **/
  aEnum.Contains = aEnum.addSymbol({ operator: "contains" });
  /**
   @property StartsWith {FilterQueryOp}
   @final
   @static
   **/
  aEnum.StartsWith = aEnum.addSymbol({ operator: "startswith" });
  /**
   @property EndsWith {FilterQueryOp}
   @final
   @static
   **/
  aEnum.EndsWith = aEnum.addSymbol({ operator: "endswith" });
  
  /**
   Aliases: "some"
   @property Any {FilterQueryOp}
   @final
   @static
   **/
  aEnum.Any = aEnum.addSymbol({ operator: "any" });
  
  /**
   Aliases: "every"
   @property All {FilterQueryOp}
   @final
   @static
   **/
  aEnum.All = aEnum.addSymbol({ operator: "all" });

  /**
   @property In {FilterQueryOp}
   @final
   @static
   **/
  aEnum.In = aEnum.addSymbol({ operator: "in" });

  /**
   @property IsTypeOf {FilterQueryOp}
   @final
   @static
   **/
  aEnum.IsTypeOf = aEnum.addSymbol({ operator: "isof" });
  
  aEnum.resolveSymbols();

  return aEnum;
})();

var BooleanQueryOp = (function () {
  var aEnum = new Enum("BooleanQueryOp");
  aEnum.And = aEnum.addSymbol({ operator: "and" });
  aEnum.Or = aEnum.addSymbol({ operator: "or" });
  aEnum.Not = aEnum.addSymbol({ operator: "not" });
  
  aEnum.resolveSymbols();

  return aEnum;
})();

/*
 An OrderByClause is a description of the properties and direction that the result
 of a query should be sorted in.  OrderByClauses are immutable, which means that any
 method that would modify an OrderByClause actually returns a new OrderByClause.

 For example for an Employee object with properties of 'Company' and 'LastName' the following would be valid expressions:

 var obc = new OrderByClause("Company.CompanyName, LastName")
 or
 var obc = new OrderByClause("Company.CompanyName desc, LastName")
 or
 var obc = new OrderByClause("Company.CompanyName, LastName", true);
 @class OrderByClause
 */
var OrderByClause = (function () {
  
  var ctor = function (propertyPaths, isDesc) {

    if (propertyPaths.length > 1) {
      // you can also pass in an array of orderByClauses
      if (propertyPaths[0] instanceof OrderByClause) {
        this.items = Array.prototype.concat.apply(propertyPaths[0].items, propertyPaths.slice(1).map(__pluck("items")) );
        return;
      }
      var items = propertyPaths.map(function (pp) {
        return new OrderByItem(pp, isDesc);
      });
    } else {
      var items = [new OrderByItem(propertyPaths[0], isDesc)];
    }
    this.items = items;
  };
  var proto = ctor.prototype;
  
  proto.validate = function (entityType) {
    if (entityType == null || entityType.isAnonymous) return;
    this.items.forEach(function (item) {
      item.validate(entityType)
    });
  };


  
  proto.getComparer = function (entityType) {
    var orderByFuncs = this.items.map(function (obc) {
      return obc.getComparer(entityType);
    });
    return function (entity1, entity2) {
      for (var i = 0; i < orderByFuncs.length; i++) {
        var result = orderByFuncs[i](entity1, entity2);
        if (result !== 0) {
          return result;
        }
      }
      return 0;
    };
  };
  
  proto.toJSONExt = function (context) {
    return this.items.map(function (item) {
      return context.propertyPathFn(item.propertyPath) + (item.isDesc ? " desc" : "");
    });
  };
  
  var OrderByItem = function (propertyPath, isDesc) {
    if (!(typeof propertyPath === 'string')) {
      throw new Error("propertyPath is not a string");
    }
    propertyPath = propertyPath.trim();
    
    var parts = propertyPath.split(' ');
    // parts[0] is the propertyPath; [1] would be whether descending or not.
    if (parts.length > 1 && isDesc !== true && isDesc !== false) {
      isDesc = __stringStartsWith(parts[1].toLowerCase(), "desc");
      if (!isDesc) {
        // isDesc is false but check to make sure its intended.
        var isAsc = __stringStartsWith(parts[1].toLowerCase(), "asc");
        if (!isAsc) {
          throw new Error("the second word in the propertyPath must begin with 'desc' or 'asc'");
        }

      }
    }
    this.propertyPath = parts[0];
    this.isDesc = isDesc;
  };
  
  var itemProto = OrderByItem.prototype;
  
  itemProto.validate = function (entityType) {
    if (entityType == null || entityType.isAnonymous) return;
    // will throw an exception on bad propertyPath
    this.lastProperty = entityType.getProperty(this.propertyPath, true);
  };
  
  itemProto.getComparer = function (entityType) {
    if (!this.lastProperty) this.validate(entityType);
    if (this.lastProperty) {
      var propDataType = this.lastProperty.dataType;
      var isCaseSensitive = this.lastProperty.parentType.metadataStore.localQueryComparisonOptions.isCaseSensitive;
    }
    var propertyPath = this.propertyPath;
    var isDesc = this.isDesc;
    
    return function (entity1, entity2) {
      var value1 = getPropertyPathValue(entity1, propertyPath);
      var value2 = getPropertyPathValue(entity2, propertyPath);
      var dataType = propDataType || (value1 && DataType.fromValue(value1)) || DataType.fromValue(value2);
      if (dataType === DataType.String) {
        if (isCaseSensitive) {
          value1 = value1 || "";
          value2 = value2 || "";
        } else {
          value1 = (value1 || "").toLowerCase();
          value2 = (value2 || "").toLowerCase();
        }
      } else {
        var normalize = DataType.getComparableFn(dataType);
        value1 = normalize(value1);
        value2 = normalize(value2);
      }
      if (value1 === value2) {
        return 0;
      } else if (value1 > value2 || value2 === undefined) {
        return isDesc ? -1 : 1;
      } else {
        return isDesc ? 1 : -1;
      }
    };
  };
  
  return ctor;
})();

// Not exposed
var SelectClause = (function () {
  
  var ctor = function (propertyPaths) {
    this.propertyPaths = propertyPaths;
    this._pathNames = propertyPaths.map(function (pp) {
      return pp.replace(".", "_");
    });
  };
  var proto = ctor.prototype;
  
  proto.validate = function (entityType) {
    if (entityType == null || entityType.isAnonymous) return; // can't validate yet
    // will throw an exception on bad propertyPath
    this.propertyPaths.forEach(function (path) {
      entityType.getProperty(path, true);
    });
  };
  
  proto.toFunction = function (/* config */) {
    var that = this;
    return function (entity) {
      var result = {};
      that.propertyPaths.forEach(function (path, i) {
        result[that._pathNames[i]] = getPropertyPathValue(entity, path);
      });
      return result;
    };
  };
  
  proto.toJSONExt = function (context) {
    return this.propertyPaths.map(function (pp) {
      return context.propertyPathFn(pp);
    })
  };
  
  return ctor;
})();

// Not exposed
var ExpandClause = (function () {
  
  // propertyPaths is an array of strings.
  var ctor = function (propertyPaths) {
    this.propertyPaths = propertyPaths;
  };
  var proto = ctor.prototype;
  
  proto.toJSONExt = function (context) {
    return this.propertyPaths.map(function (pp) {
      return context.propertyPathFn(pp);
    })
  };
  
  return ctor;
})();

// used by EntityQuery and Predicate
function getPropertyPathValue(obj, propertyPath) {
  var properties = Array.isArray(propertyPath) ? propertyPath : propertyPath.split(".");
  if (properties.length === 1) {
    return obj.getProperty(propertyPath);
  } else {
    var nextValue = obj;
    // hack use of some to perform mapFirst operation.
    properties.some(function (prop) {
      nextValue = nextValue.getProperty(prop);
      return nextValue == null;
    });
    return nextValue;
  }
}

// expose
breeze.FilterQueryOp = FilterQueryOp;
breeze.EntityQuery = EntityQuery;

// Not documented - only exposed for testing purposes
breeze.OrderByClause = OrderByClause;

;/**
@module breeze
**/

var MergeStrategy = (function () {
  /**
  MergeStrategy is an 'Enum' that determines how entities are merged into an EntityManager.

  @class MergeStrategy
  @static
  **/
  var MergeStrategy = new Enum("MergeStrategy");
  /**
  MergeStrategy.PreserveChanges updates the cached entity with the incoming values unless the cached entity is in a changed
  state (added, modified, deleted) in which case the incoming values are ignored. The updated cached entity’s EntityState will
  remain {{#crossLink "EntityState/Unchanged"}}{{/crossLink}} unless you’re importing entities in which case the new EntityState will
  be that of the imported entities.

  @property PreserveChanges {MergeStrategy}
  @final
  @static
  **/
  MergeStrategy.PreserveChanges = MergeStrategy.addSymbol();
  /**
  MergeStrategy.OverwriteChanges always updates the cached entity with incoming values even if the entity is in
  a changed state (added, modified, deleted). After the merge, the pending changes are lost.
  The new EntityState will be  {{#crossLink "EntityState/Unchanged"}}{{/crossLink}} unless you’re importing entities
  in which case the new EntityState will be that of the imported entities.

  @property OverwriteChanges {MergeStrategy}
  @final
  @static
  **/
  MergeStrategy.OverwriteChanges = MergeStrategy.addSymbol();

  /**
  SkipMerge is used to ignore incoming values. Adds the incoming entity to the cache only if there is no cached entity with the same key.
  This is the fastest merge strategy but your existing cached data will remain “stale”.

  @property SkipMerge {MergeStrategy}
  @final
  @static
  **/
  MergeStrategy.SkipMerge = MergeStrategy.addSymbol();

  /**
  Disallowed is used to throw an exception if there is an incoming entity with the same key as an entity already in the cache.
  Use this strategy when you want to be sure that the incoming entity is not already in cache.
  This is the default strategy for EntityManager.attachEntity.

  @property Disallowed {MergeStrategy}
  @final
  @static
  **/
  MergeStrategy.Disallowed = MergeStrategy.addSymbol();
  MergeStrategy.resolveSymbols();
  return MergeStrategy;
})();

var FetchStrategy = (function () {
  /**
  FetchStrategy is an 'Enum' that determines how and where entities are retrieved from as a result of a query.

  @class FetchStrategy
  @static
  **/
  var FetchStrategy = new Enum("FetchStrategy");
  /**
  FromServer is used to tell the query to execute the query against a remote data source on the server.
  @property FromServer {MergeStrategy}
  @final
  @static
  **/
  FetchStrategy.FromServer = FetchStrategy.addSymbol();
  /**
  FromLocalCache is used to tell the query to execute the query against a local EntityManager instead of going to a remote server.
  @property FromLocalCache {MergeStrategy}
  @final
  @static
  **/
  FetchStrategy.FromLocalCache = FetchStrategy.addSymbol();
  FetchStrategy.resolveSymbols();
  return FetchStrategy;
})();

var QueryOptions = (function () {
  /**
  A QueryOptions instance is used to specify the 'options' under which a query will occur.

  @class QueryOptions
  **/

  /**
  QueryOptions constructor
  @example
      var newQo = new QueryOptions( { mergeStrategy: MergeStrategy.OverwriteChanges });
      // assume em1 is a preexisting EntityManager
      em1.setProperties( { queryOptions: newQo });

  Any QueryOptions property that is not defined will be defaulted from any QueryOptions defined at a higher level in the breeze hierarchy, i.e.
  -  from query.queryOptions
  -  to   entityManager.queryOptions
  -  to   QueryOptions.defaultInstance;

  @method <ctor> QueryOptions
  @param [config] {Object}
  @param [config.fetchStrategy] {FetchStrategy}
  @param [config.mergeStrategy] {MergeStrategy}
  @param [config.includeDeleted] {Boolean} Whether query should return cached deleted entities (false by default)
  **/
  var ctor = function QueryOptions(config) {
    updateWithConfig(this, config);
  };
  var proto = ctor.prototype;
  proto._$typeName = "QueryOptions";

  /**
  A {{#crossLink "FetchStrategy"}}{{/crossLink}}
  __readOnly__
  @property fetchStrategy {FetchStrategy}
  **/

  /**
  A {{#crossLink "MergeStrategy"}}{{/crossLink}}
  __readOnly__
  @property mergeStrategy {MergeStrategy}
  **/

  /**
  Whether to include cached deleted entities in a query result (false by default).

  __readOnly__
  @property includeDeleted {Boolean}
  **/

  ctor.resolve = function (queryOptionsArray) {
    return new QueryOptions(__resolveProperties(queryOptionsArray, ["fetchStrategy", "mergeStrategy", "includeDeleted"]));
  };

  /**
  The default value whenever QueryOptions are not specified.
  @property defaultInstance {QueryOptions}
  @static
  **/
  ctor.defaultInstance = new ctor({
    fetchStrategy: FetchStrategy.FromServer,
    mergeStrategy: MergeStrategy.PreserveChanges,
    includeDeleted: false
  });

  /**
  Returns a copy of this QueryOptions with the specified {{#crossLink "MergeStrategy"}}{{/crossLink}},
  {{#crossLink "FetchStrategy"}}{{/crossLink}}, or 'includeDeleted' option applied.
  @example
      // Given an EntityManager instance, em
      var queryOptions = em.queryOptions.using(MergeStrategy.PreserveChanges);
  or
  @example
      var queryOptions = em.queryOptions.using(FetchStrategy.FromLocalCache);
  or
  @example
      var queryOptions = em.queryOptions.using({ mergeStrategy: MergeStrategy.OverwriteChanges });
  or
  @example
      var queryOptions = em.queryOptions.using({
          includeDeleted: true,
          fetchStrategy:  FetchStrategy.FromLocalCache 
      });
  @method using
  @param config {Configuration Object|MergeStrategy|FetchStrategy} The object to apply to create a new QueryOptions.
  @return {QueryOptions}
  @chainable
  **/
  proto.using = function (config) {
    if (!config) return this;
    var result = new QueryOptions(this);
    if (MergeStrategy.contains(config)) {
      config = { mergeStrategy: config };
    } else if (FetchStrategy.contains(config)) {
      config = { fetchStrategy: config };
    }
    return updateWithConfig(result, config);
  };

  /**
  Sets the 'defaultInstance' by creating a copy of the current 'defaultInstance' and then applying all of the properties of the current instance.
  The current instance is returned unchanged.
  @method setAsDefault
  @example
      var newQo = new QueryOptions( { mergeStrategy: MergeStrategy.OverwriteChanges });
      newQo.setAsDefault();
  @chainable
  **/
  proto.setAsDefault = function () {
    return __setAsDefault(this, ctor);
  };

  proto.toJSON = function () {
    return __toJson(this, {
      fetchStrategy: null,
      mergeStrategy: null,
      includeDeleted: false
    });
  };

  ctor.fromJSON = function (json) {
    return new QueryOptions({
      fetchStrategy: FetchStrategy.fromName(json.fetchStrategy),
      mergeStrategy: MergeStrategy.fromName(json.mergeStrategy),
      includeDeleted: json.includeDeleted === true
    });
  };

  function updateWithConfig(obj, config) {
    if (config) {
      assertConfig(config)
          .whereParam("fetchStrategy").isEnumOf(FetchStrategy).isOptional()
          .whereParam("mergeStrategy").isEnumOf(MergeStrategy).isOptional()
          .whereParam("includeDeleted").isBoolean().isOptional()
          .applyAll(obj);
    }
    return obj;
  }

  return ctor;
})();

breeze.QueryOptions = QueryOptions;
breeze.FetchStrategy = FetchStrategy;
breeze.MergeStrategy = MergeStrategy;


;/**
 @module breeze
 **/

var EntityGroup = (function () {

  var ctor = function EntityGroup(entityManager, entityType) {
    this.entityManager = entityManager;
    this.entityType = entityType;
    // freeze the entityType after the first instance of this type is either created or queried.
    this.entityType.isFrozen = true;
    this._indexMap = {};
    this._entities = [];
    this._emptyIndexes = [];
  };
  var proto = ctor.prototype;

  proto.attachEntity = function (entity, entityState, mergeStrategy) {
    // entity should already have an aspect.
    var aspect = entity.entityAspect;

    if (!aspect._initialized) {
      this.entityType._initializeInstance(entity);
    }
    delete aspect._initialized;

    var keyInGroup = aspect.getKey()._keyInGroup;
    var ix = this._indexMap[keyInGroup];
    if (ix >= 0) {
      var targetEntity = this._entities[ix];
      var targetEntityState = targetEntity.entityAspect.entityState;
      var wasUnchanged = targetEntityState.isUnchanged();
      if (targetEntity === entity) {
        aspect.entityState = entityState;
      } else if (mergeStrategy === MergeStrategy.Disallowed) {
        throw new Error("A MergeStrategy of 'Disallowed' does not allow you to attach an entity when an entity with the same key is already attached: " + aspect.getKey());
      } else if (mergeStrategy === MergeStrategy.OverwriteChanges || (mergeStrategy === MergeStrategy.PreserveChanges && wasUnchanged)) {
        // unwrapInstance returns an entity with server side property names - so we need to use DataProperty.getRawValueFromServer these when we apply
        // the property values back to the target.
        var rawServerEntity = this.entityManager.helper.unwrapInstance(entity);
        this.entityType._updateTargetFromRaw(targetEntity, rawServerEntity, DataProperty.getRawValueFromServer);
        targetEntity.entityAspect.setEntityState(entityState);
      }
      return targetEntity;
    } else {
      if (this._emptyIndexes.length === 0) {
        ix = this._entities.push(entity) - 1;
      } else {
        ix = this._emptyIndexes.pop();
        this._entities[ix] = entity;
      }
      this._indexMap[keyInGroup] = ix;
      aspect.entityState = entityState;
      aspect.entityGroup = this;
      aspect.entityManager = this.entityManager;
      return entity;
    }
  };

  proto.detachEntity = function (entity) {
    // by this point we have already determined that this entity
    // belongs to this group.
    var aspect = entity.entityAspect;
    var keyInGroup = aspect.getKey()._keyInGroup;
    var ix = this._indexMap[keyInGroup];
    if (ix === undefined) {
      // shouldn't happen.
      throw new Error("internal error - entity cannot be found in group");
    }
    delete this._indexMap[keyInGroup];
    this._emptyIndexes.push(ix);
    this._entities[ix] = null;
    return entity;
  };


  // returns entity based on an entity key defined either as an array of key values or an EntityKey
  proto.findEntityByKey = function (entityKey) {
    var keyInGroup;
    if (entityKey instanceof EntityKey) {
      keyInGroup = entityKey._keyInGroup;
    } else {
      keyInGroup = EntityKey.createKeyString(entityKey);
    }
    var ix = this._indexMap[keyInGroup];
    // can't use just (ix) below because 0 is valid
    return (ix !== undefined) ? this._entities[ix] : null;
  };

  proto.hasChanges = function () {
    var entities = this._entities;
    var unchanged = EntityState.Unchanged;
    for (var i = 0, len = entities.length; i < len; i++){
      var e = entities[i];
      if (e && e.entityAspect.entityState !== unchanged){
        return true;
      }
    }
    return false;
  };

  proto.getChanges = function () {
    var entities = this._entities;
    var unchanged = EntityState.Unchanged;
    var changes = [];
    for (var i = 0, len = entities.length; i < len; i++){
      var e = entities[i];
      if (e && e.entityAspect.entityState !== unchanged){
        changes.push(e);
      }
    }
    return changes;
  };

  proto.getEntities = function (entityStates) {
    var filter = getFilter(entityStates);
    return this._entities.filter(filter);
  };

  proto._checkOperation = function(operationName) {
    this._entities.forEach(function (entity) {
      entity && entity.entityAspect._checkOperation(operationName);
    });
    // for chaining;
    return this;
  };

  // do not expose this method. It is doing a special purpose INCOMPLETE fast detach operation
  // just for the entityManager clear method - the entityGroup will be in an inconsistent state
  // after this op, which is ok because it will be thrown away.
  proto._clear = function () {
    this._entities.forEach(function (entity) {
      if (entity != null) {
        entity.entityAspect._detach();
      }
    });
    this._entities = null;
    this._indexMap = null;
    this._emptyIndexes = null;
  };

  proto._updateFkVal = function (fkProp, oldValue, newValue) {
    var fkPropName = fkProp.name;
    this._entities.forEach(function (entity) {
      if (entity != null) {
        if (entity.getProperty(fkPropName) == oldValue) {
          entity.setProperty(fkPropName, newValue);
        }
      }
    });
  }

  proto._fixupKey = function (tempValue, realValue) {
    // single part keys appear directly in map
    var ix = this._indexMap[tempValue];
    if (ix === undefined) {
      throw new Error("Internal Error in key fixup - unable to locate entity");
    }
    var entity = this._entities[ix];
    var keyPropName = entity.entityType.keyProperties[0].name;
    // fks on related entities will automatically get updated by this as well
    entity.setProperty(keyPropName, realValue);
    delete entity.entityAspect.hasTempKey;
    delete this._indexMap[tempValue];
    this._indexMap[realValue] = ix;
  };

  proto._replaceKey = function (oldKey, newKey) {
    var ix = this._indexMap[oldKey._keyInGroup];
    delete this._indexMap[oldKey._keyInGroup];
    this._indexMap[newKey._keyInGroup] = ix;
  };

  function getFilter(entityStates) {
    if (!entityStates) {
      return function (e) {
        return !!e;
      };
    } else if (entityStates.length === 1) {
      var entityState = entityStates[0];
      return function (e) {
        return !!e && e.entityAspect.entityState === entityState;
      };
    } else {
      return function (e) {
        return !!e && -1 !== entityStates.indexOf(e.entityAspect.entityState);
      };
    }
  }

  return ctor;

})();

// do not expose EntityGroup - internal only


;/**
@module breeze
**/

var EntityManager = (function () {
  /**
  Instances of the EntityManager contain and manage collections of entities, either retrieved from a backend datastore or created on the client.
  @class EntityManager
  **/

  /**
  At its most basic an EntityManager can be constructed with just a service name
  @example
      var entityManager = new EntityManager( "breeze/NorthwindIBModel");
  This is the same as calling it with the following configuration object
  @example
      var entityManager = new EntityManager( {serviceName: "breeze/NorthwindIBModel" });
  Usually however, configuration objects will contain more than just the 'serviceName';
  @example
      var metadataStore = new MetadataStore();
      var entityManager = new EntityManager( {
          serviceName: "breeze/NorthwindIBModel",
          metadataStore: metadataStore
      });
  or
  @example
      return new QueryOptions({
          mergeStrategy: obj,
          fetchStrategy: this.fetchStrategy
      });
      var queryOptions = new QueryOptions({
          mergeStrategy: MergeStrategy.OverwriteChanges,
          fetchStrategy: FetchStrategy.FromServer
      });
      var validationOptions = new ValidationOptions({
          validateOnAttach: true,
          validateOnSave: true,
          validateOnQuery: false
      });
      var entityManager = new EntityManager({
          serviceName: "breeze/NorthwindIBModel",
          queryOptions: queryOptions,
          validationOptions: validationOptions
      });
  @method <ctor> EntityManager
  @param [config] {Object|String} Configuration settings or a service name.
  @param [config.serviceName] {String}
  @param [config.dataService] {DataService} An entire DataService (instead of just the serviceName above).
  @param [config.metadataStore=MetadataStore.defaultInstance] {MetadataStore}
  @param [config.queryOptions] {QueryOptions}
  @param [config.saveOptions] {SaveOptions}
  @param [config.validationOptions=ValidationOptions.defaultInstance] {ValidationOptions}
  @param [config.keyGeneratorCtor] {Function}
  **/
  var ctor = function EntityManager(config) {

    if (arguments.length > 1) {
      throw new Error("The EntityManager ctor has a single optional argument that is either a 'serviceName' or a configuration object.");
    }
    if (arguments.length === 0) {
      config = { serviceName: "" };
    } else if (typeof config === 'string') {
      config = { serviceName: config };
    }

    updateWithConfig(this, config, true);

    this.entityChanged = new Event("entityChanged", this);
    this.validationErrorsChanged = new Event("validationErrorsChanged", this);
    this.hasChangesChanged = new Event("hasChangesChanged", this);

    this.clear();

  };

  var proto = ctor.prototype;
  proto._$typeName = "EntityManager";
  Event.bubbleEvent(proto, null);

  /**
  General purpose property set method.  Any of the properties documented below
  may be set.
  @example
      // assume em1 is a previously created EntityManager
      // where we want to change some of its settings.
      em1.setProperties( {
          serviceName: "breeze/foo"
      });
  @method setProperties
  @param config {Object}
  @param [config.serviceName] {String}
  @param [config.dataService] {DataService}
  @param [config.queryOptions] {QueryOptions}
  @param [config.saveOptions] {SaveOptions}
  @param [config.validationOptions] {ValidationOptions}
  @param [config.keyGeneratorCtor] {Function}
  **/
  proto.setProperties = function (config) {
    updateWithConfig(this, config, false);
  };

  function updateWithConfig(em, config, isCtor) {
    var defaultQueryOptions = isCtor ? QueryOptions.defaultInstance : em.queryOptions;
    var defaultSaveOptions = isCtor ? SaveOptions.defaultInstance : em.saveOptions;
    var defaultValidationOptions = isCtor ? ValidationOptions.defaultInstance : em.validationOptions;


    var configParam = assertConfig(config)
        .whereParam("serviceName").isOptional().isString()
        .whereParam("dataService").isOptional().isInstanceOf(DataService)
        .whereParam("queryOptions").isInstanceOf(QueryOptions).isOptional().withDefault(defaultQueryOptions)
        .whereParam("saveOptions").isInstanceOf(SaveOptions).isOptional().withDefault(defaultSaveOptions)
        .whereParam("validationOptions").isInstanceOf(ValidationOptions).isOptional().withDefault(defaultValidationOptions)
        .whereParam("keyGeneratorCtor").isFunction().isOptional();
    if (isCtor) {
      configParam = configParam
          .whereParam("metadataStore").isInstanceOf(MetadataStore).isOptional().withDefault(new MetadataStore());
    }
    configParam.applyAll(em);

    // insure that entityManager's options versions are completely populated
    __updateWithDefaults(em.queryOptions, defaultQueryOptions);
    __updateWithDefaults(em.saveOptions, defaultSaveOptions);
    __updateWithDefaults(em.validationOptions, defaultValidationOptions);

    if (config.serviceName) {
      em.dataService = new DataService({
        serviceName: em.serviceName
      });
    }
    em.serviceName = em.dataService && em.dataService.serviceName;

    em.keyGeneratorCtor = em.keyGeneratorCtor || KeyGenerator;
    if (isCtor || config.keyGeneratorCtor) {
      em.keyGenerator = new em.keyGeneratorCtor();
    }
  }

  /**
  The service name associated with this EntityManager.

  __readOnly__
  @property serviceName {String}
  **/

  /**
  The DataService name associated with this EntityManager.

  __readOnly__
  @property dataService {DataService}
  **/

  /**
  The {{#crossLink "MetadataStore"}}{{/crossLink}} associated with this EntityManager.

  __readOnly__
  @property metadataStore {MetadataStore}
  **/

  /**
  The {{#crossLink "QueryOptions"}}{{/crossLink}} associated with this EntityManager.

  __readOnly__
  @property queryOptions {QueryOptions}
  **/

  /**
  The {{#crossLink "SaveOptions"}}{{/crossLink}} associated with this EntityManager.

  __readOnly__
  @property saveOptions {SaveOptions}
  **/

  /**
  The {{#crossLink "ValidationOptions"}}{{/crossLink}} associated with this EntityManager.

  __readOnly__
  @property validationOptions {ValidationOptions}
  **/

  /**
  The {{#crossLink "KeyGenerator"}}{{/crossLink}} constructor associated with this EntityManager.

  __readOnly__
  @property keyGeneratorCtor {KeyGenerator constructor}
  **/


  // events
  /**
  An {{#crossLink "Event"}}{{/crossLink}} that fires whenever a change to any entity in this EntityManager occurs.
  @example
      var em = new EntityManager( {serviceName: "breeze/NorthwindIBModel" });
      em.entityChanged.subscribe(function(changeArgs) {
          // This code will be executed any time any entity within the entityManager is added, modified, deleted or detached for any reason.
          var action = changeArgs.entityAction;
          var entity = changeArgs.entity;
          // .. do something to this entity when it is changed.
      });
  });

  @event entityChanged
  @param entityAction {EntityAction} The {{#crossLink "EntityAction"}}{{/crossLink}} that occured.
  @param entity {Object} The entity that changed.  If this is null, then all entities in the entityManager were affected.
  @param args {Object} Additional information about this event. This will differ based on the entityAction.
  @readOnly
  **/

  /**
  An {{#crossLink "Event"}}{{/crossLink}} that fires whenever validationErrors change for any entity in this EntityManager.
  @example
      var em = new EntityManager( {serviceName: "breeze/NorthwindIBModel" });
      em.validationErrorsChanged.subscribe(function(changeArgs) {
              // This code will be executed any time any entity within the entityManager experiences a change to its validationErrors collection.
              function (validationChangeArgs) {
                  var entity == validationChangeArgs.entity;
                  var errorsAdded = validationChangeArgs.added;
                  var errorsCleared = validationChangeArgs.removed;
                  // ... do something interesting with the order.
              });
          });
      });
  @event validationErrorsChanged
  @param entity {Entity} The entity on which the validation errors have been added or removed.
  @param added {Array of ValidationError} An array containing any newly added {{#crossLink "ValidationError"}}{{/crossLink}}s
  @param removed {Array of ValidationError} An array containing any newly removed {{#crossLink "ValidationError"}}{{/crossLink}}s. This is those
  errors that have been 'fixed'
  @readOnly
  **/

  // class methods

  /**
  Creates a new entity of a specified type and optionally initializes it. By default the new entity is created with an EntityState of Added
  but you can also optionally specify an EntityState.  An EntityState of 'Detached' will insure that the entity is created but not yet added
  to the EntityManager.
  @example
      // assume em1 is an EntityManager containing a number of preexisting entities.
      // create and add an entity;
      var emp1 = em1.createEntity("Employee");
      // create and add an initialized entity;
      var emp2 = em1.createEntity("Employee", { lastName: Smith", firstName: "John" });
      // create and attach (not add) an initialized entity
      var emp3 = em1.createEntity("Employee", { id: 435, lastName: Smith", firstName: "John" }, EntityState.Unchanged);
      // create but don't attach an entity;
      var emp4 = em1.createEntity("Employee", { id: 435, lastName: Smith", firstName: "John" }, EntityState.Detached);

  @method createEntity
  @param entityType {String|EntityType} The EntityType or the name of the type for which an instance should be created.
  @param [initialValues=null] {Config object} - Configuration object of the properties to set immediately after creation.
  @param [entityState=EntityState.Added] {EntityState} - The EntityState of the entity after being created and added to this EntityManager.
  @param [mergeStrategy=MergeStrategy.Disallowed] {MergeStrategy} - How to handle conflicts if an entity with the same key already exists within this EntityManager.
  @return {Entity} A new Entity of the specified type.
  **/
  proto.createEntity = function (entityType, initialValues, entityState, mergeStrategy) {
    assertParam(entityType, "entityType").isString().or().isInstanceOf(EntityType).check();
    assertParam(entityState, "entityState").isEnumOf(EntityState).isOptional().check();
    assertParam(mergeStrategy, "mergeStrategy").isEnumOf(MergeStrategy).isOptional().check();
    if (typeof entityType === "string") {
      entityType = this.metadataStore._getEntityType(entityType);
    }
    entityState = entityState || EntityState.Added;
    var entity;
    __using(this, "isLoading", true, function () {
      entity = entityType.createEntity(initialValues);
    });
    if (entityState !== EntityState.Detached) {
      entity = this.attachEntity(entity, entityState, mergeStrategy);
    }
    return entity;
  };


  /**
  Creates a new EntityManager and imports a previously exported result into it.
  @example
      // assume em1 is an EntityManager containing a number of preexisting entities.
      var bundle = em1.exportEntities();
      // can be stored via the web storage api
      window.localStorage.setItem("myEntityManager", bundle);
      // assume the code below occurs in a different session.
      var bundleFromStorage = window.localStorage.getItem("myEntityManager");
      // and imported
      var em2 = EntityManager.importEntities(bundleFromStorage);
      // em2 will now have a complete copy of what was in em1
  @method importEntities
  @static
  @param exportedString {String} The result of a previous 'exportEntities' call.
  @param [config] {Object} A configuration object.
  @param [config.mergeStrategy] {MergeStrategy} A  {{#crossLink "MergeStrategy"}}{{/crossLink}} to use when
  merging into an existing EntityManager.
  @param [config.metadataVersionFn] {Function} A function that takes two arguments (the current metadataVersion and the imported store's 'name')
  and may be used to perform version checking.
  @return {EntityManager} A new EntityManager.  Note that the return value of this method call is different from that
  provided by the same named method on an EntityManager instance. Use that method if you need additional information
  regarding the imported entities.
  **/
  ctor.importEntities = function (exportedString, config) {
    var em = new EntityManager();
    em.importEntities(exportedString, config);
    return em;
  };

  // instance methods

  /**
  Calls EntityAspect.acceptChanges on every changed entity in this EntityManager.
  @method acceptChanges
  **/
  proto.acceptChanges = function () {
    this.getChanges().map(function(entity) {
      return entity.entityAspect._checkOperation("acceptChanges");
    }).forEach(function (aspect) {
      aspect.acceptChanges();
    });
  };

  /**
  Exports selected entities, all entities of selected types, or an entire EntityManager cache.
  @example
  This method takes a snapshot of an EntityManager that can be stored offline or held in memory.
  Use the `EntityManager.importEntities` method to restore or merge the snapshot
  into another EntityManager at some later time.
  @example
      // let em1 be an EntityManager containing a number of existing entities.
      // export every entity in em1.
      var bundle = em1.exportEntities();
      // save to the browser's local storage
      window.localStorage.setItem("myEntityManager", bundle);
      // later retrieve the export
      var bundleFromStorage = window.localStorage.getItem("myEntityManager");
      // import the retrieved export bundle into another manager
      var em2 = em1.createEmptyCopy();
      em2.importEntities(bundleFromStorage);
      // em2 now has a complete, faithful copy of the entities that were in em1
  You can also control exactly which entities are exported.
  @example
      // get em1's unsaved changes (an array) and export them.
      var changes = em1.getChanges();
      var bundle = em1.exportEntities(changes);
      // merge these entities into em2 which may contains some of the same entities.
      // do NOT overwrite the entities in em2 if they themselves have unsaved changes.
      em2.importEntities(bundle, { mergeStrategy: MergeStrategy.PreserveChanges} );
  Metadata are included in an export by default. You may want to exclude the metadata
  especially if you're exporting just a few entities for local storage.
  @example
      var bundle = em1.exportEntities(arrayOfSelectedEntities, {includeMetadata: false});
      window.localStorage.setItem("goodStuff", bundle);
  You may still express this option as a boolean value although this older syntax is deprecated.
  @example
      // Exclude the metadata (deprecated syntax)
      var bundle = em1.exportEntities(arrayOfSelectedEntities, false);
  You can export all entities of one or more specified EntityTypes.
  @example
      // Export all Customer and Employee entities (and also exclude metadata)
      var bundle = em1.exportEntities(['Customer', 'Employee'], {includeMetadata: false});
  All of the above examples return an export bundle as a string which is the default format.
  You can export the bundle as JSON if you prefer by setting the `asString` option to false.
  @example
      // Export all Customer and Employee entities as JSON and exclude the metadata
      var bundle = em1.exportEntities(['Customer', 'Employee'],
                                      {asString: false, includeMetadata: false});
      // store JSON bundle somewhere ... perhaps indexDb ... and later import as we do here.
      em2.importEntities(bundle);
  @method exportEntities
  @param [entities] {Array of Entity | Array of EntityType | Array of String}
    The entities to export or the EntityType(s) of the entities to export;
    all entities are exported if this parameter is omitted or null.
  @param [config] {Object | Boolean} Export configuration options
  @param [config.asString=true] {Boolean} If true (default), return export bundle as a string.
  @param [config.includeMetadata=true] {Boolean} If true (default), include metadata in the export bundle.
  @return {String | Object} The export bundle either serialized (default) or as a JSON object.
  The bundle contains the metadata (unless excluded) and the entity data grouped by type.
  The entity data include property values, change-state, and temporary key mappings (if any).

  The export bundle is an undocumented, Breeze-internal representation of entity data
  suitable for export, storage, and import. The schema and contents of the bundle may change in future versions of Breeze.
  Manipulate it at your own risk with appropriate caution.
  **/
  proto.exportEntities = function (entities, config) {
    assertParam(entities, "entities").isArray().isEntity()
    .or().isNonEmptyArray().isInstanceOf(EntityType)
    .or().isNonEmptyArray().isString()
    .or().isOptional().check();

    assertParam(config, "config").isObject()
    .or().isBoolean()
    .or().isOptional().check();

    if (config == null) {
      config = { includeMetadata: true, asString: true };
    } else if (typeof config === 'boolean') { // deprecated
      config = { includeMetadata: config, asString: true };
    }

    assertConfig(config)
        .whereParam("asString").isBoolean().isOptional().withDefault(true)
        .whereParam("includeMetadata").isBoolean().isOptional().withDefault(true)
        .applyAll(config);

    var exportBundle = exportEntityGroups(this, entities);
    var json = __extend({}, exportBundle, ["tempKeys", "entityGroupMap"]);

    if (config.includeMetadata) {
      json = __extend(json, this, ["dataService", "saveOptions", "queryOptions", "validationOptions"]);
      json.metadataStore = this.metadataStore.exportMetadata();
    } else {
      json.metadataVersion = breeze.metadataVersion;
      json.metadataStoreName = this.metadataStore.name;
    }

    var result = config.asString ? JSON.stringify(json, null, __config.stringifyPad) : json;
    return result;
  };

  /**
  Imports a previously exported result into this EntityManager.
  @example
  This method can be used to make a complete copy of any previously created entityManager, even if created
  in a previous session and stored in localStorage. The static version of this method performs a
  very similar process.
  @example
      // assume em1 is an EntityManager containing a number of existing entities.
      var bundle = em1.exportEntities();
      // bundle can be stored in window.localStorage or just held in memory.
      var em2 = new EntityManager({
          serviceName: em1.serviceName,
          metadataStore: em1.metadataStore
      });
      em2.importEntities(bundle);
      // em2 will now have a complete copy of what was in em1
  It can also be used to merge the contents of a previously created EntityManager with an
  existing EntityManager with control over how the two are merged.
  @example
      var bundle = em1.exportEntities();
      // assume em2 is another entityManager containing some of the same entities possibly with modifications.
      em2.importEntities(bundle, { mergeStrategy: MergeStrategy.PreserveChanges} );
      // em2 will now contain all of the entities from both em1 and em2.  Any em2 entities with previously
      // made modifications will not have been touched, but all other entities from em1 will have been imported.
  @method importEntities
  @param exportedString {String|Json} The result of a previous 'export' call.
  @param [config] {Object} A configuration object.
  @param [config.mergeStrategy] {MergeStrategy} A  {{#crossLink "MergeStrategy"}}{{/crossLink}} to use when
  merging into an existing EntityManager.
  @param [config.metadataVersionFn] {Function} A function that takes two arguments (the current metadataVersion and the imported store's 'name')
  and may be used to perform version checking.
  @return result {Object}

  result.entities {Array of Entities} The entities that were imported.
  result.tempKeyMap {Object} Mapping from original EntityKey in the import bundle to its corresponding EntityKey in this EntityManager.
  **/
  proto.importEntities = function (exportedString, config) {
    config = config || {};
    assertConfig(config)
        .whereParam("mergeStrategy").isEnumOf(MergeStrategy).isOptional().withDefault(this.queryOptions.mergeStrategy)
        .whereParam("metadataVersionFn").isFunction().isOptional()
        .whereParam("mergeAdds").isBoolean().isOptional()
        .applyAll(config);
    var that = this;

    var json = (typeof exportedString === "string") ? JSON.parse(exportedString) : exportedString;
    if (json.metadataStore) {
      this.metadataStore.importMetadata(json.metadataStore);
      // the || clause is for backwards compat with an earlier serialization format.
      this.dataService = (json.dataService && DataService.fromJSON(json.dataService)) || new DataService({ serviceName: json.serviceName });

      this.saveOptions = new SaveOptions(json.saveOptions);
      this.queryOptions = QueryOptions.fromJSON(json.queryOptions);
      this.validationOptions = new ValidationOptions(json.validationOptions);
    } else {
      config.metadataVersionFn && config.metadataVersionFn({
        metadataVersion: json.metadataVersion,
        metadataStoreName: json.metadataStoreName
      });
    }

    var tempKeyMap = {};
    json.tempKeys.forEach(function (k) {
      var oldKey = EntityKey.fromJSON(k, that.metadataStore);
      // try to use oldKey if not already used in this keyGenerator.
      tempKeyMap[oldKey.toString()] = new EntityKey(oldKey.entityType, that.keyGenerator.generateTempKeyValue(oldKey.entityType, oldKey.values[0]));
    });
    var entitiesToLink = [];
    config.tempKeyMap = tempKeyMap;
    __wrapExecution(function () {
      that._pendingPubs = [];
    }, function (state) {
      that._pendingPubs.forEach(function (fn) {
        fn();
      });
      that._pendingPubs = null;
      that._hasChangesAction && that._hasChangesAction();
    }, function () {
      __objectForEach(json.entityGroupMap, function (entityTypeName, jsonGroup) {
        var entityType = that.metadataStore._getEntityType(entityTypeName, true);
        var targetEntityGroup = findOrCreateEntityGroup(that, entityType);
        var entities = importEntityGroup(targetEntityGroup, jsonGroup, config);
        if (entities && entities.length) {
          entitiesToLink = entitiesToLink.concat(entities);
        }
      });
      entitiesToLink.forEach(function (entity) {
        if (!entity.entityAspect.entityState.isDeleted()) {
          that._linkRelatedEntities(entity);
        }
      });
    });
    return {
      entities: entitiesToLink,
      tempKeyMapping: tempKeyMap
    };
  };


  /**
  Clears this EntityManager's cache but keeps all other settings. Note that this
  method is not as fast as creating a new EntityManager via 'new EntityManager'.
  This is because clear actually detaches all of the entities from the EntityManager.
  @example
      // assume em1 is an EntityManager containing a number of existing entities.
      em1.clear();
      // em1 is will now contain no entities, but all other setting will be maintained.
  @method clear
  **/
  proto.clear = function () {
    __objectMap(this._entityGroupMap, function (key, entityGroup) {
      return entityGroup._checkOperation();
    }).forEach(function(entityGroup) {
      entityGroup._clear();
    });

    this._entityGroupMap = {};
    this._unattachedChildrenMap = new UnattachedChildrenMap();
    this.keyGenerator = new this.keyGeneratorCtor();
    this.entityChanged.publish({ entityAction: EntityAction.Clear });
    this._setHasChanges(false);
  };


  /**
  Creates an empty copy of this EntityManager
  @example
      // assume em1 is an EntityManager containing a number of existing entities.
      var em2 = em1.createEmptyCopy();
      // em2 is a new EntityManager with all of em1's settings
      // but no entities.
  @method createEmptyCopy
  @return {EntityManager} A new EntityManager.
  **/
  proto.createEmptyCopy = function () {
    var copy = new ctor(__extend({}, this,
        ["dataService", "metadataStore", "queryOptions", "saveOptions", "validationOptions", "keyGeneratorCtor"]));
    return copy;
  };

  /**
  Attaches an entity to this EntityManager with an  {{#crossLink "EntityState"}}{{/crossLink}} of 'Added'.
  @example
      // assume em1 is an EntityManager containing a number of existing entities.
      var custType = em1.metadataStore.getEntityType("Customer");
      var cust1 = custType.createEntity();
      em1.addEntity(cust1);
  Note that this is the same as using 'attachEntity' with an {{#crossLink "EntityState"}}{{/crossLink}} of 'Added'.
  @example
      // assume em1 is an EntityManager containing a number of existing entities.
      var custType = em1.metadataStore.getEntityType("Customer");
      var cust1 = custType.createEntity();
      em1.attachEntity(cust1, EntityState.Added);
  @method addEntity
  @param entity {Entity} The entity to add.
  @return {Entity} The added entity.
  **/
  proto.addEntity = function (entity) {
    return this.attachEntity(entity, EntityState.Added);
  };

  /**
  Attaches an entity to this EntityManager with a specified {{#crossLink "EntityState"}}{{/crossLink}}.
  @example
      // assume em1 is an EntityManager containing a number of existing entities.
      var custType = em1.metadataStore.getEntityType("Customer");
      var cust1 = custType.createEntity();
      em1.attachEntity(cust1, EntityState.Added);
  @method attachEntity
  @param entity {Entity} The entity to add.
  @param [entityState=EntityState.Unchanged] {EntityState} The EntityState of the newly attached entity. If omitted this defaults to EntityState.Unchanged.
  @param [mergeStrategy=MergeStrategy.Disallowed] {MergeStrategy} How the specified entity should be merged into the EntityManager if this EntityManager already contains an entity with the same key.
  @return {Entity} The attached entity.
  **/
  proto.attachEntity = function (entity, entityState, mergeStrategy) {
    assertParam(entity, "entity").isRequired().check();
    this.metadataStore._checkEntityType(entity);
    entityState = assertParam(entityState, "entityState").isEnumOf(EntityState).isOptional().check(EntityState.Unchanged);
    mergeStrategy = assertParam(mergeStrategy, "mergeStrategy").isEnumOf(MergeStrategy).isOptional().check(MergeStrategy.Disallowed);

    if (entity.entityType.metadataStore !== this.metadataStore) {
      throw new Error("Cannot attach this entity because the EntityType (" + entity.entityType.name +
          ") and MetadataStore associated with this entity does not match this EntityManager's MetadataStore.");
    }
    var aspect = entity.entityAspect;
    if (aspect) {
      // to avoid reattaching an entity in progress
      if (aspect._inProcessEntity) return aspect._inProcessEntity;
    } else {
      // this occur's when attaching an entity created via new instead of via createEntity.
      aspect = new EntityAspect(entity);
    }
    var manager = aspect.entityManager;
    if (manager) {
      if (manager === this) {
        return entity;
      } else {
        throw new Error("This entity already belongs to another EntityManager");
      }
    }

    var that = this;
    var attachedEntity;
    __using(this, "isLoading", true, function () {
      if (entityState.isAdded()) {
        checkEntityKey(that, entity);
      }
      // attachedEntity === entity EXCEPT in the case of a merge.
      attachedEntity = that._attachEntityCore(entity, entityState, mergeStrategy);
      aspect._inProcessEntity = attachedEntity;
      try {
        // entity ( not attachedEntity) is deliberate here.
        attachRelatedEntities(that, entity, entityState, mergeStrategy);
      } finally {
        // insure that _inProcessEntity is cleared.
        aspect._inProcessEntity = null;
      }
    });
    if (this.validationOptions.validateOnAttach) {
      attachedEntity.entityAspect.validateEntity();
    }
    if (!entityState.isUnchanged()) {
      this._notifyStateChange(attachedEntity, true);
    }
    this.entityChanged.publish({ entityAction: EntityAction.Attach, entity: attachedEntity });

    return attachedEntity;
  };


  /**
  Detaches an entity from this EntityManager.
  @example
      // assume em1 is an EntityManager containing a number of existing entities.
      // assume cust1 is a customer Entity previously attached to em1
      em1.detachEntity(cust1);
      // em1 will now no longer contain cust1 and cust1 will have an
      // entityAspect.entityState of EntityState.Detached
  @method detachEntity
  @param entity {Entity} The entity to detach.
  @return {Boolean} Whether the entity could be detached. This will return false if the entity is already detached or was never attached.
  **/
  proto.detachEntity = function (entity) {
    assertParam(entity, "entity").isEntity().check();
    var aspect = entity.entityAspect;
    if (!aspect) {
      // no aspect means in couldn't appear in any group
      return false;
    }

    if (aspect.entityManager !== this) {
      throw new Error("This entity does not belong to this EntityManager.");
    }
    return aspect.setDetached();
  };

  /**
  Fetches the metadata associated with the EntityManager's current 'serviceName'.  This call
  occurs internally before the first query to any service if the metadata hasn't already been
  loaded.
  @example
  Usually you will not actually process the results of a fetchMetadata call directly, but will instead
  ask for the metadata from the EntityManager after the fetchMetadata call returns.
  @example
      var em1 = new EntityManager( "breeze/NorthwindIBModel");
      em1.fetchMetadata()
        .then(function() {
            var metadataStore = em1.metadataStore;
            // do something with the metadata
        }).fail(function(exception) {
            // handle exception here
        });
  @method fetchMetadata
  @async
  @param [callback] {Function} Function called on success.

  successFunction([schema])
  @param [callback.schema] {Object} The raw Schema object from metadata provider - Because this schema will differ depending on the metadata provider
  it is usually better to access metadata via the 'metadataStore' property of the EntityManager after this method's Promise or callback completes.
  @param [errorCallback] {Function} Function called on failure.

  failureFunction([error])
  @param [errorCallback.error] {Error} Any error that occured wrapped into an Error object.
  @return {Promise}
    - Properties on the promise success result
      - schema {Object} The raw Schema object from metadata provider - Because this schema will differ depending on the metadata provider
        it is usually better to access metadata via the 'metadataStore' property of the EntityManager instead of using this 'raw' data.
  **/
  proto.fetchMetadata = function (dataService, callback, errorCallback) {
    if (typeof (dataService) === "function") {
      // legacy support for when dataService was not an arg. i.e. first arg was callback
      errorCallback = callback;
      callback = dataService;
      dataService = null;
    } else {
      assertParam(dataService, "dataService").isInstanceOf(DataService).isOptional().check();
      assertParam(callback, "callback").isFunction().isOptional().check();
      assertParam(errorCallback, "errorCallback").isFunction().isOptional().check();
    }

    var promise = this.metadataStore.fetchMetadata(dataService || this.dataService);
    return promiseWithCallbacks(promise, callback, errorCallback);
  };

  /**
  Executes the specified query.
  @example
  This method can be called using a 'promises' syntax ( recommended)
  @example
      var em = new EntityManager(serviceName);
      var query = new EntityQuery("Orders");
      em.executeQuery(query).then( function(data) {
          var orders = data.results;
          ... query results processed here
      }).fail( function(err) {
          ... query failure processed here
      });
  or with callbacks
  @example
      var em = new EntityManager(serviceName);
      var query = new EntityQuery("Orders");
      em.executeQuery(query,
          function(data) {
              var orders = data.results;
              ... query results processed here
          },
          function(err) {
              ... query failure processed here
          });
  Either way this method is the same as calling the The {{#crossLink "EntityQuery"}}{{/crossLink}} 'execute' method.
  @example
      var em = new EntityManager(serviceName);
      var query = new EntityQuery("Orders").using(em);
      query.execute().then( function(data) {
          var orders = data.results;
          ... query results processed here
      }).fail( function(err) {
          ... query failure processed here
      });

  @method executeQuery
  @async
  @param query {EntityQuery|String}  The {{#crossLink "EntityQuery"}}{{/crossLink}} or OData query string to execute.
  @param [callback] {Function} Function called on success.

  successFunction([data])
  @param callback.data {Object}
  @param callback.data.results {Array of Entity}
  @param callback.data.query {EntityQuery} The original query
  @param callback.data.entityManager {EntityManager} The EntityManager.
  @param callback.data.httpResponse {HttpResponse} The HttpResponse returned from the server.
  @param callback.data.inlineCount {Integer} Only available if 'inlineCount(true)' was applied to the query.  Returns the count of
  items that would have been returned by the query before applying any skip or take operators, but after any filter/where predicates
  would have been applied.
  @param callback.data.retrievedEntities {Array of Entity} All entities returned by the query.  Differs from results when .expand() is used.

  @param [errorCallback] {Function} Function called on failure.

  failureFunction([error])
  @param [errorCallback.error] {Error} Any error that occured wrapped into an Error object.
  @param [errorCallback.error.query] The query that caused the error.
  @param [errorCallback.error.entityManager] The query that caused the error.
  @param [errorCallback.error.httpResponse] {HttpResponse} The HttpResponse returned from the server.


  @return {Promise}
    - Properties on the promise success result
      - results {Array of Entity}
      - query {EntityQuery} The original query
      - entityManager {EntityManager} The EntityManager.
      - httpResponse {HttpResponse} The  HttpResponse returned from the server.
      - [inlineCount] {Integer} Only available if 'inlineCount(true)' was applied to the query.  Returns the count of
    items that would have been returned by the query before applying any skip or take operators, but after any filter/where predicates
    would have been applied.
  **/
  proto.executeQuery = function (query, callback, errorCallback) {
    assertParam(query, "query").isInstanceOf(EntityQuery).or().isString().check();
    assertParam(callback, "callback").isFunction().isOptional().check();
    assertParam(errorCallback, "errorCallback").isFunction().isOptional().check();
    var promise;
    // 'resolve' methods create a new typed object with all of its properties fully resolved against a list of sources.
    // Thought about creating a 'normalized' query with these 'resolved' objects
    // but decided not to because the 'query' may not be an EntityQuery (it can be a string) and hence might not have a queryOptions or dataServices property on it.
    var queryOptions = QueryOptions.resolve([ query.queryOptions, this.queryOptions, QueryOptions.defaultInstance]);
    var dataService = DataService.resolve([ query.dataService, this.dataService]);

    if ((!dataService.hasServerMetadata ) || this.metadataStore.hasMetadataFor(dataService.serviceName)) {
      promise = executeQueryCore(this, query, queryOptions, dataService);
    } else {
      var that = this;
      promise = this.fetchMetadata(dataService).then(function () {
        return executeQueryCore(that, query, queryOptions, dataService);
      });
    }

    return promiseWithCallbacks(promise, callback, errorCallback);
  };

  /**
  Executes the specified query against this EntityManager's local cache.

  @example
  Because this method is executed immediately there is no need for a promise or a callback
  @example
      var em = new EntityManager(serviceName);
      var query = new EntityQuery("Orders");
      var orders = em.executeQueryLocally(query);

  Note that this can also be accomplished using the 'executeQuery' method with
  a FetchStrategy of FromLocalCache and making use of the Promise or callback
  @example
      var em = new EntityManager(serviceName);
      var query = new EntityQuery("Orders").using(FetchStrategy.FromLocalCache);
      em.executeQuery(query).then( function(data) {
          var orders = data.results;
          ... query results processed here
      }).fail( function(err) {
          ... query failure processed here
      });
  @method executeQueryLocally
  @param query {EntityQuery}  The {{#crossLink "EntityQuery"}}{{/crossLink}} to execute.
  @return  {Array of Entity}  Array of entities from cache that satisfy the query
  **/
  proto.executeQueryLocally = function (query) {
    return executeQueryLocallyCore(this, query).results;
  }

  function executeQueryLocallyCore(em, query) {
    assertParam(query, "query").isInstanceOf(EntityQuery).check();

    var metadataStore = em.metadataStore;
    var entityType = query._getFromEntityType(metadataStore, true);
    // there may be multiple groups is this is a base entity type.
    var groups = findOrCreateEntityGroups(em, entityType);
    // filter then order then skip then take
    var filterFunc = query.wherePredicate && query.wherePredicate.toFunction({ entityType: entityType});

    var queryOptions = QueryOptions.resolve([ query.queryOptions, em.queryOptions, QueryOptions.defaultInstance]);
    var includeDeleted = queryOptions.includeDeleted === true;

    var newFilterFunc = function (entity) {
      return entity && (includeDeleted || !entity.entityAspect.entityState.isDeleted()) && (filterFunc ? filterFunc(entity) : true);
    };

    var result = [];
    // TODO: mapMany
    groups.forEach(function (group) {
      var entities = group._entities.filter(newFilterFunc);
      if (entities.length) {
          result = result.length ? result.concat(entities) : entities;
      }
    });

    var orderByComparer = query.orderByClause && query.orderByClause.getComparer(entityType);
    if (orderByComparer) {
      result.sort(orderByComparer);
    }

    if (query.inlineCountEnabled) {
      var inlineCount = result.length;
    }

    var skipCount = query.skipCount;
    if (skipCount) {
      result = result.slice(skipCount);
    }
    var takeCount = query.takeCount;
    if (takeCount) {
      result = result.slice(0, takeCount);
    }

    var selectClause = query.selectClause;
    if (selectClause) {
      var selectFn = selectClause.toFunction();
      result = result.map(selectFn);
    }
    return {results: result, inlineCount: inlineCount};
  };

  /**
  Saves either a list of specified entities or all changed entities within this EntityManager. If there are no changes to any of the entities
  specified then there will be no server side call made but a valid 'empty' saveResult will still be returned.
  @example
  Often we will be saving all of the entities within an EntityManager that are either added, modified or deleted
  and we will let the 'saveChanges' call determine which entities these are.
  @example
      // assume em1 is an EntityManager containing a number of preexisting entities.
      // This could include added, modified and deleted entities.
      em.saveChanges().then(function(saveResult) {
          var savedEntities = saveResult.entities;
          var keyMappings = saveResult.keyMappings;
      }).fail(function (e) {
          // e is any exception that was thrown.
      });
  But we can also control exactly which entities to save and can specify specific SaveOptions
  @example
      // assume entitiesToSave is an array of entities to save.
      var saveOptions = new SaveOptions({ allowConcurrentSaves: true });
      em.saveChanges(entitiesToSave, saveOptions).then(function(saveResult) {
          var savedEntities = saveResult.entities;
          var keyMappings = saveResult.keyMappings;
      }).fail(function (e) {
          // e is any exception that was thrown.
      });
  Callback methods can also be used
  @example
      em.saveChanges(entitiesToSave, null,
      function(saveResult) {
                  var savedEntities = saveResult.entities;
                  var keyMappings = saveResult.keyMappings;
              }, function (e) {
                  // e is any exception that was thrown.
              }
      );
  @method saveChanges
  @async
  @param [entities] {Array of Entity} The list of entities to save.
  Every entity in that list will be sent to the server, whether changed or unchanged,
  as long as it is attached to this EntityManager.
  If this parameter is omitted, null or empty (the usual case),
  every entity with pending changes in this EntityManager will be saved.
  @param [saveOptions] {SaveOptions} {{#crossLink "SaveOptions"}}{{/crossLink}} for the save - will default to
  {{#crossLink "EntityManager/saveOptions"}}{{/crossLink}} if null.
  @param [callback] {Function} Function called on success.

  successFunction([saveResult])
  @param [callback.saveResult] {Object}
  @param [callback.saveResult.entities] {Array of Entity} The saved entities - with any temporary keys converted into 'real' keys.
  These entities are actually references to entities in the EntityManager cache that have been updated as a result of the
  save.
  @param [callback.saveResult.keyMappings] {Array of keyMappings} Each keyMapping has the following properties: 'entityTypeName', 'tempValue' and 'realValue'
  @param [callback.saveResult.httpResponse] {HttpResponse} The raw HttpResponse returned from the server.

  @param [errorCallback] {Function} Function called on failure.

  failureFunction([error])
  @param [errorCallback.error] {Error} Any error that occured wrapped into an Error object.
  @param [errorCallback.error.entityErrors] { Array of server side errors }  These are typically validation errors but are generally any error that can be easily isolated to a single entity.
  @param [errorCallback.error.httpResponse] {HttpResponse} The raw HttpResponse returned from the server.
  @param [errorCallback.error.saveResult] {Object} Some dataservice adapters return a 'saveResult' object
  when the failing save operation is non-transactional meaning some entities could be saved while others were not.
  The 'saveResult' object identifies both that entities that were saved (with their keyMapping)
  and that entities that were not saved (with their errors).

  @return {Promise} Promise
  **/
  proto.saveChanges = function (entities, saveOptions, callback, errorCallback) {
    assertParam(entities, "entities").isOptional().isArray().isEntity().check();
    assertParam(saveOptions, "saveOptions").isInstanceOf(SaveOptions).isOptional().check();
    assertParam(callback, "callback").isFunction().isOptional().check();
    assertParam(errorCallback, "errorCallback").isFunction().isOptional().check();

    saveOptions = saveOptions || this.saveOptions || SaveOptions.defaultInstance;
    var isFullSave = entities == null;
    var entitiesToSave = getEntitiesToSave(this, entities);

    if (entitiesToSave.length === 0) {
      var result = { entities: [], keyMappings: [] };
      if (callback) callback(result);
      return Q.resolve(result);
    }

    if (!saveOptions.allowConcurrentSaves) {
      var anyPendingSaves = entitiesToSave.some(function (entity) {
        return entity.entityAspect.isBeingSaved;
      });
      if (anyPendingSaves) {
        var err = new Error("Concurrent saves not allowed - SaveOptions.allowConcurrentSaves is false");
        if (errorCallback) errorCallback(err);
        return Q.reject(err);
      }
    }

    clearServerErrors(entitiesToSave);

    var valError = this.saveChangesValidateOnClient(entitiesToSave);
    if (valError) {
      if (errorCallback) errorCallback(valError);
      return Q.reject(valError);
    }

    var dataService = DataService.resolve([saveOptions.dataService, this.dataService]);
    var saveContext = {
      entityManager: this,
      dataService: dataService,
      processSavedEntities: processSavedEntities,
      resourceName: saveOptions.resourceName || this.saveOptions.resourceName || "SaveChanges"
    };

    // TODO: need to check that if we are doing a partial save that all entities whose temp keys
    // are referenced are also in the partial save group

    var saveBundle = { entities: entitiesToSave, saveOptions: saveOptions };


    try { // Guard against exception thrown in dataservice adapter before it goes async
      updateConcurrencyProperties(entitiesToSave);
      return dataService.adapterInstance.saveChanges(saveContext, saveBundle)
          .then(saveSuccess).then(null, saveFail);
    } catch (err) {
      // undo the marking by updateConcurrencyProperties
      markIsBeingSaved(entitiesToSave, false);
      if (errorCallback) errorCallback(err);
      return Q.reject(err);
    }

    function saveSuccess(saveResult) {
      var em = saveContext.entityManager;
      markIsBeingSaved(entitiesToSave, false);
      var savedEntities = saveResult.entities = saveContext.processSavedEntities(saveResult);

      // update _hasChanges after save.
      em._setHasChanges(null);

      // can't do this anymore because other changes might have been made while saved entities in flight.
//      var hasChanges = (isFullSave && haveSameContents(entitiesToSave, savedEntities)) ? false : null;
//      em._setHasChanges(hasChanges);

      if (callback) callback(saveResult);
      return Q.resolve(saveResult);
    }

    function processSavedEntities(saveResult) {

      var savedEntities = saveResult.entities;
      var deletedKeys = saveResult.deletedKeys || [];
      if (savedEntities.length === 0 && deletedKeys.length == 0) {
        return [];
      }
      var keyMappings = saveResult.keyMappings;
      var em = saveContext.entityManager;

      // must occur outside of isLoading block
      fixupKeys(em, keyMappings);

      __using(em, "isLoading", true, function () {

        var mappingContext = new MappingContext({
          query: null, // tells visitAndMerge this is a save instead of a query
          entityManager: em,
          mergeOptions: { mergeStrategy: MergeStrategy.OverwriteChanges },
          dataService: dataService
        });

        // The visitAndMerge operation has been optimized so that we do not actually perform a merge if the
        // the save operation did not actually return the entity - i.e. during OData and Mongo updates and deletes.
        savedEntities = mappingContext.visitAndMerge(savedEntities, { nodeType: "root" });
      });

      // detach any entities found in the em that appear in the deletedKeys list. 
      
      deletedKeys.forEach(function(key) {
        var entityType = em.metadataStore._getEntityType(key.entityTypeName);
        var ekey = new EntityKey(entityType, key.keyValues);
        var entity = em.findEntityByKey(ekey);
        if (entity) {
          entity.entityAspect.setDetached();
        }
      })

      return savedEntities;
    }

    function saveFail(error) {
      markIsBeingSaved(entitiesToSave, false);
      processServerErrors(saveContext, error);
      if (errorCallback) errorCallback(error);
      return Q.reject(error);
    }
  };

  /**
  Run the "saveChanges" pre-save client validation logic.

  This is NOT a general purpose validation method.
  It is intended for utilities that must know if saveChanges
  would reject the save due to client validation errors.

  It only validates entities if the EntityManager's
  {{#crossLink "ValidationOptions"}}{{/crossLink}}.validateOnSave is true.

  @method saveChangesValidateOnClient
  @param entitiesToSave {Array of Entity} The list of entities to save (to validate).
  @return {Error} Validation error or null if no error
  **/
  proto.saveChangesValidateOnClient = function(entitiesToSave) {

    if (this.validationOptions.validateOnSave) {
      var failedEntities = entitiesToSave.filter(function (entity) {
        var aspect = entity.entityAspect;
        var isValid = aspect.entityState.isDeleted() || aspect.validateEntity();
        return !isValid;
      });
      if (failedEntities.length > 0) {
        var valError = new Error("Client side validation errors encountered - see the entityErrors collection on this object for more detail");
        valError.entityErrors = createEntityErrors(failedEntities);
        return valError;
      }
    }
    return null;
  }

  function clearServerErrors(entities) {
    entities.forEach(function (entity) {
      var serverKeys = [];
      var aspect = entity.entityAspect;
      __objectForEach(aspect._validationErrors, function (key, ve) {
        if (ve.isServerError) serverKeys.push(key);
      });
      if (serverKeys.length === 0) return;
      aspect._processValidationOpAndPublish(function () {
        serverKeys.forEach(function (key) {
          aspect._removeValidationError(key);
        });
      });
    });
  }

  function createEntityErrors(entities) {
    var entityErrors = [];
    entities.forEach(function (entity) {
      __objectForEach(entity.entityAspect._validationErrors, function (key, ve) {
        var cfg = __extend({
          entity: entity,
          errorName: ve.validator.name
        }, ve, ["errorMessage", "propertyName", "isServerError"]);
        entityErrors.push(cfg);
      });
    });
    return entityErrors;
  }


  function processServerErrors(saveContext, error) {
    var serverErrors = error.entityErrors;
    if (!serverErrors) return;
    var entityManager = saveContext.entityManager;
    var metadataStore = entityManager.metadataStore;
    error.entityErrors = serverErrors.map(function (serr) {
      var entity = null;
      if (serr.keyValues) {
        var entityType = metadataStore._getEntityType(serr.entityTypeName);
        var ekey = new EntityKey(entityType, serr.keyValues);
        entity = entityManager.findEntityByKey(ekey);
      }

      if (entity) {
        var context = serr.propertyName ?
                      {
                        propertyName: serr.propertyName,
                        property: entityType.getProperty(serr.propertyName)
                      } : {
                      };
        var key = ValidationError.getKey(serr.errorName || serr.errorMessage, serr.propertyName);

        var ve = new ValidationError(null, context, serr.errorMessage, key);
        ve.isServerError = true;
        entity.entityAspect.addValidationError(ve);
      }

      var entityError = __extend({
        entity: entity,
        isServerError: true
      }, serr, ["errorName", "errorMessage", "propertyName"]);
      return entityError;
    });
  }

  // No longer used
//  function haveSameContents(arr1, arr2) {
//    if (arr1.length !== arr2.length) {
//      return false;
//    }
//    for (var i = 0, c = arr1.length; i < c; i++) {
//      if (arr1[i] !== arr2[i]) return false;
//    }
//    return true;
//  }


  proto._findEntityGroup = function (entityType) {
    return this._entityGroupMap[entityType.name];
  };


  /**
  Attempts to locate an entity within this EntityManager by its key.
  @example
      // assume em1 is an EntityManager containing a number of preexisting entities.
      var employee = em1.getEntityByKey("Employee", 1);
      // employee will either be an entity or null.
  @method getEntityByKey
  @param typeName {EntityType | String} The EntityType or EntityType name for this key.
  @param keyValues {Object|Array of Object} The values for this key - will usually just be a single value; an array is only needed for multipart keys.
  @return {Entity} An Entity or null;
  **/

  /**
  Attempts to locate an entity within this EntityManager by its  {{#crossLink "EntityKey"}}{{/crossLink}}.
  @example
      // assume em1 is an EntityManager containing a number of preexisting entities.
      var employeeType = em1.metadataStore.getEntityType("Employee");
      var employeeKey = new EntityKey(employeeType, 1);
      var employee = em1.getEntityByKey(employeeKey);
      // employee will either be an entity or null.
  @method getEntityByKey - overload
  @param entityKey {EntityKey} The  {{#crossLink "EntityKey"}}{{/crossLink}} of the Entity to be located.
  @return {Entity} An Entity or null;
  **/
  proto.getEntityByKey = function () {
    var entityKey = createEntityKey(this, arguments).entityKey;
    var entityTypes = entityKey._subtypes || [entityKey.entityType];
    var ek = null;
    // hack use of some to simulate mapFirst logic.
    entityTypes.some(function (et) {
      var group = this._findEntityGroup(et);
      // group version of findEntityByKey doesn't care about entityType
      ek = group && group.findEntityByKey(entityKey);
      return ek;
    }, this);
    return ek;
  };

  /**
  Attempts to fetch an entity from the server by its key with
  an option to check the local cache first. Note the this EntityManager's queryOptions.mergeStrategy
  will be used to merge any server side entity returned by this method.
  @example
      // assume em1 is an EntityManager containing a number of preexisting entities.
      em1.fetchEntityByKey("Employee", 1).then(function(result) {
          var employee = result.entity;
          var entityKey = result.entityKey;
          var fromCache = result.fromCache;
      });
  @method fetchEntityByKey
  @async
  @param typeName {EntityType | String} The EntityType or EntityType name for this key.
  @param keyValues {Object|Array of Object} The values for this key - will usually just be a single value; an array is only needed for multipart keys.
  @param checkLocalCacheFirst {Boolean=false} Whether to check this EntityManager first before going to the server. By default, the query will NOT do this.
  @return {Promise}
    - Properties on the promise success result
      - entity {Object} The entity returned or null
      - entityKey {EntityKey} The entityKey of the entity to fetch.
      - fromCache {Boolean} Whether this entity was fetched from the server or was found in the local cache.

  **/

  /**
  Attempts to fetch an entity from the server by its {{#crossLink "EntityKey"}}{{/crossLink}} with
  an option to check the local cache first.
  @example
      // assume em1 is an EntityManager containing a number of preexisting entities.
      var employeeType = em1.metadataStore.getEntityType("Employee");
      var employeeKey = new EntityKey(employeeType, 1);
      em1.fetchEntityByKey(employeeKey).then(function(result) {
          var employee = result.entity;
          var entityKey = result.entityKey;
          var fromCache = result.fromCache;
      });
  @method fetchEntityByKey - overload
  @async
  @param entityKey {EntityKey} The  {{#crossLink "EntityKey"}}{{/crossLink}} of the Entity to be located.
  @param checkLocalCacheFirst {Boolean=false} Whether to check this EntityManager first before going to the server. By default, the query will NOT do this.
  @return {Promise}
    - Properties on the promise success result
      - entity {Object} The entity returned or null
      - entityKey {EntityKey} The entityKey of the entity to fetch.
      - fromCache {Boolean} Whether this entity was fetched from the server or was found in the local cache.
  **/
  proto.fetchEntityByKey = function () {
    var dataService = DataService.resolve([this.dataService]);
    if ((!dataService.hasServerMetadata) || this.metadataStore.hasMetadataFor(dataService.serviceName)) {
      return fetchEntityByKeyCore(this, arguments);
    } else {
      var that = this;
      var args = arguments;
      return this.fetchMetadata(dataService).then(function () {
        return fetchEntityByKeyCore(that, args);
      });
    }
  };

  function fetchEntityByKeyCore(em, args) {
    var tpl = createEntityKey(em, args);
    var entityKey = tpl.entityKey;
    var checkLocalCacheFirst = tpl.remainingArgs.length === 0 ? false : !!tpl.remainingArgs[0];
    var entity;
    var foundIt = false;
    if (checkLocalCacheFirst) {
      entity = em.getEntityByKey(entityKey);
      foundIt = !!entity;
      if (foundIt &&
        // null the entity if it is deleted and we should exclude deleted entities
          !em.queryOptions.includeDeleted && entity.entityAspect.entityState.isDeleted()) {
        entity = null;
        // but resume looking if we'd overwrite deleted entity with a remote entity
        // note: em.queryOptions is always fully resolved by now
        foundIt = em.queryOptions.mergeStrategy !== MergeStrategy.OverwriteChanges;
      }
    }
    if (foundIt) {
      return Q.resolve({ entity: entity, entityKey: entityKey, fromCache: true });
    } else {
      return EntityQuery.fromEntityKey(entityKey).using(em).execute().then(function (data) {
        entity = (data.results.length === 0) ? null : data.results[0];
        return Q.resolve({ entity: entity, entityKey: entityKey, fromCache: false });
      });
    }
  };

  /**
  [Deprecated] - Attempts to locate an entity within this EntityManager by its  {{#crossLink "EntityKey"}}{{/crossLink}}.
  @example
      // assume em1 is an EntityManager containing a number of preexisting entities.
      var employeeType = em1.metadataStore.getEntityType("Employee");
      var employeeKey = new EntityKey(employeeType, 1);
      var employee = em1.findEntityByKey(employeeKey);
      // employee will either be an entity or null.
  @method findEntityByKey
  @deprecated - use getEntityByKey instead
  @param entityKey {EntityKey} The  {{#crossLink "EntityKey"}}{{/crossLink}} of the Entity to be located.
  @return {Entity} An Entity or null;
  **/
  proto.findEntityByKey = function (entityKey) {
    return this.getEntityByKey(entityKey);
  };

  /**
  Generates a temporary key for the specified entity.  This is used to insure that newly
  created entities have unique keys and to register that these keys are temporary and
  need to be automatically replaced with 'real' key values once these entities are saved.

  The EntityManager.keyGeneratorCtor property is used internally by this method to actually generate
  the keys - See the  {{#crossLink "_keyGenerator_interface"}}{{/crossLink}} interface description to see
  how a custom key generator can be plugged in.
  @example
      // assume em1 is an EntityManager containing a number of preexisting entities.
      var custType = em1.metadataStore.getEntityType("Customer");
      var customer = custType.createEntity();
      var customerId = em.generateTempKeyValue(customer);
      // The 'customer' entity 'CustomerID' property is now set to a newly generated unique id value
      // This property will change again after a successful save of the 'customer' entity.

      em1.saveChanges().then( function( data) {
          var sameCust1 = data.results[0];
          // cust1 === sameCust1;
          // but cust1.getProperty("CustomerId") != customerId
          // because the server will have generated a new id
          // and the client will have been updated with this
          // new id.
      })

  @method generateTempKeyValue
  @param entity {Entity} The Entity to generate a key for.
  @return {Object} The new key value
  **/
  proto.generateTempKeyValue = function (entity) {
    // TODO - check if this entity is attached to this EntityManager.
    assertParam(entity, "entity").isEntity().check();
    var entityType = entity.entityType;
    var nextKeyValue = this.keyGenerator.generateTempKeyValue(entityType);
    var keyProp = entityType.keyProperties[0];
    entity.setProperty(keyProp.name, nextKeyValue);
    entity.entityAspect.hasTempKey = true;
    return nextKeyValue;
  };

  /**
  Returns whether there are any changed entities of the specified {{#crossLink "EntityType"}}{{/crossLink}}s. A 'changed' Entity has
  has an {{#crossLink "EntityState"}}{{/crossLink}} of either Added, Modified or Deleted.
  @example
  This method can be used to determine if an EntityManager has any changes
  @example
      // assume em1 is an EntityManager containing a number of preexisting entities.
      if ( em1.hasChanges() {
          // do something interesting
      }
  or if it has any changes on to a specific {{#crossLink "EntityType"}}{{/crossLink}}
  @example
      // assume em1 is an EntityManager containing a number of preexisting entities.
      var custType = em1.metadataStore.getEntityType("Customer");
      if ( em1.hasChanges(custType) {
          // do something interesting
      }
  or to a collection of {{#crossLink "EntityType"}}{{/crossLink}}s
  @example
      // assume em1 is an EntityManager containing a number of preexisting entities.
      var custType = em1.metadataStore.getEntityType("Customer");
      var orderType = em1.metadataStore.getEntityType("Order");
      if ( em1.hasChanges( [custType, orderType]) {
          // do something interesting
      }
  @method hasChanges
  @param [entityTypes] {String|Array of String|EntityType|Array of EntityType} The {{#crossLink "EntityType"}}{{/crossLink}}s for which 'changed' entities will be found.
  If this parameter is omitted, all EntityTypes are searched. String parameters are treated as EntityType names.
  @return {Boolean} Whether there were any changed entities.
  **/
  proto.hasChanges = function (entityTypes) {
    if (!this._hasChanges) return false;
    if (entityTypes === undefined) return this._hasChanges;
    return this._hasChangesCore(entityTypes);
  };

  /**
  An {{#crossLink "Event"}}{{/crossLink}} that fires whenever an EntityManager transitions to or from having changes.
  @example
      var em = new EntityManager( {serviceName: "breeze/NorthwindIBModel" });
      em.hasChangesChanged.subscribe(function(args) {
              var hasChangesChanged = args.hasChanges;
              var entityManager = args.entityManager;
          });
      });

  @event hasChangesChanged
  @param entityManager {EntityManager} The EntityManager whose 'hasChanges' status has changed.
  @param hasChanges {Boolean} Whether or not this EntityManager has changes.
  @readOnly
  **/


  // backdoor to "really" check for changes.
  proto._hasChangesCore = function (entityTypes) {
    entityTypes = checkEntityTypes(this, entityTypes);
    var entityGroups = getEntityGroups(this, entityTypes);
    return entityGroups.some(function (eg) {
      return eg && eg.hasChanges();
    });
  };

  /**
  Returns a array of all changed entities of the specified {{#crossLink "EntityType"}}{{/crossLink}}s. A 'changed' Entity has
  has an {{#crossLink "EntityState"}}{{/crossLink}} of either Added, Modified or Deleted.
  @example
  This method can be used to get all of the changed entities within an EntityManager
  @example
      // assume em1 is an EntityManager containing a number of preexisting entities.
      var changedEntities = em1.getChanges();
  or you can specify that you only want the changes on a specific {{#crossLink "EntityType"}}{{/crossLink}}
  @example
      // assume em1 is an EntityManager containing a number of preexisting entities.
      var custType = em1.metadataStore.getEntityType("Customer");
      var changedCustomers = em1.getChanges(custType);
  or to a collection of {{#crossLink "EntityType"}}{{/crossLink}}s
  @example
      // assume em1 is an EntityManager containing a number of preexisting entities.
      var custType = em1.metadataStore.getEntityType("Customer");
      var orderType = em1.metadataStore.getEntityType("Order");
      var changedCustomersAndOrders = em1.getChanges([custType, orderType]);
  @method getChanges
  @param [entityTypes] {String|Array of String|EntityType|Array of EntityType} The {{#crossLink "EntityType"}}{{/crossLink}}s for which 'changed' entities will be found.
  If this parameter is omitted, all EntityTypes are searched. String parameters are treated as EntityType names.
  @return {Array of Entity} Array of Entities
  **/
  proto.getChanges = function (entityTypes) {
    entityTypes = checkEntityTypes(this, entityTypes);
    return getChangesCore(this, entityTypes);
  };

  /**
  Rejects (reverses the effects) all of the additions, modifications and deletes from this EntityManager.
  Calls EntityAspect.rejectChanges on every changed entity in this EntityManager.
  @example
      // assume em1 is an EntityManager containing a number of preexisting entities.
      var entities = em1.rejectChanges();

  @method rejectChanges
  @return {Array of Entity} The entities whose changes were rejected. These entities will all have EntityStates of
  either 'Unchanged' or 'Detached'
  **/
  proto.rejectChanges = function () {
    if (!this._hasChanges) return [];
    var changes = getChangesCore(this, null);
    // next line stops individual reject changes from each calling _hasChangesCore
    var aspects = changes.map(function(e) {
      return e.entityAspect._checkOperation("rejectChanges");
    });
    this._hasChanges = false;
    aspects.forEach(function (aspect) {
      aspect.rejectChanges();
    });
    this.hasChangesChanged.publish({ entityManager: this, hasChanges: false });
    return changes;
  };

  /**
  Returns a array of all entities of the specified {{#crossLink "EntityType"}}{{/crossLink}}s with the specified {{#crossLink "EntityState"}}{{/crossLink}}s.
  @example
  This method can be used to get all of the entities within an EntityManager
  @example
      // assume em1 is an EntityManager containing a number of preexisting entities.
      var entities = em1.getEntities();
  or you can specify that you only want the changes on a specific {{#crossLink "EntityType"}}{{/crossLink}}
  @example
      // assume em1 is an EntityManager containing a number of preexisting entities.
      var custType = em1.metadataStore.getEntityType("Customer");
      var customers = em1.getEntities(custType);
  or to a collection of {{#crossLink "EntityType"}}{{/crossLink}}s
  @example
      // assume em1 is an EntityManager containing a number of preexisting entities.
      var custType = em1.metadataStore.getEntityType("Customer");
      var orderType = em1.metadataStore.getEntityType("Order");
      var customersAndOrders = em1.getChanges([custType, orderType]);
  You can also ask for entities with a particular {{#crossLink "EntityState"}}{{/crossLink}} or EntityStates.
  @example
      // assume em1 is an EntityManager containing a number of preexisting entities.
      var custType = em1.metadataStore.getEntityType("Customer");
      var orderType = em1.metadataStore.getEntityType("Order");
      var addedCustomersAndOrders = em1.getEntities([custType, orderType], EntityState.Added);
  @method getEntities
  @param [entityTypes] {String|Array of String|EntityType|Array of EntityType} The {{#crossLink "EntityType"}}{{/crossLink}}s for which entities will be found.
  If this parameter is omitted, all EntityTypes are searched. String parameters are treated as EntityType names.
  @param [entityState] {EntityState|Array of EntityState} The {{#crossLink "EntityState"}}{{/crossLink}}s for which entities will be found.
  If this parameter is omitted, entities of all EntityStates are returned.
  @return {Array of Entity} Array of Entities
  **/
  proto.getEntities = function (entityTypes, entityStates) {
    entityTypes = checkEntityTypes(this, entityTypes);
    assertParam(entityStates, "entityStates").isOptional().isEnumOf(EntityState).or().isNonEmptyArray().isEnumOf(EntityState).check();

    entityStates = entityStates && validateEntityStates(this, entityStates);
    return getEntitiesCore(this, entityTypes, entityStates);
  };


  // protected methods

  proto._notifyStateChange = function (entity, needsSave) {
    var ecArgs = { entityAction: EntityAction.EntityStateChange, entity: entity };

    if (needsSave) {
      if (!this._hasChanges) this._setHasChanges(true);
    } else {
      // called when rejecting a change or merging an unchanged record.
      // NOTE: this can be slow with lots of entities in the cache.
      // so defer it during a query/import or save and call it once when complete ( if needed).
      if (this._hasChanges) {
        if (this.isLoading) {
          this._hasChangesAction = this._hasChangesAction || function () {
            this._setHasChanges(null);
            this.entityChanged.publish(ecArgs);
          }.bind(this);
          return;
        } else {
          this._setHasChanges(null);
        }
      }
    }
    this.entityChanged.publish(ecArgs);
  };

  proto._setHasChanges = function (hasChanges) {
    if (hasChanges == null) hasChanges = this._hasChangesCore();
    var hadChanges = this._hasChanges;
    this._hasChanges = hasChanges;
    if (hasChanges != hadChanges) {
      this.hasChangesChanged.publish({ entityManager: this, hasChanges: hasChanges });
    }
    this._hasChangesAction = null;
  }

  proto._linkRelatedEntities = function (entity) {
    var em = this;
    var entityAspect = entity.entityAspect;
    // we do not want entityState to change as a result of linkage.
    __using(em, "isLoading", true, function () {

      var unattachedMap = em._unattachedChildrenMap;
      var entityKey = entityAspect.getKey();

    var entityType = entityKey.entityType;
    while (entityType) {
      var keystring = entityKey.toString(entityType);

      // attach any unattachedChildren
      var tuples = unattachedMap.getTuplesByString(keystring);

      if (tuples && tuples.length) {
        tuples.slice(0).forEach(function (tpl) {

          var unattachedChildren = tpl.children.filter(function (e) {
            return e.entityAspect.entityState !== EntityState.Detached;
          });

          var childToParentNp, parentToChildNp;

          // np is usually childToParentNp
          // except with unidirectional 1-n where it is parentToChildNp;
          var np = tpl.navigationProperty;

          if (np.getInverse()) {
            // bidirectional
            childToParentNp = np;
            parentToChildNp = np.getInverse();

            if (parentToChildNp.isScalar) {
              var onlyChild = unattachedChildren[0];
              entity.setProperty(parentToChildNp.name, onlyChild);
              onlyChild.setProperty(childToParentNp.name, entity);
            } else {
              var currentChildren = entity.getProperty(parentToChildNp.name);
              unattachedChildren.forEach(function (child) {
                currentChildren.push(child);
                child.setProperty(childToParentNp.name, entity);
              });
            }
          } else {
            // unidirectional
            // if (np.isScalar || np.parentType !== entity.entityType) {
            if (np.isScalar) {
              // n -> 1  eg: child: OrderDetail parent: Product
              // 1 -> 1 eg child: Employee parent: Employee ( only Manager, no DirectReports property)
              childToParentNp = np;
              unattachedChildren.forEach(function (child) {
                child.setProperty(childToParentNp.name, entity);
              });
            } else {
              // 1 -> n  eg: parent: Region child: Terr
              // TODO: need to remove unattached children from the map after this; only a perf issue.
              parentToChildNp = np;
              var currentChildren = entity.getProperty(parentToChildNp.name);
              unattachedChildren.forEach(function (child) {
                // we know if can't already be there.
                currentChildren._push(child);
              });
            }
          }
          unattachedMap.removeChildrenByString(keystring, childToParentNp);
        });
      }
      entityType = entityType.baseEntityType;
    }


      // now add to unattachedMap if needed.
      entity.entityType.navigationProperties.forEach(function (np) {
        if (np.isScalar) {
          var value = entity.getProperty(np.name);
          // property is already linked up
          if (value) return;
        }

        // first determine if np contains a parent or child
        // having a parentKey means that this is a child
        // if a parent then no need for more work because children will attach to it.
        var parentKey = entityAspect.getParentKey(np);
        if (parentKey) {
          // check for empty keys - meaning that parent id's are not yet set.
          if (parentKey._isEmpty()) return;
          // if a child - look for parent in the em cache
          var parent = em.findEntityByKey(parentKey);
          if (parent) {
            // if found hook it up
            entity.setProperty(np.name, parent);
          } else {
            // else add parent to unresolvedParentMap;
            unattachedMap.addChild(parentKey, np, entity);
          }
        }
      });

      // handle unidirectional 1-x where we set x.fk
      entity.entityType.foreignKeyProperties.forEach(function (fkProp) {
        var invNp = fkProp.inverseNavigationProperty;
        if (!invNp) return;
        // unidirectional fk props only
        var fkValue = entity.getProperty(fkProp.name);
        var parentKey = new EntityKey(invNp.parentType, [fkValue]);
        var parent = em.findEntityByKey(parentKey);

        if (parent) {
          if (invNp.isScalar) {
            parent.setProperty(invNp.name, entity);
          } else {
            if (em.isLoading) {
              parent.getProperty(invNp.name)._push(entity);
            } else {
              parent.getProperty(invNp.name).push(entity);
            }
          }
        } else {
          // else add parent to unresolvedParentMap;
          unattachedMap.addChild(parentKey, invNp, entity);
        }
      });
    });
  };

  // private fns

  // takes in entityTypes as either strings or entityTypes or arrays of either
  // and returns either an entityType or an array of entityTypes or throws an error
  function checkEntityTypes(em, entityTypes) {
    assertParam(entityTypes, "entityTypes").isString().isOptional().or().isNonEmptyArray().isString()
        .or().isInstanceOf(EntityType).or().isNonEmptyArray().isInstanceOf(EntityType).check();
    if (typeof entityTypes === "string") {
      entityTypes = em.metadataStore._getEntityType(entityTypes, false);
    } else if (Array.isArray(entityTypes) && typeof entityTypes[0] === "string") {
      entityTypes = entityTypes.map(function (etName) {
        return em.metadataStore._getEntityType(etName, false);
      });
    }
    return entityTypes;
  }

  function getChangesCore(em, entityTypes) {
    var entityGroups = getEntityGroups(em, entityTypes);

    // TODO: think about writing a core.mapMany method if we see more of these.
    var selected;
    entityGroups.forEach(function (eg) {
      // eg may be undefined or null
      if (!eg) return;
      var entities = eg.getChanges();
      if (selected && selected.length) {
        selected = selected.concat(entities);
      } else {
        selected = entities;
      }
    });
    return selected || [];
  }

  function getEntitiesCore(em, entityTypes, entityStates) {
    var entityGroups = getEntityGroups(em, entityTypes);

    // TODO: think about writing a core.mapMany method if we see more of these.
    var selected;
    entityGroups.forEach(function (eg) {
      // eg may be undefined or null
      if (!eg) return;
      var entities = eg.getEntities(entityStates);
      if (selected && selected.length) {
        selected = selected.concat(entities);
      } else {
        selected = entities;
      }
    });
    return selected || [];
  }

  function createEntityKey(em, args) {
    try {
      if (args[0] instanceof EntityKey) {
        return { entityKey: args[0], remainingArgs: __arraySlice(args, 1) };
      } else if (args.length >= 2) {
        var entityType = (typeof args[0] === 'string') ? em.metadataStore._getEntityType(args[0], false) : args[0];
        return { entityKey: new EntityKey(entityType, args[1]), remainingArgs: __arraySlice(args, 2) };
      }
    } catch (e) {/* throw below */
    }
    throw new Error("Must supply an EntityKey OR an EntityType name or EntityType followed by a key value or an array of key values.");
  }

  function markIsBeingSaved(entities, flag) {
    entities.forEach(function (entity) {
      entity.entityAspect.isBeingSaved = flag;
    });
  }

  function exportEntityGroups(em, entities) {
    var entityGroupMap;
    var first = entities && entities[0];
    if (first) {
      // group entities by entityType and
      // create 'groups' that look like entityGroups.
      entityGroupMap = {};
      if (first.entityType) {
        // assume "entities" is an array of entities;
        entities.forEach(function (e) {
          if (e.entityAspect.entityState == EntityState.Detached) {
            throw new Error("Unable to export an entity with an EntityState of 'Detached'");
          }
          var group = entityGroupMap[e.entityType.name];
          if (!group) {
            group = {};
            group.entityType = e.entityType;
            group._entities = [];
            entityGroupMap[e.entityType.name] = group;
          }
          group._entities.push(e);
        });
      } else {
        // assume "entities" is an array of EntityTypes (or names)
        var entityTypes = checkEntityTypes(em, entities)
        entityTypes.forEach(function(et){
          var group = em._entityGroupMap[et.name];
          if (group && group._entities.length) {
            entityGroupMap[et.name] = group;
          }
        })
      }
    } else if (entities && entities.length === 0) {
      // empty array = export nothing
      entityGroupMap = {};
    } else {
      entityGroupMap = em._entityGroupMap;
    }

    var tempKeys = [];
    var newGroupMap = {};
    __objectForEach(entityGroupMap, function (entityTypeName, entityGroup) {
      newGroupMap[entityTypeName] = exportEntityGroup(entityGroup, tempKeys);
    });

    return { entityGroupMap: newGroupMap, tempKeys: tempKeys };
  }

  function exportEntityGroup(entityGroup, tempKeys) {
    var resultGroup = {};
    var entityType = entityGroup.entityType;
    var dps = entityType.dataProperties;
    var serializerFn = getSerializerFn(entityType);
    var rawEntities = [];
    entityGroup._entities.forEach(function (entity) {
      if (entity) {
        var rawEntity = structuralObjectToJson(entity, dps, serializerFn, tempKeys);
        rawEntities.push(rawEntity);
      }
    });
    resultGroup.entities = rawEntities;
    return resultGroup;
  }

  function structuralObjectToJson(so, dps, serializerFn, tempKeys) {

    var result = {};
    dps.forEach(function (dp) {
      var dpName = dp.name;
      var value = so.getProperty(dpName);
      if (value == null && dp.defaultValue == null) return;

      if (value && dp.isComplexProperty) {
        var coDps = dp.dataType.dataProperties;
        value = __map(value, function (v) {
          return structuralObjectToJson(v, coDps, serializerFn);
        });
      } else {
        value = serializerFn ? serializerFn(dp, value) : value;
        if (dp.isUnmapped) {
          value = __toJSONSafe(value);
        }
      }
      if (value === undefined) return;
      result[dpName] = value;
    });
    var aspect, newAspect;
    if (so.entityAspect) {
      aspect = so.entityAspect;
      var entityState = aspect.entityState;
      newAspect = {
        tempNavPropNames: exportTempKeyInfo(aspect, tempKeys),
        entityState: entityState.name
      };
      if (aspect.extraMetadata) {
        newAspect.extraMetadata = aspect.extraMetadata;
      }
      if (entityState.isModified() || entityState.isDeleted()) {
        newAspect.originalValuesMap = aspect.originalValues;
      }
      result.entityAspect = newAspect;
    } else {
      aspect = so.complexAspect;
      newAspect = {};
      if (aspect.originalValues && !__isEmpty(aspect.originalValues)) {
        newAspect.originalValuesMap = aspect.originalValues;
      }

      result.complexAspect = newAspect;
    }

    return result;
  }

  function exportTempKeyInfo(entityAspect, tempKeys) {
    var entity = entityAspect.entity;
    if (entityAspect.hasTempKey) {
      tempKeys.push(entityAspect.getKey().toJSON());
    }
    // create map for this entity with foreignKeys that are 'temporary'
    // map -> key: tempKey, value: fkPropName
    var tempNavPropNames;
    entity.entityType.navigationProperties.forEach(function (np) {
      if (np.relatedDataProperties) {
        var relatedValue = entity.getProperty(np.name);
        if (relatedValue && relatedValue.entityAspect.hasTempKey) {
          tempNavPropNames = tempNavPropNames || [];
          tempNavPropNames.push(np.name);
        }
      }
    });
    return tempNavPropNames;
  }

  function importEntityGroup(entityGroup, jsonGroup, config) {

    var tempKeyMap = config.tempKeyMap;

    var entityType = entityGroup.entityType;
    var mergeStrategy = config.mergeStrategy;
    var mergeAdds = config.mergeAdds;

    var targetEntity = null;

    var em = entityGroup.entityManager;
    var entityChanged = em.entityChanged;
    var entitiesToLink = [];
    var rawValueFn = DataProperty.getRawValueFromClient;
    jsonGroup.entities.forEach(function (rawEntity) {
      var newAspect = rawEntity.entityAspect;

      var entityKey = entityType.getEntityKeyFromRawEntity(rawEntity, rawValueFn);
      var entityState = EntityState.fromName(newAspect.entityState);
      if (!entityState || entityState == EntityState.Detached ) {
        throw new Error("Only entities with a non detached entity state may be imported.");
      }

      // Merge if raw entity is in cache UNLESS this is a new entity w/ a temp key
      // Cannot safely merge such entities even if could match temp key to an entity in cache.
      // Can enable merge of entities w/temp key using "mergeAdds" - use at your own risk!
      var newTempKey = !mergeAdds && entityState.isAdded() && getMappedKey(tempKeyMap, entityKey);
      targetEntity = newTempKey ? null : entityGroup.findEntityByKey(entityKey);

      if (targetEntity) {
        if (mergeStrategy === MergeStrategy.SkipMerge) {
          // deliberate fall thru
        } else if (mergeStrategy === MergeStrategy.Disallowed) {
          throw new Error("A MergeStrategy of 'Disallowed' prevents " + entityKey.toString() + " from being merged");
        } else {
          var targetEntityState = targetEntity.entityAspect.entityState;
          var wasUnchanged = targetEntityState.isUnchanged();
          if (mergeStrategy === MergeStrategy.OverwriteChanges || wasUnchanged) {
            entityType._updateTargetFromRaw(targetEntity, rawEntity, rawValueFn);
            targetEntity.entityAspect.setEntityState(entityState);
            entityChanged.publish({ entityAction: EntityAction.MergeOnImport, entity: targetEntity });
          }
        }
      } else {
        targetEntity = entityType._createInstanceCore();
        entityType._updateTargetFromRaw(targetEntity, rawEntity, rawValueFn);
        if (newTempKey) {
          targetEntity.entityAspect.hasTempKey = true;
          // fixup pk
          targetEntity.setProperty(entityType.keyProperties[0].name, newTempKey.values[0]);

          // fixup foreign keys
          // This is safe because the entity is detached here and therefore originalValues will not be updated.
          if (newAspect.tempNavPropNames) {
            newAspect.tempNavPropNames.forEach(function (npName) {
              var np = entityType.getNavigationProperty(npName);
              var fkPropName = np.relatedDataProperties[0].name;
              var oldFkValue = targetEntity.getProperty(fkPropName);
              var fk = new EntityKey(np.entityType, [oldFkValue]);
              var newFk = getMappedKey(tempKeyMap, fk);
              targetEntity.setProperty(fkPropName, newFk.values[0]);
            });
          }
        }
        // Now performed in attachEntity
        targetEntity = entityGroup.attachEntity(targetEntity, entityState);
        entityChanged.publish({ entityAction: EntityAction.AttachOnImport, entity: targetEntity });
        if (!entityState.isUnchanged()) {
          em._notifyStateChange(targetEntity, true);
        }

      }

      entitiesToLink.push(targetEntity);
    });
    return entitiesToLink;
  }

  function getMappedKey(tempKeyMap, entityKey) {
    var newKey = tempKeyMap[entityKey.toString()];
    if (newKey) return newKey;
    var subtypes = entityKey._subtypes;
    if (!subtypes) return null;
    for (var i = 0, j = subtypes.length; i < j; i++) {
      newKey = tempKeyMap[entityKey.toString(subtypes[i])];
      if (newKey) return newKey;
    }
    return null;
  }

  function promiseWithCallbacks(promise, callback, errorCallback) {
    promise = promise.then(function (data) {
      if (callback) callback(data);
      return Q.resolve(data);
    }, function (error) {
      if (errorCallback) errorCallback(error);
      return Q.reject(error);
    });
    return promise;
  }

  function getEntitiesToSave(em, entities) {
    var entitiesToSave;
    if (entities) {
      entitiesToSave = entities.filter(function (e) {
        if (e.entityAspect.entityManager !== em) {
          throw new Error("Only entities in this entityManager may be saved");
        }
        return !e.entityAspect.entityState.isDetached();
      });
    } else {
      entitiesToSave = em.getChanges();
    }
    return entitiesToSave;
  }

  function fixupKeys(em, keyMappings) {
    em._inKeyFixup = true;
    keyMappings.forEach(function (km) {
      var group = em._entityGroupMap[km.entityTypeName];
      if (!group) {
        throw new Error("Unable to locate the following fully qualified EntityType name: " + km.entityTypeName);
      }
      group._fixupKey(km.tempValue, km.realValue);
    });
    em._inKeyFixup = false;
  }

  function getEntityGroups(em, entityTypes) {
    var groupMap = em._entityGroupMap;
    if (entityTypes) {
      return __toArray(entityTypes).map(function (et) {
        if (et instanceof EntityType) {
          return groupMap[et.name];
        } else {
          throw new Error("The EntityManager.getChanges() 'entityTypes' parameter must be either an entityType or an array of entityTypes or null");
        }
      });
    } else {
      return __getOwnPropertyValues(groupMap);
    }
  }

  function checkEntityKey(em, entity) {
    var ek = entity.entityAspect.getKey();
    // return properties that are = to defaultValues
    var keyPropsWithDefaultValues = __arrayZip(entity.entityType.keyProperties, ek.values, function (kp, kv) {
      return (kp.defaultValue === kv) ? kp : null;
    }).filter(function (kp) {
      return kp !== null;
    });
    if (keyPropsWithDefaultValues.length) {
      if (entity.entityType.autoGeneratedKeyType !== AutoGeneratedKeyType.None) {
        em.generateTempKeyValue(entity);
      } else {
        // we will allow attaches of entities where only part of the key is set.
        if (keyPropsWithDefaultValues.length === ek.values.length) {
          throw new Error("Cannot attach an object of type  (" + entity.entityType.name + ") to an EntityManager without first setting its key or setting its entityType 'AutoGeneratedKeyType' property to something other than 'None'");
        }
      }
    }
  }

  function validateEntityStates(em, entityStates) {
    if (!entityStates) return null;
    entityStates = __toArray(entityStates);
    entityStates.forEach(function (es) {
      if (!EntityState.contains(es)) {
        throw new Error("The EntityManager.getChanges() 'entityStates' parameter must either be null, an entityState or an array of entityStates");
      }
    });
    return entityStates;
  }

  proto._attachEntityCore = function (entity, entityState, mergeStrategy) {
    var group = findOrCreateEntityGroup(this, entity.entityType);
    var attachedEntity = group.attachEntity(entity, entityState, mergeStrategy);
    this._linkRelatedEntities(attachedEntity);
    return attachedEntity;
  }

  proto._updateFkVal = function (fkProp, oldValue, newValue) {
    var group = this._entityGroupMap[fkProp.parentType.name];
    if (!group) return;
    group._updateFkVal(fkProp, oldValue, newValue);
  }

  function attachRelatedEntities(em, entity, entityState, mergeStrategy) {
    var navProps = entity.entityType.navigationProperties;
    navProps.forEach(function (np) {
      var related = entity.getProperty(np.name);
      if (np.isScalar) {
        if (!related) return;
        em.attachEntity(related, entityState, mergeStrategy);
      } else {
        related.forEach(function (e) {
          em.attachEntity(e, entityState, mergeStrategy);
        });
      }
    });
  }

  // returns a promise
  function executeQueryCore(em, query, queryOptions, dataService) {
    try {
      var results;
      var metadataStore = em.metadataStore;

      if (metadataStore.isEmpty() && dataService.hasServerMetadata) {
        throw new Error("cannot execute _executeQueryCore until metadataStore is populated.");
      }

      if (queryOptions.fetchStrategy === FetchStrategy.FromLocalCache) {
        try {
          var qr = executeQueryLocallyCore(em, query);
          return Q.resolve({ results: qr.results, entityManager: em, inlineCount: qr.inlineCount, query: query });
        } catch (e) {
          return Q.reject(e);
        }
      }

      var mappingContext = new MappingContext({
        query: query,
        entityManager: em,
        dataService: dataService,
        mergeOptions: {
          mergeStrategy: queryOptions.mergeStrategy,
          noTracking: !!query.noTrackingEnabled,
          includeDeleted: queryOptions.includeDeleted
        }
      });

      var validateOnQuery = em.validationOptions.validateOnQuery;

      return dataService.adapterInstance.executeQuery(mappingContext).then(function (data) {
        var result = __wrapExecution(function () {
          var state = { isLoading: em.isLoading };
          em.isLoading = true;
          em._pendingPubs = [];
          return state;
        }, function (state) {
          // cleanup
          em.isLoading = state.isLoading;
          em._pendingPubs.forEach(function (fn) {
            fn();
          });
          em._pendingPubs = null;
          em._hasChangesAction && em._hasChangesAction();
          // HACK for GC
          query = null;
          mappingContext = null;
          // HACK: some errors thrown in next function do not propogate properly - this catches them.

          if (state.error) {
            Q.reject(state.error);
          }

        }, function () {
          var nodes = dataService.jsonResultsAdapter.extractResults(data);
          nodes = __toArray(nodes);

          results = mappingContext.visitAndMerge(nodes, { nodeType: "root" });
          if (validateOnQuery) {
            results.forEach(function (r) {
              // anon types and simple types will not have an entityAspect.
              r.entityAspect && r.entityAspect.validateEntity();
            });
          }
          mappingContext.processDeferred();
          // if query has expand clauses walk each of the 'results' and mark the expanded props as loaded.
          markLoadedNavProps(results, query);
          var retrievedEntities = __objectMap(mappingContext.refMap);
          return { results: results, query: query, entityManager: em, httpResponse: data.httpResponse, inlineCount: data.inlineCount, retrievedEntities: retrievedEntities };
        });
        return Q.resolve(result);
      }, function (e) {
        if (e) {
          e.query = query;
          e.entityManager = em;
        }
        return Q.reject(e);
      });

    } catch (e) {
      if (e) {
        e.query = query;
      }
      return Q.reject(e);
    }
  }

  function markLoadedNavProps(entities, query) {
    if (query.noTrackingEnabled) return;
    var expandClause = query.expandClause;
    if (expandClause == null) return;
    expandClause.propertyPaths.forEach(function (propertyPath) {
      var propNames = propertyPath.split('.');
      markLoadedNavPath(entities, propNames);
    });
  }

  function markLoadedNavPath(entities, propNames) {
    var propName = propNames[0];
    entities.forEach(function (entity) {
      var ea = entity.entityAspect;
      if (!ea) return; // entity may not be a 'real' entity in the case of a projection.
      ea._markAsLoaded(propName);
      if (propNames.length === 1) return;
      var next = entity.getProperty(propName);
      if (!next) return; // no children to process.
      // strange logic because nonscalar nav values are NOT really arrays
      // otherwise we could use Array.isArray
      if (!next.arrayChanged) next = [next];
      markLoadedNavPath(next, propNames.slice(1));
    });
  }

  function updateConcurrencyProperties(entities) {
    var candidates = entities.filter(function (e) {
      e.entityAspect.isBeingSaved = true;
      return e.entityAspect.entityState.isModified()
          && e.entityType.concurrencyProperties.length > 0;

    });
    if (candidates.length === 0) return;
    candidates.forEach(function (c) {
      c.entityType.concurrencyProperties.forEach(function (cp) {
        updateConcurrencyProperty(c, cp);
      });
    });
  }

  function updateConcurrencyProperty(entity, property) {
    // check if property has already been updated
    if (entity.entityAspect.originalValues[property.name]) return;
    var value = entity.getProperty(property.name);
    if (!value) value = property.dataType.defaultValue;
    if (property.dataType.isNumeric) {
      entity.setProperty(property.name, value + 1);
    } else if (property.dataType.getConcurrencyValue) {
      // DataType has its own implementation
      var nextValue = property.dataType.getConcurrencyValue(value);
      entity.setProperty(property.name, nextValue);
    } else if (property.dataType === DataType.Binary) {
      // best guess - that this is a timestamp column and is computed on the server during save
      // - so no need to set it here.
      return;
    } else {
      // this just leaves DataTypes of Boolean, String and Byte - none of which should be the
      // type for a concurrency column.
      // NOTE: thought about just returning here but would rather be safe for now.
      throw new Error("Unable to update the value of concurrency property before saving: " + property.name);
    }
  }


  function findOrCreateEntityGroup(em, entityType) {
    var group = em._entityGroupMap[entityType.name];
    if (!group) {
      group = new EntityGroup(em, entityType);
      em._entityGroupMap[entityType.name] = group;
    }
    return group;
  }

  function findOrCreateEntityGroups(em, entityType) {
    var entityTypes = entityType.getSelfAndSubtypes();
    return entityTypes.map(function (et) {
      return findOrCreateEntityGroup(em, et);
    });
  }


  proto.helper = {
    unwrapInstance: unwrapInstance,
    unwrapOriginalValues: unwrapOriginalValues,
    unwrapChangedValues: unwrapChangedValues
  };


  function unwrapInstance(structObj, transformFn) {

    var rawObject = {};
    var stype = structObj.entityType || structObj.complexType;
    var serializerFn = getSerializerFn(stype);
    var unmapped = {};
    stype.dataProperties.forEach(function (dp) {
      if (dp.isComplexProperty) {
        rawObject[dp.nameOnServer] = __map(structObj.getProperty(dp.name), function (co) {
          return unwrapInstance(co, transformFn);
        });
      } else {
        var val = structObj.getProperty(dp.name);
        val = transformFn ? transformFn(dp, val) : val;
        if (val === undefined) return;
        val = serializerFn ? serializerFn(dp, val) : val;
        if (val !== undefined) {
          if (dp.isUnmapped) {
            unmapped[dp.nameOnServer] = __toJSONSafe(val);
          } else {
            rawObject[dp.nameOnServer] = val;
          }
        }
      }
    });

    if (!__isEmpty(unmapped)) {
      rawObject.__unmapped = unmapped;
    }
    return rawObject;
  }

  function unwrapOriginalValues(target, metadataStore, transformFn) {
    var stype = target.entityType || target.complexType;
    var aspect = target.entityAspect || target.complexAspect;
    var fn = metadataStore.namingConvention.clientPropertyNameToServer;
    var result = {};
    __objectForEach(aspect.originalValues, function (propName, val) {
      var prop = stype.getProperty(propName);
      val = transformFn ? transformFn(prop, val) : val;
      if (val !== undefined) {
        result[fn(propName, prop)] = val;
      }
    });
    stype.complexProperties.forEach(function (cp) {
      var nextTarget = target.getProperty(cp.name);
      if (cp.isScalar) {
        var unwrappedCo = unwrapOriginalValues(nextTarget, metadataStore, transformFn);
        if (!__isEmpty(unwrappedCo)) {
          result[fn(cp.name, cp)] = unwrappedCo;
        }
      } else {
        var unwrappedCos = nextTarget.map(function (item) {
          return unwrapOriginalValues(item, metadataStore, transformFn);
        });
        result[fn(cp.name, cp)] = unwrappedCos;
      }
    });
    return result;
  }

  function unwrapChangedValues(entity, metadataStore, transformFn) {
    var stype = entity.entityType;
    var serializerFn = getSerializerFn(stype);
    var fn = metadataStore.namingConvention.clientPropertyNameToServer;
    var result = {};
    __objectForEach(entity.entityAspect.originalValues, function (propName, value) {
      var prop = stype.getProperty(propName);
      var val = entity.getProperty(propName);
      val = transformFn ? transformFn(prop, val) : val;
      if (val === undefined) return;
      val = serializerFn ? serializerFn(prop, val) : val;
      if (val !== undefined) {
        result[fn(propName, prop)] = val;
      }
    });
    // any change to any complex object or array of complex objects returns the ENTIRE
    // current complex object or complex object array.  This is by design. Complex Objects
    // are atomic.
    stype.complexProperties.forEach(function (cp) {
      if (cpHasOriginalValues(entity, cp)) {
        var coOrCos = entity.getProperty(cp.name);
        result[fn(cp.name, cp)] = __map(coOrCos, function (co) {
          return unwrapInstance(co, transformFn);
        });
      }
    });
    return result;
  }

  function cpHasOriginalValues(structuralObject, cp) {
    var coOrCos = structuralObject.getProperty(cp.name);
    if (cp.isScalar) {
      return coHasOriginalValues(coOrCos);
    } else {
      // this occurs when a nonscalar co array has had cos added or removed.
      if (coOrCos._origValues) return true;
      return coOrCos.some(function (co) {
        return coHasOriginalValues(co);
      });
    }
  }

  function coHasOriginalValues(co) {
    // next line checks all non complex properties of the co.
    if (!__isEmpty(co.complexAspect.originalValues)) return true;
    // now need to recursively check each of the cps
    return co.complexType.complexProperties.some(function (cp) {
      return cpHasOriginalValues(co, cp);
    });
  }

  function getSerializerFn(stype) {
    return stype.serializerFn || (stype.metadataStore && stype.metadataStore.serializerFn);
  }


  function UnattachedChildrenMap() {
    // key is EntityKey.toString(), value is array of { navigationProperty, children }
    this.map = {};
  }

  UnattachedChildrenMap.prototype.addChild = function (parentEntityKey, navigationProperty, child) {
    var tuple = this.getTuple(parentEntityKey, navigationProperty);
    if (!tuple) {
      tuple = { navigationProperty: navigationProperty, children: [] };
      __getArray(this.map, parentEntityKey.toString()).push(tuple);
    }
    tuple.children.push(child);
  };

  // UnattachedChildrenMap.prototype.removeChildren = function (parentEntityKey, navigationProperty) {
  //   var tuples = this.getTuples(parentEntityKey);
  //   if (!tuples) return;
  //   __arrayRemoveItem(tuples, function (t) {
  //     return t.navigationProperty === navigationProperty;
  //   });
  //   if (!tuples.length) {
  //     delete this.map[parentEntityKey.toString()];
  //   }
  // };

  UnattachedChildrenMap.prototype.removeChildrenByString = function (parentEntityKeyString, navigationProperty) {
    var tuples = this.map[parentEntityKeyString];
    if (!tuples) return;
    __arrayRemoveItem(tuples, function (t) {
      return t.navigationProperty === navigationProperty;
    });
    if (!tuples.length) {
      delete this.map[parentEntityKeyString];
    }
  };

  // UnattachedChildrenMap.prototype.getChildren = function (parentEntityKey, navigationProperty) {
  //   var tuple = this.getTuple(parentEntityKey, navigationProperty);
  //   if (tuple) {
  //     return tuple.children.filter(function (child) {
  //       // it may have later been detached.
  //       return !child.entityAspect.entityState.isDetached();
  //     });
  //   } else {
  //     return null;
  //   }
  // };

  UnattachedChildrenMap.prototype.getTuple = function (parentEntityKey, navigationProperty) {
    var tuples = this.getTuples(parentEntityKey);
    if (!tuples) return null;
    var tuple = __arrayFirst(tuples, function (t) {
      return t.navigationProperty === navigationProperty;
    });
    return tuple;
  };


  UnattachedChildrenMap.prototype.getTuples = function (parentEntityKey) {
    var allTuples = [];
    var tuples = this.map[parentEntityKey.toString()];
    if (tuples) {
      allTuples = allTuples.concat(tuples);
    }
    var entityType = parentEntityKey.entityType;
    while (entityType.baseEntityType) {
      entityType = entityType.baseEntityType;
      var baseKey = parentEntityKey.toString(entityType);
      tuples = this.map[baseKey];
      if (tuples) {
        allTuples = allTuples.concat(tuples);
      }
    }
    return (allTuples.length) ? allTuples : undefined;
  };

  UnattachedChildrenMap.prototype.getTuplesByString = function (parentEntityKeyString) {
    return this.map[parentEntityKeyString];
  };

  return ctor;
})();


// expose
breeze.EntityManager = EntityManager;

;/**
 @module breeze
 **/

// Internal helper class

var MappingContext = (function () {

  var ctor = function MappingContext(config) {

    __extend(this, config, [
      "query", "entityManager", "dataService", "mergeOptions"
    ]);

    // calc'd props
    this.refMap = {};
    this.deferredFns = [];
    this.jsonResultsAdapter = this.dataService.jsonResultsAdapter;
    this.metadataStore = this.entityManager.metadataStore;
    this.rawValueFn = DataProperty.getRawValueFromServer; // think about passing this in later.
  };

  var proto = ctor.prototype;
  var parseRawValue = DataType.parseRawValue;
  proto._$typeName = "MappingContext";

  proto.getUrl = function () {
    var query = this.query;
    if (!query) {
      throw new Error("query cannot be empty");
    }
    var uriString;
    if (typeof query === 'string') {
      uriString = query;
    } else if (query instanceof EntityQuery) {
      uriString = this.dataService.uriBuilder.buildUri(query, this.metadataStore);
    } else {
      throw new Error("unable to recognize query parameter as either a string or an EntityQuery");
    }
    return  this.dataService.qualifyUrl(uriString);
  }

  proto.visitAndMerge = function (nodes, nodeContext) {
    var query = this.query;
    var jra = this.jsonResultsAdapter;
    nodeContext = nodeContext || {};
    var that = this;
    return __map(nodes, function (node) {
      if (query == null && node.entityAspect) {
        // don't bother merging a result from a save that was not returned from the server.
        if (node.entityAspect.entityState.isDeleted()) {
          that.entityManager.detachEntity(node);
        } else {
          node.entityAspect.acceptChanges();
        }
        return node;
      }

      var meta = jra.visitNode(node, that, nodeContext) || {};
      node = meta.node || node;
      if (query && nodeContext.nodeType === "root" && !meta.entityType) {
        meta.entityType = query._getToEntityType && query._getToEntityType(that.metadataStore);
      }
      return processMeta(that, node, meta);
    }, this.mergeOptions.includeDeleted);
  };

  proto.processDeferred = function () {
    if (this.deferredFns.length > 0) {
      this.deferredFns.forEach(function (fn) {
        fn();
      });
    }
  }

  function processMeta(mc, node, meta, assignFn) {
    // == is deliberate here instead of ===
    if (meta.ignore || node == null) {
      return null;
    } else if (meta.nodeRefId) {
      var refValue = resolveEntityRef(mc, meta.nodeRefId);
      if (typeof refValue === "function" && assignFn != null) {
        mc.deferredFns.push(function () {
          assignFn(refValue);
        });
        return undefined; // deferred and will be set later;
      }
      return refValue;
    } else if (meta.entityType) {
      var entityType = meta.entityType;
      if (mc.mergeOptions.noTracking) {
        node = processNoMerge(mc, entityType, node);
        if (entityType.noTrackingFn) {
          node = entityType.noTrackingFn(node, entityType);
        }
        if (meta.nodeId) {
          mc.refMap[meta.nodeId] = node;
        }
        return node;
      } else {
        if (entityType.isComplexType) {
          // because we still need to do serverName to client name processing
          return processNoMerge(mc, entityType, node);
        } else {
          return mergeEntity(mc, node, meta);
        }
      }
    } else {

      if ((!meta.passThru) && typeof node === 'object' && !__isDate(node)) {
        node = processAnonType(mc, node);
      }

      // updating the refMap for entities is handled by updateEntityRef for entities.
      if (meta.nodeId) {
        mc.refMap[meta.nodeId] = node;
      }
      return node;
    }
  }

  function processNoMerge(mc, stype, node) {
    var result = {};

    stype.dataProperties.forEach(function (dp) {
      if (dp.isComplexProperty) {
        result[dp.name] = __map(node[dp.nameOnServer], function (v) {
          return processNoMerge(mc, dp.dataType, v);
        });
      } else {
        result[dp.name] = parseRawValue(node[dp.nameOnServer], dp.dataType);
      }
    });

    stype.navigationProperties && stype.navigationProperties.forEach(function (np) {
      var nodeContext = { nodeType: "navProp", navigationProperty: np };
      visitNode(node[np.nameOnServer], mc, nodeContext, result, np.name);
    });

    return result;
  }

  function processAnonType(mc, node) {
    // node is guaranteed to be an object by this point, i.e. not a scalar
    var keyFn = mc.metadataStore.namingConvention.serverPropertyNameToClient;
    var result = {};

    __objectForEach(node, function (key, value) {
      var newKey = keyFn(key);
      var nodeContext = { nodeType: "anonProp", propertyName: newKey };
      visitNode(value, mc, nodeContext, result, newKey);
    });
    return result;
  }

  function visitNode(node, mc, nodeContext, result, key) {
    var jra = mc.jsonResultsAdapter;
    var meta = jra.visitNode(node, mc, nodeContext) || {};
    // allows visitNode to change the value;
    node = meta.node || node;

    if (meta.ignore) return;
    if (meta.passThru) return node;
    if (Array.isArray(node)) {
      nodeContext.nodeType = nodeContext.nodeType + "Item";
      result[key] = node.map(function (v, ix) {
        meta = jra.visitNode(v, mc, nodeContext) || {};
        v = meta.node || v;
        return processMeta(mc, v, meta, function (refValue) {
          result[key][ix] = refValue();
        });
      });
    } else {
      result[key] = processMeta(mc, node, meta, function (refValue) {
        result[key] = refValue();
      });
    }
  }

  function resolveEntityRef(mc, nodeRefId) {
    var entity = mc.refMap[nodeRefId];
    if (entity === undefined) {
      return function () {
        return mc.refMap[nodeRefId];
      };
    } else {
      return entity;
    }
  }

  function updateEntityRef(mc, targetEntity, node) {
    var nodeId = node._$meta.nodeId;
    if (!nodeId && node._$meta.extraMetadata) {
      // odata case.  refMap isn't really used, but is returned as data.retrievedEntities, so we populated it anyway.
      nodeId = node._$meta.extraMetadata.uriKey;
    }
    if (nodeId != null) {
      mc.refMap[nodeId] = targetEntity;
    }
  }

  // can return null for a deleted entity if includeDeleted == false
  function mergeEntity(mc, node, meta) {
    node._$meta = meta;
    var em = mc.entityManager;

    var entityType = meta.entityType;
    if (typeof (entityType) === 'string') {
      entityType = mc.metadataStore._getEntityType(entityType, false);
    }
    node.entityType = entityType;

    var mergeStrategy = mc.mergeOptions.mergeStrategy;
    var isSaving = mc.query == null;

    var entityKey = entityType.getEntityKeyFromRawEntity(node, mc.rawValueFn);
    var targetEntity = em.findEntityByKey(entityKey);
    if (targetEntity) {
      if (isSaving && targetEntity.entityAspect.entityState.isDeleted()) {
        em.detachEntity(targetEntity);
        return targetEntity;
      }
      var targetEntityState = targetEntity.entityAspect.entityState;
      if (mergeStrategy === MergeStrategy.Disallowed) {
        throw new Error("A MergeStrategy of 'Disallowed' prevents " + entityKey.toString() + " from being merged");
      } else if (mergeStrategy === MergeStrategy.SkipMerge) {
        updateEntityNoMerge(mc, targetEntity, node);
      } else {
        if (mergeStrategy === MergeStrategy.OverwriteChanges
            || targetEntityState.isUnchanged()) {
          updateEntity(mc, targetEntity, node);
          targetEntity.entityAspect.wasLoaded = true;
          if (meta.extraMetadata) {
            targetEntity.entityAspect.extraMetadata = meta.extraMetadata;
          }
          targetEntity.entityAspect.entityState = EntityState.Unchanged;
          clearOriginalValues(targetEntity);
          targetEntity.entityAspect.propertyChanged.publish({ entity: targetEntity, propertyName: null });
          var action = isSaving ? EntityAction.MergeOnSave : EntityAction.MergeOnQuery;
          em.entityChanged.publish({ entityAction: action, entity: targetEntity });
          // this is needed to handle an overwrite of a modified entity with an unchanged entity
          // which might in turn cause _hasChanges to change.
          if (!targetEntityState.isUnchanged()) {
            em._notifyStateChange(targetEntity, false);
          }
        } else {
          if (targetEntityState == EntityState.Deleted && !mc.mergeOptions.includeDeleted) {
            return null;
          }
          updateEntityNoMerge(mc, targetEntity, node);
        }
      }
    } else {
      targetEntity = entityType._createInstanceCore();

      updateEntity(mc, targetEntity, node);

      if (meta.extraMetadata) {
        targetEntity.entityAspect.extraMetadata = meta.extraMetadata;
      }
      // em._attachEntityCore(targetEntity, EntityState.Unchanged, MergeStrategy.Disallowed);
      em._attachEntityCore(targetEntity, EntityState.Unchanged, mergeStrategy);
      targetEntity.entityAspect.wasLoaded = true;
      em.entityChanged.publish({ entityAction: EntityAction.AttachOnQuery, entity: targetEntity });
    }
    return targetEntity;
  }

  // copied from entityAspect
  function clearOriginalValues(target) {
    var aspect = target.entityAspect || target.complexAspect;
    aspect.originalValues = {};
    var stype = target.entityType || target.complexType;
    stype.complexProperties.forEach(function (cp) {
      var cos = target.getProperty(cp.name);
      if (cp.isScalar) {
        clearOriginalValues(cos);
      } else {
        cos._acceptChanges();
        cos.forEach(clearOriginalValues);
      }
    });
  }

  function updateEntityNoMerge(mc, targetEntity, node) {
    updateEntityRef(mc, targetEntity, node);
    // we still need to merge related entities even if top level entity wasn't modified.
    node.entityType.navigationProperties.forEach(function (np) {
      if (np.isScalar) {
        mergeRelatedEntityCore(mc, node, np);
      } else {
        mergeRelatedEntitiesCore(mc, node, np);
      }
    });
  }

  function updateEntity(mc, targetEntity, node) {
    updateEntityRef(mc, targetEntity, node);
    var entityType = targetEntity.entityType;
    entityType._updateTargetFromRaw(targetEntity, node, mc.rawValueFn);

    entityType.navigationProperties.forEach(function (np) {
      if (np.isScalar) {
        mergeRelatedEntity(mc, np, targetEntity, node);
      } else {
        mergeRelatedEntities(mc, np, targetEntity, node);
      }
    });
  }

  function mergeRelatedEntity(mc, navigationProperty, targetEntity, rawEntity) {

    var relatedEntity = mergeRelatedEntityCore(mc, rawEntity, navigationProperty);
    if (relatedEntity == null) return;
    if (typeof relatedEntity === 'function') {
      mc.deferredFns.push(function () {
        relatedEntity = relatedEntity();
        updateRelatedEntity(relatedEntity, targetEntity, navigationProperty);
      });
    } else {
      updateRelatedEntity(relatedEntity, targetEntity, navigationProperty);
    }
  }

  function mergeRelatedEntities(mc, navigationProperty, targetEntity, rawEntity) {
    var relatedEntities = mergeRelatedEntitiesCore(mc, rawEntity, navigationProperty);
    if (relatedEntities == null) return;

    var inverseProperty = navigationProperty.getInverse();
    if (!inverseProperty) return;

    var originalRelatedEntities = targetEntity.getProperty(navigationProperty.name);
    originalRelatedEntities.wasLoaded = true;

    relatedEntities.forEach(function (relatedEntity) {
      if (typeof relatedEntity === 'function') {
        mc.deferredFns.push(function () {
          relatedEntity = relatedEntity();
          updateRelatedEntityInCollection(mc, relatedEntity, originalRelatedEntities, targetEntity, inverseProperty);
        });
      } else {
        updateRelatedEntityInCollection(mc, relatedEntity, originalRelatedEntities, targetEntity, inverseProperty);
      }
    });
  }

  function mergeRelatedEntityCore(mc, rawEntity, navigationProperty) {
    var relatedRawEntity = rawEntity[navigationProperty.nameOnServer];
    if (!relatedRawEntity) return null;

    var relatedEntity = mc.visitAndMerge(relatedRawEntity, { nodeType: "navProp", navigationProperty: navigationProperty });
    return relatedEntity;
  }

  function mergeRelatedEntitiesCore(mc, rawEntity, navigationProperty) {
    var relatedRawEntities = rawEntity[navigationProperty.nameOnServer];
    if (!relatedRawEntities) return null;

    // needed if what is returned is not an array and we expect one - this happens with __deferred in OData.
    if (!Array.isArray(relatedRawEntities)) {
      // return null;
      relatedRawEntities = relatedRawEntities.results; // OData v3 will look like this with an expand
      if (!relatedRawEntities) {
        return null;
      }
    }

    var relatedEntities = mc.visitAndMerge(relatedRawEntities, { nodeType: "navPropItem", navigationProperty: navigationProperty });
    return relatedEntities;
  }

  function updateRelatedEntity(relatedEntity, targetEntity, navigationProperty) {
    if (!relatedEntity) return;
    var propName = navigationProperty.name;
    var currentRelatedEntity = targetEntity.getProperty(propName);

    // check if the related entity is already hooked up
    if (currentRelatedEntity !== relatedEntity) {
      // if not hook up both directions.
      targetEntity.setProperty(propName, relatedEntity);
      var inverseProperty = navigationProperty.getInverse();
      if (!inverseProperty) return;
      if (inverseProperty.isScalar) {
        relatedEntity.setProperty(inverseProperty.name, targetEntity);
      } else {
        var collection = relatedEntity.getProperty(inverseProperty.name);
        collection.push(targetEntity);

      }
    }
  }

  function updateRelatedEntityInCollection(mc, relatedEntity, relatedEntities, targetEntity, inverseProperty) {
    if (!relatedEntity) return;

    // don't update relatedCollection if preserveChanges & relatedEntity has an fkChange.
    if (relatedEntity.entityAspect.entityState === EntityState.Modified
      && mc.mergeOptions.mergeStrategy === MergeStrategy.PreserveChanges) {
      var origValues = relatedEntity.entityAspect.originalValues;
      var fkWasModified = inverseProperty.relatedDataProperties.some(function(dp) {
        return origValues[dp.name] != undefined;
      });
      if (fkWasModified) return;
    }
    // check if the related entity is already hooked up
    var thisEntity = relatedEntity.getProperty(inverseProperty.name);

    if (thisEntity !== targetEntity) {
      // if not - hook it up.
      relatedEntities.push(relatedEntity);
      relatedEntity.setProperty(inverseProperty.name, targetEntity);
    }
  }


  return ctor;
})();
   


;/**
@module breeze
**/

var SaveOptions = (function () {
  /**
  A SaveOptions instance is used to specify the 'options' under which a save will occur.

  @class SaveOptions
  **/

  /**
  @method <ctor> SaveOptions
  @param config {Object}
  @param [config.allowConcurrentSaves] {Boolean} Whether multiple saves can be in-flight at the same time. The default is false.
  @param [config.resourceName] {String} Resource name to be used during the save - this defaults to "SaveChanges"
  @param [config.dataService] {DataService} The DataService to be used for this save.
  @param [config.tag] {Object} Free form value that will be sent to the server during the save.
  **/
  var ctor = function SaveOptions(config) {
    updateWithConfig(this, config);
  };

  var proto = ctor.prototype;
  proto._$typeName = "SaveOptions";

  /**
  Sets the 'defaultInstance' by creating a copy of the current 'defaultInstance' and then applying all of the properties of the current instance.
  The current instance is returned unchanged.
  @method setAsDefault
  @chainable
  **/
  proto.setAsDefault = function () {
    return __setAsDefault(this, ctor);
  };

  /**
  Whether another save can be occuring at the same time as this one - default is false.

  __readOnly__
  @property allowConcurrentSaves {Boolean}
  **/

  /**
  A {{#crossLink "DataService"}}{{/crossLink}}.
  __readOnly__
  @property dataService {DataService}
  **/

  /**
  The resource name to call to perform the save.
  __readOnly__
  @property resourceName {String}
  **/

  /**
  A free form value that will be sent to the server.

  __readOnly__
  @property tag {Object}
  **/

  /**
  The default value whenever SaveOptions are not specified.
  @property defaultInstance {SaveOptions}
  @static
  **/

  /**
  Returns a copy of this SaveOptions with the specified config options applied.
  @example
      var saveOptions = em1.saveOptions.using( {resourceName: "anotherResource" });

  @method using
  @param config {Configuration Object|} The object to apply to create a new SaveOptions.
  @param [config.allowConcurrentSaves] {Boolean} Whether multiple saves can be in-flight at the same time. The default is false.
  @param [config.resourceName] {String} Resource name to be used during the save - this defaults to "SaveChanges"
  @param [config.dataService] {DataService} The DataService to be used for this save.
  @param [config.tag] {Object} Free form value that will be sent to the server during the save.
  @chainable
  **/
  proto.using = function (config) {
    return updateWithConfig(this, config);
  };

  function updateWithConfig(obj, config) {
    if (config) {
      assertConfig(config)
          .whereParam("resourceName").isOptional().isString()
          .whereParam("dataService").isOptional().isInstanceOf(DataService)
          .whereParam("allowConcurrentSaves").isBoolean().isOptional()
          .whereParam("tag").isOptional()
          .applyAll(obj);
    }
    return obj;
  }

  ctor.defaultInstance = new ctor({ allowConcurrentSaves: false});
  return ctor;
})();

breeze.SaveOptions = SaveOptions;


;breeze.AbstractDataServiceAdapter = (function () {

  var ajaxImpl;

  var ctor = function () {
  };

  var proto = ctor.prototype; // minifies better (as seen in jQuery)

  proto.checkForRecomposition = function (interfaceInitializedArgs) {
    if (interfaceInitializedArgs.interfaceName === "ajax" && interfaceInitializedArgs.isDefault) {
      this.initialize();
    }
  };

  proto.initialize = function () {
    ajaxImpl = breeze.config.getAdapterInstance("ajax");

    // don't cache 'ajax' because then we would need to ".bind" it, and don't want to because of brower support issues.
    if (ajaxImpl && ajaxImpl.ajax) {
      return;
    }
    throw new Error("Unable to find ajax adapter for dataservice adapter '" + (this.name || '') + "'.");
  };

  proto.fetchMetadata = function (metadataStore, dataService) {
    var serviceName = dataService.serviceName;
    var url = dataService.qualifyUrl("Metadata");

    var deferred = Q.defer();

    ajaxImpl.ajax({
      type: "GET",
      url: url,
      dataType: 'json',
      success: function (httpResponse) {

        // might have been fetched by another query
        if (metadataStore.hasMetadataFor(serviceName)) {
          return deferred.resolve("already fetched");
        }
        var data = httpResponse.data;
        try {
          var metadata = typeof (data) === "string" ? JSON.parse(data) : data;
          metadataStore.importMetadata(metadata);
        } catch (e) {
          var errMsg = "Unable to either parse or import metadata: " + e.message;
          return handleHttpError(deferred, httpResponse, "Metadata query failed for: " + url + ". " + errMsg);
        }

        // import may have brought in the service.
        if (!metadataStore.hasMetadataFor(serviceName)) {
          metadataStore.addDataService(dataService);
        }

        return deferred.resolve(metadata);

      },
      error: function (httpResponse) {
        handleHttpError(deferred, httpResponse, "Metadata query failed for: " + url);
      }
    });
    return deferred.promise;
  };

  proto.executeQuery = function (mappingContext) {
    var adapter = mappingContext.adapter = this;
    var deferred = Q.defer();
    var url = mappingContext.getUrl();

    var params = {
      type: "GET",
      url: url,
      params: mappingContext.query.parameters,
      dataType: 'json',
      success: function (httpResponse) {
        var data = httpResponse.data;
        try {
          var rData;
          var results = data && (data.results || data.Results);
          if (results) {
            rData = { results: results, inlineCount: data.inlineCount || data.InlineCount, httpResponse: httpResponse };
          } else {
            rData = { results: data, httpResponse: httpResponse };
          }

          deferred.resolve(rData);
        } catch (e) {
          if (e instanceof Error) {
            deferred.reject(e);
          } else {
            handleHttpError(deferred, httpResponse);
          }
        }

      },
      error: function (httpResponse) {
        handleHttpError(deferred, httpResponse);
      }
    };
    if (mappingContext.dataService.useJsonp) {
      params.dataType = 'jsonp';
      params.crossDomain = true;
    }
    ajaxImpl.ajax(params);
    return deferred.promise;
  };

  proto.saveChanges = function (saveContext, saveBundle) {
    var adapter = saveContext.adapter = this;
    var deferred = Q.defer();
    saveBundle = adapter._prepareSaveBundle(saveContext, saveBundle);
    /* HS modifications start */
    /* Implement a workaround for JSON stringify circular reference error.
     Need to go to jscompress.com and create breeze.min.js from this modified file */
    //var bundle = JSON.stringify(saveBundle);

    var cache = [];
    var bundle = JSON.stringify(saveBundle, function (key, value) {
        if (typeof value === 'object' && value !== null) {
            if (cache.indexOf(value) !== -1) {
                // Circular reference found, discard key
                return;
            }
            // Store value in our collection
            cache.push(value);
        }
        return value;
    });
    cache = null; // Enable garbage collection
    /* HS modifications end */

    var url = saveContext.dataService.qualifyUrl(saveContext.resourceName);

    ajaxImpl.ajax({
      type: "POST",
      url: url,
      dataType: 'json',
      contentType: "application/json",
      data: bundle,
      success: function (httpResponse) {
        httpResponse.saveContext = saveContext;
        var data = httpResponse.data;
        if (data.Errors || data.errors) {
          handleHttpError(deferred, httpResponse);
        } else {
          var saveResult = adapter._prepareSaveResult(saveContext, data);
          saveResult.httpResponse = httpResponse;
          deferred.resolve(saveResult);
        }
      },
      error: function (httpResponse) {
        httpResponse.saveContext = saveContext;
        handleHttpError(deferred, httpResponse);
      }
    });

    return deferred.promise;
  };

  proto._prepareSaveBundle = function (/*saveContext, saveBundle*/) {
    // The implementor should call _createChangeRequestInterceptor
    throw new Error("Need a concrete implementation of _prepareSaveBundle");
  };

  /**
   Returns a constructor function for a "ChangeRequestInterceptor"
   that can tweak the saveBundle both as it is built and when it is completed
   by a concrete DataServiceAdapater.

   Initialized with a default, no-op implementation that developers can replace with a
   substantive implementation that changes the individual entity change requests
   or aspects of the entire 'saveBundle' without having to write their own DataService adapters.

   @example
   var adapter = breeze.config.getAdapterInstance('dataService');
   adapter.changeRequestInterceptor = function (saveContext, saveBundle) {
        this.getRequest = function (request, entity, index) {
            // alter the request that the adapter prepared for this entity
            // based on the entity, saveContext, and saveBundle
            // e.g., add a custom header or prune the originalValuesMap
            return request;
        };
        this.done = function (requests) {
            // alter the array of requests representing the entire change-set
            // based on the saveContext and saveBundle
        };
    }
   @method changeRequestInterceptor
   @param saveContext {Object} The BreezeJS "context" for the save operation.
   @param saveBundle {Object} Contains the array of entities-to-be-saved (AKA, the entity change-set).
   @return {Function} Constructor for a "ChangeRequestInterceptor".
   **/
  proto.changeRequestInterceptor = DefaultChangeRequestInterceptor;

  //This is a default, no-op implementation that developers can replace.
  function DefaultChangeRequestInterceptor(saveContext, saveBundle) {
    /**
     Prepare and return the save data for an entity change-set.

     The adapter calls this method for each entity in the change-set,
     after it has prepared a "change request" for that object.

     The method can do anything to the request but it must return a valid, non-null request.
     @example
     this.getRequest = function (request, entity, index) {
            // alter the request that the adapter prepared for this entity
            // based on the entity, saveContext, and saveBundle
            // e.g., add a custom header or prune the originalValuesMap
            return request;
        };
     @method getRequest
     @param request {Object} The object representing the adapter's request to save this entity.
     @param entity {Entity} The entity-to-be-save as it is in cache
     @param index {Integer} The zero-based index of this entity in the change-set array
     @return {Function} The potentially revised request.
     **/
    this.getRequest = function (request, entity, index) {
      return request;
    };

    /**
     Last chance to change anything about the 'requests' array
     after it has been built with requests for all of the entities-to-be-saved.

     The 'requests' array is the same as 'saveBundle.entities' in many implementations

     This method can do anything to the array including add and remove requests.
     It's up to you to ensure that server will accept the requests array data as valid.

     Returned value is ignored.
     @example
     this.done = function (requests) {
            // alter the array of requests representing the entire change-set
            // based on the saveContext and saveBundle
        };
     @method done
     @param requests {Array of Object} The adapter's array of request for this changeset.
     **/
    this.done = function (requests) {
    };
  }

  proto._createChangeRequestInterceptor = function (saveContext, saveBundle) {
    var adapter = saveContext.adapter;
    var cri = adapter.changeRequestInterceptor;
    var isFn = __isFunction;

    if (isFn(cri)) {
      var pre = adapter.name + " DataServiceAdapter's ChangeRequestInterceptor";
      var post = " is missing or not a function.";
      var interceptor = new cri(saveContext, saveBundle);
      if (!isFn(interceptor.getRequest)) {
        throw new Error(pre + '.getRequest' + post);
      }
      if (!isFn(interceptor.done)) {
        throw new Error(pre + '.done' + post);
      }
      return interceptor;
    } else {
      return new DefaultChangeRequestInterceptor(saveContext, saveBundle);
    }
  }

  proto._prepareSaveResult = function (/* saveContext, data */) {
    throw new Error("Need a concrete implementation of _prepareSaveResult");
  };

  proto.jsonResultsAdapter = new JsonResultsAdapter({
    name: "noop",

    visitNode: function (/* node, mappingContext, nodeContext */) {
      return {};
    }

  });

  function handleHttpError(deferred, httpResponse, messagePrefix) {
    var err = createError(httpResponse);
    proto._catchNoConnectionError(err);
    if (messagePrefix) {
      err.message = messagePrefix + "; " + err.message;
    }
    return deferred.reject(err);
  }


  function createError(httpResponse) {
    var err = new Error();
    err.httpResponse = httpResponse;
    err.status = httpResponse.status;

    var errObj = httpResponse.data;

    if (!errObj) {
      err.message = httpResponse.error && httpResponse.error.toString();
      return err;
    }

    // some ajax providers will convert errant result into an object ( angular), others will not (jQuery)
    // if not do it here.
    if (typeof errObj === "string") {
      try {
        errObj = JSON.parse(errObj);
      } catch (e) {
        // sometimes httpResponse.data is just the error message itself
        err.message = errObj;
        return err;
      }
    }

    var saveContext = httpResponse.saveContext;

    // if any of the follow properties exist the source is .NET
    var tmp = errObj.Message || errObj.ExceptionMessage || errObj.EntityErrors || errObj.Errors;
    var isDotNet = !!tmp;
    var message, entityErrors;
    if (!isDotNet) {
      message = errObj.message;
      entityErrors = errObj.errors || errObj.entityErrors;
    } else {
      var tmp = errObj;
      do {
        // .NET exceptions can provide both ExceptionMessage and Message but ExceptionMethod if it
        // exists has a more detailed message.
        message = tmp.ExceptionMessage || tmp.Message;
        tmp = tmp.InnerException;
      } while (tmp);
      // .EntityErrors will only occur as a result of an EntityErrorsException being deliberately thrown on the server
      entityErrors = errObj.Errors || errObj.EntityErrors;
      entityErrors = entityErrors && entityErrors.map(function (e) {
        return {
          errorName: e.ErrorName,
          entityTypeName: MetadataStore.normalizeTypeName(e.EntityTypeName),
          keyValues: e.KeyValues,
          propertyName: e.PropertyName,
          errorMessage: e.ErrorMessage
        };
      });
    }

    if (saveContext && entityErrors) {
      var propNameFn = saveContext.entityManager.metadataStore.namingConvention.serverPropertyNameToClient;
      entityErrors.forEach(function (e) {
        e.propertyName = e.propertyName && propNameFn(e.propertyName);
      });
      err.entityErrors = entityErrors
    }

    err.message = message || "Server side errors encountered - see the entityErrors collection on this object for more detail";
    return err;
  }

  // Put this at the bottom of your http error analysis
  proto._catchNoConnectionError = function (err) {
    if (err.status == 0 && err.message == null) {
      err.message = "HTTP response status 0 and no message.  " +
          "Likely did not or could not reach server. Is the server running?";
    }
  }

  return ctor;

})();
;// Angular ajax adapter
// See https://docs.angularjs.org/api/ng/service/$http
(function (factory) {
  // Module systems magic dance.
  if (typeof breeze === "object") {
    factory(breeze);
  } else if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
    // CommonJS or Node: hard-coded dependency on "breeze-client"
    factory(require("breeze-client"));
  } else if (typeof define === "function" && define["amd"]) {
    // AMD anonymous module with hard-coded dependency on "breeze-client"
    define(["breeze-client"], factory);
  }
}(function (breeze) {
  "use strict";
  var core = breeze.core;

  var ctor = function AjaxAngularAdapter() {
    this.name = "angular";
    this.defaultSettings = { };
    this.requestInterceptor = null;
    // Will set:
    //   this.$http;
    //   this.$rootScope;
  };
  var proto = ctor.prototype;

  proto.initialize = function () {

    var ng = core.requireLib("angular");
    if (ng) {
      var $injector = ng.injector(['ng']);
      var http, rootScope;
      $injector.invoke(['$http', '$rootScope', function ($http, $rootScope) {
        http = $http;
        rootScope = $rootScope;
      }]);
      this.$http = http;
      this.$rootScope = rootScope;
    }

  };

  proto.setHttp = function (http) {
    this.$http = http;
    this.$rootScope = null; // to suppress $rootScope.digest
  };


  proto.ajax = function (config) {
    if (!this.$http) {
      throw new Error("Unable to locate angular for ajax adapter");
    }
    var ngConfig = {
      method: config.type,
      url: config.url,
      dataType: config.dataType,
      contentType: config.contentType,
      crossDomain: config.crossDomain,
      headers: config.headers || {}
    }

    if (config.params) {
      // Hack: because of the way that Angular handles writing parameters out to the url.
      // so this approach takes over the url param writing completely.
      // See: http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/
      var delim = (ngConfig.url.indexOf("?") >= 0) ? "&" : "?";
      ngConfig.url = ngConfig.url + delim + encodeParams(config.params);
    }

    if (config.data) {
      ngConfig.data = config.data;
    }

    if (!core.isEmpty(this.defaultSettings)) {
      var compositeConfig = core.extend({}, this.defaultSettings);
      ngConfig = core.extend(compositeConfig, ngConfig);
      // extend is shallow; extend headers separately
      var headers =core.extend({}, this.defaultSettings.headers); // copy default headers 1st
      ngConfig.headers = core.extend(headers, ngConfig.headers);
    }

    var requestInfo = {
      adapter: this,      // this adapter
      config: ngConfig,   // angular's $http configuration object
      dsaConfig: config,  // the config arg from the calling Breeze DataServiceAdapter
      success: successFn, // adapter's success callback
      error: errorFn,     // adapter's error callback
      responseSuccess: responseSuccessFn, // adapter's success callback (ng 1.6+)
      responseError: responseErrorFn      // adapter's error callback (ng 1.6+)
    }

    if (core.isFunction(this.requestInterceptor)) {
      this.requestInterceptor(requestInfo);
      if (this.requestInterceptor.oneTime) {
        this.requestInterceptor = null;
      }
    }

    if (requestInfo.config) { // exists unless requestInterceptor killed it.
      var prom = this.$http(requestInfo.config);
      if (prom.success) {
        // response for ng < 1.6        
        prom.success(requestInfo.success).error(requestInfo.error);
      } else {
        // response for ng 1.6+
        prom.then(requestInfo.responseSuccess).catch(requestInfo.responseError);
      }
      this.$rootScope && this.$rootScope.$digest();
    }

    function responseSuccessFn(response) {
      return successFn(response.data, response.status, response.headers, response.config, response.statusText);
    }

    function successFn(data, status, headers, xconfig, statusText) {
      // HACK: because $http returns a server side null as a string containing "null" - this is WRONG.
      if (data === "null") data = null;
      var httpResponse = {
        config: config,
        data: data,
        getHeaders: headers,
        ngConfig: xconfig,
        status: status,
        statusText: statusText
      };
      config.success(httpResponse);
    }

    function responseErrorFn(response) {
      return errorFn(response.data, response.status, response.headers, response.config, response.statusText);
    }

    function errorFn(data, status, headers, xconfig, statusText) {
      // Timeout appears as an error with status===0 and no data.
      // Make it better
      if (status === 0 && data == null) {
        data = 'timeout';
      }
      var httpResponse = {
        config: config,
        data: data,
        getHeaders: headers,
        ngConfig: xconfig,
        status: status,
        statusText: statusText
      };
      config.error(httpResponse);
    }
  };

  function encodeParams(obj) {
    var query = '';
    var subValue, innerObj, fullSubName;

    for (var name in obj) {
      var value = obj[name];

      if (value instanceof Array) {
        for (var i = 0; i < value.length; ++i) {
          subValue = value[i];
          fullSubName = name + '[' + i + ']';
          innerObj = {};
          innerObj[fullSubName] = subValue;
          query += encodeParams(innerObj) + '&';
        }
      } else if (value && value.toISOString) { // a feature of Date-like things
        query += encodeURIComponent(name) + '=' + encodeURIComponent(value.toISOString()) + '&';
      } else if (value instanceof Object) {
        for (var subName in value) {
          subValue = value[subName];
          fullSubName = name + '[' + subName + ']';
          innerObj = {};
          innerObj[fullSubName] = subValue;
          query += encodeParams(innerObj) + '&';
        }
      } else if (value === null) {
        query += encodeURIComponent(name) + '=&';
      } else if (value !== undefined) {
        query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
      }
    }

    return query.length ? query.substr(0, query.length - 1) : query;
  }

  breeze.config.registerAdapter("ajax", ctor);

}));
;// jQuery ajax adapter ( JQuery v.>=1.5 )
// see https://api.jquery.com/jQuery.ajax/
(function (factory) {
  // Module systems magic dance.
  if (typeof breeze === "object") {
    factory(breeze);
  } else if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
    // CommonJS or Node: hard-coded dependency on "breeze-client"
    factory(require("breeze-client"));
  } else if (typeof define === "function" && define["amd"]) {
    // AMD anonymous module with hard-coded dependency on "breeze-client"
    define(["breeze-client"], factory);
  }
}(function (breeze) {
  "use strict";
  var core = breeze.core;

  var jQuery;

  var ctor = function AjaxJQueryAdapter() {
    this.name = "jQuery";
    this.defaultSettings = { };
    this.requestInterceptor = null;
  };
  var proto = ctor.prototype;

  proto.initialize = function () {
    // look for the jQuery lib but don't fail immediately if not found
    jQuery = core.requireLib("jQuery;jquery");
  };

  proto.ajax = function (config) {
    if (!jQuery) {
      throw new Error("Unable to locate jQuery");
    }
    var jqConfig = {
      type: config.type,
      url: config.url,
      data: config.params || config.data,
      dataType: config.dataType,
      contentType: config.contentType,
      crossDomain: config.crossDomain,
      headers: config.headers || {}
    }

    if (!core.isEmpty(this.defaultSettings)) {
      var compositeConfig = core.extend({}, this.defaultSettings);
      jqConfig = core.extend(compositeConfig, jqConfig);
      // extend is shallow; extend headers separately
      var headers =core.extend({}, this.defaultSettings.headers); // copy default headers 1st
      jqConfig.headers = core.extend(headers, jqConfig.headers);
    }

    var requestInfo = {
      adapter: this,      // this adapter
      config: jqConfig,   // jQuery's ajax 'settings' object
      dsaConfig: config,  // the config arg from the calling Breeze DataServiceAdapter
      success: successFn, // adapter's success callback
      error: errorFn      // adapter's error callback
    }

    if (core.isFunction(this.requestInterceptor)) {
      this.requestInterceptor(requestInfo);
      if (this.requestInterceptor.oneTime) {
        this.requestInterceptor = null;
      }
    }

    if (requestInfo.config) { // exists unless requestInterceptor killed it.
      requestInfo.jqXHR = jQuery.ajax(requestInfo.config)
          .done(requestInfo.success)
          .fail(requestInfo.error);
    }

    function successFn(data, statusText, jqXHR) {
      var httpResponse = {
        config: config,
        data: data,
        getHeaders: getHeadersFn(jqXHR),
        status: jqXHR.status,
        statusText: statusText
      };
      config.success(httpResponse);
      jqXHR.onreadystatechange = null;
      jqXHR.abort = null;
    }

    function errorFn(jqXHR, statusText, errorThrown) {
      var httpResponse = {
        config: config,
        data: jqXHR.responseText,
        error: errorThrown,
        getHeaders: getHeadersFn(jqXHR),
        status: jqXHR.status,
        statusText: statusText
      };
      config.error(httpResponse);
      jqXHR.onreadystatechange = null;
      jqXHR.abort = null;
    }
  };

  function getHeadersFn(jqXHR) {
    if (jqXHR.status === 0) { // timeout or abort; no headers
      return function (headerName) {
        return (headerName && headerName.length > 0) ? "" : {};
      };
    } else { // jqXHR should have header functions
      return function (headerName) {
        return (headerName && headerName.length > 0) ?
               jqXHR.getResponseHeader(headerName) :
               jqXHR.getAllResponseHeaders();
      };
    }
  }

  breeze.config.registerAdapter("ajax", ctor);

}));
;(function (factory) {
  if (typeof breeze === "object") {
    factory(breeze);
  } else if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
    // CommonJS or Node: hard-coded dependency on "breeze-client"
    factory(require("breeze-client"));
  } else if (typeof define === "function" && define["amd"]) {
    // AMD anonymous module with hard-coded dependency on "breeze-client"
    define(["breeze-client"], factory);
  }
}(function (breeze) {
  "use strict";
  var core = breeze.core;

  var MetadataStore = breeze.MetadataStore;
  var JsonResultsAdapter = breeze.JsonResultsAdapter;
  var DataProperty = breeze.DataProperty;
  var DataType = breeze.DataType;
  var AutoGeneratedKeyType = breeze.AutoGeneratedKeyType;

  var OData;

  var ctor = function DataServiceODataAdapter() {
    this.name = "OData";
  };

  var proto = ctor.prototype; // minifies better (as seen in jQuery)

  proto.initialize = function () {
    OData = core.requireLib("OData", "Needed to support remote OData services");
    OData.jsonHandler.recognizeDates = true;
  };
  // borrow from AbstractDataServiceAdapter
  var abstractDsaProto = breeze.AbstractDataServiceAdapter.prototype;
  proto._catchNoConnectionError = abstractDsaProto._catchNoConnectionError;
  proto.changeRequestInterceptor = abstractDsaProto.changeRequestInterceptor;
  proto._createChangeRequestInterceptor = abstractDsaProto._createChangeRequestInterceptor;
  proto.headers = { "DataServiceVersion": "2.0" };

  // Absolute URL is the default as of Breeze 1.5.5.  
  // To use relative URL (like pre-1.5.5), add adapterInstance.relativeUrl = true:
  //
  //     var ds = breeze.config.initializeAdapterInstance("dataService", "webApiOData");
  //     ds.relativeUrl = true; 
  //
  // To use custom url construction, add adapterInstance.relativeUrl = myfunction(dataService, url):
  //
  //     var ds = breeze.config.initializeAdapterInstance("dataService", "webApiOData");
  //     ds.relativeUrl = function(dataService, url) {
  //        return somehowConvert(url);
  //     }
  //

  proto.getAbsoluteUrl = function (dataService, url){
    var serviceName = dataService.qualifyUrl('');
    // only prefix with serviceName if not already on the url
    var base = (core.stringStartsWith(url, serviceName)) ? '' : serviceName;
    // If no protocol, turn base into an absolute URI
    if (window && serviceName.indexOf('//') < 0) { 
      // no protocol; make it absolute
      base = window.location.protocol + '//' + window.location.host + 
            (core.stringStartsWith(serviceName, '/') ? '' : '/') +
            base;
    }
    return base + url;
  };

  proto.getRoutePrefix = function (dataService) {
      // Get the routePrefix from a Web API OData service name.
      // The routePrefix is presumed to be the pathname within the dataService.serviceName
      // Examples of servicename -> routePrefix:
      //   'http://localhost:55802/odata/' -> 'odata/'
      //   'http://198.154.121.75/service/odata/' -> 'service/odata/'
      var parser;
      if (typeof document === 'object') { // browser
          parser = document.createElement('a');
          parser.href = dataService.serviceName;
      } else { // node
          parser = url.parse(dataService.serviceName);
      }
      var prefix = parser.pathname;
      if (prefix[0] === '/') {
          prefix = prefix.substr(1);
      } // drop leading '/'  (all but IE)
      if (prefix.substr(-1) !== '/') {
          prefix += '/';
      }      // ensure trailing '/'
      return prefix;
  };

  // crude serializer.  Doesn't recurse
  function toQueryString(obj) {
    var parts = [];
    for (var i in obj) {
      if (obj.hasOwnProperty(i)) {
        parts.push(encodeURIComponent(i) + "=" + encodeURIComponent(obj[i]));
      }
    }
    return parts.join("&");
  }

  proto.executeQuery = function (mappingContext) {

    var deferred = breeze.Q.defer();
    var url;
    if (this.relativeUrl === true) {
      url = mappingContext.getUrl();
    } else if (core.isFunction(this.relativeUrl)) {
      url = this.relativeUrl(mappingContext.dataService, mappingContext.getUrl());
    } else {
      url = this.getAbsoluteUrl(mappingContext.dataService, mappingContext.getUrl());
    }

    // Add query params if .withParameters was used
    if (!core.isEmpty(mappingContext.query.parameters)) {
      var paramString = toQueryString(mappingContext.query.parameters);
      var sep = url.indexOf("?") < 0 ? "?" : "&";
      url = url + sep + paramString;
    }

    OData.read({
          requestUri: url,
          headers: core.extend({}, this.headers)
        },
        function (data, response) {
          var inlineCount;
          if (data.__count) {
            // OData can return data.__count as a string
            inlineCount = parseInt(data.__count, 10);
          }
          // Odata returns different result structure when it returns multiple entities (data.results) vs single entity (data directly).
          // @see http://www.odata.org/documentation/odata-version-2-0/json-format/#RepresentingCollectionsOfEntries
          // and http://www.odata.org/documentation/odata-version-2-0/json-format/#RepresentingEntries
          var results;
          if (data.results) {
            results = data.results;
          } else {
            results = data;
          }
          return deferred.resolve({ results: results, inlineCount: inlineCount, httpResponse: response });
        },
        function (error) {
          return deferred.reject(createError(error, url));
        }
    );
    return deferred.promise;
  };


  proto.fetchMetadata = function (metadataStore, dataService) {

    var deferred = breeze.Q.defer();

    var serviceName = dataService.serviceName;

    var url;
    if (this.relativeUrl === true) {
      url = dataService.qualifyUrl('$metadata');
    } else if (core.isFunction(this.relativeUrl)) {
      url = this.relativeUrl(dataService, '$metadata');
    } else {
      url = this.getAbsoluteUrl(dataService, '$metadata');
    }

    var mheaders = core.extend({}, this.headers);
    mheaders.Accept = 'application/*; odata.metadata=full';

    // OData.read(url,
    OData.read({
          requestUri: url,
          // headers: { "Accept": "application/json"}
          headers: mheaders
        },
        function (data) {
          // data.dataServices.schema is an array of schemas. with properties of
          // entityContainer[], association[], entityType[], and namespace.
          if (!data || !data.dataServices) {
            var error = new Error("Metadata query failed for: " + url);
            return deferred.reject(error);
          }
          var csdlMetadata = data.dataServices;

          // might have been fetched by another query
          if (!metadataStore.hasMetadataFor(serviceName)) {
            try {
              metadataStore.importMetadata(csdlMetadata);
            } catch (e) {
              return deferred.reject(new Error("Metadata query failed for " + url + "; Unable to process returned metadata: " + e.message));
            }

            metadataStore.addDataService(dataService);
          }

          return deferred.resolve(csdlMetadata);

        }, function (error) {
          var err = createError(error, url);
          err.message = "Metadata query failed for: " + url + "; " + (err.message || "");
          return deferred.reject(err);
        },
        OData.metadataHandler
    );

    return deferred.promise;

  };



  proto.saveChanges = function (saveContext, saveBundle) {
    var adapter = saveContext.adapter = this;
    var deferred = breeze.Q.defer();

    var url;
    if (this.relativeUrl === true) {
      saveContext.routePrefix = adapter.getRoutePrefix(saveContext.dataService);
      url = saveContext.dataService.qualifyUrl("$batch");
    } else if (core.isFunction(adapter.relativeUrl)) {
      saveContext.routePrefix = adapter.relativeUrl(saveContext.dataService, '');
      url = saveContext.routePrefix + '$batch';
    } else {
      saveContext.routePrefix = adapter.getAbsoluteUrl(saveContext.dataService, '');
      url = saveContext.routePrefix + '$batch';
    }

    var requestData = createChangeRequests(saveContext, saveBundle);
    var tempKeys = saveContext.tempKeys;
    var contentKeys = saveContext.contentKeys;

    OData.request({
      headers: core.extend({}, this.headers),
      requestUri: url,
      method: "POST",
      data: requestData
    }, function (data, response) {
      var entities = [];
      var keyMappings = [];
      var saveResult = { entities: entities, keyMappings: keyMappings };
      data.__batchResponses.forEach(function (br) {
        br.__changeResponses.forEach(function (cr) {
          var response = cr.response || cr;
          var statusCode = response.statusCode;
          if ((!statusCode) || statusCode >= 400) {
            deferred.reject(createError(cr, url));
            return;
          }

          var contentId = cr.headers["Content-ID"];
          // Olingo sends different case of 'ID' for the header name.
          if (!contentId) {
            contentId = cr.headers["Content-Id"];
          }

          var rawEntity = cr.data;
          if (rawEntity) {
            var tempKey = tempKeys[contentId];
            if (tempKey) {
              var entityType = tempKey.entityType;
              if (entityType.autoGeneratedKeyType !== AutoGeneratedKeyType.None) {
                var tempValue = tempKey.values[0];
                var realKey = entityType.getEntityKeyFromRawEntity(rawEntity, DataProperty.getRawValueFromServer);
                var keyMapping = { entityTypeName: entityType.name, tempValue: tempValue, realValue: realKey.values[0] };
                keyMappings.push(keyMapping);
              }
            }
            entities.push(rawEntity);
          } else {
            var origEntity = contentKeys[contentId];
            entities.push(origEntity);
          }
        });
      });
      return deferred.resolve(saveResult);
    }, function (err) {
      return deferred.reject(createError(err, url));
    }, OData.batchHandler);

    return deferred.promise;

  };

  proto.jsonResultsAdapter = new JsonResultsAdapter({
    name: "OData_default",

    visitNode: function (node, mappingContext, nodeContext) {
      var result = {};
      if (node == null) return result;
      var metadata = node.__metadata;
      if (metadata != null) {
        // TODO: may be able to make this more efficient by caching of the previous value.
        var entityTypeName = MetadataStore.normalizeTypeName(metadata.type);
        var et = entityTypeName && mappingContext.entityManager.metadataStore.getEntityType(entityTypeName, true);
        // OData response doesn't distinguish a projection from a whole entity.
        // We'll assume that whole-entity data would have at least as many properties  (<=)
        // as the EntityType has mapped properties on the basis that
        // most projections remove properties rather than add them.
        // If not, assume it's a projection and do NOT treat as an entity
        if (et && et._mappedPropertiesCount <= Object.keys(node).length - 1) {
          // if (et && et._mappedPropertiesCount === Object.keys(node).length - 1) { // OLD
          result.entityType = et;
          var uriKey = metadata.uri || metadata.id;
          if (uriKey) {
            // Strip baseUri to make uriKey a relative uri
            // Todo: why is this necessary when absolute works for every OData source tested?
            var re = new RegExp('^' + mappingContext.dataService.serviceName, 'i');
            uriKey = uriKey.replace(re, '');
          }
          result.extraMetadata = {
            uriKey: uriKey,
            etag: metadata.etag
          }
        }
      }
      // OData v3 - projection arrays will be enclosed in a results array
      if (node.results) {
        result.node = node.results;
      }

      var propertyName = nodeContext.propertyName;
      result.ignore = node.__deferred != null || propertyName === "__metadata" ||
        // EntityKey properties can be produced by EDMX models
          (propertyName === "EntityKey" && node.$type && core.stringStartsWith(node.$type, "System.Data"));
      return result;
    }

  });

  function transformValue(prop, val) {
    if (prop.isUnmapped) return undefined;
    if (prop.dataType === DataType.DateTimeOffset) {
      // The datajs lib tries to treat client dateTimes that are defined as DateTimeOffset on the server differently
      // from other dateTimes. This fix compensates before the save.
      val = val && new Date(val.getTime() - (val.getTimezoneOffset() * 60000));
    } else if (prop.dataType.quoteJsonOData) {
      val = val != null ? val.toString() : val;
    }
    return val;
  }

  function createChangeRequests(saveContext, saveBundle) {
    var changeRequestInterceptor = saveContext.adapter._createChangeRequestInterceptor(saveContext, saveBundle);
    var changeRequests = [];
    var tempKeys = [];
    var contentKeys = [];
    var entityManager = saveContext.entityManager;
    var helper = entityManager.helper;
    var id = 0;
    var routePrefix = saveContext.routePrefix;

    saveBundle.entities.forEach(function (entity, index) {
      var aspect = entity.entityAspect;
      id = id + 1; // we are deliberately skipping id=0 because Content-ID = 0 seems to be ignored.
      var request = { headers: { "Content-ID": id, "DataServiceVersion": "2.0" } };
      contentKeys[id] = entity;
      if (aspect.entityState.isAdded()) {
        request.requestUri = routePrefix + entity.entityType.defaultResourceName;
        request.method = "POST";
        request.data = helper.unwrapInstance(entity, transformValue);
        tempKeys[id] = aspect.getKey();
      } else if (aspect.entityState.isModified()) {
        updateDeleteMergeRequest(request, aspect, routePrefix);
        request.method = "MERGE";
        request.data = helper.unwrapChangedValues(entity, entityManager.metadataStore, transformValue);
        // should be a PATCH/MERGE
      } else if (aspect.entityState.isDeleted()) {
        updateDeleteMergeRequest(request, aspect, routePrefix);
        request.method = "DELETE";
      } else {
        return;
      }
      request = changeRequestInterceptor.getRequest(request, entity, index);
      changeRequests.push(request);
    });
    saveContext.contentKeys = contentKeys;
    saveContext.tempKeys = tempKeys;
    changeRequestInterceptor.done(changeRequests);
    return {
      __batchRequests: [
        {
          __changeRequests: changeRequests
        }
      ]
    };

  }

  function updateDeleteMergeRequest(request, aspect, routePrefix) {
    var uriKey;
    var extraMetadata = aspect.extraMetadata;
    if (extraMetadata == null) {
      uriKey = getUriKey(aspect);
      aspect.extraMetadata = {
        uriKey: uriKey
      }
    } else {
      uriKey = extraMetadata.uriKey;
      if (extraMetadata.etag) {
        request.headers["If-Match"] = extraMetadata.etag;
      }
    }
    request.requestUri =
      // use routePrefix if uriKey lacks protocol (i.e., relative uri)
      uriKey.indexOf('//') > 0 ? uriKey : routePrefix + uriKey;
  }

  function getUriKey(aspect) {
    var entityType = aspect.entity.entityType;
    var resourceName = entityType.defaultResourceName;
    var kps = entityType.keyProperties;
    var uriKey = resourceName + "(";
    if (kps.length === 1) {
      uriKey = uriKey + fmtProperty(kps[0], aspect) + ")";
    } else {
      var delim = "";
      kps.forEach(function (kp) {
        uriKey = uriKey + delim + kp.nameOnServer + "=" + fmtProperty(kp, aspect);
        delim = ",";
      });
      uriKey = uriKey + ")";
    }
    return uriKey;
  }

  function fmtProperty(prop, aspect) {
    return prop.dataType.fmtOData(aspect.getPropertyValue(prop.name));
  }

  function createError(error, url) {
    // OData errors can have the message buried very deeply - and nonobviously
    // this code is tricky so be careful changing the response.body parsing.
    var result = new Error();
    var response = error && error.response;
    if (!response) {
      // in case DataJS returns "No handler for this data"
      result.message = error;
      result.statusText = error;
      return result;
    }
    result.message = response.statusText;
    result.statusText = response.statusText;
    result.status = response.statusCode;
    // non std
    if (url) result.url = url;
    result.body = response.body;
    if (response.body) {
      var nextErr;
      try {
        var body = JSON.parse(response.body);
        result.body = body;
        // OData v3 logic
        if (body['odata.error']) {
          body = body['odata.error'];
        }
        var msg = "";
        do {
          nextErr = body.error || body.innererror;
          if (!nextErr) msg = msg + getMessage(body);
          nextErr = nextErr || body.internalexception;
          body = nextErr || body;
        } while (nextErr);
        if (msg.length > 0) {
          result.message = msg;
        }
      } catch (e) {

      }
    }
    proto._catchNoConnectionError(result);
    return result;
  }

  function getMessage(body) {
    var msg = body.message || "";
    return ((typeof (msg) === "string") ? msg : msg.value) + "; ";
  }

  breeze.config.registerAdapter("dataService", ctor);


  var webApiODataCtor = function () {
    this.name = "webApiOData";
  }

  breeze.core.extend(webApiODataCtor.prototype, proto);

  breeze.config.registerAdapter("dataService", webApiODataCtor);
  // OData 4 adapter
  var webApiOData4Ctor = function () {
    this.name = "webApiOData4";
  }
  breeze.core.extend(webApiOData4Ctor.prototype, webApiODataCtor.prototype);
  webApiOData4Ctor.prototype.initialize = function () {
    // Aargh... they moved the cheese.
    var datajs = core.requireLib("datajs", "Needed to support remote OData v4 services");
    OData = datajs.V4.oData;
    OData.json.jsonHandler.recognizeDates = true;
  };
  webApiOData4Ctor.prototype.headers = { "OData-Version": "4.0" };
  breeze.config.registerAdapter("dataService", webApiOData4Ctor);


}));;(function (factory) {
  if (typeof breeze === "object") {
    factory(breeze);
  } else if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
    // CommonJS or Node: hard-coded dependency on "breeze-client"
    factory(require("breeze-client"));
  } else if (typeof define === "function" && define["amd"]) {
    // AMD anonymous module with hard-coded dependency on "breeze-client"
    define(["breeze-client"], factory);
  }
}(function (breeze) {
  "use strict";

  var MetadataStore = breeze.MetadataStore;
  var JsonResultsAdapter = breeze.JsonResultsAdapter;
  var AbstractDataServiceAdapter = breeze.AbstractDataServiceAdapter;

  var ctor = function DataServiceWebApiAdapter() {
    this.name = "webApi";
  };
  var proto = ctor.prototype = new AbstractDataServiceAdapter();

  proto._prepareSaveBundle = function (saveContext, saveBundle) {
    var changeRequestInterceptor = this._createChangeRequestInterceptor(saveContext, saveBundle);
    var em = saveContext.entityManager;
    var metadataStore = em.metadataStore;
    var helper = em.helper;

    saveBundle.entities = saveBundle.entities.map(function (e, ix) {
      var rawEntity = helper.unwrapInstance(e);

      var autoGeneratedKey = null;
      if (e.entityType.autoGeneratedKeyType !== breeze.AutoGeneratedKeyType.None) {
        autoGeneratedKey = {
          propertyName: e.entityType.keyProperties[0].nameOnServer,
          autoGeneratedKeyType: e.entityType.autoGeneratedKeyType.name
        };
      }

      var originalValuesOnServer = helper.unwrapOriginalValues(e, metadataStore);
      rawEntity.entityAspect = {
        entityTypeName: e.entityType.name,
        defaultResourceName: e.entityType.defaultResourceName,
        entityState: e.entityAspect.entityState.name,
        originalValuesMap: originalValuesOnServer,
        autoGeneratedKey: autoGeneratedKey
      };
      rawEntity = changeRequestInterceptor.getRequest(rawEntity, e, ix);
      return rawEntity;
    });

    saveBundle.saveOptions = { tag: saveBundle.saveOptions.tag };
    changeRequestInterceptor.done(saveBundle.entities);
    return saveBundle;
  };

  proto._prepareSaveResult = function (saveContext, data) {
    // use the jsonResultAdapter to extractResults and extractKeyMappings
    var jra = saveContext.dataService.jsonResultsAdapter || this.jsonResultsAdapter;
    var entities = jra.extractSaveResults(data) || [];
    var keyMappings = jra.extractKeyMappings(data) || [];
    var deletedKeys = jra.extractDeletedKeys ? (jra.extractDeletedKeys(data)) || [] : [];

    if (keyMappings.length) {
      // HACK: need to change the 'case' of properties in the saveResult
      // but KeyMapping properties internally are still ucase. ugh...
      keyMappings = keyMappings.map(function (km) {
        if (km.entityTypeName) return km; // it's already lower case

        var entityTypeName = MetadataStore.normalizeTypeName(km.EntityTypeName);
        return { entityTypeName: entityTypeName, tempValue: km.TempValue, realValue: km.RealValue };
      });
    }

    if (deletedKeys.length) {
      deletedKeys = deletedKeys.map(function(dk) {
        if (dk.entityTypeName) return dk; // it's already lower case
        var entityTypeName = MetadataStore.normalizeTypeName(dk.EntityTypeName);
        // NOTE the dk.KeyValue => keyValues transition - needed because we are deserializing an .NET EntityKey
        return { entityTypeName: entityTypeName, keyValues: dk.KeyValue }; 
      });
    }
    
    return { entities: entities, keyMappings: keyMappings, deletedKeys: deletedKeys };
  };

  proto.jsonResultsAdapter = new JsonResultsAdapter({

    name: "webApi_default",

    visitNode: function (node, mappingContext, nodeContext) {
      if (node == null) return {};
      var entityTypeName = MetadataStore.normalizeTypeName(node.$type);
      var entityType = entityTypeName && mappingContext.entityManager.metadataStore._getEntityType(entityTypeName, true);
      var propertyName = nodeContext.propertyName;
      var ignore = propertyName && propertyName.substr(0, 1) === "$";

      return {
        entityType: entityType,
        nodeId: node.$id,
        nodeRefId: node.$ref,
        ignore: ignore
      };
    }

  });


  breeze.config.registerAdapter("dataService", ctor);

}));;(function (factory) {
  if (typeof breeze === "object") {
    factory(breeze);
  } else if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
    // CommonJS or Node: hard-coded dependency on "breeze-client"
    factory(require("breeze-client"));
  } else if (typeof define === "function" && define["amd"]) {
    // AMD anonymous module with hard-coded dependency on "breeze-client"
    define(["breeze-client"], factory);
  }
}(function (breeze) {
  "use strict";
  var core = breeze.core;

  var ctor = function ModelLibraryBackingStoreAdapter() {
    this.name = "backingStore";
  };
  // protoFn used instead of proto here to avoid naming collision with function params.
  var protoFn = ctor.prototype;

  protoFn.initialize = function () {

  };

  protoFn.getTrackablePropertyNames = function (entity) {
    var names = [];
    for (var p in entity) {
      if (p === "entityType") continue;
      if (p === "_$typeName") continue;
      if (p === "_pendingSets") continue;
      if (p === "_backingStore") continue;
      var val = entity[p];
      if (!core.isFunction(val)) {
        names.push(p);
      }
    }
    return names;
  };

  // This method is called during Metadata initialization
  protoFn.initializeEntityPrototype = function (proto) {

    proto.getProperty = function (propertyName) {
      return this[propertyName];
    };

    proto.setProperty = function (propertyName, value) {
      //if (!this._backingStore.hasOwnProperty(propertyName)) {
      //    throw new Error("Unknown property name:" + propertyName);
      //}
      this[propertyName] = value;
      // allow setProperty chaining.
      return this;
    };

    movePropDefsToProto(proto);
  };

  // This method is called when an EntityAspect is first created - this will occur as part of the entityType.createEntity call.
  // which can be called either directly or via standard query materialization

  // entity is either an entity or a complexObject
  protoFn.startTracking = function (entity, proto) {
    // can't touch the normal property sets within this method - access the backingStore directly instead.
    var bs = movePropsToBackingStore(entity);

    // assign default values to the entity
    var stype = entity.entityType || entity.complexType;
    stype.getProperties().forEach(function (prop) {

      var propName = prop.name;
      var val = entity[propName];

      if (prop.isDataProperty) {
        if (prop.isComplexProperty) {
          if (prop.isScalar) {
            val = prop.dataType._createInstanceCore(entity, prop);
          } else {
            val = breeze.makeComplexArray([], entity, prop);
          }
        } else if (!prop.isScalar) {
          val = breeze.makePrimitiveArray([], entity, prop);
        } else if (val === undefined) {
          val = prop.defaultValue;
        }

      } else if (prop.isNavigationProperty) {
        if (val !== undefined) {
          throw new Error("Cannot assign a navigation property in an entity ctor.: " + propName);
        }
        if (prop.isScalar) {
          // TODO: change this to nullstob later.
          val = null;
        } else {
          val = breeze.makeRelationArray([], entity, prop);
        }
      } else {
        throw new Error("unknown property: " + propName);
      }
      // can't touch the normal property sets within this method (IE9 Bug) - so we access the backingStore directly instead.
      // otherwise we could just do
      // entity[propName] = val
      // after all of the interception logic had been injected.
      if (prop.isSettable || prop.isNavigationProperty) {
        bs[propName] = val;
      }
    });
  };


  // private methods

  // This method is called during Metadata initialization to correctly "wrap" properties.
  function movePropDefsToProto(proto) {
    var stype = proto.entityType || proto.complexType;
    var extra = stype._extra;

    var alreadyWrapped = extra.alreadyWrappedProps || {};

    stype.getProperties().forEach(function (prop) {
      var propName = prop.name;
      // we only want to wrap props that haven't already been wrapped
      if (alreadyWrapped[propName]) return;

      // If property is already defined on the prototype then wrap it in another propertyDescriptor.
      // otherwise create a propDescriptor for it.
      var descr;
      if (propName in proto) {
        descr = wrapPropDescription(proto, prop);
      } else {
        descr = makePropDescription(proto, prop);
      }
      // descr will be null for a wrapped descr that is not configurable
      if (descr != null) {
        Object.defineProperty(proto, propName, descr);
      }
      alreadyWrapped[propName] = true;
    });
    extra.alreadyWrappedProps = alreadyWrapped;
  }

  // This method is called when an instance is first created via materialization or createEntity.
  // this method cannot be called while a 'defineProperty' accessor is executing
  // because of IE bug mentioned above.

  function movePropsToBackingStore(instance) {

    var bs = getBackingStore(instance);
    var proto = Object.getPrototypeOf(instance);
    var stype = proto.entityType || proto.complexType;
    stype.getProperties().forEach(function (prop) {
      var propName = prop.name;
      if (prop.isUnmapped) {
        // insure that any unmapped properties that were added after entityType
        // was first created are wrapped with a property descriptor.
        if (!core.getPropertyDescriptor(proto, propName)) {
          var descr = makePropDescription(proto, prop);
          Object.defineProperty(proto, propName, descr);
        }
      }
      if (!instance.hasOwnProperty(propName)) return;
      // pulls off the value, removes the instance property and then rewrites it via ES5 accessor
      var value = instance[propName];
      delete instance[propName];
      instance[propName] = value;
    });
    return bs;
  }



  function makePropDescription(proto, property) {
    var propName = property.name;
    var pendingStores = proto._pendingBackingStores;
    if (!pendingStores) {
      pendingStores = [];
      proto._pendingBackingStores = pendingStores;
    }
    var descr = {
      get: function () {
        var bs = this._backingStore || getBackingStore(this);
        return bs[propName];
      },
      set: function (value) {
        // IE9 cannot touch instance._backingStore here
        var bs = this._backingStore || getPendingBackingStore(this);
        var accessorFn = getAccessorFn(bs, propName);
        this._$interceptor(property, value, accessorFn);
      },
      enumerable: true,
      configurable: true
    };

    descr.set.rawSet = function (value) {
      var bs = this._backingStore || getPendingBackingStore(this);
      var accessorFn = getAccessorFn(bs, propName);
      accessorFn(value);
    };
    return descr;

  }

  function getAccessorFn(bs, propName) {
    return function() {
      if (arguments.length === 0) {
        return bs[propName];
      } else {
        bs[propName] = arguments[0];
        return undefined;
      }
    };
  }


  function wrapPropDescription(proto, property) {
    if (!proto.hasOwnProperty(property.name)) {
      var nextProto = Object.getPrototypeOf(proto);
      return wrapPropDescription(nextProto, property);
    }

    var propDescr = Object.getOwnPropertyDescriptor(proto, property.name);
    // if not configurable; we can't touch it - so leave.
    if (!propDescr.configurable) return undefined;
    // if a data descriptor - don't change it - this is basically a static property - i.e. defined on every instance of the type with the same value.
    if (propDescr.value) return undefined;
    // if a read only property descriptor - no need to change it.
    if (!propDescr.set) return undefined;

    var localAccessorFn = function (entity) {
      return function () {
        if (arguments.length === 0) {
          return propDescr.get.bind(entity)();
        } else {
          var set = propDescr.set;
          while (set.rawSet) {
              set = set.rawSet;
          }
          set.bind(entity)(arguments[0]);
          return undefined;
        }
      };
    };

    var newDescr = {
      get: function () {
        return propDescr.get.bind(this)();
      },
      set: function (value) {
        this._$interceptor(property, value, localAccessorFn(this));
      },
      enumerable: propDescr.enumerable,
      configurable: true
    };
    newDescr.set.rawSet = propDescr.set;
    return newDescr;
  };


  function getBackingStore(instance) {
    var proto = Object.getPrototypeOf(instance);
    processPendingStores(proto);
    var bs = instance._backingStore;
    if (!bs) {
      bs = {};
      instance._backingStore = bs;
    }
    return bs;
  }

  // workaround for IE9 bug where instance properties cannot be changed when executing a property 'set' method.
  function getPendingBackingStore(instance) {
    var proto = Object.getPrototypeOf(instance);
    var pendingStores = proto._pendingBackingStores;
    var pending = core.arrayFirst(pendingStores, function (pending) {
      return pending.entity === instance;
    });
    if (pending) return pending.backingStore;
    var bs = {};
    pendingStores.push({ entity: instance, backingStore: bs });
    return bs;
  }

  function processPendingStores(proto) {
    var pendingStores = proto._pendingBackingStores;
    if (pendingStores) {
      pendingStores.forEach(function (pending) {
        pending.entity._backingStore = pending.backingStore;
      });
      pendingStores.length = 0;
    }
  }


  breeze.config.registerAdapter("modelLibrary", ctor);

}));
;(function (factory) {
  if (typeof breeze === "object") {
    factory(breeze);
  } else if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
    // CommonJS or Node: hard-coded dependency on "breeze-client"
    factory(require("breeze-client"));
  } else if (typeof define === "function" && define["amd"]) {
    // AMD anonymous module with hard-coded dependency on "breeze-client"
    define(["breeze-client"], factory);
  }
}(function (breeze) {
  "use strict";
  var core = breeze.core;
  var canIsolateES5Props = core.__isES5Supported;

  var ko;

  var ctor = function ModelLibraryKnockoutAdapter() {
    this.name = "ko";
  };
  // protoFn used instead of proto here to avoid naming collision with function params.
  var protoFn = ctor.prototype;

  protoFn.initialize = function () {
    ko = core.requireLib("ko;knockout", "The Knockout library");
    ko.extenders.intercept = function (target, interceptorOptions) {
      var instance = interceptorOptions.instance;
      var property = interceptorOptions.property;

      // create a computed observable to intercept writes to our observable
      var result;
      if (target.splice) {
        result = ko.computed({
          read: target  //always return the original observables value
        });
      } else {
        result = ko.computed({
          read: target,  //always return the original observables value
          write: function (newValue) {
            instance._$interceptor(property, newValue, target);
            return instance;
          }
        });
      }
      //return the new computed observable
      return result;
    };

  };

  protoFn.getTrackablePropertyNames = function (entity) {
    var names = [];
    for (var p in entity) {
      if (p === "entityType") continue;
      if (p === "_$typeName") continue;

      var propDescr = getES5PropDescriptor(entity, p);
      if (propDescr && propDescr.get) {
        names.push(p);
      } else {
        var val = entity[p];
        if (ko.isObservable(val)) {
          names.push(p);
        } else if (!core.isFunction(val)) {
          names.push(p);
        }
      }
    }
    return names;
  };

  protoFn.initializeEntityPrototype = function (proto) {

    proto.getProperty = function (propertyName) {
      return this[propertyName]();
    };

    proto.setProperty = function (propertyName, value) {
      this[propertyName](value);
      // allow set property chaining.
      return this;
    };

    if (canIsolateES5Props) {
      isolateES5Props(proto);
    }

  };

  function isolateES5Props(proto) {

    var stype = proto.entityType || proto.complexType;
    var es5Descriptors = {};
    stype.getProperties().forEach(function (prop) {
      var propDescr = getES5PropDescriptor(proto, prop.name);
      if (propDescr) {
        es5Descriptors[prop.name] = propDescr;
      }
    });
    if (!core.isEmpty(es5Descriptors)) {
      var extra = stype._extra;
      extra.es5Descriptors = es5Descriptors;
      stype._koDummy = ko.observable(null);
    }

  }

  function getES5PropDescriptor(proto, propName) {
    if (!canIsolateES5Props) {
      return null;
    }
    if (proto.hasOwnProperty(propName)) {
      return Object.getOwnPropertyDescriptor && Object.getOwnPropertyDescriptor(proto, propName);
    } else {
      var nextProto = Object.getPrototypeOf(proto);
      return nextProto ? getES5PropDescriptor(nextProto, propName) : null;
    }
  }

  protoFn.startTracking = function (entity, proto) {
    // create ko's for each property and assign defaultValues

    var stype = entity.entityType || entity.complexType;
    var es5Descriptors = stype._extra.es5Descriptors || {};

    // sort unmapped properties to the end
    stype.getProperties().sort(function (p1, p2) {
      var v1 = p1.isUnmapped ? 1 : 0;
      var v2 = p2.isUnmapped ? 1 : 0;
      return v1 - v2;
    }).forEach(function (prop) {
      var propName = prop.name;
      var val = entity[propName];
      var propDescr = es5Descriptors[propName];
      var koObj;

      // check if property is an ES5 property
      if (propDescr) {
        var getFn = propDescr.get.bind(entity);
        if (propDescr.set) {
          var setFn = propDescr.set.bind(entity);
          var rawAccessorFn = function (newValue) {
            if (arguments.length === 0) {
              getFn();
              return;
            } else {
              setFn(newValue);
            }
          }
          koObj = ko.computed({
            read: function () {
              stype._koDummy();
              return getFn();
            },
            write: function (newValue) {
              entity._$interceptor(prop, newValue, rawAccessorFn);
              stype._koDummy.valueHasMutated();
              return entity;
            }
          });
        } else {
          koObj = ko.computed({
            read: getFn,
            write: function () {
            }

          });
        }
        // check if property is already exposed as a ko object
      } else if (ko.isObservable(val)) {
        if (prop.isNavigationProperty) {
          throw new Error("Cannot assign a navigation property in an entity ctor.: " + propName);
        }
        koObj = val;
        // otherwise
      } else {
        val = initializeValueForProp(entity, prop, val);
        koObj = prop.isScalar ? ko.observable(val) : ko.observableArray(val);
      }


      if (prop.isScalar) {
        if (propDescr) {
          Object.defineProperty(entity, propName, {
            enumerable: true,
            configurable: true,
            writable: true,
            value: koObj
          });
        } else {
          var koExt = koObj.extend({ intercept: { instance: entity, property: prop } });
          entity[propName] = koExt;
        }
      } else {
        val._koObj = koObj;
        // code to suppress extra breeze notification when
        // ko's array methods are called.
        koObj.subscribe(onBeforeChange, null, "beforeChange");
        // code to insure that any direct breeze changes notify ko
        val.arrayChanged.subscribe(onArrayChanged);

        koObj.equalityComparer = function () {
          throw new Error("Collection navigation properties may NOT be set.");
        };
        entity[propName] = koObj;
      }

    });

  };

  function initializeValueForProp(entity, prop, val) {
    if (prop.isDataProperty) {
      if (prop.isComplexProperty) {
        // TODO: right now we create Empty complexObjects here - these should actually come from the entity
        if (prop.isScalar) {
          val = prop.dataType._createInstanceCore(entity, prop);
        } else {
          val = breeze.makeComplexArray([], entity, prop);
        }
      } else if (!prop.isScalar) {
        val = breeze.makePrimitiveArray([], entity, prop);
      } else if (val === undefined) {
        val = prop.defaultValue;
      }

    } else if (prop.isNavigationProperty) {
      if (val !== undefined) {
        throw new Error("Cannot assign a navigation property in an entity ctor.: " + prop.name);
      }
      if (prop.isScalar) {
        // TODO: change this to nullEntity later.
        val = null;
      } else {
        val = breeze.makeRelationArray([], entity, prop);
      }
    } else {
      throw new Error("unknown property: " + prop.name);
    }
    return val;
  }


  function onBeforeChange(args) {
    args._koObj._suppressBreeze = true;
  }

  function onArrayChanged(args) {
    var koObj = args.array._koObj;
    if (koObj._suppressBreeze) {
      koObj._suppressBreeze = false;
    } else {
      koObj.valueHasMutated();
    }
  }

  breeze.config.registerAdapter("modelLibrary", ctor);

}));
;(function (factory) {
  if (typeof breeze === "object") {
    factory(breeze);
  } else if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
    // CommonJS or Node: hard-coded dependency on "breeze-client"
    factory(require("breeze-client"));
  } else if (typeof define === "function" && define["amd"]) {
    // AMD anonymous module with hard-coded dependency on "breeze-client"
    define(["breeze-client"], factory);
  }
}(function (breeze) {
  "use strict";

  var EntityType = breeze.EntityType;

  var ctor = function UriBuilderJsonAdapter() {
    this.name = "json";
  };
  var proto = ctor.prototype;

  proto.initialize = function() {};

  proto.buildUri = function (entityQuery, metadataStore) {
    // force entityType validation;
    var entityType = entityQuery._getFromEntityType(metadataStore, false);
    if (!entityType) entityType = new EntityType(metadataStore);
    var json = entityQuery.toJSONExt( { entityType: entityType, toNameOnServer: true});
    json.from = undefined;
    json.queryOptions = undefined;

    var jsonString = JSON.stringify(json);
    var urlBody = encodeURIComponent(jsonString);
    return entityQuery.resourceName + "?" + urlBody;

  };

  breeze.config.registerAdapter("uriBuilder", ctor);

}));



;(function (factory) {
  if (typeof breeze === "object") {
    factory(breeze);
  } else if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
    // CommonJS or Node: hard-coded dependency on "breeze-client"
    factory(require("breeze-client"));
  } else if (typeof define === "function" && define["amd"]) {
    // AMD anonymous module with hard-coded dependency on "breeze-client"
    define(["breeze-client"], factory);
  }
}(function (breeze) {
  "use strict";
  var EntityType = breeze.EntityType;
  var toODataFragmentVisitor;

  var ctor = function UriBuilderODataAdapter() {
    this.name = "odata";
  };
  var proto = ctor.prototype;

  proto.initialize = function() {};

  proto.buildUri = function (entityQuery, metadataStore) {
    // force entityType validation;
    var entityType = entityQuery._getFromEntityType(metadataStore, false);
    if (!entityType) {
      // anonymous type but still has naming convention info avail
      entityType = new EntityType(metadataStore);
    }

    var queryOptions = {};
    queryOptions["$filter"] = toWhereODataFragment(entityQuery.wherePredicate);
    queryOptions["$orderby"] = toOrderByODataFragment(entityQuery.orderByClause);

    if (entityQuery.skipCount) {
      queryOptions["$skip"] = entityQuery.skipCount;
    }

    if (entityQuery.takeCount != null) {
      queryOptions["$top"] = entityQuery.takeCount;
    }

    queryOptions["$expand"] = toExpandODataFragment(entityQuery.expandClause);
    queryOptions["$select"] = toSelectODataFragment(entityQuery.selectClause);

    if (entityQuery.inlineCountEnabled) {
      queryOptions["$inlinecount"] = "allpages";
    }

    var qoText = toQueryOptionsString(queryOptions);
    return entityQuery.resourceName + qoText;

    // private methods to this func.

    function toWhereODataFragment(wherePredicate) {
      if (!wherePredicate) return undefined;
      // validation occurs inside of the toODataFragment call here.
      return wherePredicate.visit({ entityType: entityType}, toODataFragmentVisitor );
    }

    function toOrderByODataFragment(orderByClause) {
      if (!orderByClause) return undefined;
      orderByClause.validate(entityType);
      var strings = orderByClause.items.map(function (item) {
        return entityType.clientPropertyPathToServer(item.propertyPath, "/") + (item.isDesc ? " desc" : "");
      });
      // should return something like CompanyName,Address/City desc
      return strings.join(',');
    }

    function toSelectODataFragment(selectClause) {
      if (!selectClause) return undefined;
      selectClause.validate(entityType);
      var frag = selectClause.propertyPaths.map(function (pp) {
        return  entityType.clientPropertyPathToServer(pp, "/");
      }).join(",");
      return frag;
    }

    function toExpandODataFragment(expandClause) {
      if (!expandClause) return undefined;
      // no validate on expand clauses currently.
      // expandClause.validate(entityType);
      var frag = expandClause.propertyPaths.map(function (pp) {
        return entityType.clientPropertyPathToServer(pp, "/");
      }).join(",");
      return frag;
    }

    function toQueryOptionsString(queryOptions) {
      var qoStrings = [];
      for (var qoName in queryOptions) {
        var qoValue = queryOptions[qoName];
        if (qoValue !== undefined) {
          if (qoValue instanceof Array) {
            qoValue.forEach(function (qov) {
              qoStrings.push(qoName + "=" + encodeURIComponent(qov));
            });
          } else {
            qoStrings.push(qoName + "=" + encodeURIComponent(qoValue));
          }
        }
      }

      if (qoStrings.length > 0) {
        return "?" + qoStrings.join("&");
      } else {
        return "";
      }
    }
  };

  breeze.Predicate.prototype.toODataFragment = function(context) {
    return this.visit( context, toODataFragmentVisitor);
  }

  toODataFragmentVisitor = (function () {
    var visitor = {

      passthruPredicate: function () {
        return this.value;
      },

      unaryPredicate: function (context) {
        var predVal = this.pred.visit(context);
        return odataOpFrom(this) + " " + "(" + predVal + ")";
      },

      binaryPredicate: function (context) {
        var expr1Val = this.expr1.visit(context);
        var expr2Val = this.expr2.visit(context);
        var prefix = context.prefix;
        if (prefix) {
          expr1Val = prefix + "/" + expr1Val;
        }

        var odataOp = odataOpFrom(this);

        if (this.op.key === 'in') {
          var result = expr2Val.map(function (v) {
            return "(" + expr1Val + " eq " + v + ")";
          }).join(" or ");
          return result;
        } else if (this.op.isFunction) {
          if (odataOp === "substringof") {
            return odataOp + "(" + expr2Val + "," + expr1Val + ") eq true";
          } else {
            return odataOp + "(" + expr1Val + "," + expr2Val + ") eq true";
          }
        } else {
          return expr1Val + " " + odataOp + " " + expr2Val;
        }
      },

      andOrPredicate: function (context) {
        var result = this.preds.map(function (pred) {
          var predVal = pred.visit(context);
          return "(" + predVal + ")";
        }).join(" " + odataOpFrom(this) + " ");
        return result;
      },

      anyAllPredicate: function (context) {
        var exprVal = this.expr.visit(context);
        if (!this.pred.op) {
          return exprVal + "/" + odataOpFrom(this) + "()";
        }
        var prefix = context.prefix;
        if (prefix) {
          exprVal = prefix + "/" + exprVal;
          prefix = "x" + (parseInt(prefix.substring(1)) + 1);
        } else {
          prefix = "x1";
        }
        // need to create a new context because of 'prefix'
        var newContext = breeze.core.extend({}, context);
        newContext.entityType = this.expr.dataType;
        newContext.prefix = prefix;
        var newPredVal = this.pred.visit(newContext);
        return exprVal + "/" + odataOpFrom(this) + "(" + prefix + ": " + newPredVal + ")";
      },

      litExpr: function () {
        if (Array.isArray(this.value)) {
          return this.value.map(function(v) { return this.dataType.fmtOData(v)}, this);
        } else {
          return this.dataType.fmtOData(this.value);
        }
      },

      propExpr: function (context) {
        var entityType = context.entityType;
        // '/' is the OData path delimiter
        return entityType ? entityType.clientPropertyPathToServer(this.propertyPath, "/") : this.propertyPath;
      },

      fnExpr: function (context) {
        var exprVals = this.exprs.map(function(expr) {
          return expr.visit(context);
        });
        return this.fnName + "(" + exprVals.join(",") + ")";
      }
    };

    var _operatorMap = {
      'contains': 'substringof'
    };

    function odataOpFrom(node) {
      var op = node.op.key;
      var odataOp = _operatorMap[op];
      return odataOp || op;
    }

    return visitor;
  }());

  breeze.config.registerAdapter("uriBuilder", ctor);

}));





;
// set defaults
// will no longer fail at initialization time if jQuery is not found.
breeze.config.initializeAdapterInstances( { dataService: "webApi", ajax: "jQuery", uriBuilder: "odata" });

var ko = __requireLibCore("ko");

if (ko) {
    breeze.config.initializeAdapterInstance("modelLibrary", "ko");
} else {
    breeze.config.initializeAdapterInstance("modelLibrary", "backingStore");
}

return breeze;
});
;
//#region Copyright, Version, and Description
/*
 * Copyright 2013 IdeaBlade, Inc.  All Rights Reserved.  
 * Use, reproduction, distribution, and modification of this code is subject to the terms and 
 * conditions of the IdeaBlade Breeze license, available at http://www.breezejs.com/license
 *
 * Author: Ward Bell
 * Version: 1.0
 * --------------------------------------------------------------------------------
 * Adds "Save Queuing" capability to new EntityManagers
 * "Save Queuing" automatically queues and defers an EntityManager.saveChanges call
 * when another save is in progress for that manager.
 *
 * Without "Save Queuing", an EntityManager will throw an exception when
 * saveChanges is called while another save is in progress.
 *
 * "Save Queuing" is experimental. It may become part of BreezeJS in future
 * although not necessarily in this form or with this API
 * 
 * Must call EntityManager.enableSaveQueuing(true) to turn it on;
 * EntityManager.enableSaveQueuing(false) restores the manager's original 
 * saveChanges method as it was at the time saveQueuing was first enabled.
 * 
 * This module adds "enableSaveQueuing" to the EntityManager prototype.
 * Calling "enableSaveQueuing(true)" adds a new _saveQueuing object 
 * to the manager instance.
 * 
 * !!! Use with caution !!!
 * "Save Queuing" is recommended only in simple "auto-save" scenarios wherein
 * users make rapid changes and the UI saves immediately as they do so.
 * It is usually better (and safer) to disable save in the UI
 * while waiting for a prior save to complete
 *
 * All members of EntityManager._saveQueuing are internal; 
 * touch them at your own risk.
 */
//#endregion
(function (breeze, Q) {
    var EntityManager = breeze.EntityManager;

    /**
    Enable (default) or disable "Save Queuing" for this manager
    **/
    EntityManager.prototype.enableSaveQueuing = function (enable) {
        enable = enable === undefined ? true : enable;
        if (!this._saveQueuing) {
            this._saveQueuing = new SaveQueuing(this);
        }
        if (enable) {
            this.saveChanges = saveChangesWithQueuing;
        } else {
            this.saveChanges = this._saveQueuing.baseSaveChanges;
        }
    };


    var SaveQueuing = function (entityManager) {
        this.entityManager = entityManager;
        this.baseSaveChanges = entityManager.saveChanges;
        this.isSaving = false;
        this.saveQueue = [];
    };

    SaveQueuing.prototype.isEnabled = function () {
        return this.entityManager.saveChanges === saveChangesWithQueuing;
    };

    /**
    Replacement for EntityManager.saveChanges, extended with "Save Queuing"
    **/
    function saveChangesWithQueuing() {
        var saveQueuing = this._saveQueuing;
        var args = [].slice.call(arguments);

        if (saveQueuing.isSaving) {
            // save in progress; queue the save for later
            return saveQueuing.queueSaveChanges(args);
        } else {
            // note that save is in progrees; then save
            saveQueuing.isSaving = true;
            return saveQueuing.innerSaveChanges(args);
        }
    }

    SaveQueuing.prototype.queueSaveChanges = function (args) {
        var self = this;
        var deferredSave = Q.defer();
        self.saveQueue.push(deferredSave);

        // clone saveOptions because may change later, before this save is dequeued
        args[1] = breeze.core.extend(new breeze.SaveOptions(),
            args[1] || this.entityManager.saveOptions || breeze.SaveOptions.defaultInstance);

        var savePromise = deferredSave.promise;
        return savePromise
            .then(function () { return self.innerSaveChanges(args); })
            .fail(function (error) { self.saveFailed(error); });
    };

    SaveQueuing.prototype.innerSaveChanges = function (args) {
        var self = this;
        return self.baseSaveChanges.apply(self.entityManager, args)
            .then(function (saveResult) { return self.saveSucceeded(saveResult); })
            .fail(function (error) { self.saveFailed(error); });
    };

    // Default methods and Error class for initializing new saveQueuing objects
    SaveQueuing.prototype.saveSucceeded = defaultSaveSucceeded;
    SaveQueuing.prototype.saveFailed = defaultSaveFailed;
    SaveQueuing.prototype.QueuedSaveFailedError = QueuedSaveFailedError;

    function defaultSaveSucceeded(saveResult) {
        var saveQueuing = this;
        var deferredSave = saveQueuing.saveQueue.shift();
        if (deferredSave) {
            deferredSave.resolve();
        }
        if (saveQueuing.saveQueue.length === 0) {
            saveQueuing.isSaving = false;
        }
        return saveResult;
    };

    function defaultSaveFailed(error) {
        var saveQueuing = this;
        saveQueuing.isSaving = false;
        var saveQueue = saveQueuing.saveQueue;
        var deferredSave;
        // clear the save queue, calling reject on each deferred save
        while (deferredSave = saveQueue.shift()) {
            deferredSave.reject(new saveQueuing.QueuedSaveFailedError(error, saveQueuing));
        }
        throw error; // so rest of current promise chain can hear error
    }

    //#region QueuedSaveFailedError
    //Custom Error sub-class; thrown when rejecting queued saves.
    function QueuedSaveFailedError(errObject) {
        this.name = "QueuedSaveFailedError";
        this.message = "Queued save failed";
        this.innerError = errObject;
    }

    QueuedSaveFailedError.prototype = new Error();
    QueuedSaveFailedError.prototype.constructor = QueuedSaveFailedError;
    //#endregion

})(breeze, Q);;
!function(a,b){"function"==typeof define&&define.amd?define(["jquery"],b):"object"==typeof exports?module.exports=b(require("jquery")):b(a.jQuery)}(this,function(a){"function"!=typeof Object.create&&(Object.create=function(a){function b(){}return b.prototype=a,new b});var b={init:function(b){return this.options=a.extend({},a.noty.defaults,b),this.options.layout=this.options.custom?a.noty.layouts.inline:a.noty.layouts[this.options.layout],a.noty.themes[this.options.theme]?this.options.theme=a.noty.themes[this.options.theme]:this.options.themeClassName=this.options.theme,this.options=a.extend({},this.options,this.options.layout.options),this.options.id="noty_"+(new Date).getTime()*Math.floor(1e6*Math.random()),this._build(),this},_build:function(){var b=a('<div class="noty_bar noty_type_'+this.options.type+'"></div>').attr("id",this.options.id);if(b.append(this.options.template).find(".noty_text").html(this.options.text),this.$bar=null!==this.options.layout.parent.object?a(this.options.layout.parent.object).css(this.options.layout.parent.css).append(b):b,this.options.themeClassName&&this.$bar.addClass(this.options.themeClassName).addClass("noty_container_type_"+this.options.type),this.options.buttons){this.options.closeWith=[],this.options.timeout=!1;var c=a("<div/>").addClass("noty_buttons");null!==this.options.layout.parent.object?this.$bar.find(".noty_bar").append(c):this.$bar.append(c);var d=this;a.each(this.options.buttons,function(b,c){var e=a("<button/>").addClass(c.addClass?c.addClass:"gray").html(c.text).attr("id",c.id?c.id:"button-"+b).attr("title",c.title).appendTo(d.$bar.find(".noty_buttons")).on("click",function(b){a.isFunction(c.onClick)&&c.onClick.call(e,d,b)})})}this.$message=this.$bar.find(".noty_message"),this.$closeButton=this.$bar.find(".noty_close"),this.$buttons=this.$bar.find(".noty_buttons"),a.noty.store[this.options.id]=this},show:function(){var b=this;return b.options.custom?b.options.custom.find(b.options.layout.container.selector).append(b.$bar):a(b.options.layout.container.selector).append(b.$bar),b.options.theme&&b.options.theme.style&&b.options.theme.style.apply(b),"function"===a.type(b.options.layout.css)?this.options.layout.css.apply(b.$bar):b.$bar.css(this.options.layout.css||{}),b.$bar.addClass(b.options.layout.addClass),b.options.layout.container.style.apply(a(b.options.layout.container.selector),[b.options.within]),b.showing=!0,b.options.theme&&b.options.theme.style&&b.options.theme.callback.onShow.apply(this),a.inArray("click",b.options.closeWith)>-1&&b.$bar.css("cursor","pointer").one("click",function(a){b.stopPropagation(a),b.options.callback.onCloseClick&&b.options.callback.onCloseClick.apply(b),b.close()}),a.inArray("hover",b.options.closeWith)>-1&&b.$bar.one("mouseenter",function(){b.close()}),a.inArray("button",b.options.closeWith)>-1&&b.$closeButton.one("click",function(a){b.stopPropagation(a),b.close()}),-1==a.inArray("button",b.options.closeWith)&&b.$closeButton.remove(),b.options.callback.onShow&&b.options.callback.onShow.apply(b),"string"==typeof b.options.animation.open?(b.$bar.css("height",b.$bar.innerHeight()),b.$bar.on("click",function(a){b.wasClicked=!0}),b.$bar.show().addClass(b.options.animation.open).one("webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend",function(){b.options.callback.afterShow&&b.options.callback.afterShow.apply(b),b.showing=!1,b.shown=!0,b.hasOwnProperty("wasClicked")&&(b.$bar.off("click",function(a){b.wasClicked=!0}),b.close())})):b.$bar.animate(b.options.animation.open,b.options.animation.speed,b.options.animation.easing,function(){b.options.callback.afterShow&&b.options.callback.afterShow.apply(b),b.showing=!1,b.shown=!0}),b.options.timeout&&b.$bar.delay(b.options.timeout).promise().done(function(){b.close()}),this},close:function(){if(!(this.closed||this.$bar&&this.$bar.hasClass("i-am-closing-now"))){var b=this;if(this.showing)return void b.$bar.queue(function(){b.close.apply(b)});if(!this.shown&&!this.showing){var c=[];return a.each(a.noty.queue,function(a,d){d.options.id!=b.options.id&&c.push(d)}),void(a.noty.queue=c)}b.$bar.addClass("i-am-closing-now"),b.options.callback.onClose&&b.options.callback.onClose.apply(b),"string"==typeof b.options.animation.close?b.$bar.addClass(b.options.animation.close).one("webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend",function(){b.options.callback.afterClose&&b.options.callback.afterClose.apply(b),b.closeCleanUp()}):b.$bar.clearQueue().stop().animate(b.options.animation.close,b.options.animation.speed,b.options.animation.easing,function(){b.options.callback.afterClose&&b.options.callback.afterClose.apply(b)}).promise().done(function(){b.closeCleanUp()})}},closeCleanUp:function(){var b=this;b.options.modal&&(a.notyRenderer.setModalCount(-1),0==a.notyRenderer.getModalCount()&&a(".noty_modal").fadeOut(b.options.animation.fadeSpeed,function(){a(this).remove()})),a.notyRenderer.setLayoutCountFor(b,-1),0==a.notyRenderer.getLayoutCountFor(b)&&a(b.options.layout.container.selector).remove(),"undefined"!=typeof b.$bar&&null!==b.$bar&&("string"==typeof b.options.animation.close?(b.$bar.css("transition","all 100ms ease").css("border",0).css("margin",0).height(0),b.$bar.one("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd",function(){b.$bar.remove(),b.$bar=null,b.closed=!0,b.options.theme.callback&&b.options.theme.callback.onClose&&b.options.theme.callback.onClose.apply(b)})):(b.$bar.remove(),b.$bar=null,b.closed=!0)),delete a.noty.store[b.options.id],b.options.theme.callback&&b.options.theme.callback.onClose&&b.options.theme.callback.onClose.apply(b),b.options.dismissQueue||(a.noty.ontap=!0,a.notyRenderer.render()),b.options.maxVisible>0&&b.options.dismissQueue&&a.notyRenderer.render()},setText:function(a){return this.closed||(this.options.text=a,this.$bar.find(".noty_text").html(a)),this},setType:function(a){return this.closed||(this.options.type=a,this.options.theme.style.apply(this),this.options.theme.callback.onShow.apply(this)),this},setTimeout:function(a){if(!this.closed){var b=this;this.options.timeout=a,b.$bar.delay(b.options.timeout).promise().done(function(){b.close()})}return this},stopPropagation:function(a){a=a||window.event,"undefined"!=typeof a.stopPropagation?a.stopPropagation():a.cancelBubble=!0},closed:!1,showing:!1,shown:!1};a.notyRenderer={},a.notyRenderer.init=function(c){var d=Object.create(b).init(c);return d.options.killer&&a.noty.closeAll(),d.options.force?a.noty.queue.unshift(d):a.noty.queue.push(d),a.notyRenderer.render(),"object"==a.noty.returns?d:d.options.id},a.notyRenderer.render=function(){var b=a.noty.queue[0];"object"===a.type(b)?b.options.dismissQueue?b.options.maxVisible>0?a(b.options.layout.container.selector+" > li").length<b.options.maxVisible&&a.notyRenderer.show(a.noty.queue.shift()):a.notyRenderer.show(a.noty.queue.shift()):a.noty.ontap&&(a.notyRenderer.show(a.noty.queue.shift()),a.noty.ontap=!1):a.noty.ontap=!0},a.notyRenderer.show=function(b){b.options.modal&&(a.notyRenderer.createModalFor(b),a.notyRenderer.setModalCount(1)),b.options.custom?0==b.options.custom.find(b.options.layout.container.selector).length?b.options.custom.append(a(b.options.layout.container.object).addClass("i-am-new")):b.options.custom.find(b.options.layout.container.selector).removeClass("i-am-new"):0==a(b.options.layout.container.selector).length?a("body").append(a(b.options.layout.container.object).addClass("i-am-new")):a(b.options.layout.container.selector).removeClass("i-am-new"),a.notyRenderer.setLayoutCountFor(b,1),b.show()},a.notyRenderer.createModalFor=function(b){if(0==a(".noty_modal").length){var c=a("<div/>").addClass("noty_modal").addClass(b.options.theme).data("noty_modal_count",0);b.options.theme.modal&&b.options.theme.modal.css&&c.css(b.options.theme.modal.css),c.prependTo(a("body")).fadeIn(b.options.animation.fadeSpeed),a.inArray("backdrop",b.options.closeWith)>-1&&c.on("click",function(b){a.noty.closeAll()})}},a.notyRenderer.getLayoutCountFor=function(b){return a(b.options.layout.container.selector).data("noty_layout_count")||0},a.notyRenderer.setLayoutCountFor=function(b,c){return a(b.options.layout.container.selector).data("noty_layout_count",a.notyRenderer.getLayoutCountFor(b)+c)},a.notyRenderer.getModalCount=function(){return a(".noty_modal").data("noty_modal_count")||0},a.notyRenderer.setModalCount=function(b){return a(".noty_modal").data("noty_modal_count",a.notyRenderer.getModalCount()+b)},a.fn.noty=function(b){return b.custom=a(this),a.notyRenderer.init(b)},a.noty={},a.noty.queue=[],a.noty.ontap=!0,a.noty.layouts={},a.noty.themes={},a.noty.returns="object",a.noty.store={},a.noty.get=function(b){return a.noty.store.hasOwnProperty(b)?a.noty.store[b]:!1},a.noty.close=function(b){return a.noty.get(b)?a.noty.get(b).close():!1},a.noty.setText=function(b,c){return a.noty.get(b)?a.noty.get(b).setText(c):!1},a.noty.setType=function(b,c){return a.noty.get(b)?a.noty.get(b).setType(c):!1},a.noty.clearQueue=function(){a.noty.queue=[]},a.noty.closeAll=function(){a.noty.clearQueue(),a.each(a.noty.store,function(a,b){b.close()})};var c=window.alert;return a.noty.consumeAlert=function(b){window.alert=function(c){b?b.text=c:b={text:c},a.notyRenderer.init(b)}},a.noty.stopConsumeAlert=function(){window.alert=c},a.noty.defaults={layout:"top",theme:"defaultTheme",type:"alert",text:"",dismissQueue:!0,template:'<div class="noty_message"><span class="noty_text"></span><div class="noty_close"></div></div>',animation:{open:{height:"toggle"},close:{height:"toggle"},easing:"swing",speed:500,fadeSpeed:"fast"},timeout:!1,force:!1,modal:!1,maxVisible:5,killer:!1,closeWith:["click"],callback:{onShow:function(){},afterShow:function(){},onClose:function(){},afterClose:function(){},onCloseClick:function(){}},buttons:!1},a(window).on("resize",function(){a.each(a.noty.layouts,function(b,c){c.container.style.apply(a(c.container.selector))})}),window.noty=function(b){return a.notyRenderer.init(b)},a.noty.layouts.bottom={name:"bottom",options:{},container:{object:'<ul id="noty_bottom_layout_container" />',selector:"ul#noty_bottom_layout_container",style:function(){a(this).css({bottom:0,left:"5%",position:"fixed",width:"90%",height:"auto",margin:0,padding:0,listStyleType:"none",zIndex:9999999})}},parent:{object:"<li />",selector:"li",css:{}},css:{display:"none"},addClass:""},a.noty.layouts.bottomCenter={name:"bottomCenter",options:{},container:{object:'<ul id="noty_bottomCenter_layout_container" />',selector:"ul#noty_bottomCenter_layout_container",style:function(){a(this).css({bottom:20,left:0,position:"fixed",width:"310px",height:"auto",margin:0,padding:0,listStyleType:"none",zIndex:1e7}),a(this).css({left:(a(window).width()-a(this).outerWidth(!1))/2+"px"})}},parent:{object:"<li />",selector:"li",css:{}},css:{display:"none",width:"310px"},addClass:""},a.noty.layouts.bottomLeft={name:"bottomLeft",options:{},container:{object:'<ul id="noty_bottomLeft_layout_container" />',selector:"ul#noty_bottomLeft_layout_container",style:function(){a(this).css({bottom:20,left:20,position:"fixed",width:"310px",height:"auto",margin:0,padding:0,listStyleType:"none",zIndex:1e7}),window.innerWidth<600&&a(this).css({left:5})}},parent:{object:"<li />",selector:"li",css:{}},css:{display:"none",width:"310px"},addClass:""},a.noty.layouts.bottomRight={name:"bottomRight",options:{},container:{object:'<ul id="noty_bottomRight_layout_container" />',selector:"ul#noty_bottomRight_layout_container",style:function(){a(this).css({bottom:20,right:20,position:"fixed",width:"310px",height:"auto",margin:0,padding:0,listStyleType:"none",zIndex:1e7}),window.innerWidth<600&&a(this).css({right:5})}},parent:{object:"<li />",selector:"li",css:{}},css:{display:"none",width:"310px"},addClass:""},a.noty.layouts.center={name:"center",options:{},container:{object:'<ul id="noty_center_layout_container" />',selector:"ul#noty_center_layout_container",style:function(){a(this).css({position:"fixed",width:"310px",height:"auto",margin:0,padding:0,listStyleType:"none",zIndex:1e7});var b=a(this).clone().css({visibility:"hidden",display:"block",position:"absolute",top:0,left:0}).attr("id","dupe");a("body").append(b),b.find(".i-am-closing-now").remove(),b.find("li").css("display","block");var c=b.height();b.remove(),a(this).hasClass("i-am-new")?a(this).css({left:(a(window).width()-a(this).outerWidth(!1))/2+"px",top:(a(window).height()-c)/2+"px"}):a(this).animate({left:(a(window).width()-a(this).outerWidth(!1))/2+"px",top:(a(window).height()-c)/2+"px"},500)}},parent:{object:"<li />",selector:"li",css:{}},css:{display:"none",width:"310px"},addClass:""},a.noty.layouts.centerLeft={name:"centerLeft",options:{},container:{object:'<ul id="noty_centerLeft_layout_container" />',selector:"ul#noty_centerLeft_layout_container",style:function(){a(this).css({left:20,position:"fixed",width:"310px",height:"auto",margin:0,padding:0,listStyleType:"none",zIndex:1e7});var b=a(this).clone().css({visibility:"hidden",display:"block",position:"absolute",top:0,left:0}).attr("id","dupe");a("body").append(b),b.find(".i-am-closing-now").remove(),b.find("li").css("display","block");var c=b.height();b.remove(),a(this).hasClass("i-am-new")?a(this).css({top:(a(window).height()-c)/2+"px"}):a(this).animate({top:(a(window).height()-c)/2+"px"},500),window.innerWidth<600&&a(this).css({left:5})}},parent:{object:"<li />",selector:"li",css:{}},css:{display:"none",width:"310px"},addClass:""},a.noty.layouts.centerRight={name:"centerRight",options:{},container:{object:'<ul id="noty_centerRight_layout_container" />',selector:"ul#noty_centerRight_layout_container",style:function(){a(this).css({right:20,position:"fixed",width:"310px",height:"auto",margin:0,padding:0,listStyleType:"none",zIndex:1e7});var b=a(this).clone().css({visibility:"hidden",display:"block",position:"absolute",top:0,left:0}).attr("id","dupe");a("body").append(b),b.find(".i-am-closing-now").remove(),b.find("li").css("display","block");var c=b.height();b.remove(),a(this).hasClass("i-am-new")?a(this).css({top:(a(window).height()-c)/2+"px"}):a(this).animate({top:(a(window).height()-c)/2+"px"},500),window.innerWidth<600&&a(this).css({right:5})}},parent:{object:"<li />",selector:"li",css:{}},css:{display:"none",width:"310px"},addClass:""},a.noty.layouts.inline={name:"inline",options:{},container:{object:'<ul class="noty_inline_layout_container" />',selector:"ul.noty_inline_layout_container",style:function(){a(this).css({width:"100%",height:"auto",margin:0,padding:0,listStyleType:"none",zIndex:9999999})}},parent:{object:"<li />",selector:"li",css:{}},css:{display:"none"},addClass:""},a.noty.layouts.top={name:"top",options:{},container:{object:'<ul id="noty_top_layout_container" />',selector:"ul#noty_top_layout_container",style:function(){a(this).css({top:0,left:"5%",position:"fixed",width:"90%",height:"auto",margin:0,padding:0,listStyleType:"none",zIndex:9999999})}},parent:{object:"<li />",selector:"li",css:{}},css:{display:"none"},addClass:""},a.noty.layouts.topCenter={name:"topCenter",options:{},container:{object:'<ul id="noty_topCenter_layout_container" />',selector:"ul#noty_topCenter_layout_container",style:function(){a(this).css({top:20,left:0,position:"fixed",width:"310px",height:"auto",margin:0,padding:0,listStyleType:"none",zIndex:1e7}),a(this).css({left:(a(window).width()-a(this).outerWidth(!1))/2+"px"})}},parent:{object:"<li />",selector:"li",css:{}},css:{display:"none",width:"310px"},addClass:""},a.noty.layouts.topLeft={name:"topLeft",options:{},container:{object:'<ul id="noty_topLeft_layout_container" />',selector:"ul#noty_topLeft_layout_container",style:function(){a(this).css({top:20,left:20,position:"fixed",width:"310px",height:"auto",margin:0,padding:0,listStyleType:"none",zIndex:1e7}),window.innerWidth<600&&a(this).css({left:5})}},parent:{object:"<li />",selector:"li",css:{}},css:{display:"none",width:"310px"},addClass:""},a.noty.layouts.topRight={name:"topRight",options:{},container:{object:'<ul id="noty_topRight_layout_container" />',selector:"ul#noty_topRight_layout_container",style:function(){a(this).css({top:20,right:20,position:"fixed",width:"310px",height:"auto",margin:0,padding:0,listStyleType:"none",zIndex:1e7}),window.innerWidth<600&&a(this).css({right:5})}},parent:{object:"<li />",selector:"li",css:{}},css:{display:"none",width:"310px"},addClass:""},a.noty.themes.bootstrapTheme={name:"bootstrapTheme",modal:{css:{position:"fixed",width:"100%",height:"100%",backgroundColor:"#000",zIndex:1e4,opacity:.6,display:"none",left:0,top:0}},style:function(){var b=this.options.layout.container.selector;switch(a(b).addClass("list-group"),this.$closeButton.append('<span aria-hidden="true">&times;</span><span class="sr-only">Close</span>'),this.$closeButton.addClass("close"),this.$bar.addClass("list-group-item").css("padding","0px"),this.options.type){case"alert":case"notification":this.$bar.addClass("list-group-item-info");break;case"warning":this.$bar.addClass("list-group-item-warning");break;case"error":this.$bar.addClass("list-group-item-danger");break;case"information":this.$bar.addClass("list-group-item-info");break;case"success":this.$bar.addClass("list-group-item-success")}this.$message.css({fontSize:"13px",lineHeight:"16px",textAlign:"center",padding:"8px 10px 9px",width:"auto",position:"relative"})},callback:{onShow:function(){},onClose:function(){}}},a.noty.themes.defaultTheme={name:"defaultTheme",helpers:{borderFix:function(){if(this.options.dismissQueue){var b=this.options.layout.container.selector+" "+this.options.layout.parent.selector;switch(this.options.layout.name){case"top":a(b).css({borderRadius:"0px 0px 0px 0px"}),a(b).last().css({borderRadius:"0px 0px 5px 5px"});break;case"topCenter":case"topLeft":case"topRight":case"bottomCenter":case"bottomLeft":case"bottomRight":case"center":case"centerLeft":case"centerRight":case"inline":a(b).css({borderRadius:"0px 0px 0px 0px"}),a(b).first().css({"border-top-left-radius":"5px","border-top-right-radius":"5px"}),a(b).last().css({"border-bottom-left-radius":"5px","border-bottom-right-radius":"5px"});break;case"bottom":a(b).css({borderRadius:"0px 0px 0px 0px"}),a(b).first().css({borderRadius:"5px 5px 0px 0px"})}}}},modal:{css:{position:"fixed",width:"100%",height:"100%",backgroundColor:"#000",zIndex:1e4,opacity:.6,display:"none",left:0,top:0}},style:function(){switch(this.$bar.css({overflow:"hidden",background:"url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAoCAQAAAClM0ndAAAAhklEQVR4AdXO0QrCMBBE0bttkk38/w8WRERpdyjzVOc+HxhIHqJGMQcFFkpYRQotLLSw0IJ5aBdovruMYDA/kT8plF9ZKLFQcgF18hDj1SbQOMlCA4kao0iiXmah7qBWPdxpohsgVZyj7e5I9KcID+EhiDI5gxBYKLBQYKHAQoGFAoEks/YEGHYKB7hFxf0AAAAASUVORK5CYII=') repeat-x scroll left top #fff"}),this.$message.css({fontSize:"13px",lineHeight:"16px",textAlign:"center",padding:"8px 10px 9px",width:"auto",position:"relative"}),this.$closeButton.css({position:"absolute",top:4,right:4,width:10,height:10,background:"url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAQAAAAnOwc2AAAAxUlEQVR4AR3MPUoDURSA0e++uSkkOxC3IAOWNtaCIDaChfgXBMEZbQRByxCwk+BasgQRZLSYoLgDQbARxry8nyumPcVRKDfd0Aa8AsgDv1zp6pYd5jWOwhvebRTbzNNEw5BSsIpsj/kurQBnmk7sIFcCF5yyZPDRG6trQhujXYosaFoc+2f1MJ89uc76IND6F9BvlXUdpb6xwD2+4q3me3bysiHvtLYrUJto7PD/ve7LNHxSg/woN2kSz4txasBdhyiz3ugPGetTjm3XRokAAAAASUVORK5CYII=)",display:"none",cursor:"pointer"}),this.$buttons.css({padding:5,textAlign:"right",borderTop:"1px solid #ccc",backgroundColor:"#fff"}),this.$buttons.find("button").css({marginLeft:5}),this.$buttons.find("button:first").css({marginLeft:0}),this.$bar.on({mouseenter:function(){a(this).find(".noty_close").stop().fadeTo("normal",1)},mouseleave:function(){a(this).find(".noty_close").stop().fadeTo("normal",0)}}),this.options.layout.name){case"top":this.$bar.css({borderRadius:"0px 0px 5px 5px",borderBottom:"2px solid #eee",borderLeft:"2px solid #eee",borderRight:"2px solid #eee",boxShadow:"0 2px 4px rgba(0, 0, 0, 0.1)"});break;case"topCenter":case"center":case"bottomCenter":case"inline":this.$bar.css({borderRadius:"5px",border:"1px solid #eee",boxShadow:"0 2px 4px rgba(0, 0, 0, 0.1)"}),this.$message.css({fontSize:"13px",textAlign:"center"});break;case"topLeft":case"topRight":case"bottomLeft":case"bottomRight":case"centerLeft":case"centerRight":this.$bar.css({borderRadius:"5px",border:"1px solid #eee",boxShadow:"0 2px 4px rgba(0, 0, 0, 0.1)"}),this.$message.css({fontSize:"13px",textAlign:"left"});break;case"bottom":this.$bar.css({borderRadius:"5px 5px 0px 0px",borderTop:"2px solid #eee",borderLeft:"2px solid #eee",borderRight:"2px solid #eee",boxShadow:"0 -2px 4px rgba(0, 0, 0, 0.1)"});break;default:this.$bar.css({border:"2px solid #eee",boxShadow:"0 2px 4px rgba(0, 0, 0, 0.1)"})}switch(this.options.type){case"alert":case"notification":this.$bar.css({backgroundColor:"#FFF",borderColor:"#CCC",color:"#444"});break;case"warning":this.$bar.css({backgroundColor:"#FFEAA8",borderColor:"#FFC237",color:"#826200"}),this.$buttons.css({borderTop:"1px solid #FFC237"});break;case"error":this.$bar.css({backgroundColor:"red",borderColor:"darkred",color:"#FFF"}),this.$message.css({fontWeight:"bold"}),this.$buttons.css({borderTop:"1px solid darkred"});break;case"information":this.$bar.css({backgroundColor:"#57B7E2",borderColor:"#0B90C4",color:"#FFF"}),this.$buttons.css({borderTop:"1px solid #0B90C4"});break;case"success":this.$bar.css({backgroundColor:"lightgreen",borderColor:"#50C24E",color:"darkgreen"}),this.$buttons.css({borderTop:"1px solid #50C24E"});break;default:this.$bar.css({backgroundColor:"#FFF",borderColor:"#CCC",color:"#444"})}},callback:{onShow:function(){a.noty.themes.defaultTheme.helpers.borderFix.apply(this)},onClose:function(){a.noty.themes.defaultTheme.helpers.borderFix.apply(this)}}},a.noty.themes.relax={name:"relax",helpers:{},modal:{css:{position:"fixed",width:"100%",height:"100%",backgroundColor:"#000",zIndex:1e4,opacity:.6,display:"none",left:0,top:0}},style:function(){switch(this.$bar.css({overflow:"hidden",margin:"4px 0",borderRadius:"2px"}),this.$message.css({fontSize:"14px",lineHeight:"16px",textAlign:"center",padding:"10px",width:"auto",position:"relative"}),this.$closeButton.css({position:"absolute",top:4,right:4,width:10,height:10,background:"url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAQAAAAnOwc2AAAAxUlEQVR4AR3MPUoDURSA0e++uSkkOxC3IAOWNtaCIDaChfgXBMEZbQRByxCwk+BasgQRZLSYoLgDQbARxry8nyumPcVRKDfd0Aa8AsgDv1zp6pYd5jWOwhvebRTbzNNEw5BSsIpsj/kurQBnmk7sIFcCF5yyZPDRG6trQhujXYosaFoc+2f1MJ89uc76IND6F9BvlXUdpb6xwD2+4q3me3bysiHvtLYrUJto7PD/ve7LNHxSg/woN2kSz4txasBdhyiz3ugPGetTjm3XRokAAAAASUVORK5CYII=)",display:"none",cursor:"pointer"}),this.$buttons.css({padding:5,textAlign:"right",borderTop:"1px solid #ccc",backgroundColor:"#fff"}),this.$buttons.find("button").css({marginLeft:5}),this.$buttons.find("button:first").css({marginLeft:0}),this.$bar.on({mouseenter:function(){a(this).find(".noty_close").stop().fadeTo("normal",1)},mouseleave:function(){a(this).find(".noty_close").stop().fadeTo("normal",0)}}),this.options.layout.name){case"top":this.$bar.css({borderBottom:"2px solid #eee",borderLeft:"2px solid #eee",borderRight:"2px solid #eee",borderTop:"2px solid #eee",boxShadow:"0 2px 4px rgba(0, 0, 0, 0.1)"});break;case"topCenter":case"center":case"bottomCenter":case"inline":this.$bar.css({border:"1px solid #eee",boxShadow:"0 2px 4px rgba(0, 0, 0, 0.1)"}),this.$message.css({fontSize:"13px",textAlign:"center"});break;case"topLeft":case"topRight":case"bottomLeft":case"bottomRight":case"centerLeft":case"centerRight":this.$bar.css({border:"1px solid #eee",boxShadow:"0 2px 4px rgba(0, 0, 0, 0.1)"}),this.$message.css({fontSize:"13px",textAlign:"left"});break;case"bottom":this.$bar.css({borderTop:"2px solid #eee",borderLeft:"2px solid #eee",borderRight:"2px solid #eee",borderBottom:"2px solid #eee",boxShadow:"0 -2px 4px rgba(0, 0, 0, 0.1)"});break;default:this.$bar.css({border:"2px solid #eee",boxShadow:"0 2px 4px rgba(0, 0, 0, 0.1)"})}switch(this.options.type){case"alert":case"notification":this.$bar.css({backgroundColor:"#FFF",borderColor:"#dedede",color:"#444"});break;case"warning":this.$bar.css({backgroundColor:"#FFEAA8",borderColor:"#FFC237",color:"#826200"}),this.$buttons.css({borderTop:"1px solid #FFC237"});break;case"error":this.$bar.css({backgroundColor:"#FF8181",borderColor:"#e25353",color:"#FFF"}),this.$message.css({fontWeight:"bold"}),this.$buttons.css({borderTop:"1px solid darkred"});break;case"information":this.$bar.css({backgroundColor:"#78C5E7",borderColor:"#3badd6",color:"#FFF"}),this.$buttons.css({borderTop:"1px solid #0B90C4"});break;case"success":this.$bar.css({backgroundColor:"#BCF5BC",borderColor:"#7cdd77",color:"darkgreen"}),this.$buttons.css({borderTop:"1px solid #50C24E"});break;default:this.$bar.css({backgroundColor:"#FFF",borderColor:"#CCC",color:"#444"})}},callback:{onShow:function(){},onClose:function(){}}},window.noty});;
(function($) {

    $.noty.themes.docAssemblerTheme = {
		name: 'docAssemblerTheme',
		helpers: {
			borderFix: function() {
				if (this.options.dismissQueue) {
					var selector = this.options.layout.container.selector + ' ' + this.options.layout.parent.selector;
					switch (this.options.layout.name) {
						case 'top':
							$(selector).css({borderRadius: '0px 0px 0px 0px'});
							$(selector).last().css({borderRadius: '0px 0px 5px 5px'}); break;
						case 'topCenter': case 'topLeft': case 'topRight':
						case 'bottomCenter': case 'bottomLeft': case 'bottomRight':
						case 'center': case 'centerLeft': case 'centerRight': case 'inline':
							$(selector).css({borderRadius: '0px 0px 0px 0px'});
							$(selector).first().css({'border-top-left-radius': '5px', 'border-top-right-radius': '5px'});
							$(selector).last().css({'border-bottom-left-radius': '5px', 'border-bottom-right-radius': '5px'}); break;
						case 'bottom':
							$(selector).css({borderRadius: '0px 0px 0px 0px'});
							$(selector).first().css({borderRadius: '5px 5px 0px 0px'}); break;
						default: break;
					}
				}
			}
		},
		modal: {
			css: {
				position: 'fixed',
				width: '100%',
				height: '100%',
				backgroundColor: '#000',
				zIndex: 10000,
				opacity: 0.6,
				display: 'none',
				left: 0,
				top: 0
			}
		},
		style: function() {

			this.$bar.css({
				overflow: 'hidden'
				//background: "url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAoCAYAAAAPOoFWAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPZJREFUeNq81tsOgjAMANB2ov7/7ypaN7IlIwi9rGuT8QSc9EIDAsAznxvY4pXPKr05RUE5MEVB+TyWfCEl9LZApYopCmo9C4FKSMtYoI8Bwv79aQJU4l6hXXCZrQbokJEksxHo9KMOgc6w1atHXM8K9DVC7FQnJ0i8iK3QooGgbnyKgMDygBWyYFZoqx4qS27KqLZJjA1D0jK6QJcYEQEiWv9PGkTsbqxQ8oT+ZtZB6AkdsJnQDnMoHXHLGKOgDYuCWmYhEERCI5gaamW0bnHdA3k2ltlIN+2qKRyCND0bhqSYCyTB3CAOc4WusBEIpkeBuPgJMAAX8Hs1NfqHRgAAAABJRU5ErkJggg==') repeat-x scroll left top #fff"
			});

			this.$message.css({
				fontSize: '13px',
				lineHeight: '16px',
				textAlign: 'center',
				padding: '8px 10px 9px',
				width: 'auto',
				position: 'relative'
			});

			this.$closeButton.css({
				position: 'absolute',
				top: 4, right: 4,
				width: 10, height: 10,
				//background: "url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAATpJREFUeNoszrFqVFEUheG19zlz7sQ7ijMQBAvfYBqbpJCoZSAQbOwEE1IHGytbLQUJ8SUktW8gCCFJMSGSNxCmFBJO7j5rpXD6n5/P5vM53H3b3T9LOiB5AQDuDjM7BnA7DMPHDGBH0nuSzwHsRcRVRNRSysuU0i6AOwA/02w2+9Fae00SEbEh6SGAR5K+k3zWWptKepCm0+kpyRoRGyRBcpPkDsn1iEBr7drdP2VJZyQXERGSPpiZAViTBACXKaV9kqd5uVzCzO5KKb/d/UZSDwD/eyxqree1VqSu6zKAF2Z2RPJJaw0rAkjOJT0m+SuT/AbgDcmnkmBmfwAsJL1dXQ8lWY6IGwB1ZbrOOb8zs8thGP4COFwx/mE8Ho9Go9ErMzvJOW/1fY/JZIJSypqZfXX3L13X9fcDAKJct1sx3OiuAAAAAElFTkSuQmCC)",
				display: 'none',
				cursor: 'pointer'
			});

			this.$buttons.css({
				padding: 5,
				textAlign: 'right',
				borderTop: '1px solid #ccc',
				backgroundColor: '#fff'
			});

			this.$buttons.find('button').css({
				marginLeft: 5
			});

			this.$buttons.find('button:first').css({
				marginLeft: 0
			});

			this.$bar.bind({
				mouseenter: function() { $(this).find('.noty_close').stop().fadeTo('normal',1); },
				mouseleave: function() { $(this).find('.noty_close').stop().fadeTo('normal',0); }
			});

			switch (this.options.layout.name) {
				case 'top':
					this.$bar.css({
						borderRadius: '0px 0px 5px 5px',
						borderBottom: '2px solid #eee',
						borderLeft: '2px solid #eee',
						borderRight: '2px solid #eee',
						boxShadow: "0 2px 4px rgba(0, 0, 0, 0.1)"
					});
				break;
				case 'topCenter': case 'center': case 'bottomCenter': case 'inline':
					this.$bar.css({
						borderRadius: '5px',
						border: '1px solid #eee',
						boxShadow: "0 2px 4px rgba(0, 0, 0, 0.1)"
					});
					this.$message.css({fontSize: '13px', textAlign: 'center'});
				break;
				case 'topLeft': case 'topRight':
				case 'bottomLeft': case 'bottomRight':
				case 'centerLeft': case 'centerRight':
					this.$bar.css({
						borderRadius: '5px',
						border: '1px solid #eee',
						boxShadow: "0 2px 4px rgba(0, 0, 0, 0.1)"
					});
					this.$message.css({fontSize: '13px', textAlign: 'left'});
				break;
				case 'bottom':
					this.$bar.css({
						borderRadius: '5px 5px 0px 0px',
						borderTop: '2px solid #eee',
						borderLeft: '2px solid #eee',
						borderRight: '2px solid #eee',
						boxShadow: "0 -2px 4px rgba(0, 0, 0, 0.1)"
					});
				break;
				default:
					this.$bar.css({
						border: '2px solid #eee',
						boxShadow: "0 2px 4px rgba(0, 0, 0, 0.1)"
					});
				break;
			}

			switch (this.options.type) {
				case 'alert': case 'notification':
                    this.$bar.css({ backgroundColor: '#5cb85c', borderColor: '#5cb85c', color: 'white' }); break;
				case 'warning':
				    this.$bar.css({ backgroundColor: '#f0ad4e', borderColor: '#f0ad4e', color: 'white' });
				    this.$buttons.css({ borderTop: '1px solid #f0ad4e' }); break;
				case 'error':
				    this.$bar.css({ backgroundColor: '#d9534f', borderColor: '#d9534f', color: 'white' });
		            this.$message.css({fontWeight: 'bold'});
				    this.$buttons.css({ borderTop: '1px solid #d9534f' }); break;
				case 'information':
                    this.$bar.css({ backgroundColor: '#25AAE1', borderColor: '#25AAE1', color: 'white' });
                    this.$buttons.css({ borderTop: '1px solid #25AAE1' }); break;
				case 'success':
                    this.$bar.css({ backgroundColor: '#5cb85c', borderColor: '#5cb85c', color: 'white' });
                    this.$buttons.css({ borderTop: '1px solid #5cb85c' }); break;
				default:
				    this.$bar.css({ backgroundColor: '#428bca', borderColor: '#428bca', color: 'white' }); break;
			}
		},
		callback: {
		    onShow: function () { $.noty.themes.docAssemblerTheme.helpers.borderFix.apply(this); },
		    onClose: function () { $.noty.themes.docAssemblerTheme.helpers.borderFix.apply(this); }
		}
	};

})(jQuery);
;
/*
 HTML5 Shiv v3.6.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
*/
(function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag();
a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x<style>article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}</style>";
c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="<xyz></xyz>";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode||
"undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup main mark meter nav output progress section summary time video",version:"3.6.2",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f);if(g)return a.createDocumentFragment();
for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d<h;d++)c.createElement(e[d]);return c}};l.html5=e;q(f)})(this,document);
;
// ES6-shim 0.9.2 (c) 2013 Paul Miller (http://paulmillr.com)
// ES6-shim may be freely distributed under the MIT license.
// For more details and documentation:
// https://github.com/paulmillr/es6-shim/

(function (undefined) {
    'use strict';

    var isCallableWithoutNew = function (func) {
        try { func(); }
        catch (e) { return false; }
        return true;
    };

    var arePropertyDescriptorsSupported = function () {
        try {
            Object.defineProperty({}, 'x', {});
            return true;
        } catch (e) { /* this is IE 8. */
            return false;
        }
    };

    var startsWithRejectsRegex = function () {
        var rejectsRegex = false;
        if (String.prototype.startsWith) {
            try {
                '/a/'.startsWith(/a/);
            } catch (e) { /* this is spec compliant */
                rejectsRegex = true;
            }
        }
        return rejectsRegex;
    };

    var main = function () {
        var globals = (typeof global === 'undefined') ? window : global;
        var global_isFinite = globals.isFinite;
        var supportsDescriptors = !!Object.defineProperty && arePropertyDescriptorsSupported();
        var startsWithIsCompliant = startsWithRejectsRegex();
        var _slice = Array.prototype.slice;
        var _indexOf = String.prototype.indexOf;
        var _toString = Object.prototype.toString;
        var _hasOwnProperty = Object.prototype.hasOwnProperty;

        // Define configurable, writable and non-enumerable props
        // if they don’t exist.
        var defineProperties = function (object, map) {
            Object.keys(map).forEach(function (name) {
                var method = map[name];
                if (name in object) return;
                if (supportsDescriptors) {
                    Object.defineProperty(object, name, {
                        configurable: true,
                        enumerable: false,
                        writable: true,
                        value: method
                    });
                } else {
                    object[name] = method;
                }
            });
        };

        var ES = {
            CheckObjectCoercible: function (x) {
                if (x == null) throw TypeError('Cannot call method on ' + x);
                return x;
            },

            ToInt32: function (x) {
                return x >> 0;
            },

            ToUint32: function (x) {
                return x >>> 0;
            },

            toInteger: function (value) {
                var number = +value;
                if (Number.isNaN(number)) return 0;
                if (number === 0 || !Number.isFinite(number)) return number;
                return Math.sign(number) * Math.floor(Math.abs(number));
            }
        };

        defineProperties(String, {
            fromCodePoint: function () {
                var points = _slice.call(arguments, 0, arguments.length);
                var result = [];
                var next;
                for (var i = 0, length = points.length; i < length; i++) {
                    next = Number(points[i]);
                    if (!Object.is(next, ES.toInteger(next)) ||
                        next < 0 || next > 0x10FFFF) {
                        throw new RangeError('Invalid code point ' + next);
                    }

                    if (next < 0x10000) {
                        result.push(String.fromCharCode(next));
                    } else {
                        next -= 0x10000;
                        result.push(String.fromCharCode((next >> 10) + 0xD800));
                        result.push(String.fromCharCode((next % 0x400) + 0xDC00));
                    }
                }
                return result.join('');
            },

            raw: function () {
                var callSite = arguments.length > 0 ? arguments[0] : undefined;
                var substitutions = _slice.call(arguments, 1, arguments.length);
                var cooked = Object(callSite);
                var rawValue = cooked.raw;
                var raw = Object(rawValue);
                var len = Object.keys(raw).length;
                var literalsegments = ES.ToUint32(len);
                if (literalsegments === 0) {
                    return '';
                }

                var stringElements = [];
                var nextIndex = 0;
                var nextKey, next, nextSeg, nextSub;
                while (nextIndex < literalsegments) {
                    nextKey = String(nextIndex);
                    next = raw[nextKey];
                    nextSeg = String(next);
                    stringElements.push(nextSeg);
                    if (nextIndex + 1 >= literalsegments) {
                        break;
                    }
                    next = substitutions[nextKey];
                    if (next === undefined) {
                        break;
                    }
                    nextSub = String(next);
                    stringElements.push(nextSub);
                    nextIndex++;
                }
                return stringElements.join('');
            }
        });

        var StringShims = {
            // Fast repeat, uses the `Exponentiation by squaring` algorithm.
            // Perf: http://jsperf.com/string-repeat2/2
            repeat: (function () {
                var repeat = function (s, times) {
                    if (times < 1) return '';
                    if (times % 2) return repeat(s, times - 1) + s;
                    var half = repeat(s, times / 2);
                    return half + half;
                };

                return function (times) {
                    var thisStr = String(ES.CheckObjectCoercible(this));
                    times = ES.toInteger(times);
                    if (times < 0 || times === Infinity) {
                        throw new RangeError('Invalid String#repeat value');
                    }
                    return repeat(thisStr, times);
                };
            })(),

            startsWith: function (searchStr) {
                var thisStr = String(ES.CheckObjectCoercible(this));
                if (_toString.call(searchStr) === '[object RegExp]') throw new TypeError('Cannot call method "startsWith" with a regex');
                searchStr = String(searchStr);
                var startArg = arguments.length > 1 ? arguments[1] : undefined;
                var start = Math.max(ES.toInteger(startArg), 0);
                return thisStr.slice(start, start + searchStr.length) === searchStr;
            },

            endsWith: function (searchStr) {
                var thisStr = String(ES.CheckObjectCoercible(this));
                if (_toString.call(searchStr) === '[object RegExp]') throw new TypeError('Cannot call method "endsWith" with a regex');
                searchStr = String(searchStr);
                var thisLen = thisStr.length;
                var posArg = arguments.length > 1 ? arguments[1] : undefined;
                var pos = posArg === undefined ? thisLen : ES.toInteger(posArg);
                var end = Math.min(Math.max(pos, 0), thisLen);
                return thisStr.slice(end - searchStr.length, end) === searchStr;
            },

            contains: function (searchString) {
                var position = arguments.length > 1 ? arguments[1] : undefined;
                // Somehow this trick makes method 100% compat with the spec.
                return _indexOf.call(this, searchString, position) !== -1;
            },

            codePointAt: function (pos) {
                var thisStr = String(ES.CheckObjectCoercible(this));
                var position = ES.toInteger(pos);
                var length = thisStr.length;
                if (position < 0 || position >= length) return undefined;
                var first = thisStr.charCodeAt(position);
                var isEnd = (position + 1 === length);
                if (first < 0xD800 || first > 0xDBFF || isEnd) return first;
                var second = thisStr.charCodeAt(position + 1);
                if (second < 0xDC00 || second > 0xDFFF) return first;
                return ((first - 0xD800) * 1024) + (second - 0xDC00) + 0x10000;
            }
        };
        defineProperties(String.prototype, StringShims);

        if (!startsWithIsCompliant) {
            // Firefox has a noncompliant startsWith implementation
            String.prototype.startsWith = StringShims.startsWith;
            String.prototype.endsWith = StringShims.endsWith;
        }

        defineProperties(Array, {
            from: function (iterable) {
                var mapFn = arguments.length > 1 ? arguments[1] : undefined;
                var thisArg = arguments.length > 2 ? arguments[2] : undefined;

                if (mapFn !== undefined && _toString.call(mapFn) !== '[object Function]') {
                    throw new TypeError('Array.from: when provided, the second argument must be a function');
                }

                var list = Object(iterable);
                var length = ES.ToUint32(list.length);
                var result = typeof this === 'function' ? Object(new this(length)) : new Array(length);

                for (var i = 0; i < length; i++) {
                    var value = list[i];
                    if (mapFn !== undefined) {
                        result[i] = thisArg ? mapFn.call(thisArg, value) : mapFn(value);
                    } else {
                        result[i] = value;
                    }
                }

                result.length = length;
                return result;
            },

            of: function () {
                return Array.from(arguments);
            }
        });

        defineProperties(globals, {
            ArrayIterator: function (array, kind) {
                this.i = 0;
                this.array = array;
                this.kind = kind;
            }
        });

        defineProperties(ArrayIterator.prototype, {
            next: function () {
                var i = this.i;
                this.i = i + 1;
                var array = this.array;

                if (i >= array.length) {
                    throw new Error();
                }

                if (array.hasOwnProperty(i)) {
                    var kind = this.kind;
                    var retval;
                    if (kind === "key") {
                        retval = i;
                    }
                    if (kind === "value") {
                        retval = array[i];
                    }
                    if (kind === "entry") {
                        retval = [i, array[i]];
                    }
                } else {
                    retval = this.next();
                }
                return retval;
            }
        });

        defineProperties(Array.prototype, {
            copyWithin: function (target, start) {
                var o = Object(this);
                var len = Math.max(ES.toInteger(o.length), 0);
                var to = target < 0 ? Math.max(len + target, 0) : Math.min(target, len);
                var from = start < 0 ? Math.max(len + start, 0) : Math.min(start, len);
                var end = arguments.length > 2 ? arguments[2] : len;
                var final = end < 0 ? Math.max(len + end, 0) : Math.min(end, len);
                var count = Math.min(final - from, len - to);
                var direction = 1;
                if (from < to && to < (from + count)) {
                    direction = -1;
                    from += count - 1;
                    to += count - 1;
                }
                while (count > 0) {
                    if (_hasOwnProperty.call(o, from)) {
                        o[to] = o[from];
                    } else {
                        delete o[from];
                    }
                    from += direction;
                    to += direction;
                    count -= 1;
                }
                return o;
            },
            fill: function (value) {
                var len = this.length;
                var start = arguments.length > 1 ? ES.toInteger(arguments[1]) : 0;
                var end = arguments.length > 2 ? ES.toInteger(arguments[2]) : len;

                var relativeStart = start < 0 ? Math.max(len + start, 0) : Math.min(start, len);

                for (var i = relativeStart; i < len && i < end; ++i) {
                    this[i] = value;
                }
                return this;
            },

            find: function (predicate) {
                var list = Object(this);
                var length = ES.ToUint32(list.length);
                if (length === 0) return undefined;
                if (typeof predicate !== 'function') {
                    throw new TypeError('Array#find: predicate must be a function');
                }
                var thisArg = arguments.length > 1 ? arguments[1] : undefined;
                for (var i = 0, value; i < length && i in list; i++) {
                    value = list[i];
                    if (predicate.call(thisArg, value, i, list)) return value;
                }
                return undefined;
            },

            findIndex: function (predicate) {
                var list = Object(this);
                var length = ES.ToUint32(list.length);
                if (length === 0) return -1;
                if (typeof predicate !== 'function') {
                    throw new TypeError('Array#findIndex: predicate must be a function');
                }
                var thisArg = arguments.length > 1 ? arguments[1] : undefined;
                for (var i = 0, value; i < length && i in list; i++) {
                    value = list[i];
                    if (predicate.call(thisArg, value, i, list)) return i;
                }
                return -1;
            },

            keys: function () {
                return new ArrayIterator(this, "key");
            },

            values: function () {
                return new ArrayIterator(this, "value");
            },

            entries: function () {
                return new ArrayIterator(this, "entry");
            }
        });

        var maxSafeInteger = Math.pow(2, 53) - 1;
        defineProperties(Number, {
            MAX_SAFE_INTEGER: maxSafeInteger,
            MIN_SAFE_INTEGER: -maxSafeInteger,
            EPSILON: 2.220446049250313e-16,

            parseInt: globals.parseInt,
            parseFloat: globals.parseFloat,

            isFinite: function (value) {
                return typeof value === 'number' && global_isFinite(value);
            },

            isSafeInteger: function (value) {
                return typeof value === 'number' &&
                  !Number.isNaN(value) &&
                  Number.isFinite(value) &&
                  parseInt(value, 10) === value &&
                  Math.abs(value) <= Number.MAX_SAFE_INTEGER;
            },

            isNaN: function (value) {
                // NaN !== NaN, but they are identical.
                // NaNs are the only non-reflexive value, i.e., if x !== x,
                // then x is NaN.
                // isNaN is broken: it converts its argument to number, so
                // isNaN('foo') => true
                return value !== value;
            },

        });

        defineProperties(Number.prototype, {
            clz: function () {
                var number = +this;
                if (!number || !Number.isFinite(number)) return 32;
                number = number < 0 ? Math.ceil(number) : Math.floor(number);
                number = number - Math.floor(number / 0x100000000) * 0x100000000;
                return 32 - (number).toString(2).length;
            }
        });

        if (supportsDescriptors) {
            defineProperties(Object, {
                getOwnPropertyDescriptors: function (subject) {
                    var descs = {};
                    Object.getOwnPropertyNames(subject).forEach(function (propName) {
                        descs[propName] = Object.getOwnPropertyDescriptor(subject, propName);
                    });
                    return descs;
                },

                getPropertyDescriptor: function (subject, name) {
                    var pd = Object.getOwnPropertyDescriptor(subject, name);
                    var proto = Object.getPrototypeOf(subject);
                    while (pd === undefined && proto !== null) {
                        pd = Object.getOwnPropertyDescriptor(proto, name);
                        proto = Object.getPrototypeOf(proto);
                    }
                    return pd;
                },

                getPropertyNames: function (subject) {
                    var result = Object.getOwnPropertyNames(subject);
                    var proto = Object.getPrototypeOf(subject);

                    var addProperty = function (property) {
                        if (result.indexOf(property) === -1) {
                            result.push(property);
                        }
                    };

                    while (proto !== null) {
                        Object.getOwnPropertyNames(proto).forEach(addProperty);
                        proto = Object.getPrototypeOf(proto);
                    }
                    return result;
                },

                // 19.1.3.1
                assign: function (target, source) {
                    return Object.keys(source).reduce(function (target, key) {
                        target[key] = source[key];
                        return target;
                    }, target);
                },

                // 19.1.3.15
                mixin: function (target, source) {
                    var props = Object.getOwnPropertyNames(source);
                    return props.reduce(function (target, property) {
                        var descriptor = Object.getOwnPropertyDescriptor(source, property);
                        return Object.defineProperty(target, property, descriptor);
                    }, target);
                }
            });

            // 19.1.3.9
            // shim from https://gist.github.com/WebReflection/5593554
            defineProperties(Object, {
                setPrototypeOf: (function (Object, magic) {
                    var set;

                    var checkArgs = function (O, proto) {
                        if (typeof O !== 'object' || O === null) {
                            throw new TypeError('cannot set prototype on a non-object');
                        }
                        if (typeof proto !== 'object') {
                            throw new TypeError('can only set prototype to an object or null');
                        }
                    };

                    var setPrototypeOf = function (O, proto) {
                        checkArgs(O, proto);
                        set.call(O, proto);
                        return O;
                    };

                    try {
                        // this works already in Firefox and Safari
                        set = Object.getOwnPropertyDescriptor(Object.prototype, magic).set;
                        set.call({}, null);
                    } catch (e) {
                        if (Object.prototype !== {}[magic]) {
                            // IE < 11 cannot be shimmed
                            return;
                        }
                        // probably Chrome or some old Mobile stock browser
                        set = function (proto) {
                            this[magic] = proto;
                        };
                        // please note that this will **not** work
                        // in those browsers that do not inherit
                        // __proto__ by mistake from Object.prototype
                        // in these cases we should probably throw an error
                        // or at least be informed about the issue
                        setPrototypeOf.polyfill = setPrototypeOf(
                          setPrototypeOf({}, null),
                          Object.prototype
                        ) instanceof Object;
                        // setPrototypeOf.polyfill === true means it works as meant
                        // setPrototypeOf.polyfill === false means it's not 100% reliable
                        // setPrototypeOf.polyfill === undefined
                        // or
                        // setPrototypeOf.polyfill ==  null means it's not a polyfill
                        // which means it works as expected
                        // we can even delete Object.prototype.__proto__;
                    }
                    return setPrototypeOf;
                })(Object, '__proto__')
            });
        }

        defineProperties(Object, {
            getOwnPropertyKeys: function (subject) {
                return Object.keys(subject);
            },

            is: function (a, b) {
                if (a === b) {
                    // 0 === -0, but they are not identical.
                    if (a === 0) return 1 / a === 1 / b;
                    return true;
                }
                return Number.isNaN(a) && Number.isNaN(b);
            }
        });

        var MathShims = {
            acosh: function (value) {
                value = Number(value);
                if (Number.isNaN(value) || value < 1) return NaN;
                if (value === 1) return 0;
                if (value === Infinity) return value;
                return Math.log(value + Math.sqrt(value * value - 1));
            },

            asinh: function (value) {
                value = Number(value);
                if (value === 0 || !global_isFinite(value)) {
                    return value;
                }
                return value < 0 ? -Math.asinh(-value) : Math.log(value + Math.sqrt(value * value + 1));
            },

            atanh: function (value) {
                value = Number(value);
                if (Number.isNaN(value) || value < -1 || value > 1) {
                    return NaN;
                }
                if (value === -1) return -Infinity;
                if (value === 1) return Infinity;
                if (value === 0) return value;
                return 0.5 * Math.log((1 + value) / (1 - value));
            },

            cbrt: function (value) {
                value = Number(value);
                if (value === 0) return value;
                var negate = value < 0, result;
                if (negate) value = -value;
                result = Math.pow(value, 1 / 3);
                return negate ? -result : result;
            },

            cosh: function (value) {
                value = Number(value);
                if (value === 0) return 1; // +0 or -0
                if (Number.isNaN(value)) return NaN;
                if (!global_isFinite(value)) return Infinity;
                if (value < 0) value = -value;
                if (value > 21) return Math.exp(value) / 2;
                return (Math.exp(value) + Math.exp(-value)) / 2;
            },

            expm1: function (value) {
                value = Number(value);
                if (value === -Infinity) return -1;
                if (!global_isFinite(value) || value === 0) return value;
                var result = 0;
                var n = 50;
                for (var i = 1; i < n; i++) {
                    for (var j = 2, factorial = 1; j <= i; j++) {
                        factorial *= j;
                    }
                    result += Math.pow(value, i) / factorial;
                }
                return result;
            },

            hypot: function (x, y) {
                var anyNaN = false;
                var allZero = true;
                var anyInfinity = false;
                var numbers = [];
                Array.prototype.every.call(arguments, function (arg) {
                    var num = Number(arg);
                    if (Number.isNaN(num)) anyNaN = true;
                    else if (num === Infinity || num === -Infinity) anyInfinity = true;
                    else if (num !== 0) allZero = false;
                    if (anyInfinity) {
                        return false;
                    } else if (!anyNaN) {
                        numbers.push(Math.abs(num));
                    }
                    return true;
                });
                if (anyInfinity) return Infinity;
                if (anyNaN) return NaN;
                if (allZero) return 0;

                numbers.sort(function (a, b) { return b - a; });
                var largest = numbers[0];
                var divided = numbers.map(function (number) { return number / largest; });
                var sum = divided.reduce(function (sum, number) { return sum += number * number; }, 0);
                return largest * Math.sqrt(sum);
            },

            log2: function (value) {
                return Math.log(value) * Math.LOG2E;
            },

            log10: function (value) {
                return Math.log(value) * Math.LOG10E;
            },

            log1p: function (value) {
                value = Number(value);
                if (value < -1 || Number.isNaN(value)) return NaN;
                if (value === 0 || value === Infinity) return value;
                if (value === -1) return -Infinity;
                var result = 0;
                var n = 50;

                if (value < 0 || value > 1) return Math.log(1 + value);
                for (var i = 1; i < n; i++) {
                    if ((i % 2) === 0) {
                        result -= Math.pow(value, i) / i;
                    } else {
                        result += Math.pow(value, i) / i;
                    }
                }

                return result;
            },

            sign: function (value) {
                var number = +value;
                if (number === 0) return number;
                if (Number.isNaN(number)) return number;
                return number < 0 ? -1 : 1;
            },

            sinh: function (value) {
                value = Number(value);
                if (!global_isFinite(value) || value === 0) return value;
                return (Math.exp(value) - Math.exp(-value)) / 2;
            },

            tanh: function (value) {
                value = Number(value);
                if (Number.isNaN(value) || value === 0) return value;
                if (value === Infinity) return 1;
                if (value === -Infinity) return -1;
                return (Math.exp(value) - Math.exp(-value)) / (Math.exp(value) + Math.exp(-value));
            },

            trunc: function (value) {
                var number = Number(value);
                return number < 0 ? -Math.floor(-number) : Math.floor(number);
            },

            imul: function (x, y) {
                // taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul
                var ah = (x >>> 16) & 0xffff;
                var al = x & 0xffff;
                var bh = (y >>> 16) & 0xffff;
                var bl = y & 0xffff;
                // the shift by 0 fixes the sign on the high part
                // the final |0 converts the unsigned value into a signed value
                return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0) | 0);
            }
        };
        defineProperties(Math, MathShims);

        if (Math.imul(0xffffffff, 5) !== -5) {
            // Safari 6.1, at least, reports "0" for this value
            Math.imul = MathShims.imul;
        }

        // Map and Set require a true ES5 environment
        if (supportsDescriptors) {

            var fastkey = function fastkey(key) {
                var type = typeof key;
                if (type === 'string') {
                    return '$' + key;
                } else if (type === 'number' && !Object.is(key, -0)) {
                    return key;
                }
                return null;
            };

            var emptyObject = function emptyObject() {
                // accomodate some older not-quite-ES5 browsers
                return Object.create ? Object.create(null) : {};
            };

            var collectionShims = {
                Map: (function () {

                    var empty = {};

                    function MapEntry(key, value) {
                        this.key = key;
                        this.value = value;
                        this.next = null;
                        this.prev = null;
                    }

                    MapEntry.prototype.isRemoved = function () {
                        return this.key === empty;
                    };

                    function MapIterator(map, kind) {
                        this.head = map._head;
                        this.i = this.head.next;
                        this.kind = kind;
                    }

                    MapIterator.prototype = {
                        next: function () {
                            var i = this.i, kind = this.kind, head = this.head, result;
                            while (i !== head) {
                                this.i = i.next;
                                if (!i.isRemoved()) {
                                    if (kind === "key") {
                                        result = i.key;
                                    } else if (kind === "value") {
                                        result = i.value;
                                    } else {
                                        result = [i.key, i.value];
                                    }
                                    return { value: result, done: false };
                                }
                                i = this.i;
                            }
                            return { value: undefined, done: true };
                        }
                    };

                    function Map() {
                        if (!(this instanceof Map)) throw new TypeError('Map must be called with "new"');

                        var head = new MapEntry(null, null);
                        // circular doubly-linked list.
                        head.next = head.prev = head;

                        defineProperties(this, {
                            '_head': head,
                            '_storage': emptyObject(),
                            '_size': 0
                        });
                    }

                    Object.defineProperty(Map.prototype, 'size', {
                        configurable: true,
                        enumerable: false,
                        get: function () {
                            return this._size;
                        }
                    });

                    defineProperties(Map.prototype, {
                        get: function (key) {
                            var fkey = fastkey(key);
                            if (fkey !== null) {
                                // fast O(1) path
                                var entry = this._storage[fkey];
                                return entry ? entry.value : undefined;
                            }
                            var head = this._head, i = head;
                            while ((i = i.next) !== head) {
                                if (Object.is(i.key, key)) {
                                    return i.value;
                                }
                            }
                            return undefined;
                        },

                        has: function (key) {
                            var fkey = fastkey(key);
                            if (fkey !== null) {
                                // fast O(1) path
                                return fkey in this._storage;
                            }
                            var head = this._head, i = head;
                            while ((i = i.next) !== head) {
                                if (Object.is(i.key, key)) {
                                    return true;
                                }
                            }
                            return false;
                        },

                        set: function (key, value) {
                            var head = this._head, i = head, entry;
                            var fkey = fastkey(key);
                            if (fkey !== null) {
                                // fast O(1) path
                                if (fkey in this._storage) {
                                    this._storage[fkey].value = value;
                                    return;
                                } else {
                                    entry = this._storage[fkey] = new MapEntry(key, value);
                                    i = head.prev;
                                    // fall through
                                }
                            }
                            while ((i = i.next) !== head) {
                                if (Object.is(i.key, key)) {
                                    i.value = value;
                                    return;
                                }
                            }
                            entry = entry ? entry : new MapEntry(key, value);
                            entry.next = this._head;
                            entry.prev = this._head.prev;
                            entry.prev.next = entry;
                            entry.next.prev = entry;
                            this._size += 1;
                        },

                        'delete': function (key) {
                            var head = this._head, i = head;
                            var fkey = fastkey(key);
                            if (fkey !== null) {
                                // fast O(1) path
                                if (!(fkey in this._storage)) {
                                    return false;
                                }
                                i = this._storage[fkey].prev;
                                delete this._storage[fkey];
                                // fall through
                            }
                            while ((i = i.next) !== head) {
                                if (Object.is(i.key, key)) {
                                    i.key = i.value = empty;
                                    i.prev.next = i.next;
                                    i.next.prev = i.prev;
                                    this._size -= 1;
                                    return true;
                                }
                            }
                            return false;
                        },

                        clear: function () {
                            this._size = 0;
                            this._storage = emptyObject();
                            var head = this._head, i = head, p = i.next;
                            while ((i = p) !== head) {
                                i.key = i.value = empty;
                                p = i.next;
                                i.next = i.prev = head;
                            }
                            head.next = head.prev = head;
                        },

                        keys: function () {
                            return new MapIterator(this, "key");
                        },

                        values: function () {
                            return new MapIterator(this, "value");
                        },

                        entries: function () {
                            return new MapIterator(this, "key+value");
                        },

                        forEach: function (callback) {
                            var context = arguments.length > 1 ? arguments[1] : null;
                            var entireMap = this;

                            var head = this._head, i = head;
                            while ((i = i.next) !== head) {
                                if (!i.isRemoved()) {
                                    callback.call(context, i.value, i.key, entireMap);
                                }
                            }
                        }
                    });

                    return Map;
                })(),

                Set: (function () {
                    // Creating a Map is expensive.  To speed up the common case of
                    // Sets containing only string or numeric keys, we use an object
                    // as backing storage and lazily create a full Map only when
                    // required.
                    var SetShim = function Set() {
                        if (!(this instanceof SetShim)) throw new TypeError('Set must be called with "new"');
                        defineProperties(this, {
                            '[[SetData]]': null,
                            '_storage': emptyObject()
                        });
                    };

                    // Switch from the object backing storage to a full Map.
                    var ensureMap = function ensureMap(set) {
                        if (!set['[[SetData]]']) {
                            var m = set['[[SetData]]'] = new collectionShims.Map();
                            Object.keys(set._storage).forEach(function (k) {
                                // fast check for leading '$'
                                if (k.charCodeAt(0) === 36) {
                                    k = k.substring(1);
                                } else {
                                    k = +k;
                                }
                                m.set(k, k);
                            });
                            set._storage = null; // free old backing storage
                        }
                    };

                    Object.defineProperty(SetShim.prototype, 'size', {
                        configurable: true,
                        enumerable: false,
                        get: function () {
                            ensureMap(this);
                            return this['[[SetData]]'].size;
                        }
                    });

                    defineProperties(SetShim.prototype, {
                        has: function (key) {
                            var fkey;
                            if (this._storage && (fkey = fastkey(key)) !== null) {
                                return !!this._storage[fkey];
                            }
                            ensureMap(this);
                            return this['[[SetData]]'].has(key);
                        },

                        add: function (key) {
                            var fkey;
                            if (this._storage && (fkey = fastkey(key)) !== null) {
                                this._storage[fkey] = true;
                                return;
                            }
                            ensureMap(this);
                            return this['[[SetData]]'].set(key, key);
                        },

                        'delete': function (key) {
                            var fkey;
                            if (this._storage && (fkey = fastkey(key)) !== null) {
                                delete this._storage[fkey];
                                return;
                            }
                            ensureMap(this);
                            return this['[[SetData]]']['delete'](key);
                        },

                        clear: function () {
                            if (this._storage) {
                                this._storage = emptyObject();
                                return;
                            }
                            return this['[[SetData]]'].clear();
                        },

                        keys: function () {
                            ensureMap(this);
                            return this['[[SetData]]'].keys();
                        },

                        values: function () {
                            ensureMap(this);
                            return this['[[SetData]]'].values();
                        },

                        entries: function () {
                            ensureMap(this);
                            return this['[[SetData]]'].entries();
                        },

                        forEach: function (callback) {
                            var context = arguments.length > 1 ? arguments[1] : null;
                            var entireSet = this;
                            ensureMap(this);
                            this['[[SetData]]'].forEach(function (value, key) {
                                callback.call(context, key, key, entireSet);
                            });
                        }
                    });

                    return SetShim;
                })()
            };
            defineProperties(globals, collectionShims);

            if (globals.Map || globals.Set) {
                /*
                  - In Firefox < 23, Map#size is a function.
                  - In all current Firefox, Set#entries/keys/values & Map#clear do not exist
                  - https://bugzilla.mozilla.org/show_bug.cgi?id=869996
                  - In Firefox 24, Map and Set do not implement forEach
                  - In Firefox 25 at least, Map and Set are callable without "new"
                */
                if (
                  typeof globals.Map.prototype.clear !== 'function' ||
                  new globals.Set().size !== 0 ||
                  new globals.Map().size !== 0 ||
                  typeof globals.Set.prototype.keys !== 'function' ||
                  typeof globals.Map.prototype.forEach !== 'function' ||
                  typeof globals.Set.prototype.forEach !== 'function' ||
                  isCallableWithoutNew(globals.Map) ||
                  isCallableWithoutNew(globals.Set)
                ) {
                    globals.Map = collectionShims.Map;
                    globals.Set = collectionShims.Set;
                }
            }
        }
    };

    if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {
        define(main); // RequireJS
    } else {
        main(); // CommonJS and <script>
    }
})();

;
//     Underscore.js 1.5.1
//     http://underscorejs.org
//     (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
//     Underscore may be freely distributed under the MIT license.

(function() {

  // Baseline setup
  // --------------

  // Establish the root object, `window` in the browser, or `global` on the server.
  var root = this;

  // Save the previous value of the `_` variable.
  var previousUnderscore = root._;

  // Establish the object that gets returned to break out of a loop iteration.
  var breaker = {};

  // Save bytes in the minified (but not gzipped) version:
  var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;

  // Create quick reference variables for speed access to core prototypes.
  var
    push             = ArrayProto.push,
    slice            = ArrayProto.slice,
    concat           = ArrayProto.concat,
    toString         = ObjProto.toString,
    hasOwnProperty   = ObjProto.hasOwnProperty;

  // All **ECMAScript 5** native function implementations that we hope to use
  // are declared here.
  var
    nativeForEach      = ArrayProto.forEach,
    nativeMap          = ArrayProto.map,
    nativeReduce       = ArrayProto.reduce,
    nativeReduceRight  = ArrayProto.reduceRight,
    nativeFilter       = ArrayProto.filter,
    nativeEvery        = ArrayProto.every,
    nativeSome         = ArrayProto.some,
    nativeIndexOf      = ArrayProto.indexOf,
    nativeLastIndexOf  = ArrayProto.lastIndexOf,
    nativeIsArray      = Array.isArray,
    nativeKeys         = Object.keys,
    nativeBind         = FuncProto.bind;

  // Create a safe reference to the Underscore object for use below.
  var _ = function(obj) {
    if (obj instanceof _) return obj;
    if (!(this instanceof _)) return new _(obj);
    this._wrapped = obj;
  };

  // Export the Underscore object for **Node.js**, with
  // backwards-compatibility for the old `require()` API. If we're in
  // the browser, add `_` as a global object via a string identifier,
  // for Closure Compiler "advanced" mode.
  if (typeof exports !== 'undefined') {
    if (typeof module !== 'undefined' && module.exports) {
      exports = module.exports = _;
    }
    exports._ = _;
  } else {
    root._ = _;
  }

  // Current version.
  _.VERSION = '1.5.1';

  // Collection Functions
  // --------------------

  // The cornerstone, an `each` implementation, aka `forEach`.
  // Handles objects with the built-in `forEach`, arrays, and raw objects.
  // Delegates to **ECMAScript 5**'s native `forEach` if available.
  var each = _.each = _.forEach = function(obj, iterator, context) {
    if (obj == null) return;
    if (nativeForEach && obj.forEach === nativeForEach) {
      obj.forEach(iterator, context);
    } else if (obj.length === +obj.length) {
      for (var i = 0, l = obj.length; i < l; i++) {
        if (iterator.call(context, obj[i], i, obj) === breaker) return;
      }
    } else {
      for (var key in obj) {
        if (_.has(obj, key)) {
          if (iterator.call(context, obj[key], key, obj) === breaker) return;
        }
      }
    }
  };

  // Return the results of applying the iterator to each element.
  // Delegates to **ECMAScript 5**'s native `map` if available.
  _.map = _.collect = function(obj, iterator, context) {
    var results = [];
    if (obj == null) return results;
    if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
    each(obj, function(value, index, list) {
      results.push(iterator.call(context, value, index, list));
    });
    return results;
  };

  var reduceError = 'Reduce of empty array with no initial value';

  // **Reduce** builds up a single result from a list of values, aka `inject`,
  // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
  _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
    var initial = arguments.length > 2;
    if (obj == null) obj = [];
    if (nativeReduce && obj.reduce === nativeReduce) {
      if (context) iterator = _.bind(iterator, context);
      return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
    }
    each(obj, function(value, index, list) {
      if (!initial) {
        memo = value;
        initial = true;
      } else {
        memo = iterator.call(context, memo, value, index, list);
      }
    });
    if (!initial) throw new TypeError(reduceError);
    return memo;
  };

  // The right-associative version of reduce, also known as `foldr`.
  // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
  _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
    var initial = arguments.length > 2;
    if (obj == null) obj = [];
    if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
      if (context) iterator = _.bind(iterator, context);
      return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
    }
    var length = obj.length;
    if (length !== +length) {
      var keys = _.keys(obj);
      length = keys.length;
    }
    each(obj, function(value, index, list) {
      index = keys ? keys[--length] : --length;
      if (!initial) {
        memo = obj[index];
        initial = true;
      } else {
        memo = iterator.call(context, memo, obj[index], index, list);
      }
    });
    if (!initial) throw new TypeError(reduceError);
    return memo;
  };

  // Return the first value which passes a truth test. Aliased as `detect`.
  _.find = _.detect = function(obj, iterator, context) {
    var result;
    any(obj, function(value, index, list) {
      if (iterator.call(context, value, index, list)) {
        result = value;
        return true;
      }
    });
    return result;
  };

  // Return all the elements that pass a truth test.
  // Delegates to **ECMAScript 5**'s native `filter` if available.
  // Aliased as `select`.
  _.filter = _.select = function(obj, iterator, context) {
    var results = [];
    if (obj == null) return results;
    if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
    each(obj, function(value, index, list) {
      if (iterator.call(context, value, index, list)) results.push(value);
    });
    return results;
  };

  // Return all the elements for which a truth test fails.
  _.reject = function(obj, iterator, context) {
    return _.filter(obj, function(value, index, list) {
      return !iterator.call(context, value, index, list);
    }, context);
  };

  // Determine whether all of the elements match a truth test.
  // Delegates to **ECMAScript 5**'s native `every` if available.
  // Aliased as `all`.
  _.every = _.all = function(obj, iterator, context) {
    iterator || (iterator = _.identity);
    var result = true;
    if (obj == null) return result;
    if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
    each(obj, function(value, index, list) {
      if (!(result = result && iterator.call(context, value, index, list))) return breaker;
    });
    return !!result;
  };

  // Determine if at least one element in the object matches a truth test.
  // Delegates to **ECMAScript 5**'s native `some` if available.
  // Aliased as `any`.
  var any = _.some = _.any = function(obj, iterator, context) {
    iterator || (iterator = _.identity);
    var result = false;
    if (obj == null) return result;
    if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
    each(obj, function(value, index, list) {
      if (result || (result = iterator.call(context, value, index, list))) return breaker;
    });
    return !!result;
  };

  // Determine if the array or object contains a given value (using `===`).
  // Aliased as `include`.
  _.contains = _.include = function(obj, target) {
    if (obj == null) return false;
    if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
    return any(obj, function(value) {
      return value === target;
    });
  };

  // Invoke a method (with arguments) on every item in a collection.
  _.invoke = function(obj, method) {
    var args = slice.call(arguments, 2);
    var isFunc = _.isFunction(method);
    return _.map(obj, function(value) {
      return (isFunc ? method : value[method]).apply(value, args);
    });
  };

  // Convenience version of a common use case of `map`: fetching a property.
  _.pluck = function(obj, key) {
    return _.map(obj, function(value){ return value[key]; });
  };

  // Convenience version of a common use case of `filter`: selecting only objects
  // containing specific `key:value` pairs.
  _.where = function(obj, attrs, first) {
    if (_.isEmpty(attrs)) return first ? void 0 : [];
    return _[first ? 'find' : 'filter'](obj, function(value) {
      for (var key in attrs) {
        if (attrs[key] !== value[key]) return false;
      }
      return true;
    });
  };

  // Convenience version of a common use case of `find`: getting the first object
  // containing specific `key:value` pairs.
  _.findWhere = function(obj, attrs) {
    return _.where(obj, attrs, true);
  };

  // Return the maximum element or (element-based computation).
  // Can't optimize arrays of integers longer than 65,535 elements.
  // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)
  _.max = function(obj, iterator, context) {
    if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
      return Math.max.apply(Math, obj);
    }
    if (!iterator && _.isEmpty(obj)) return -Infinity;
    var result = {computed : -Infinity, value: -Infinity};
    each(obj, function(value, index, list) {
      var computed = iterator ? iterator.call(context, value, index, list) : value;
      computed > result.computed && (result = {value : value, computed : computed});
    });
    return result.value;
  };

  // Return the minimum element (or element-based computation).
  _.min = function(obj, iterator, context) {
    if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
      return Math.min.apply(Math, obj);
    }
    if (!iterator && _.isEmpty(obj)) return Infinity;
    var result = {computed : Infinity, value: Infinity};
    each(obj, function(value, index, list) {
      var computed = iterator ? iterator.call(context, value, index, list) : value;
      computed < result.computed && (result = {value : value, computed : computed});
    });
    return result.value;
  };

  // Shuffle an array.
  _.shuffle = function(obj) {
    var rand;
    var index = 0;
    var shuffled = [];
    each(obj, function(value) {
      rand = _.random(index++);
      shuffled[index - 1] = shuffled[rand];
      shuffled[rand] = value;
    });
    return shuffled;
  };

  // An internal function to generate lookup iterators.
  var lookupIterator = function(value) {
    return _.isFunction(value) ? value : function(obj){ return obj[value]; };
  };

  // Sort the object's values by a criterion produced by an iterator.
  _.sortBy = function(obj, value, context) {
    var iterator = lookupIterator(value);
    return _.pluck(_.map(obj, function(value, index, list) {
      return {
        value : value,
        index : index,
        criteria : iterator.call(context, value, index, list)
      };
    }).sort(function(left, right) {
      var a = left.criteria;
      var b = right.criteria;
      if (a !== b) {
        if (a > b || a === void 0) return 1;
        if (a < b || b === void 0) return -1;
      }
      return left.index < right.index ? -1 : 1;
    }), 'value');
  };

  // An internal function used for aggregate "group by" operations.
  var group = function(obj, value, context, behavior) {
    var result = {};
    var iterator = lookupIterator(value == null ? _.identity : value);
    each(obj, function(value, index) {
      var key = iterator.call(context, value, index, obj);
      behavior(result, key, value);
    });
    return result;
  };

  // Groups the object's values by a criterion. Pass either a string attribute
  // to group by, or a function that returns the criterion.
  _.groupBy = function(obj, value, context) {
    return group(obj, value, context, function(result, key, value) {
      (_.has(result, key) ? result[key] : (result[key] = [])).push(value);
    });
  };

  // Counts instances of an object that group by a certain criterion. Pass
  // either a string attribute to count by, or a function that returns the
  // criterion.
  _.countBy = function(obj, value, context) {
    return group(obj, value, context, function(result, key) {
      if (!_.has(result, key)) result[key] = 0;
      result[key]++;
    });
  };

  // Use a comparator function to figure out the smallest index at which
  // an object should be inserted so as to maintain order. Uses binary search.
  _.sortedIndex = function(array, obj, iterator, context) {
    iterator = iterator == null ? _.identity : lookupIterator(iterator);
    var value = iterator.call(context, obj);
    var low = 0, high = array.length;
    while (low < high) {
      var mid = (low + high) >>> 1;
      iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
    }
    return low;
  };

  // Safely create a real, live array from anything iterable.
  _.toArray = function(obj) {
    if (!obj) return [];
    if (_.isArray(obj)) return slice.call(obj);
    if (obj.length === +obj.length) return _.map(obj, _.identity);
    return _.values(obj);
  };

  // Return the number of elements in an object.
  _.size = function(obj) {
    if (obj == null) return 0;
    return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
  };

  // Array Functions
  // ---------------

  // Get the first element of an array. Passing **n** will return the first N
  // values in the array. Aliased as `head` and `take`. The **guard** check
  // allows it to work with `_.map`.
  _.first = _.head = _.take = function(array, n, guard) {
    if (array == null) return void 0;
    return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
  };

  // Returns everything but the last entry of the array. Especially useful on
  // the arguments object. Passing **n** will return all the values in
  // the array, excluding the last N. The **guard** check allows it to work with
  // `_.map`.
  _.initial = function(array, n, guard) {
    return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
  };

  // Get the last element of an array. Passing **n** will return the last N
  // values in the array. The **guard** check allows it to work with `_.map`.
  _.last = function(array, n, guard) {
    if (array == null) return void 0;
    if ((n != null) && !guard) {
      return slice.call(array, Math.max(array.length - n, 0));
    } else {
      return array[array.length - 1];
    }
  };

  // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
  // Especially useful on the arguments object. Passing an **n** will return
  // the rest N values in the array. The **guard**
  // check allows it to work with `_.map`.
  _.rest = _.tail = _.drop = function(array, n, guard) {
    return slice.call(array, (n == null) || guard ? 1 : n);
  };

  // Trim out all falsy values from an array.
  _.compact = function(array) {
    return _.filter(array, _.identity);
  };

  // Internal implementation of a recursive `flatten` function.
  var flatten = function(input, shallow, output) {
    if (shallow && _.every(input, _.isArray)) {
      return concat.apply(output, input);
    }
    each(input, function(value) {
      if (_.isArray(value) || _.isArguments(value)) {
        shallow ? push.apply(output, value) : flatten(value, shallow, output);
      } else {
        output.push(value);
      }
    });
    return output;
  };

  // Return a completely flattened version of an array.
  _.flatten = function(array, shallow) {
    return flatten(array, shallow, []);
  };

  // Return a version of the array that does not contain the specified value(s).
  _.without = function(array) {
    return _.difference(array, slice.call(arguments, 1));
  };

  // Produce a duplicate-free version of the array. If the array has already
  // been sorted, you have the option of using a faster algorithm.
  // Aliased as `unique`.
  _.uniq = _.unique = function(array, isSorted, iterator, context) {
    if (_.isFunction(isSorted)) {
      context = iterator;
      iterator = isSorted;
      isSorted = false;
    }
    var initial = iterator ? _.map(array, iterator, context) : array;
    var results = [];
    var seen = [];
    each(initial, function(value, index) {
      if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
        seen.push(value);
        results.push(array[index]);
      }
    });
    return results;
  };

  // Produce an array that contains the union: each distinct element from all of
  // the passed-in arrays.
  _.union = function() {
    return _.uniq(_.flatten(arguments, true));
  };

  // Produce an array that contains every item shared between all the
  // passed-in arrays.
  _.intersection = function(array) {
    var rest = slice.call(arguments, 1);
    return _.filter(_.uniq(array), function(item) {
      return _.every(rest, function(other) {
        return _.indexOf(other, item) >= 0;
      });
    });
  };

  // Take the difference between one array and a number of other arrays.
  // Only the elements present in just the first array will remain.
  _.difference = function(array) {
    var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
    return _.filter(array, function(value){ return !_.contains(rest, value); });
  };

  // Zip together multiple lists into a single array -- elements that share
  // an index go together.
  _.zip = function() {
    var length = _.max(_.pluck(arguments, "length").concat(0));
    var results = new Array(length);
    for (var i = 0; i < length; i++) {
      results[i] = _.pluck(arguments, '' + i);
    }
    return results;
  };

  // Converts lists into objects. Pass either a single array of `[key, value]`
  // pairs, or two parallel arrays of the same length -- one of keys, and one of
  // the corresponding values.
  _.object = function(list, values) {
    if (list == null) return {};
    var result = {};
    for (var i = 0, l = list.length; i < l; i++) {
      if (values) {
        result[list[i]] = values[i];
      } else {
        result[list[i][0]] = list[i][1];
      }
    }
    return result;
  };

  // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
  // we need this function. Return the position of the first occurrence of an
  // item in an array, or -1 if the item is not included in the array.
  // Delegates to **ECMAScript 5**'s native `indexOf` if available.
  // If the array is large and already in sort order, pass `true`
  // for **isSorted** to use binary search.
  _.indexOf = function(array, item, isSorted) {
    if (array == null) return -1;
    var i = 0, l = array.length;
    if (isSorted) {
      if (typeof isSorted == 'number') {
        i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);
      } else {
        i = _.sortedIndex(array, item);
        return array[i] === item ? i : -1;
      }
    }
    if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
    for (; i < l; i++) if (array[i] === item) return i;
    return -1;
  };

  // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
  _.lastIndexOf = function(array, item, from) {
    if (array == null) return -1;
    var hasIndex = from != null;
    if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
      return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
    }
    var i = (hasIndex ? from : array.length);
    while (i--) if (array[i] === item) return i;
    return -1;
  };

  // Generate an integer Array containing an arithmetic progression. A port of
  // the native Python `range()` function. See
  // [the Python documentation](http://docs.python.org/library/functions.html#range).
  _.range = function(start, stop, step) {
    if (arguments.length <= 1) {
      stop = start || 0;
      start = 0;
    }
    step = arguments[2] || 1;

    var len = Math.max(Math.ceil((stop - start) / step), 0);
    var idx = 0;
    var range = new Array(len);

    while(idx < len) {
      range[idx++] = start;
      start += step;
    }

    return range;
  };

  // Function (ahem) Functions
  // ------------------

  // Reusable constructor function for prototype setting.
  var ctor = function(){};

  // Create a function bound to a given object (assigning `this`, and arguments,
  // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
  // available.
  _.bind = function(func, context) {
    var args, bound;
    if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
    if (!_.isFunction(func)) throw new TypeError;
    args = slice.call(arguments, 2);
    return bound = function() {
      if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
      ctor.prototype = func.prototype;
      var self = new ctor;
      ctor.prototype = null;
      var result = func.apply(self, args.concat(slice.call(arguments)));
      if (Object(result) === result) return result;
      return self;
    };
  };

  // Partially apply a function by creating a version that has had some of its
  // arguments pre-filled, without changing its dynamic `this` context.
  _.partial = function(func) {
    var args = slice.call(arguments, 1);
    return function() {
      return func.apply(this, args.concat(slice.call(arguments)));
    };
  };

  // Bind all of an object's methods to that object. Useful for ensuring that
  // all callbacks defined on an object belong to it.
  _.bindAll = function(obj) {
    var funcs = slice.call(arguments, 1);
    if (funcs.length === 0) throw new Error("bindAll must be passed function names");
    each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
    return obj;
  };

  // Memoize an expensive function by storing its results.
  _.memoize = function(func, hasher) {
    var memo = {};
    hasher || (hasher = _.identity);
    return function() {
      var key = hasher.apply(this, arguments);
      return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
    };
  };

  // Delays a function for the given number of milliseconds, and then calls
  // it with the arguments supplied.
  _.delay = function(func, wait) {
    var args = slice.call(arguments, 2);
    return setTimeout(function(){ return func.apply(null, args); }, wait);
  };

  // Defers a function, scheduling it to run after the current call stack has
  // cleared.
  _.defer = function(func) {
    return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
  };

  // Returns a function, that, when invoked, will only be triggered at most once
  // during a given window of time. Normally, the throttled function will run
  // as much as it can, without ever going more than once per `wait` duration;
  // but if you'd like to disable the execution on the leading edge, pass
  // `{leading: false}`. To disable execution on the trailing edge, ditto.
  _.throttle = function(func, wait, options) {
    var context, args, result;
    var timeout = null;
    var previous = 0;
    options || (options = {});
    var later = function() {
      previous = options.leading === false ? 0 : new Date;
      timeout = null;
      result = func.apply(context, args);
    };
    return function() {
      var now = new Date;
      if (!previous && options.leading === false) previous = now;
      var remaining = wait - (now - previous);
      context = this;
      args = arguments;
      if (remaining <= 0) {
        clearTimeout(timeout);
        timeout = null;
        previous = now;
        result = func.apply(context, args);
      } else if (!timeout && options.trailing !== false) {
        timeout = setTimeout(later, remaining);
      }
      return result;
    };
  };

  // Returns a function, that, as long as it continues to be invoked, will not
  // be triggered. The function will be called after it stops being called for
  // N milliseconds. If `immediate` is passed, trigger the function on the
  // leading edge, instead of the trailing.
  _.debounce = function(func, wait, immediate) {
    var result;
    var timeout = null;
    return function() {
      var context = this, args = arguments;
      var later = function() {
        timeout = null;
        if (!immediate) result = func.apply(context, args);
      };
      var callNow = immediate && !timeout;
      clearTimeout(timeout);
      timeout = setTimeout(later, wait);
      if (callNow) result = func.apply(context, args);
      return result;
    };
  };

  // Returns a function that will be executed at most one time, no matter how
  // often you call it. Useful for lazy initialization.
  _.once = function(func) {
    var ran = false, memo;
    return function() {
      if (ran) return memo;
      ran = true;
      memo = func.apply(this, arguments);
      func = null;
      return memo;
    };
  };

  // Returns the first function passed as an argument to the second,
  // allowing you to adjust arguments, run code before and after, and
  // conditionally execute the original function.
  _.wrap = function(func, wrapper) {
    return function() {
      var args = [func];
      push.apply(args, arguments);
      return wrapper.apply(this, args);
    };
  };

  // Returns a function that is the composition of a list of functions, each
  // consuming the return value of the function that follows.
  _.compose = function() {
    var funcs = arguments;
    return function() {
      var args = arguments;
      for (var i = funcs.length - 1; i >= 0; i--) {
        args = [funcs[i].apply(this, args)];
      }
      return args[0];
    };
  };

  // Returns a function that will only be executed after being called N times.
  _.after = function(times, func) {
    return function() {
      if (--times < 1) {
        return func.apply(this, arguments);
      }
    };
  };

  // Object Functions
  // ----------------

  // Retrieve the names of an object's properties.
  // Delegates to **ECMAScript 5**'s native `Object.keys`
  _.keys = nativeKeys || function(obj) {
    if (obj !== Object(obj)) throw new TypeError('Invalid object');
    var keys = [];
    for (var key in obj) if (_.has(obj, key)) keys.push(key);
    return keys;
  };

  // Retrieve the values of an object's properties.
  _.values = function(obj) {
    var values = [];
    for (var key in obj) if (_.has(obj, key)) values.push(obj[key]);
    return values;
  };

  // Convert an object into a list of `[key, value]` pairs.
  _.pairs = function(obj) {
    var pairs = [];
    for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]);
    return pairs;
  };

  // Invert the keys and values of an object. The values must be serializable.
  _.invert = function(obj) {
    var result = {};
    for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key;
    return result;
  };

  // Return a sorted list of the function names available on the object.
  // Aliased as `methods`
  _.functions = _.methods = function(obj) {
    var names = [];
    for (var key in obj) {
      if (_.isFunction(obj[key])) names.push(key);
    }
    return names.sort();
  };

  // Extend a given object with all the properties in passed-in object(s).
  _.extend = function(obj) {
    each(slice.call(arguments, 1), function(source) {
      if (source) {
        for (var prop in source) {
          obj[prop] = source[prop];
        }
      }
    });
    return obj;
  };

  // Return a copy of the object only containing the whitelisted properties.
  _.pick = function(obj) {
    var copy = {};
    var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
    each(keys, function(key) {
      if (key in obj) copy[key] = obj[key];
    });
    return copy;
  };

   // Return a copy of the object without the blacklisted properties.
  _.omit = function(obj) {
    var copy = {};
    var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
    for (var key in obj) {
      if (!_.contains(keys, key)) copy[key] = obj[key];
    }
    return copy;
  };

  // Fill in a given object with default properties.
  _.defaults = function(obj) {
    each(slice.call(arguments, 1), function(source) {
      if (source) {
        for (var prop in source) {
          if (obj[prop] === void 0) obj[prop] = source[prop];
        }
      }
    });
    return obj;
  };

  // Create a (shallow-cloned) duplicate of an object.
  _.clone = function(obj) {
    if (!_.isObject(obj)) return obj;
    return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
  };

  // Invokes interceptor with the obj, and then returns obj.
  // The primary purpose of this method is to "tap into" a method chain, in
  // order to perform operations on intermediate results within the chain.
  _.tap = function(obj, interceptor) {
    interceptor(obj);
    return obj;
  };

  // Internal recursive comparison function for `isEqual`.
  var eq = function(a, b, aStack, bStack) {
    // Identical objects are equal. `0 === -0`, but they aren't identical.
    // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
    if (a === b) return a !== 0 || 1 / a == 1 / b;
    // A strict comparison is necessary because `null == undefined`.
    if (a == null || b == null) return a === b;
    // Unwrap any wrapped objects.
    if (a instanceof _) a = a._wrapped;
    if (b instanceof _) b = b._wrapped;
    // Compare `[[Class]]` names.
    var className = toString.call(a);
    if (className != toString.call(b)) return false;
    switch (className) {
      // Strings, numbers, dates, and booleans are compared by value.
      case '[object String]':
        // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
        // equivalent to `new String("5")`.
        return a == String(b);
      case '[object Number]':
        // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
        // other numeric values.
        return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
      case '[object Date]':
      case '[object Boolean]':
        // Coerce dates and booleans to numeric primitive values. Dates are compared by their
        // millisecond representations. Note that invalid dates with millisecond representations
        // of `NaN` are not equivalent.
        return +a == +b;
      // RegExps are compared by their source patterns and flags.
      case '[object RegExp]':
        return a.source == b.source &&
               a.global == b.global &&
               a.multiline == b.multiline &&
               a.ignoreCase == b.ignoreCase;
    }
    if (typeof a != 'object' || typeof b != 'object') return false;
    // Assume equality for cyclic structures. The algorithm for detecting cyclic
    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
    var length = aStack.length;
    while (length--) {
      // Linear search. Performance is inversely proportional to the number of
      // unique nested structures.
      if (aStack[length] == a) return bStack[length] == b;
    }
    // Objects with different constructors are not equivalent, but `Object`s
    // from different frames are.
    var aCtor = a.constructor, bCtor = b.constructor;
    if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
                             _.isFunction(bCtor) && (bCtor instanceof bCtor))) {
      return false;
    }
    // Add the first object to the stack of traversed objects.
    aStack.push(a);
    bStack.push(b);
    var size = 0, result = true;
    // Recursively compare objects and arrays.
    if (className == '[object Array]') {
      // Compare array lengths to determine if a deep comparison is necessary.
      size = a.length;
      result = size == b.length;
      if (result) {
        // Deep compare the contents, ignoring non-numeric properties.
        while (size--) {
          if (!(result = eq(a[size], b[size], aStack, bStack))) break;
        }
      }
    } else {
      // Deep compare objects.
      for (var key in a) {
        if (_.has(a, key)) {
          // Count the expected number of properties.
          size++;
          // Deep compare each member.
          if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
        }
      }
      // Ensure that both objects contain the same number of properties.
      if (result) {
        for (key in b) {
          if (_.has(b, key) && !(size--)) break;
        }
        result = !size;
      }
    }
    // Remove the first object from the stack of traversed objects.
    aStack.pop();
    bStack.pop();
    return result;
  };

  // Perform a deep comparison to check if two objects are equal.
  _.isEqual = function(a, b) {
    return eq(a, b, [], []);
  };

  // Is a given array, string, or object empty?
  // An "empty" object has no enumerable own-properties.
  _.isEmpty = function(obj) {
    if (obj == null) return true;
    if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
    for (var key in obj) if (_.has(obj, key)) return false;
    return true;
  };

  // Is a given value a DOM element?
  _.isElement = function(obj) {
    return !!(obj && obj.nodeType === 1);
  };

  // Is a given value an array?
  // Delegates to ECMA5's native Array.isArray
  _.isArray = nativeIsArray || function(obj) {
    return toString.call(obj) == '[object Array]';
  };

  // Is a given variable an object?
  _.isObject = function(obj) {
    return obj === Object(obj);
  };

  // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
  each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
    _['is' + name] = function(obj) {
      return toString.call(obj) == '[object ' + name + ']';
    };
  });

  // Define a fallback version of the method in browsers (ahem, IE), where
  // there isn't any inspectable "Arguments" type.
  if (!_.isArguments(arguments)) {
    _.isArguments = function(obj) {
      return !!(obj && _.has(obj, 'callee'));
    };
  }

  // Optimize `isFunction` if appropriate.
  if (typeof (/./) !== 'function') {
    _.isFunction = function(obj) {
      return typeof obj === 'function';
    };
  }

  // Is a given object a finite number?
  _.isFinite = function(obj) {
    return isFinite(obj) && !isNaN(parseFloat(obj));
  };

  // Is the given value `NaN`? (NaN is the only number which does not equal itself).
  _.isNaN = function(obj) {
    return _.isNumber(obj) && obj != +obj;
  };

  // Is a given value a boolean?
  _.isBoolean = function(obj) {
    return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
  };

  // Is a given value equal to null?
  _.isNull = function(obj) {
    return obj === null;
  };

  // Is a given variable undefined?
  _.isUndefined = function(obj) {
    return obj === void 0;
  };

  // Shortcut function for checking if an object has a given property directly
  // on itself (in other words, not on a prototype).
  _.has = function(obj, key) {
    return hasOwnProperty.call(obj, key);
  };

  // Utility Functions
  // -----------------

  // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
  // previous owner. Returns a reference to the Underscore object.
  _.noConflict = function() {
    root._ = previousUnderscore;
    return this;
  };

  // Keep the identity function around for default iterators.
  _.identity = function(value) {
    return value;
  };

  // Run a function **n** times.
  _.times = function(n, iterator, context) {
    var accum = Array(Math.max(0, n));
    for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
    return accum;
  };

  // Return a random integer between min and max (inclusive).
  _.random = function(min, max) {
    if (max == null) {
      max = min;
      min = 0;
    }
    return min + Math.floor(Math.random() * (max - min + 1));
  };

  // List of HTML entities for escaping.
  var entityMap = {
    escape: {
      '&': '&amp;',
      '<': '&lt;',
      '>': '&gt;',
      '"': '&quot;',
      "'": '&#x27;',
      '/': '&#x2F;'
    }
  };
  entityMap.unescape = _.invert(entityMap.escape);

  // Regexes containing the keys and values listed immediately above.
  var entityRegexes = {
    escape:   new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
    unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
  };

  // Functions for escaping and unescaping strings to/from HTML interpolation.
  _.each(['escape', 'unescape'], function(method) {
    _[method] = function(string) {
      if (string == null) return '';
      return ('' + string).replace(entityRegexes[method], function(match) {
        return entityMap[method][match];
      });
    };
  });

  // If the value of the named `property` is a function then invoke it with the
  // `object` as context; otherwise, return it.
  _.result = function(object, property) {
    if (object == null) return void 0;
    var value = object[property];
    return _.isFunction(value) ? value.call(object) : value;
  };

  // Add your own custom functions to the Underscore object.
  _.mixin = function(obj) {
    each(_.functions(obj), function(name){
      var func = _[name] = obj[name];
      _.prototype[name] = function() {
        var args = [this._wrapped];
        push.apply(args, arguments);
        return result.call(this, func.apply(_, args));
      };
    });
  };

  // Generate a unique integer id (unique within the entire client session).
  // Useful for temporary DOM ids.
  var idCounter = 0;
  _.uniqueId = function(prefix) {
    var id = ++idCounter + '';
    return prefix ? prefix + id : id;
  };

  // By default, Underscore uses ERB-style template delimiters, change the
  // following template settings to use alternative delimiters.
  _.templateSettings = {
    evaluate    : /<%([\s\S]+?)%>/g,
    interpolate : /<%=([\s\S]+?)%>/g,
    escape      : /<%-([\s\S]+?)%>/g
  };

  // When customizing `templateSettings`, if you don't want to define an
  // interpolation, evaluation or escaping regex, we need one that is
  // guaranteed not to match.
  var noMatch = /(.)^/;

  // Certain characters need to be escaped so that they can be put into a
  // string literal.
  var escapes = {
    "'":      "'",
    '\\':     '\\',
    '\r':     'r',
    '\n':     'n',
    '\t':     't',
    '\u2028': 'u2028',
    '\u2029': 'u2029'
  };

  var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;

  // JavaScript micro-templating, similar to John Resig's implementation.
  // Underscore templating handles arbitrary delimiters, preserves whitespace,
  // and correctly escapes quotes within interpolated code.
  _.template = function(text, data, settings) {
    var render;
    settings = _.defaults({}, settings, _.templateSettings);

    // Combine delimiters into one regular expression via alternation.
    var matcher = new RegExp([
      (settings.escape || noMatch).source,
      (settings.interpolate || noMatch).source,
      (settings.evaluate || noMatch).source
    ].join('|') + '|$', 'g');

    // Compile the template source, escaping string literals appropriately.
    var index = 0;
    var source = "__p+='";
    text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
      source += text.slice(index, offset)
        .replace(escaper, function(match) { return '\\' + escapes[match]; });

      if (escape) {
        source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
      }
      if (interpolate) {
        source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
      }
      if (evaluate) {
        source += "';\n" + evaluate + "\n__p+='";
      }
      index = offset + match.length;
      return match;
    });
    source += "';\n";

    // If a variable is not specified, place data values in local scope.
    if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';

    source = "var __t,__p='',__j=Array.prototype.join," +
      "print=function(){__p+=__j.call(arguments,'');};\n" +
      source + "return __p;\n";

    try {
      render = new Function(settings.variable || 'obj', '_', source);
    } catch (e) {
      e.source = source;
      throw e;
    }

    if (data) return render(data, _);
    var template = function(data) {
      return render.call(this, data, _);
    };

    // Provide the compiled function source as a convenience for precompilation.
    template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';

    return template;
  };

  // Add a "chain" function, which will delegate to the wrapper.
  _.chain = function(obj) {
    return _(obj).chain();
  };

  // OOP
  // ---------------
  // If Underscore is called as a function, it returns a wrapped object that
  // can be used OO-style. This wrapper holds altered versions of all the
  // underscore functions. Wrapped objects may be chained.

  // Helper function to continue chaining intermediate results.
  var result = function(obj) {
    return this._chain ? _(obj).chain() : obj;
  };

  // Add all of the Underscore functions to the wrapper object.
  _.mixin(_);

  // Add all mutator Array functions to the wrapper.
  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
    var method = ArrayProto[name];
    _.prototype[name] = function() {
      var obj = this._wrapped;
      method.apply(obj, arguments);
      if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
      return result.call(this, obj);
    };
  });

  // Add all accessor Array functions to the wrapper.
  each(['concat', 'join', 'slice'], function(name) {
    var method = ArrayProto[name];
    _.prototype[name] = function() {
      return result.call(this, method.apply(this._wrapped, arguments));
    };
  });

  _.extend(_.prototype, {

    // Start chaining a wrapped Underscore object.
    chain: function() {
      this._chain = true;
      return this;
    },

    // Extracts the result from a wrapped and chained object.
    value: function() {
      return this._wrapped;
    }

  });

}).call(this);
;
firstBy = (function () { function e(f) { f.thenBy = t; return f } function t(y, x) { x = this; return e(function (a, b) { return x(a, b) || y(a, b) }) } return e })();;
/**
 * Really Simple Color Picker in jQuery
 *
 * Licensed under the MIT (MIT-LICENSE.txt) licenses.
 *
 * Copyright (c) 2008-2012
 * Lakshan Perera (www.laktek.com) & Daniel Lacy (daniellacy.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */(function(a){var b,c,d=0,e={control:a('<div class="colorPicker-picker">&nbsp;</div>'),palette:a('<div id="colorPicker_palette" class="colorPicker-palette" />'),swatch:a('<div class="colorPicker-swatch">&nbsp;</div>'),hexLabel:a('<label for="colorPicker_hex">Hex</label>'),hexField:a('<input type="text" id="colorPicker_hex" />')},f="transparent",g;a.fn.colorPicker=function(b){return this.each(function(){var c=a(this),g=a.extend({},a.fn.colorPicker.defaults,b),h=a.fn.colorPicker.toHex(c.val().length>0?c.val():g.pickerDefault),i=e.control.clone(),j=e.palette.clone().attr("id","colorPicker_palette-"+d),k=e.hexLabel.clone(),l=e.hexField.clone(),m=j[0].id,n,o;a.each(g.colors,function(b){n=e.swatch.clone(),g.colors[b]===f?(n.addClass(f).text("X"),a.fn.colorPicker.bindPalette(l,n,f)):(n.css("background-color","#"+this),a.fn.colorPicker.bindPalette(l,n)),n.appendTo(j)}),k.attr("for","colorPicker_hex-"+d),l.attr({id:"colorPicker_hex-"+d,value:h}),l.bind("keydown",function(b){if(b.keyCode===13){var d=a.fn.colorPicker.toHex(a(this).val());a.fn.colorPicker.changeColor(d?d:c.val())}b.keyCode===27&&a.fn.colorPicker.hidePalette()}),l.bind("keyup",function(b){var d=a.fn.colorPicker.toHex(a(b.target).val());a.fn.colorPicker.previewColor(d?d:c.val())}),a('<div class="colorPicker_hexWrap" />').append(k).appendTo(j),j.find(".colorPicker_hexWrap").append(l),g.showHexField===!1&&(l.hide(),k.hide()),a("body").append(j),j.hide(),i.css("background-color",h),i.bind("click",function(){c.is(":not(:disabled)")&&a.fn.colorPicker.togglePalette(a("#"+m),a(this))}),b&&b.onColorChange?i.data("onColorChange",b.onColorChange):i.data("onColorChange",function(){}),(o=c.data("text"))&&i.html(o),c.after(i),c.bind("change",function(){c.next(".colorPicker-picker").css("background-color",a.fn.colorPicker.toHex(a(this).val()))}),c.val(h);if(c[0].tagName.toLowerCase()==="input")try{c.attr("type","hidden")}catch(p){c.css("visibility","hidden").css("position","absolute")}else c.hide();d++})},a.extend(!0,a.fn.colorPicker,{toHex:function(a){if(a.match(/[0-9A-F]{6}|[0-9A-F]{3}$/i))return a.charAt(0)==="#"?a:"#"+a;if(!a.match(/^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/))return!1;var b=[parseInt(RegExp.$1,10),parseInt(RegExp.$2,10),parseInt(RegExp.$3,10)],c=function(a){if(a.length<2)for(var b=0,c=2-a.length;b<c;b++)a="0"+a;return a};if(b.length===3){var d=c(b[0].toString(16)),e=c(b[1].toString(16)),f=c(b[2].toString(16));return"#"+d+e+f}},checkMouse:function(d,e){var f=c,g=a(d.target).parents("#"+f.attr("id")).length;if(d.target===a(f)[0]||d.target===b[0]||g>0)return;a.fn.colorPicker.hidePalette()},hidePalette:function(){a(document).unbind("mousedown",a.fn.colorPicker.checkMouse),a(".colorPicker-palette").hide()},showPalette:function(c){var d=b.prev("input").val();c.css({top:b.offset().top+b.outerHeight(),left:b.offset().left}),a("#color_value").val(d),c.show(),a(document).bind("mousedown",a.fn.colorPicker.checkMouse)},togglePalette:function(d,e){e&&(b=e),c=d,c.is(":visible")?a.fn.colorPicker.hidePalette():a.fn.colorPicker.showPalette(d)},changeColor:function(c){b.css("background-color",c),b.prev("input").val(c).change(),a.fn.colorPicker.hidePalette(),b.data("onColorChange").call(b,a(b).prev("input").attr("id"),c)},previewColor:function(a){if(b){b.css("background-color",a)}},bindPalette:function(c,d,e){e=e?e:a.fn.colorPicker.toHex(d.css("background-color")),d.bind({click:function(b){g=e,a.fn.colorPicker.changeColor(e)},mouseover:function(b){g=c.val(),a(this).css("border-color","#598FEF"),c.val(e),a.fn.colorPicker.previewColor(e)},mouseout:function(d){a(this).css("border-color","#000"),c.val(b.css("background-color")),c.val(g),a.fn.colorPicker.previewColor(g)}})}}),a.fn.colorPicker.defaults={pickerDefault:"FFFFFF",colors:["000000","993300","333300","000080","333399","333333","800000","FF6600","808000","008000","008080","0000FF","666699","808080","FF0000","FF9900","99CC00","339966","33CCCC","3366FF","800080","999999","FF00FF","FFCC00","FFFF00","00FF00","00FFFF","00CCFF","993366","C0C0C0","FF99CC","FFCC99","FFFF99","CCFFFF","99CCFF","FFFFFF"],addColors:[],showHexField:!0}})(jQuery);;
ko.bindingHandlers.jqColorPicker = {
    init: function (element, valueAccessor, allBindingsAccessor) {

        // set default value
        var value = ko.utils.unwrapObservable(valueAccessor());
        $(element).val(value);

        //initialize datepicker with some optional options
        var options = allBindingsAccessor().colorPickerOptions || {};
        $(element).colorPicker(options);

        //handle the field changing
        ko.utils.registerEventHandler(element, "change", function () {
            var observable = valueAccessor();
            if (observable !== "") {
                observable($(element).val());
            }
        });

        //handle disposal (if KO removes by the template binding)
        ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
            $(element).colorPicker("destroy");
        });

    },
    update: function (element, valueAccessor, allBindingsAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        $(element).val(value);
        $(element).change();
    }
};;
/*!
* Fine Uploader
*
* Copyright 2015, Widen Enterprises, Inc. info@fineuploader.com
*
* Version: 5.2.1
*
* Homepage: http://fineuploader.com
*
* Repository: git://github.com/FineUploader/fine-uploader.git
*
* Licensed only under the Widen Commercial License (http://fineuploader.com/licensing).
*/ 


var qq=function(a){"use strict";return{hide:function(){return a.style.display="none",this},attach:function(b,c){return a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent&&a.attachEvent("on"+b,c),function(){qq(a).detach(b,c)}},detach:function(b,c){return a.removeEventListener?a.removeEventListener(b,c,!1):a.attachEvent&&a.detachEvent("on"+b,c),this},contains:function(b){return b?a===b?!0:a.contains?a.contains(b):!!(8&b.compareDocumentPosition(a)):!1},insertBefore:function(b){return b.parentNode.insertBefore(a,b),this},remove:function(){return a.parentNode.removeChild(a),this},css:function(b){if(null==a.style)throw new qq.Error("Can't apply style to node as it is not on the HTMLElement prototype chain!");return null!=b.opacity&&"string"!=typeof a.style.opacity&&"undefined"!=typeof a.filters&&(b.filter="alpha(opacity="+Math.round(100*b.opacity)+")"),qq.extend(a.style,b),this},hasClass:function(b,c){var d=new RegExp("(^| )"+b+"( |$)");return d.test(a.className)||!(!c||!d.test(a.parentNode.className))},addClass:function(b){return qq(a).hasClass(b)||(a.className+=" "+b),this},removeClass:function(b){var c=new RegExp("(^| )"+b+"( |$)");return a.className=a.className.replace(c," ").replace(/^\s+|\s+$/g,""),this},getByClass:function(b){var c,d=[];return a.querySelectorAll?a.querySelectorAll("."+b):(c=a.getElementsByTagName("*"),qq.each(c,function(a,c){qq(c).hasClass(b)&&d.push(c)}),d)},children:function(){for(var b=[],c=a.firstChild;c;)1===c.nodeType&&b.push(c),c=c.nextSibling;return b},setText:function(b){return a.innerText=b,a.textContent=b,this},clearText:function(){return qq(a).setText("")},hasAttribute:function(b){var c;return a.hasAttribute?a.hasAttribute(b)?null==/^false$/i.exec(a.getAttribute(b)):!1:(c=a[b],void 0===c?!1:null==/^false$/i.exec(c))}}};!function(){"use strict";qq.canvasToBlob=function(a,b,c){return qq.dataUriToBlob(a.toDataURL(b,c))},qq.dataUriToBlob=function(a){var b,c,d,e,f=function(a,b){var c=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,d=c&&new c;return d?(d.append(a),d.getBlob(b)):new Blob([a],{type:b})};return c=a.split(",")[0].indexOf("base64")>=0?atob(a.split(",")[1]):decodeURI(a.split(",")[1]),e=a.split(",")[0].split(":")[1].split(";")[0],b=new ArrayBuffer(c.length),d=new Uint8Array(b),qq.each(c,function(a,b){d[a]=b.charCodeAt(0)}),f(b,e)},qq.log=function(a,b){window.console&&(b&&"info"!==b?window.console[b]?window.console[b](a):window.console.log("<"+b+"> "+a):window.console.log(a))},qq.isObject=function(a){return a&&!a.nodeType&&"[object Object]"===Object.prototype.toString.call(a)},qq.isFunction=function(a){return"function"==typeof a},qq.isArray=function(a){return"[object Array]"===Object.prototype.toString.call(a)||a&&window.ArrayBuffer&&a.buffer&&a.buffer.constructor===ArrayBuffer},qq.isItemList=function(a){return"[object DataTransferItemList]"===Object.prototype.toString.call(a)},qq.isNodeList=function(a){return"[object NodeList]"===Object.prototype.toString.call(a)||a.item&&a.namedItem},qq.isString=function(a){return"[object String]"===Object.prototype.toString.call(a)},qq.trimStr=function(a){return String.prototype.trim?a.trim():a.replace(/^\s+|\s+$/g,"")},qq.format=function(a){var b=Array.prototype.slice.call(arguments,1),c=a,d=c.indexOf("{}");return qq.each(b,function(a,b){var e=c.substring(0,d),f=c.substring(d+2);return c=e+b+f,d=c.indexOf("{}",d+b.length),0>d?!1:void 0}),c},qq.isFile=function(a){return window.File&&"[object File]"===Object.prototype.toString.call(a)},qq.isFileList=function(a){return window.FileList&&"[object FileList]"===Object.prototype.toString.call(a)},qq.isFileOrInput=function(a){return qq.isFile(a)||qq.isInput(a)},qq.isInput=function(a,b){var c=function(a){var c=a.toLowerCase();return b?"file"!==c:"file"===c};return window.HTMLInputElement&&"[object HTMLInputElement]"===Object.prototype.toString.call(a)&&a.type&&c(a.type)?!0:a.tagName&&"input"===a.tagName.toLowerCase()&&a.type&&c(a.type)?!0:!1},qq.isBlob=function(a){return window.Blob&&"[object Blob]"===Object.prototype.toString.call(a)?!0:void 0},qq.isXhrUploadSupported=function(){var a=document.createElement("input");return a.type="file",void 0!==a.multiple&&"undefined"!=typeof File&&"undefined"!=typeof FormData&&"undefined"!=typeof qq.createXhrInstance().upload},qq.createXhrInstance=function(){if(window.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(a){return qq.log("Neither XHR or ActiveX are supported!","error"),null}},qq.isFolderDropSupported=function(a){return a.items&&a.items.length>0&&a.items[0].webkitGetAsEntry},qq.isFileChunkingSupported=function(){return!qq.androidStock()&&qq.isXhrUploadSupported()&&(void 0!==File.prototype.slice||void 0!==File.prototype.webkitSlice||void 0!==File.prototype.mozSlice)},qq.sliceBlob=function(a,b,c){var d=a.slice||a.mozSlice||a.webkitSlice;return d.call(a,b,c)},qq.arrayBufferToHex=function(a){var b="",c=new Uint8Array(a);return qq.each(c,function(a,c){var d=c.toString(16);d.length<2&&(d="0"+d),b+=d}),b},qq.readBlobToHex=function(a,b,c){var d=qq.sliceBlob(a,b,b+c),e=new FileReader,f=new qq.Promise;return e.onload=function(){f.success(qq.arrayBufferToHex(e.result))},e.onerror=f.failure,e.readAsArrayBuffer(d),f},qq.extend=function(a,b,c){return qq.each(b,function(b,d){c&&qq.isObject(d)?(void 0===a[b]&&(a[b]={}),qq.extend(a[b],d,!0)):a[b]=d}),a},qq.override=function(a,b){var c={},d=b(c);return qq.each(d,function(b,d){void 0!==a[b]&&(c[b]=a[b]),a[b]=d}),a},qq.indexOf=function(a,b,c){if(a.indexOf)return a.indexOf(b,c);c=c||0;var d=a.length;for(0>c&&(c+=d);d>c;c+=1)if(a.hasOwnProperty(c)&&a[c]===b)return c;return-1},qq.getUniqueId=function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(a){var b=0|16*Math.random(),c="x"==a?b:8|3&b;return c.toString(16)})},qq.ie=function(){return-1!==navigator.userAgent.indexOf("MSIE")||-1!==navigator.userAgent.indexOf("Trident")},qq.ie7=function(){return-1!==navigator.userAgent.indexOf("MSIE 7")},qq.ie8=function(){return-1!==navigator.userAgent.indexOf("MSIE 8")},qq.ie10=function(){return-1!==navigator.userAgent.indexOf("MSIE 10")},qq.ie11=function(){return qq.ie()&&-1!==navigator.userAgent.indexOf("rv:11")},qq.safari=function(){return void 0!==navigator.vendor&&-1!==navigator.vendor.indexOf("Apple")},qq.chrome=function(){return void 0!==navigator.vendor&&-1!==navigator.vendor.indexOf("Google")},qq.opera=function(){return void 0!==navigator.vendor&&-1!==navigator.vendor.indexOf("Opera")},qq.firefox=function(){return!qq.ie11()&&-1!==navigator.userAgent.indexOf("Mozilla")&&void 0!==navigator.vendor&&""===navigator.vendor},qq.windows=function(){return"Win32"===navigator.platform},qq.android=function(){return-1!==navigator.userAgent.toLowerCase().indexOf("android")},qq.androidStock=function(){return qq.android()&&navigator.userAgent.toLowerCase().indexOf("chrome")<0},qq.ios6=function(){return qq.ios()&&-1!==navigator.userAgent.indexOf(" OS 6_")},qq.ios7=function(){return qq.ios()&&-1!==navigator.userAgent.indexOf(" OS 7_")},qq.ios8=function(){return qq.ios()&&-1!==navigator.userAgent.indexOf(" OS 8_")},qq.ios800=function(){return qq.ios()&&-1!==navigator.userAgent.indexOf(" OS 8_0 ")},qq.ios=function(){return-1!==navigator.userAgent.indexOf("iPad")||-1!==navigator.userAgent.indexOf("iPod")||-1!==navigator.userAgent.indexOf("iPhone")},qq.iosChrome=function(){return qq.ios()&&-1!==navigator.userAgent.indexOf("CriOS")},qq.iosSafari=function(){return qq.ios()&&!qq.iosChrome()&&-1!==navigator.userAgent.indexOf("Safari")},qq.iosSafariWebView=function(){return qq.ios()&&!qq.iosChrome()&&!qq.iosSafari()},qq.preventDefault=function(a){a.preventDefault?a.preventDefault():a.returnValue=!1},qq.toElement=function(){var a=document.createElement("div");return function(b){a.innerHTML=b;var c=a.firstChild;return a.removeChild(c),c}}(),qq.each=function(a,b){var c,d;if(a)if(window.Storage&&a.constructor===window.Storage)for(c=0;c<a.length&&(d=b(a.key(c),a.getItem(a.key(c))),d!==!1);c++);else if(qq.isArray(a)||qq.isItemList(a)||qq.isNodeList(a))for(c=0;c<a.length&&(d=b(c,a[c]),d!==!1);c++);else if(qq.isString(a))for(c=0;c<a.length&&(d=b(c,a.charAt(c)),d!==!1);c++);else for(c in a)if(Object.prototype.hasOwnProperty.call(a,c)&&(d=b(c,a[c]),d===!1))break},qq.bind=function(a,b){if(qq.isFunction(a)){var c=Array.prototype.slice.call(arguments,2);return function(){var d=qq.extend([],c);return arguments.length&&(d=d.concat(Array.prototype.slice.call(arguments))),a.apply(b,d)}}throw new Error("first parameter must be a function!")},qq.obj2url=function(a,b,c){var d=[],e="&",f=function(a,c){var e=b?/\[\]$/.test(b)?b:b+"["+c+"]":c;"undefined"!==e&&"undefined"!==c&&d.push("object"==typeof a?qq.obj2url(a,e,!0):"[object Function]"===Object.prototype.toString.call(a)?encodeURIComponent(e)+"="+encodeURIComponent(a()):encodeURIComponent(e)+"="+encodeURIComponent(a))};return!c&&b?(e=/\?/.test(b)?/\?$/.test(b)?"":"&":"?",d.push(b),d.push(qq.obj2url(a))):"[object Array]"===Object.prototype.toString.call(a)&&"undefined"!=typeof a?qq.each(a,function(a,b){f(b,a)}):"undefined"!=typeof a&&null!==a&&"object"==typeof a?qq.each(a,function(a,b){f(b,a)}):d.push(encodeURIComponent(b)+"="+encodeURIComponent(a)),b?d.join(e):d.join(e).replace(/^&/,"").replace(/%20/g,"+")},qq.obj2FormData=function(a,b,c){return b||(b=new FormData),qq.each(a,function(a,d){a=c?c+"["+a+"]":a,qq.isObject(d)?qq.obj2FormData(d,b,a):qq.isFunction(d)?b.append(a,d()):b.append(a,d)}),b},qq.obj2Inputs=function(a,b){var c;return b||(b=document.createElement("form")),qq.obj2FormData(a,{append:function(a,d){c=document.createElement("input"),c.setAttribute("name",a),c.setAttribute("value",d),b.appendChild(c)}}),b},qq.parseJson=function(json){return window.JSON&&qq.isFunction(JSON.parse)?JSON.parse(json):eval("("+json+")")},qq.getExtension=function(a){var b=a.lastIndexOf(".")+1;return b>0?a.substr(b,a.length-b):void 0},qq.getFilename=function(a){return qq.isInput(a)?a.value.replace(/.*(\/|\\)/,""):qq.isFile(a)&&null!==a.fileName&&void 0!==a.fileName?a.fileName:a.name},qq.DisposeSupport=function(){var a=[];return{dispose:function(){var b;do b=a.shift(),b&&b();while(b)},attach:function(){var a=arguments;this.addDisposer(qq(a[0]).attach.apply(this,Array.prototype.slice.call(arguments,1)))},addDisposer:function(b){a.push(b)}}}}(),function(){"use strict";qq.Error=function(a){this.message="[Fine Uploader "+qq.version+"] "+a},qq.Error.prototype=new Error}(),qq.version="5.2.1",qq.supportedFeatures=function(){"use strict";function a(){var a,b=!0;try{a=document.createElement("input"),a.type="file",qq(a).hide(),a.disabled&&(b=!1)}catch(c){b=!1}return b}function b(){return(qq.chrome()||qq.opera())&&void 0!==navigator.userAgent.match(/Chrome\/[2][1-9]|Chrome\/[3-9][0-9]/)}function c(){return(qq.chrome()||qq.opera())&&void 0!==navigator.userAgent.match(/Chrome\/[1][4-9]|Chrome\/[2-9][0-9]/)}function d(){if(window.XMLHttpRequest){var a=qq.createXhrInstance();return void 0!==a.withCredentials}return!1}function e(){return void 0!==window.XDomainRequest}function f(){return d()?!0:e()}function g(){return void 0!==document.createElement("input").webkitdirectory}function h(){try{return!!window.localStorage}catch(a){return!1}}function i(){var a=document.createElement("span");return("draggable"in a||"ondragstart"in a&&"ondrop"in a)&&!qq.android()&&!qq.ios()}var j,k,l,m,n,o,p,q,r,s,t,u,v,w,x;return j=a(),m=j&&qq.isXhrUploadSupported(),k=m&&!qq.androidStock(),l=m&&i(),n=l&&b(),o=m&&qq.isFileChunkingSupported(),p=m&&o&&h(),q=m&&c(),r=j&&(void 0!==window.postMessage||m),t=d(),s=e(),u=f(),v=g(),w=m&&void 0!==window.FileReader,x=function(){return m?!qq.androidStock()&&!qq.iosChrome():!1}(),{ajaxUploading:m,blobUploading:k,canDetermineSize:m,chunking:o,deleteFileCors:u,deleteFileCorsXdr:s,deleteFileCorsXhr:t,dialogElement:!!window.HTMLDialogElement,fileDrop:l,folderDrop:n,folderSelection:v,imagePreviews:w,imageValidation:w,itemSizeValidation:m,pause:o,progressBar:x,resume:p,scaling:w&&k,tiffPreviews:qq.safari(),unlimitedScaledImageSize:!qq.ios(),uploading:j,uploadCors:r,uploadCustomHeaders:m,uploadNonMultipart:m,uploadViaPaste:q}}(),qq.isGenericPromise=function(a){"use strict";return!!(a&&a.then&&qq.isFunction(a.then))},qq.Promise=function(){"use strict";var a,b,c=[],d=[],e=[],f=0;qq.extend(this,{then:function(e,g){return 0===f?(e&&c.push(e),g&&d.push(g)):-1===f?g&&g.apply(null,b):e&&e.apply(null,a),this},done:function(c){return 0===f?e.push(c):c.apply(null,void 0===b?a:b),this},success:function(){return f=1,a=arguments,c.length&&qq.each(c,function(b,c){c.apply(null,a)}),e.length&&qq.each(e,function(b,c){c.apply(null,a)}),this},failure:function(){return f=-1,b=arguments,d.length&&qq.each(d,function(a,c){c.apply(null,b)}),e.length&&qq.each(e,function(a,c){c.apply(null,b)}),this}})},qq.BlobProxy=function(a,b){"use strict";qq.extend(this,{referenceBlob:a,create:function(){return b(a)}})},qq.UploadButton=function(a){"use strict";function b(){var a=document.createElement("input");return a.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME,d),a.setAttribute("title","file input"),e.setMultiple(g.multiple,a),g.folders&&qq.supportedFeatures.folderSelection&&a.setAttribute("webkitdirectory",""),g.acceptFiles&&a.setAttribute("accept",g.acceptFiles),a.setAttribute("type","file"),a.setAttribute("name",g.name),qq(a).css({position:"absolute",right:0,top:0,fontFamily:"Arial",fontSize:qq.ie()&&!qq.ie8()?"3500px":"118px",margin:0,padding:0,cursor:"pointer",opacity:0}),!qq.ie7()&&qq(a).css({height:"100%"}),g.element.appendChild(a),f.attach(a,"change",function(){g.onChange(a)}),f.attach(a,"mouseover",function(){qq(g.element).addClass(g.hoverClass)}),f.attach(a,"mouseout",function(){qq(g.element).removeClass(g.hoverClass)}),f.attach(a,"focus",function(){qq(g.element).addClass(g.focusClass)}),f.attach(a,"blur",function(){qq(g.element).removeClass(g.focusClass)}),a}var c,d,e=this,f=new qq.DisposeSupport,g={element:null,multiple:!1,acceptFiles:null,folders:!1,name:"qqfile",onChange:function(){},ios8BrowserCrashWorkaround:!1,hoverClass:"qq-upload-button-hover",focusClass:"qq-upload-button-focus"};qq.extend(g,a),d=qq.getUniqueId(),qq(g.element).css({position:"relative",overflow:"hidden",direction:"ltr"}),qq.extend(this,{getInput:function(){return c},getButtonId:function(){return d},setMultiple:function(a,b){var c=b||this.getInput();g.ios8BrowserCrashWorkaround&&qq.ios8()&&(qq.iosChrome()||qq.iosSafariWebView())?c.setAttribute("multiple",""):a?c.setAttribute("multiple",""):c.removeAttribute("multiple")},setAcceptFiles:function(a){a!==g.acceptFiles&&c.setAttribute("accept",a)},reset:function(){c.parentNode&&qq(c).remove(),qq(g.element).removeClass(g.focusClass),c=null,c=b()}}),c=b()},qq.UploadButton.BUTTON_ID_ATTR_NAME="qq-button-id",qq.UploadData=function(a){"use strict";function b(a){if(qq.isArray(a)){var b=[];return qq.each(a,function(a,c){b.push(e[c])}),b}return e[a]}function c(a){if(qq.isArray(a)){var b=[];return qq.each(a,function(a,c){b.push(e[f[c]])}),b}return e[f[a]]}function d(a){var b=[],c=[].concat(a);return qq.each(c,function(a,c){var d=g[c];void 0!==d&&qq.each(d,function(a,c){b.push(e[c])})}),b}var e=[],f={},g={},h={},i={};qq.extend(this,{addFile:function(b){var c=b.status||qq.status.SUBMITTING,d=e.push({name:b.name,originalName:b.name,uuid:b.uuid,size:null==b.size?-1:b.size,status:c})-1;return b.batchId&&(e[d].batchId=b.batchId,void 0===i[b.batchId]&&(i[b.batchId]=[]),i[b.batchId].push(d)),b.proxyGroupId&&(e[d].proxyGroupId=b.proxyGroupId,void 0===h[b.proxyGroupId]&&(h[b.proxyGroupId]=[]),h[b.proxyGroupId].push(d)),e[d].id=d,f[b.uuid]=d,void 0===g[c]&&(g[c]=[]),g[c].push(d),a.onStatusChange(d,null,c),d},retrieve:function(a){return qq.isObject(a)&&e.length?void 0!==a.id?b(a.id):void 0!==a.uuid?c(a.uuid):a.status?d(a.status):void 0:qq.extend([],e,!0)},reset:function(){e=[],f={},g={},i={}},setStatus:function(b,c){var d=e[b].status,f=qq.indexOf(g[d],b);g[d].splice(f,1),e[b].status=c,void 0===g[c]&&(g[c]=[]),g[c].push(b),a.onStatusChange(b,d,c)},uuidChanged:function(a,b){var c=e[a].uuid;e[a].uuid=b,f[b]=a,delete f[c]},updateName:function(a,b){e[a].name=b},updateSize:function(a,b){e[a].size=b},setParentId:function(a,b){e[a].parentId=b},getIdsInProxyGroup:function(a){var b=e[a].proxyGroupId;return b?h[b]:[]},getIdsInBatch:function(a){var b=e[a].batchId;return i[b]}})},qq.status={SUBMITTING:"submitting",SUBMITTED:"submitted",REJECTED:"rejected",QUEUED:"queued",CANCELED:"canceled",PAUSED:"paused",UPLOADING:"uploading",UPLOAD_RETRYING:"retrying upload",UPLOAD_SUCCESSFUL:"upload successful",UPLOAD_FAILED:"upload failed",DELETE_FAILED:"delete failed",DELETING:"deleting",DELETED:"deleted"},function(){"use strict";qq.basePublicApi={addBlobs:function(a,b,c){this.addFiles(a,b,c)},addFiles:function(a,b,c){this._maybeHandleIos8SafariWorkaround();var d=0===this._storedIds.length?qq.getUniqueId():this._currentBatchId,e=qq.bind(function(a){this._handleNewFile({blob:a,name:this._options.blobs.defaultName},d,l)},this),f=qq.bind(function(a){this._handleNewFile(a,d,l)},this),g=qq.bind(function(a){var b=qq.canvasToBlob(a);this._handleNewFile({blob:b,name:this._options.blobs.defaultName+".png"},d,l)},this),h=qq.bind(function(a){var b=a.quality&&a.quality/100,c=qq.canvasToBlob(a.canvas,a.type,b);this._handleNewFile({blob:c,name:a.name},d,l)},this),i=qq.bind(function(a){if(qq.isInput(a)&&qq.supportedFeatures.ajaxUploading){var b=Array.prototype.slice.call(a.files),c=this;qq.each(b,function(a,b){c._handleNewFile(b,d,l)})}else this._handleNewFile(a,d,l)},this),j=function(){qq.isFileList(a)&&(a=Array.prototype.slice.call(a)),a=[].concat(a)},k=this,l=[];this._currentBatchId=d,a&&(j(),qq.each(a,function(a,b){qq.isFileOrInput(b)?i(b):qq.isBlob(b)?e(b):qq.isObject(b)?b.blob&&b.name?f(b):b.canvas&&b.name&&h(b):b.tagName&&"canvas"===b.tagName.toLowerCase()?g(b):k.log(b+" is not a valid file container!  Ignoring!","warn")}),this.log("Received "+l.length+" files."),this._prepareItemsForUpload(l,b,c))},cancel:function(a){this._handler.cancel(a)},cancelAll:function(){var a=[],b=this;qq.extend(a,this._storedIds),qq.each(a,function(a,c){b.cancel(c)}),this._handler.cancelAll()},clearStoredFiles:function(){this._storedIds=[]},continueUpload:function(a){var b=this._uploadData.retrieve({id:a});return qq.supportedFeatures.pause&&this._options.chunking.enabled?b.status===qq.status.PAUSED?(this.log(qq.format("Paused file ID {} ({}) will be continued.  Not paused.",a,this.getName(a))),this._uploadFile(a),!0):(this.log(qq.format("Ignoring continue for file ID {} ({}).  Not paused.",a,this.getName(a)),"error"),!1):!1},deleteFile:function(a){return this._onSubmitDelete(a)},doesExist:function(a){return this._handler.isValid(a)},drawThumbnail:function(a,b,c,d){var e,f,g=new qq.Promise;return this._imageGenerator?(e=this._thumbnailUrls[a],f={scale:c>0,maxSize:c>0?c:null},!d&&qq.supportedFeatures.imagePreviews&&(e=this.getFile(a)),null==e?g.failure({container:b,error:"File or URL not found."}):this._imageGenerator.generate(e,b,f).then(function(a){g.success(a)},function(a,b){g.failure({container:a,error:b||"Problem generating thumbnail"})})):g.failure({container:b,error:"Missing image generator module"}),g},getButton:function(a){return this._getButton(this._buttonIdsForFileIds[a])},getEndpoint:function(a){return this._endpointStore.get(a)},getFile:function(a){return this._handler.getFile(a)||null},getInProgress:function(){return this._uploadData.retrieve({status:[qq.status.UPLOADING,qq.status.UPLOAD_RETRYING,qq.status.QUEUED]}).length},getName:function(a){return this._uploadData.retrieve({id:a}).name},getParentId:function(a){var b=this.getUploads({id:a}),c=null;return b&&void 0!==b.parentId&&(c=b.parentId),c},getResumableFilesData:function(){return this._handler.getResumableFilesData()},getSize:function(a){return this._uploadData.retrieve({id:a}).size},getNetUploads:function(){return this._netUploaded},getRemainingAllowedItems:function(){var a=this._currentItemLimit;return a>0?a-this._netUploadedOrQueued:null},getUploads:function(a){return this._uploadData.retrieve(a)},getUuid:function(a){return this._uploadData.retrieve({id:a}).uuid},log:function(a,b){!this._options.debug||b&&"info"!==b?b&&"info"!==b&&qq.log("[Fine Uploader "+qq.version+"] "+a,b):qq.log("[Fine Uploader "+qq.version+"] "+a)},pauseUpload:function(a){var b=this._uploadData.retrieve({id:a});if(!qq.supportedFeatures.pause||!this._options.chunking.enabled)return!1;if(qq.indexOf([qq.status.UPLOADING,qq.status.UPLOAD_RETRYING],b.status)>=0){if(this._handler.pause(a))return this._uploadData.setStatus(a,qq.status.PAUSED),!0;this.log(qq.format("Unable to pause file ID {} ({}).",a,this.getName(a)),"error")}else this.log(qq.format("Ignoring pause for file ID {} ({}).  Not in progress.",a,this.getName(a)),"error");return!1},reset:function(){this.log("Resetting uploader..."),this._handler.reset(),this._storedIds=[],this._autoRetries=[],this._retryTimeouts=[],this._preventRetries=[],this._thumbnailUrls=[],qq.each(this._buttons,function(a,b){b.reset()}),this._paramsStore.reset(),this._endpointStore.reset(),this._netUploadedOrQueued=0,this._netUploaded=0,this._uploadData.reset(),this._buttonIdsForFileIds=[],this._pasteHandler&&this._pasteHandler.reset(),this._options.session.refreshOnReset&&this._refreshSessionData(),this._succeededSinceLastAllComplete=[],this._failedSinceLastAllComplete=[],this._totalProgress&&this._totalProgress.reset()},retry:function(a){return this._manualRetry(a)},scaleImage:function(a,b){var c=this;return qq.Scaler.prototype.scaleImage(a,b,{log:qq.bind(c.log,c),getFile:qq.bind(c.getFile,c),uploadData:c._uploadData})},setCustomHeaders:function(a,b){this._customHeadersStore.set(a,b)},setDeleteFileCustomHeaders:function(a,b){this._deleteFileCustomHeadersStore.set(a,b)},setDeleteFileEndpoint:function(a,b){this._deleteFileEndpointStore.set(a,b)},setDeleteFileParams:function(a,b){this._deleteFileParamsStore.set(a,b)},setEndpoint:function(a,b){this._endpointStore.set(a,b)},setItemLimit:function(a){this._currentItemLimit=a},setName:function(a,b){this._uploadData.updateName(a,b)},setParams:function(a,b){this._paramsStore.set(a,b)},setUuid:function(a,b){return this._uploadData.uuidChanged(a,b)},uploadStoredFiles:function(){var a;if(0===this._storedIds.length)this._itemError("noFilesError");else for(;this._storedIds.length;)a=this._storedIds.shift(),this._uploadFile(a)}},qq.basePrivateApi={_addCannedFile:function(a){var b=this._uploadData.addFile({uuid:a.uuid,name:a.name,size:a.size,status:qq.status.UPLOAD_SUCCESSFUL});return a.deleteFileEndpoint&&this.setDeleteFileEndpoint(a.deleteFileEndpoint,b),a.deleteFileParams&&this.setDeleteFileParams(a.deleteFileParams,b),a.thumbnailUrl&&(this._thumbnailUrls[b]=a.thumbnailUrl),this._netUploaded++,this._netUploadedOrQueued++,b},_annotateWithButtonId:function(a,b){qq.isFile(a)&&(a.qqButtonId=this._getButtonId(b))},_batchError:function(a){this._options.callbacks.onError(null,null,a,void 0)},_createDeleteHandler:function(){var a=this;return new qq.DeleteFileAjaxRequester({method:this._options.deleteFile.method.toUpperCase(),maxConnections:this._options.maxConnections,uuidParamName:this._options.request.uuidName,customHeaders:this._deleteFileCustomHeadersStore,paramsStore:this._deleteFileParamsStore,endpointStore:this._deleteFileEndpointStore,cors:this._options.cors,log:qq.bind(a.log,a),onDelete:function(b){a._onDelete(b),a._options.callbacks.onDelete(b)},onDeleteComplete:function(b,c,d){a._onDeleteComplete(b,c,d),a._options.callbacks.onDeleteComplete(b,c,d)}})},_createPasteHandler:function(){var a=this;return new qq.PasteSupport({targetElement:this._options.paste.targetElement,callbacks:{log:qq.bind(a.log,a),pasteReceived:function(b){a._handleCheckedCallback({name:"onPasteReceived",callback:qq.bind(a._options.callbacks.onPasteReceived,a,b),onSuccess:qq.bind(a._handlePasteSuccess,a,b),identifier:"pasted image"})}}})},_createStore:function(a,b){var c={},d=a,e={},f=function(a){return qq.isObject(a)?qq.extend({},a):a},g=function(){return qq.isFunction(b)?b():b},h=function(a,c){b&&qq.isObject(c)&&qq.extend(c,g()),e[a]&&qq.extend(c,e[a])};return{set:function(a,b){null==b?(c={},d=f(a)):c[b]=f(a)},get:function(a){var b;return b=null!=a&&c[a]?c[a]:f(d),h(a,b),f(b)},addReadOnly:function(a,b){qq.isObject(c)&&(e[a]=e[a]||{},qq.extend(e[a],b))},remove:function(a){return delete c[a]},reset:function(){c={},e={},d=a}}},_createUploadDataTracker:function(){var a=this;return new qq.UploadData({getName:function(b){return a.getName(b)},getUuid:function(b){return a.getUuid(b)},getSize:function(b){return a.getSize(b)},onStatusChange:function(b,c,d){a._onUploadStatusChange(b,c,d),a._options.callbacks.onStatusChange(b,c,d),a._maybeAllComplete(b,d),a._totalProgress&&setTimeout(function(){a._totalProgress.onStatusChange(b,c,d)},0)}})},_createUploadButton:function(a){function b(){return qq.supportedFeatures.ajaxUploading?d._options.workarounds.iosEmptyVideos&&qq.ios()&&!qq.ios6()&&d._isAllowedExtension(f,".mov")?!1:void 0===a.multiple?d._options.multiple:a.multiple:!1}var c,d=this,e=a.accept||this._options.validation.acceptFiles,f=a.allowedExtensions||this._options.validation.allowedExtensions;return c=new qq.UploadButton({element:a.element,folders:a.folders,name:this._options.request.inputName,multiple:b(),acceptFiles:e,onChange:function(a){d._onInputChange(a)},hoverClass:this._options.classes.buttonHover,focusClass:this._options.classes.buttonFocus,ios8BrowserCrashWorkaround:this._options.workarounds.ios8BrowserCrash}),this._disposeSupport.addDisposer(function(){c.dispose()}),d._buttons.push(c),c},_createUploadHandler:function(a,b){var c=this,d={},e={debug:this._options.debug,maxConnections:this._options.maxConnections,cors:this._options.cors,paramsStore:this._paramsStore,endpointStore:this._endpointStore,chunking:this._options.chunking,resume:this._options.resume,blobs:this._options.blobs,log:qq.bind(c.log,c),preventRetryParam:this._options.retry.preventRetryResponseProperty,onProgress:function(a,b,e,f){0>e||0>f||(d[a]?(d[a].loaded!==e||d[a].total!==f)&&(c._onProgress(a,b,e,f),c._options.callbacks.onProgress(a,b,e,f)):(c._onProgress(a,b,e,f),c._options.callbacks.onProgress(a,b,e,f)),d[a]={loaded:e,total:f})},onComplete:function(a,b,e,f){delete d[a];var g,h=c.getUploads({id:a}).status;h!==qq.status.UPLOAD_SUCCESSFUL&&h!==qq.status.UPLOAD_FAILED&&(g=c._onComplete(a,b,e,f),g instanceof qq.Promise?g.done(function(){c._options.callbacks.onComplete(a,b,e,f)}):c._options.callbacks.onComplete(a,b,e,f))},onCancel:function(a,b,d){var e=new qq.Promise;return c._handleCheckedCallback({name:"onCancel",callback:qq.bind(c._options.callbacks.onCancel,c,a,b),onFailure:e.failure,onSuccess:function(){d.then(function(){c._onCancel(a,b)}),e.success()},identifier:a}),e},onUploadPrep:qq.bind(this._onUploadPrep,this),onUpload:function(a,b){c._onUpload(a,b),c._options.callbacks.onUpload(a,b)},onUploadChunk:function(a,b,d){c._onUploadChunk(a,d),c._options.callbacks.onUploadChunk(a,b,d)},onUploadChunkSuccess:function(){c._options.callbacks.onUploadChunkSuccess.apply(c,arguments)},onResume:function(a,b,d){return c._options.callbacks.onResume(a,b,d)},onAutoRetry:function(){return c._onAutoRetry.apply(c,arguments)},onUuidChanged:function(a,b){c.log("Server requested UUID change from '"+c.getUuid(a)+"' to '"+b+"'"),c.setUuid(a,b)},getName:qq.bind(c.getName,c),getUuid:qq.bind(c.getUuid,c),getSize:qq.bind(c.getSize,c),setSize:qq.bind(c._setSize,c),getDataByUuid:function(a){return c.getUploads({uuid:a})},isQueued:function(a){var b=c.getUploads({id:a}).status;return b===qq.status.QUEUED||b===qq.status.SUBMITTED||b===qq.status.UPLOAD_RETRYING||b===qq.status.PAUSED},getIdsInProxyGroup:c._uploadData.getIdsInProxyGroup,getIdsInBatch:c._uploadData.getIdsInBatch};return qq.each(this._options.request,function(a,b){e[a]=b}),e.customHeaders=this._customHeadersStore,a&&qq.each(a,function(a,b){e[a]=b}),new qq.UploadHandlerController(e,b)},_fileOrBlobRejected:function(a){this._netUploadedOrQueued--,this._uploadData.setStatus(a,qq.status.REJECTED)},_formatSize:function(a){var b=-1;do a/=1e3,b++;while(a>999);return Math.max(a,.1).toFixed(1)+this._options.text.sizeSymbols[b]},_generateExtraButtonSpecs:function(){var a=this;this._extraButtonSpecs={},qq.each(this._options.extraButtons,function(b,c){var d=c.multiple,e=qq.extend({},a._options.validation,!0),f=qq.extend({},c);void 0===d&&(d=a._options.multiple),f.validation&&qq.extend(e,c.validation,!0),qq.extend(f,{multiple:d,validation:e},!0),a._initExtraButton(f)})},_getButton:function(a){var b=this._extraButtonSpecs[a];return b?b.element:a===this._defaultButtonId?this._options.button:void 0},_getButtonId:function(a){var b,c,d=a;if(d instanceof qq.BlobProxy&&(d=d.referenceBlob),d&&!qq.isBlob(d)){if(qq.isFile(d))return d.qqButtonId;if("input"===d.tagName.toLowerCase()&&"file"===d.type.toLowerCase())return d.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);if(b=d.getElementsByTagName("input"),qq.each(b,function(a,b){return"file"===b.getAttribute("type")?(c=b,!1):void 0}),c)return c.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME)}},_getNotFinished:function(){return this._uploadData.retrieve({status:[qq.status.UPLOADING,qq.status.UPLOAD_RETRYING,qq.status.QUEUED,qq.status.SUBMITTING,qq.status.SUBMITTED,qq.status.PAUSED]}).length},_getValidationBase:function(a){var b=this._extraButtonSpecs[a];return b?b.validation:this._options.validation},_getValidationDescriptor:function(a){return a.file instanceof qq.BlobProxy?{name:qq.getFilename(a.file.referenceBlob),size:a.file.referenceBlob.size}:{name:this.getUploads({id:a.id}).name,size:this.getUploads({id:a.id}).size}},_getValidationDescriptors:function(a){var b=this,c=[];return qq.each(a,function(a,d){c.push(b._getValidationDescriptor(d))}),c},_handleCameraAccess:function(){if(this._options.camera.ios&&qq.ios()){var a="image/*;capture=camera",b=this._options.camera.button,c=b?this._getButtonId(b):this._defaultButtonId,d=this._options;c&&c!==this._defaultButtonId&&(d=this._extraButtonSpecs[c]),d.multiple=!1,null===d.validation.acceptFiles?d.validation.acceptFiles=a:d.validation.acceptFiles+=","+a,qq.each(this._buttons,function(a,b){return b.getButtonId()===c?(b.setMultiple(d.multiple),b.setAcceptFiles(d.acceptFiles),!1):void 0})}},_handleCheckedCallback:function(a){var b=this,c=a.callback();return qq.isGenericPromise(c)?(this.log(a.name+" - waiting for "+a.name+" promise to be fulfilled for "+a.identifier),c.then(function(c){b.log(a.name+" promise success for "+a.identifier),a.onSuccess(c)},function(){a.onFailure?(b.log(a.name+" promise failure for "+a.identifier),a.onFailure()):b.log(a.name+" promise failure for "+a.identifier)})):(c!==!1?a.onSuccess(c):a.onFailure?(this.log(a.name+" - return value was 'false' for "+a.identifier+".  Invoking failure callback."),a.onFailure()):this.log(a.name+" - return value was 'false' for "+a.identifier+".  Will not proceed."),c)},_handleNewFile:function(a,b,c){var d=this,e=qq.getUniqueId(),f=-1,g=qq.getFilename(a),h=a.blob||a,i=this._customNewFileHandler?this._customNewFileHandler:qq.bind(d._handleNewFileGeneric,d);!qq.isInput(h)&&h.size>=0&&(f=h.size),i(h,g,e,f,c,b,this._options.request.uuidName,{uploadData:d._uploadData,paramsStore:d._paramsStore,addFileToHandler:function(a,b){d._handler.add(a,b),d._netUploadedOrQueued++,d._trackButton(a)}})},_handleNewFileGeneric:function(a,b,c,d,e,f){var g=this._uploadData.addFile({uuid:c,name:b,size:d,batchId:f});this._handler.add(g,a),this._trackButton(g),this._netUploadedOrQueued++,e.push({id:g,file:a})},_handlePasteSuccess:function(a,b){var c=a.type.split("/")[1],d=b;null==d&&(d=this._options.paste.defaultName),d+="."+c,this.addFiles({name:d,blob:a})},_initExtraButton:function(a){var b=this._createUploadButton({element:a.element,multiple:a.multiple,accept:a.validation.acceptFiles,folders:a.folders,allowedExtensions:a.validation.allowedExtensions});this._extraButtonSpecs[b.getButtonId()]=a},_initFormSupportAndParams:function(){this._formSupport=qq.FormSupport&&new qq.FormSupport(this._options.form,qq.bind(this.uploadStoredFiles,this),qq.bind(this.log,this)),this._formSupport&&this._formSupport.attachedToForm?(this._paramsStore=this._createStore(this._options.request.params,this._formSupport.getFormInputsAsObject),this._options.autoUpload=this._formSupport.newAutoUpload,this._formSupport.newEndpoint&&(this._options.request.endpoint=this._formSupport.newEndpoint)):this._paramsStore=this._createStore(this._options.request.params)
},_isDeletePossible:function(){return qq.DeleteFileAjaxRequester&&this._options.deleteFile.enabled?this._options.cors.expected?qq.supportedFeatures.deleteFileCorsXhr?!0:qq.supportedFeatures.deleteFileCorsXdr&&this._options.cors.allowXdr?!0:!1:!0:!1},_isAllowedExtension:function(a,b){var c=!1;return a.length?(qq.each(a,function(a,d){if(qq.isString(d)){var e=new RegExp("\\."+d+"$","i");if(null!=b.match(e))return c=!0,!1}}),c):!0},_itemError:function(a,b,c){function d(a,b){g=g.replace(a,b)}var e,f,g=this._options.messages[a],h=[],i=[].concat(b),j=i[0],k=this._getButtonId(c),l=this._getValidationBase(k);return qq.each(l.allowedExtensions,function(a,b){qq.isString(b)&&h.push(b)}),e=h.join(", ").toLowerCase(),d("{file}",this._options.formatFileName(j)),d("{extensions}",e),d("{sizeLimit}",this._formatSize(l.sizeLimit)),d("{minSizeLimit}",this._formatSize(l.minSizeLimit)),f=g.match(/(\{\w+\})/g),null!==f&&qq.each(f,function(a,b){d(b,i[a])}),this._options.callbacks.onError(null,j,g,void 0),g},_manualRetry:function(a,b){return this._onBeforeManualRetry(a)?(this._netUploadedOrQueued++,this._uploadData.setStatus(a,qq.status.UPLOAD_RETRYING),b?b(a):this._handler.retry(a),!0):void 0},_maybeAllComplete:function(a,b){var c=this,d=this._getNotFinished();b===qq.status.UPLOAD_SUCCESSFUL?this._succeededSinceLastAllComplete.push(a):b===qq.status.UPLOAD_FAILED&&this._failedSinceLastAllComplete.push(a),0===d&&(this._succeededSinceLastAllComplete.length||this._failedSinceLastAllComplete.length)&&setTimeout(function(){c._onAllComplete(c._succeededSinceLastAllComplete,c._failedSinceLastAllComplete)},0)},_maybeHandleIos8SafariWorkaround:function(){var a=this;if(this._options.workarounds.ios8SafariUploads&&qq.ios800()&&qq.iosSafari())throw setTimeout(function(){window.alert(a._options.messages.unsupportedBrowserIos8Safari)},0),new qq.Error(this._options.messages.unsupportedBrowserIos8Safari)},_maybeParseAndSendUploadError:function(a,b,c,d){if(!c.success)if(d&&200!==d.status&&!c.error)this._options.callbacks.onError(a,b,"XHR returned response code "+d.status,d);else{var e=c.error?c.error:this._options.text.defaultResponseError;this._options.callbacks.onError(a,b,e,d)}},_maybeProcessNextItemAfterOnValidateCallback:function(a,b,c,d,e){var f=this;if(b.length>c)if(a||!this._options.validation.stopOnFirstInvalidFile)setTimeout(function(){var a=f._getValidationDescriptor(b[c]),g=f._getButtonId(b[c].file),h=f._getButton(g);f._handleCheckedCallback({name:"onValidate",callback:qq.bind(f._options.callbacks.onValidate,f,a,h),onSuccess:qq.bind(f._onValidateCallbackSuccess,f,b,c,d,e),onFailure:qq.bind(f._onValidateCallbackFailure,f,b,c,d,e),identifier:"Item '"+a.name+"', size: "+a.size})},0);else if(!a)for(;c<b.length;c++)f._fileOrBlobRejected(b[c].id)},_onAllComplete:function(a,b){this._totalProgress&&this._totalProgress.onAllComplete(a,b,this._preventRetries),this._options.callbacks.onAllComplete(qq.extend([],a),qq.extend([],b)),this._succeededSinceLastAllComplete=[],this._failedSinceLastAllComplete=[]},_onAutoRetry:function(a,b,c,d,e){var f=this;return f._preventRetries[a]=c[f._options.retry.preventRetryResponseProperty],f._shouldAutoRetry(a,b,c)?(f._maybeParseAndSendUploadError.apply(f,arguments),f._options.callbacks.onAutoRetry(a,b,f._autoRetries[a]),f._onBeforeAutoRetry(a,b),f._retryTimeouts[a]=setTimeout(function(){f.log("Retrying "+b+"..."),f._uploadData.setStatus(a,qq.status.UPLOAD_RETRYING),e?e(a):f._handler.retry(a)},1e3*f._options.retry.autoAttemptDelay),!0):void 0},_onBeforeAutoRetry:function(a,b){this.log("Waiting "+this._options.retry.autoAttemptDelay+" seconds before retrying "+b+"...")},_onBeforeManualRetry:function(a){var b,c=this._currentItemLimit;return this._preventRetries[a]?(this.log("Retries are forbidden for id "+a,"warn"),!1):this._handler.isValid(a)?(b=this.getName(a),this._options.callbacks.onManualRetry(a,b)===!1?!1:c>0&&this._netUploadedOrQueued+1>c?(this._itemError("retryFailTooManyItems"),!1):(this.log("Retrying upload for '"+b+"' (id: "+a+")..."),!0)):(this.log("'"+a+"' is not a valid file ID","error"),!1)},_onCancel:function(a){this._netUploadedOrQueued--,clearTimeout(this._retryTimeouts[a]);var b=qq.indexOf(this._storedIds,a);!this._options.autoUpload&&b>=0&&this._storedIds.splice(b,1),this._uploadData.setStatus(a,qq.status.CANCELED)},_onComplete:function(a,b,c,d){return c.success?(c.thumbnailUrl&&(this._thumbnailUrls[a]=c.thumbnailUrl),this._netUploaded++,this._uploadData.setStatus(a,qq.status.UPLOAD_SUCCESSFUL)):(this._netUploadedOrQueued--,this._uploadData.setStatus(a,qq.status.UPLOAD_FAILED),c[this._options.retry.preventRetryResponseProperty]===!0&&(this._preventRetries[a]=!0)),this._maybeParseAndSendUploadError(a,b,c,d),c.success?!0:!1},_onDelete:function(a){this._uploadData.setStatus(a,qq.status.DELETING)},_onDeleteComplete:function(a,b,c){var d=this.getName(a);c?(this._uploadData.setStatus(a,qq.status.DELETE_FAILED),this.log("Delete request for '"+d+"' has failed.","error"),void 0===b.withCredentials?this._options.callbacks.onError(a,d,"Delete request failed",b):this._options.callbacks.onError(a,d,"Delete request failed with response code "+b.status,b)):(this._netUploadedOrQueued--,this._netUploaded--,this._handler.expunge(a),this._uploadData.setStatus(a,qq.status.DELETED),this.log("Delete request for '"+d+"' has succeeded."))},_onInputChange:function(a){var b;if(qq.supportedFeatures.ajaxUploading){for(b=0;b<a.files.length;b++)this._annotateWithButtonId(a.files[b],a);this.addFiles(a.files)}else a.value.length>0&&this.addFiles(a);qq.each(this._buttons,function(a,b){b.reset()})},_onProgress:function(a,b,c,d){this._totalProgress&&this._totalProgress.onIndividualProgress(a,c,d)},_onSubmit:function(){},_onSubmitCallbackSuccess:function(a){this._onSubmit.apply(this,arguments),this._uploadData.setStatus(a,qq.status.SUBMITTED),this._onSubmitted.apply(this,arguments),this._options.callbacks.onSubmitted.apply(this,arguments),this._options.autoUpload?this._uploadFile(a):this._storeForLater(a)},_onSubmitDelete:function(a,b,c){var d,e=this.getUuid(a);return b&&(d=qq.bind(b,this,a,e,c)),this._isDeletePossible()?(this._handleCheckedCallback({name:"onSubmitDelete",callback:qq.bind(this._options.callbacks.onSubmitDelete,this,a),onSuccess:d||qq.bind(this._deleteHandler.sendDelete,this,a,e,c),identifier:a}),!0):(this.log("Delete request ignored for ID "+a+", delete feature is disabled or request not possible "+"due to CORS on a user agent that does not support pre-flighting.","warn"),!1)},_onSubmitted:function(){},_onTotalProgress:function(a,b){this._options.callbacks.onTotalProgress(a,b)},_onUploadPrep:function(){},_onUpload:function(a){this._uploadData.setStatus(a,qq.status.UPLOADING)},_onUploadChunk:function(){},_onUploadStatusChange:function(a,b,c){c===qq.status.PAUSED&&clearTimeout(this._retryTimeouts[a])},_onValidateBatchCallbackFailure:function(a){var b=this;qq.each(a,function(a,c){b._fileOrBlobRejected(c.id)})},_onValidateBatchCallbackSuccess:function(a,b,c,d,e){var f,g=this._currentItemLimit,h=this._netUploadedOrQueued;0===g||g>=h?b.length>0?this._handleCheckedCallback({name:"onValidate",callback:qq.bind(this._options.callbacks.onValidate,this,a[0],e),onSuccess:qq.bind(this._onValidateCallbackSuccess,this,b,0,c,d),onFailure:qq.bind(this._onValidateCallbackFailure,this,b,0,c,d),identifier:"Item '"+b[0].file.name+"', size: "+b[0].file.size}):this._itemError("noFilesError"):(this._onValidateBatchCallbackFailure(b),f=this._options.messages.tooManyItemsError.replace(/\{netItems\}/g,h).replace(/\{itemLimit\}/g,g),this._batchError(f))},_onValidateCallbackFailure:function(a,b,c,d){var e=b+1;this._fileOrBlobRejected(a[b].id,a[b].file.name),this._maybeProcessNextItemAfterOnValidateCallback(!1,a,e,c,d)},_onValidateCallbackSuccess:function(a,b,c,d){var e=this,f=b+1,g=this._getValidationDescriptor(a[b]);this._validateFileOrBlobData(a[b],g).then(function(){e._upload(a[b].id,c,d),e._maybeProcessNextItemAfterOnValidateCallback(!0,a,f,c,d)},function(){e._maybeProcessNextItemAfterOnValidateCallback(!1,a,f,c,d)})},_prepareItemsForUpload:function(a,b,c){if(0===a.length)return this._itemError("noFilesError"),void 0;var d=this._getValidationDescriptors(a),e=this._getButtonId(a[0].file),f=this._getButton(e);this._handleCheckedCallback({name:"onValidateBatch",callback:qq.bind(this._options.callbacks.onValidateBatch,this,d,f),onSuccess:qq.bind(this._onValidateBatchCallbackSuccess,this,d,a,b,c,f),onFailure:qq.bind(this._onValidateBatchCallbackFailure,this,a),identifier:"batch validation"})},_preventLeaveInProgress:function(){var a=this;this._disposeSupport.attach(window,"beforeunload",function(b){return a.getInProgress()?(b=b||window.event,b.returnValue=a._options.messages.onLeave,a._options.messages.onLeave):void 0})},_refreshSessionData:function(){var a=this,b=this._options.session;qq.Session&&null!=this._options.session.endpoint&&(this._session||(qq.extend(b,this._options.cors),b.log=qq.bind(this.log,this),b.addFileRecord=qq.bind(this._addCannedFile,this),this._session=new qq.Session(b)),setTimeout(function(){a._session.refresh().then(function(b,c){a._options.callbacks.onSessionRequestComplete(b,!0,c)},function(b,c){a._options.callbacks.onSessionRequestComplete(b,!1,c)})},0))},_setSize:function(a,b){this._uploadData.updateSize(a,b),this._totalProgress&&this._totalProgress.onNewSize(a)},_shouldAutoRetry:function(a){var b=this._uploadData.retrieve({id:a});return!this._preventRetries[a]&&this._options.retry.enableAuto&&b.status!==qq.status.PAUSED&&(void 0===this._autoRetries[a]&&(this._autoRetries[a]=0),this._autoRetries[a]<this._options.retry.maxAutoAttempts)?(this._autoRetries[a]+=1,!0):!1},_storeForLater:function(a){this._storedIds.push(a)},_trackButton:function(a){var b;b=qq.supportedFeatures.ajaxUploading?this._handler.getFile(a).qqButtonId:this._getButtonId(this._handler.getInput(a)),b&&(this._buttonIdsForFileIds[a]=b)},_upload:function(a,b,c){var d=this.getName(a);b&&this.setParams(b,a),c&&this.setEndpoint(c,a),this._handleCheckedCallback({name:"onSubmit",callback:qq.bind(this._options.callbacks.onSubmit,this,a,d),onSuccess:qq.bind(this._onSubmitCallbackSuccess,this,a,d),onFailure:qq.bind(this._fileOrBlobRejected,this,a,d),identifier:a})},_uploadFile:function(a){this._handler.upload(a)||this._uploadData.setStatus(a,qq.status.QUEUED)},_validateFileOrBlobData:function(a,b){var c=this,d=function(){return a.file instanceof qq.BlobProxy?a.file.referenceBlob:a.file}(),e=b.name,f=b.size,g=this._getButtonId(a.file),h=this._getValidationBase(g),i=new qq.Promise;return i.then(function(){},function(){c._fileOrBlobRejected(a.id,e)}),qq.isFileOrInput(d)&&!this._isAllowedExtension(h.allowedExtensions,e)?(this._itemError("typeError",e,d),i.failure()):0===f?(this._itemError("emptyError",e,d),i.failure()):f>0&&h.sizeLimit&&f>h.sizeLimit?(this._itemError("sizeError",e,d),i.failure()):f>0&&f<h.minSizeLimit?(this._itemError("minSizeError",e,d),i.failure()):(qq.ImageValidation&&qq.supportedFeatures.imagePreviews&&qq.isFile(d)?new qq.ImageValidation(d,qq.bind(c.log,c)).validate(h.image).then(i.success,function(a){c._itemError(a+"ImageError",e,d),i.failure()}):i.success(),i)},_wrapCallbacks:function(){var a,b,c;a=this,b=function(b,c,d){var e;try{return c.apply(a,d)}catch(f){e=f.message||f.toString(),a.log("Caught exception in '"+b+"' callback - "+e,"error")}};for(c in this._options.callbacks)!function(){var d,e;d=c,e=a._options.callbacks[d],a._options.callbacks[d]=function(){return b(d,e,arguments)}}()}}}(),function(){"use strict";qq.FineUploaderBasic=function(a){var b=this;this._options={debug:!1,button:null,multiple:!0,maxConnections:3,disableCancelForFormUploads:!1,autoUpload:!0,request:{customHeaders:{},endpoint:"/server/upload",filenameParam:"qqfilename",forceMultipart:!0,inputName:"qqfile",method:"POST",params:{},paramsInBody:!0,totalFileSizeName:"qqtotalfilesize",uuidName:"qquuid"},validation:{allowedExtensions:[],sizeLimit:0,minSizeLimit:0,itemLimit:0,stopOnFirstInvalidFile:!0,acceptFiles:null,image:{maxHeight:0,maxWidth:0,minHeight:0,minWidth:0}},callbacks:{onSubmit:function(){},onSubmitted:function(){},onComplete:function(){},onAllComplete:function(){},onCancel:function(){},onUpload:function(){},onUploadChunk:function(){},onUploadChunkSuccess:function(){},onResume:function(){},onProgress:function(){},onTotalProgress:function(){},onError:function(){},onAutoRetry:function(){},onManualRetry:function(){},onValidateBatch:function(){},onValidate:function(){},onSubmitDelete:function(){},onDelete:function(){},onDeleteComplete:function(){},onPasteReceived:function(){},onStatusChange:function(){},onSessionRequestComplete:function(){}},messages:{typeError:"{file} has an invalid extension. Valid extension(s): {extensions}.",sizeError:"{file} is too large, maximum file size is {sizeLimit}.",minSizeError:"{file} is too small, minimum file size is {minSizeLimit}.",emptyError:"{file} is empty, please select files again without it.",noFilesError:"No files to upload.",tooManyItemsError:"Too many items ({netItems}) would be uploaded.  Item limit is {itemLimit}.",maxHeightImageError:"Image is too tall.",maxWidthImageError:"Image is too wide.",minHeightImageError:"Image is not tall enough.",minWidthImageError:"Image is not wide enough.",retryFailTooManyItems:"Retry failed - you have reached your file limit.",onLeave:"The files are being uploaded, if you leave now the upload will be canceled.",unsupportedBrowserIos8Safari:"Unrecoverable error - this browser does not permit file uploading of any kind due to serious bugs in iOS8 Safari.  Please use iOS8 Chrome until Apple fixes these issues."},retry:{enableAuto:!1,maxAutoAttempts:3,autoAttemptDelay:5,preventRetryResponseProperty:"preventRetry"},classes:{buttonHover:"qq-upload-button-hover",buttonFocus:"qq-upload-button-focus"},chunking:{enabled:!1,concurrent:{enabled:!1},mandatory:!1,paramNames:{partIndex:"qqpartindex",partByteOffset:"qqpartbyteoffset",chunkSize:"qqchunksize",totalFileSize:"qqtotalfilesize",totalParts:"qqtotalparts"},partSize:2e6,success:{endpoint:null}},resume:{enabled:!1,recordsExpireIn:7,paramNames:{resuming:"qqresume"}},formatFileName:function(a){return a},text:{defaultResponseError:"Upload failure reason unknown",sizeSymbols:["kB","MB","GB","TB","PB","EB"]},deleteFile:{enabled:!1,method:"DELETE",endpoint:"/server/upload",customHeaders:{},params:{}},cors:{expected:!1,sendCredentials:!1,allowXdr:!1},blobs:{defaultName:"misc_data"},paste:{targetElement:null,defaultName:"pasted_image"},camera:{ios:!1,button:null},extraButtons:[],session:{endpoint:null,params:{},customHeaders:{},refreshOnReset:!0},form:{element:"qq-form",autoUpload:!1,interceptSubmit:!0},scaling:{sendOriginal:!0,orient:!0,defaultType:null,defaultQuality:80,failureText:"Failed to scale",includeExif:!1,sizes:[]},workarounds:{iosEmptyVideos:!0,ios8SafariUploads:!0,ios8BrowserCrash:!1}},qq.extend(this._options,a,!0),this._buttons=[],this._extraButtonSpecs={},this._buttonIdsForFileIds=[],this._wrapCallbacks(),this._disposeSupport=new qq.DisposeSupport,this._storedIds=[],this._autoRetries=[],this._retryTimeouts=[],this._preventRetries=[],this._thumbnailUrls=[],this._netUploadedOrQueued=0,this._netUploaded=0,this._uploadData=this._createUploadDataTracker(),this._initFormSupportAndParams(),this._customHeadersStore=this._createStore(this._options.request.customHeaders),this._deleteFileCustomHeadersStore=this._createStore(this._options.deleteFile.customHeaders),this._deleteFileParamsStore=this._createStore(this._options.deleteFile.params),this._endpointStore=this._createStore(this._options.request.endpoint),this._deleteFileEndpointStore=this._createStore(this._options.deleteFile.endpoint),this._handler=this._createUploadHandler(),this._deleteHandler=qq.DeleteFileAjaxRequester&&this._createDeleteHandler(),this._options.button&&(this._defaultButtonId=this._createUploadButton({element:this._options.button}).getButtonId()),this._generateExtraButtonSpecs(),this._handleCameraAccess(),this._options.paste.targetElement&&(qq.PasteSupport?this._pasteHandler=this._createPasteHandler():this.log("Paste support module not found","error")),this._preventLeaveInProgress(),this._imageGenerator=qq.ImageGenerator&&new qq.ImageGenerator(qq.bind(this.log,this)),this._refreshSessionData(),this._succeededSinceLastAllComplete=[],this._failedSinceLastAllComplete=[],this._scaler=qq.Scaler&&new qq.Scaler(this._options.scaling,qq.bind(this.log,this))||{},this._scaler.enabled&&(this._customNewFileHandler=qq.bind(this._scaler.handleNewFile,this._scaler)),qq.TotalProgress&&qq.supportedFeatures.progressBar&&(this._totalProgress=new qq.TotalProgress(qq.bind(this._onTotalProgress,this),function(a){var c=b._uploadData.retrieve({id:a});return c&&c.size||0})),this._currentItemLimit=this._options.validation.itemLimit},qq.FineUploaderBasic.prototype=qq.basePublicApi,qq.extend(qq.FineUploaderBasic.prototype,qq.basePrivateApi)}(),qq.AjaxRequester=function(a){"use strict";function b(){return qq.indexOf(["GET","POST","HEAD"],w.method)>=0}function c(){var a=!1;return qq.each(a,function(b,c){return qq.indexOf(["Accept","Accept-Language","Content-Language","Content-Type"],c)<0?(a=!0,!1):void 0}),a}function d(a){return w.cors.expected&&void 0===a.withCredentials}function e(){var a;return(window.XMLHttpRequest||window.ActiveXObject)&&(a=qq.createXhrInstance(),void 0===a.withCredentials&&(a=new XDomainRequest)),a}function f(a,b){var c=v[a].xhr;return c||(c=b?b:w.cors.expected?e():qq.createXhrInstance(),v[a].xhr=c),c}function g(a){var b,c=qq.indexOf(u,a),d=w.maxConnections;delete v[a],u.splice(c,1),u.length>=d&&d>c&&(b=u[d-1],j(b))}function h(a,b){var c=f(a),e=w.method,h=b===!0;g(a),h?s(e+" request for "+a+" has failed","error"):d(c)||q(c.status)||(h=!0,s(e+" request for "+a+" has failed - response code "+c.status,"error")),w.onComplete(a,c,h)}function i(a){var b,c=v[a].additionalParams,d=w.mandatedParams;return w.paramsStore.get&&(b=w.paramsStore.get(a)),c&&qq.each(c,function(a,c){b=b||{},b[a]=c}),d&&qq.each(d,function(a,c){b=b||{},b[a]=c}),b}function j(a,b){var c,e=f(a,b),g=w.method,h=i(a),j=v[a].payload;return w.onSend(a),c=k(a,h),d(e)?(e.onload=n(a),e.onerror=o(a)):e.onreadystatechange=l(a),m(a),e.open(g,c,!0),w.cors.expected&&w.cors.sendCredentials&&!d(e)&&(e.withCredentials=!0),p(a),s("Sending "+g+" request for "+a),j?e.send(j):t||!h?e.send():h&&w.contentType&&w.contentType.toLowerCase().indexOf("application/x-www-form-urlencoded")>=0?e.send(qq.obj2url(h,"")):h&&w.contentType&&w.contentType.toLowerCase().indexOf("application/json")>=0?e.send(JSON.stringify(h)):e.send(h),e}function k(a,b){var c=w.endpointStore.get(a),d=v[a].addToPath;return void 0!=d&&(c+="/"+d),t&&b?qq.obj2url(b,c):c}function l(a){return function(){4===f(a).readyState&&h(a)}}function m(a){var b=w.onProgress;b&&(f(a).upload.onprogress=function(c){c.lengthComputable&&b(a,c.loaded,c.total)})}function n(a){return function(){h(a)}}function o(a){return function(){h(a,!0)}}function p(a){var e=f(a),g=w.customHeaders,h=v[a].additionalHeaders||{},i=w.method,j={};d(e)||(w.acceptHeader&&e.setRequestHeader("Accept",w.acceptHeader),w.allowXRequestedWithAndCacheControl&&(w.cors.expected&&b()&&!c(g)||(e.setRequestHeader("X-Requested-With","XMLHttpRequest"),e.setRequestHeader("Cache-Control","no-cache"))),!w.contentType||"POST"!==i&&"PUT"!==i||e.setRequestHeader("Content-Type",w.contentType),qq.extend(j,qq.isFunction(g)?g(a):g),qq.extend(j,h),qq.each(j,function(a,b){e.setRequestHeader(a,b)}))}function q(a){return qq.indexOf(w.successfulResponseCodes[w.method],a)>=0}function r(a,b,c,d,e,f){v[a]={addToPath:c,additionalParams:d,additionalHeaders:e,payload:f};var g=u.push(a);return g<=w.maxConnections?j(a,b):void 0}var s,t,u=[],v={},w={acceptHeader:null,validMethods:["PATCH","POST","PUT"],method:"POST",contentType:"application/x-www-form-urlencoded",maxConnections:3,customHeaders:{},endpointStore:{},paramsStore:{},mandatedParams:{},allowXRequestedWithAndCacheControl:!0,successfulResponseCodes:{DELETE:[200,202,204],PATCH:[200,201,202,203,204],POST:[200,201,202,203,204],PUT:[200,201,202,203,204],GET:[200]},cors:{expected:!1,sendCredentials:!1},log:function(){},onSend:function(){},onComplete:function(){},onProgress:null};if(qq.extend(w,a),s=w.log,qq.indexOf(w.validMethods,w.method)<0)throw new Error("'"+w.method+"' is not a supported method for this type of request!");t="GET"===w.method||"DELETE"===w.method,qq.extend(this,{initTransport:function(a){var b,c,d,e,f;return{withPath:function(a){return b=a,this},withParams:function(a){return c=a,this},withHeaders:function(a){return d=a,this},withPayload:function(a){return e=a,this},withCacheBuster:function(){return f=!0,this},send:function(g){return f&&qq.indexOf(["GET","DELETE"],w.method)>=0&&(c.qqtimestamp=(new Date).getTime()),r(a,g,b,c,d,e)}}},canceled:function(a){g(a)}})},qq.UploadHandler=function(a){"use strict";var b=a.proxy,c={},d=b.onCancel,e=b.getName;qq.extend(this,{add:function(a,b){c[a]=b,c[a].temp={}},cancel:function(a){var b=this,f=new qq.Promise,g=d(a,e(a),f);g.then(function(){b.isValid(a)&&(c[a].canceled=!0,b.expunge(a)),f.success()})},expunge:function(a){delete c[a]},getThirdPartyFileId:function(a){return c[a].key},isValid:function(a){return void 0!==c[a]},reset:function(){c={}},_getFileState:function(a){return c[a]},_setThirdPartyFileId:function(a,b){c[a].key=b},_wasCanceled:function(a){return!!c[a].canceled}})},qq.UploadHandlerController=function(a,b){"use strict";var c,d,e,f=this,g=!1,h=!1,i={paramsStore:{},maxConnections:3,chunking:{enabled:!1,multiple:{enabled:!1}},log:function(){},onProgress:function(){},onComplete:function(){},onCancel:function(){},onUploadPrep:function(){},onUpload:function(){},onUploadChunk:function(){},onUploadChunkSuccess:function(){},onAutoRetry:function(){},onResume:function(){},onUuidChanged:function(){},getName:function(){},setSize:function(){},isQueued:function(){},getIdsInProxyGroup:function(){},getIdsInBatch:function(){}},j={done:function(a,b,c,d){var f=e._getChunkData(a,b);e._getFileState(a).attemptingResume=!1,delete e._getFileState(a).temp.chunkProgress[b],e._getFileState(a).loaded+=f.size,i.onUploadChunkSuccess(a,e._getChunkDataForCallback(f),c,d)},finalize:function(a){var b=i.getSize(a),c=i.getName(a);d("All chunks have been uploaded for "+a+" - finalizing...."),e.finalizeChunks(a).then(function(f,g){d("Finalize successful for "+a);var h=m.normalizeResponse(f,!0);i.onProgress(a,c,b,b),e._maybeDeletePersistedChunkData(a),m.cleanup(a,h,g)},function(b,e){var f=m.normalizeResponse(b,!1);d("Problem finalizing chunks for file ID "+a+" - "+f.error,"error"),f.reset&&j.reset(a),i.onAutoRetry(a,c,f,e)||m.cleanup(a,f,e)})},hasMoreParts:function(a){return!!e._getFileState(a).chunking.remaining.length},nextPart:function(a){var b=e._getFileState(a).chunking.remaining.shift();return b>=e._getTotalChunks(a)&&(b=null),b},reset:function(a){d("Server or callback has ordered chunking effort to be restarted on next attempt for item ID "+a,"error"),e._maybeDeletePersistedChunkData(a),e.reevaluateChunking(a),e._getFileState(a).loaded=0},sendNext:function(a){var b=i.getSize(a),c=i.getName(a),f=j.nextPart(a),g=e._getChunkData(a,f),l=e._getFileState(a).attemptingResume,n=e._getFileState(a).chunking.inProgress||[];null==e._getFileState(a).loaded&&(e._getFileState(a).loaded=0),l&&i.onResume(a,c,g)===!1&&(j.reset(a),f=j.nextPart(a),g=e._getChunkData(a,f),l=!1),null==f&&0===n.length?j.finalize(a):(d("Sending chunked upload request for item "+a+": bytes "+(g.start+1)+"-"+g.end+" of "+b),i.onUploadChunk(a,c,e._getChunkDataForCallback(g)),n.push(f),e._getFileState(a).chunking.inProgress=n,h&&k.open(a,f),h&&k.available()&&e._getFileState(a).chunking.remaining.length&&j.sendNext(a),e.uploadChunk(a,f,l).then(function(b,c){d("Chunked upload request succeeded for "+a+", chunk "+f),e.clearCachedChunk(a,f);var g=e._getFileState(a).chunking.inProgress||[],h=m.normalizeResponse(b,!0),i=qq.indexOf(g,f);d(qq.format("Chunk {} for file {} uploaded successfully.",f,a)),j.done(a,f,h,c),i>=0&&g.splice(i,1),e._maybePersistChunkedState(a),j.hasMoreParts(a)||0!==g.length?j.hasMoreParts(a)&&j.sendNext(a):j.finalize(a)},function(b,g){d("Chunked upload request failed for "+a+", chunk "+f),e.clearCachedChunk(a,f);var l,n=m.normalizeResponse(b,!1);n.reset?j.reset(a):(l=qq.indexOf(e._getFileState(a).chunking.inProgress,f),l>=0&&(e._getFileState(a).chunking.inProgress.splice(l,1),e._getFileState(a).chunking.remaining.unshift(f))),e._getFileState(a).temp.ignoreFailure||(h&&(e._getFileState(a).temp.ignoreFailure=!0,qq.each(e._getXhrs(a),function(a,b){b.abort()}),e.moveInProgressToRemaining(a),k.free(a,!0)),i.onAutoRetry(a,c,n,g)||m.cleanup(a,n,g))}).done(function(){e.clearXhr(a,f)}))}},k={_open:[],_openChunks:{},_waiting:[],available:function(){var a=i.maxConnections,b=0,c=0;return qq.each(k._openChunks,function(a,d){b++,c+=d.length}),a-(k._open.length-b+c)},free:function(a,b){var c,f=!b,g=qq.indexOf(k._waiting,a),h=qq.indexOf(k._open,a);delete k._openChunks[a],m.getProxyOrBlob(a)instanceof qq.BlobProxy&&(d("Generated blob upload has ended for "+a+", disposing generated blob."),delete e._getFileState(a).file),g>=0?k._waiting.splice(g,1):f&&h>=0&&(k._open.splice(h,1),c=k._waiting.shift(),c>=0&&(k._open.push(c),m.start(c)))},getWaitingOrConnected:function(){var a=[];return qq.each(k._openChunks,function(b,c){c&&c.length&&a.push(parseInt(b))}),qq.each(k._open,function(b,c){k._openChunks[c]||a.push(parseInt(c))}),a=a.concat(k._waiting)},isUsingConnection:function(a){return qq.indexOf(k._open,a)>=0},open:function(a,b){return null==b&&k._waiting.push(a),k.available()?(null==b?(k._waiting.pop(),k._open.push(a)):function(){var c=k._openChunks[a]||[];c.push(b),k._openChunks[a]=c}(),!0):!1},reset:function(){k._waiting=[],k._open=[]}},l={send:function(a,b){e._getFileState(a).loaded=0,d("Sending simple upload request for "+a),e.uploadFile(a).then(function(c,e){d("Simple upload request succeeded for "+a);var f=m.normalizeResponse(c,!0),g=i.getSize(a);i.onProgress(a,b,g,g),m.maybeNewUuid(a,f),m.cleanup(a,f,e)},function(c,e){d("Simple upload request failed for "+a);var f=m.normalizeResponse(c,!1);i.onAutoRetry(a,b,f,e)||m.cleanup(a,f,e)})}},m={cancel:function(a){d("Cancelling "+a),i.paramsStore.remove(a),k.free(a)},cleanup:function(a,b,c){var d=i.getName(a);i.onComplete(a,d,b,c),e._getFileState(a)&&e._clearXhrs&&e._clearXhrs(a),k.free(a)},getProxyOrBlob:function(a){return e.getProxy&&e.getProxy(a)||e.getFile&&e.getFile(a)},initHandler:function(){var a=b?qq[b]:qq.traditional,c=qq.supportedFeatures.ajaxUploading?"Xhr":"Form";e=new a[c+"UploadHandler"](i,{getDataByUuid:i.getDataByUuid,getName:i.getName,getSize:i.getSize,getUuid:i.getUuid,log:d,onCancel:i.onCancel,onProgress:i.onProgress,onUuidChanged:i.onUuidChanged}),e._removeExpiredChunkingRecords&&e._removeExpiredChunkingRecords()},isDeferredEligibleForUpload:function(a){return i.isQueued(a)},maybeDefer:function(a,b){return b&&!e.getFile(a)&&b instanceof qq.BlobProxy?(i.onUploadPrep(a),d("Attempting to generate a blob on-demand for "+a),b.create().then(function(b){d("Generated an on-demand blob for "+a),e.updateBlob(a,b),i.setSize(a,b.size),e.reevaluateChunking(a),m.maybeSendDeferredFiles(a)},function(b){var e={};b&&(e.error=b),d(qq.format("Failed to generate blob for ID {}.  Error message: {}.",a,b),"error"),i.onComplete(a,i.getName(a),qq.extend(e,c),null),m.maybeSendDeferredFiles(a),k.free(a)}),!1):m.maybeSendDeferredFiles(a)},maybeSendDeferredFiles:function(a){var b=i.getIdsInProxyGroup(a),c=!1;return b&&b.length?(d("Maybe ready to upload proxy group file "+a),qq.each(b,function(b,d){if(m.isDeferredEligibleForUpload(d)&&e.getFile(d))c=d===a,m.now(d);else if(m.isDeferredEligibleForUpload(d))return!1})):(c=!0,m.now(a)),c},maybeNewUuid:function(a,b){void 0!==b.newUuid&&i.onUuidChanged(a,b.newUuid)},normalizeResponse:function(a,b){var c=a;return qq.isObject(a)||(c={},qq.isString(a)&&!b&&(c.error=a)),c.success=b,c},now:function(a){var b=i.getName(a);if(!f.isValid(a))throw new qq.Error(a+" is not a valid file ID to upload!");i.onUpload(a,b),g&&e._shouldChunkThisFile(a)?j.sendNext(a):l.send(a,b)},start:function(a){var b=m.getProxyOrBlob(a);return b?m.maybeDefer(a,b):(m.now(a),!0)}};qq.extend(this,{add:function(){e.add.apply(this,arguments)},upload:function(a){return k.open(a)?m.start(a):!1},retry:function(a){return h&&(e._getFileState(a).temp.ignoreFailure=!1),k.isUsingConnection(a)?m.start(a):f.upload(a)},cancel:function(a){var b=e.cancel(a);qq.isGenericPromise(b)?b.then(function(){m.cancel(a)}):b!==!1&&m.cancel(a)},cancelAll:function(){var a,b=k.getWaitingOrConnected();if(b.length)for(a=b.length-1;a>=0;a--)f.cancel(b[a]);k.reset()},getFile:function(a){return e.getProxy&&e.getProxy(a)?e.getProxy(a).referenceBlob:e.getFile&&e.getFile(a)},isProxied:function(a){return!(!e.getProxy||!e.getProxy(a))},getInput:function(a){return e.getInput?e.getInput(a):void 0},reset:function(){d("Resetting upload handler"),f.cancelAll(),k.reset(),e.reset()},expunge:function(a){return f.isValid(a)?e.expunge(a):void 0},isValid:function(a){return e.isValid(a)},getResumableFilesData:function(){return e.getResumableFilesData?e.getResumableFilesData():[]},getThirdPartyFileId:function(a){return f.isValid(a)?e.getThirdPartyFileId(a):void 0},pause:function(a){return f.isResumable(a)&&e.pause&&f.isValid(a)&&e.pause(a)?(k.free(a),e.moveInProgressToRemaining(a),!0):!1},isResumable:function(a){return!!e.isResumable&&e.isResumable(a)}}),qq.extend(i,a),d=i.log,g=i.chunking.enabled&&qq.supportedFeatures.chunking,h=g&&i.chunking.concurrent.enabled,c=function(){var a={};return a[i.preventRetryParam]=!0,a}(),m.initHandler()},qq.FormUploadHandler=function(a){"use strict";function b(a){delete k[a],m&&(clearTimeout(l[a]),delete l[a],q.stopReceivingMessages(a));var b=document.getElementById(g._getIframeName(a));b&&(b.setAttribute("src","javascript:false;"),qq(b).remove())}function c(a){return a.split("_")[0]}function d(a){var b=qq.toElement("<iframe src='javascript:false;' name='"+a+"' />");return b.setAttribute("id",a),b.style.display="none",document.body.appendChild(b),b}function e(a,b){var d=a.id,e=c(d),f=o(e);j[f]=b,k[e]=qq(a).attach("load",function(){g.getInput(e)&&(p("Received iframe load event for CORS upload request (iframe name "+d+")"),l[d]=setTimeout(function(){var a="No valid message received from loaded iframe for iframe name "+d;p(a,"error"),b({error:a})},1e3))}),q.receiveMessage(d,function(a){p("Received the following window message: '"+a+"'");var b,e=(c(d),g._parseJsonResponse(a)),f=e.uuid;f&&j[f]?(p("Handling response for iframe name "+d),clearTimeout(l[d]),delete l[d],g._detachLoadEvent(d),b=j[f],delete j[f],q.stopReceivingMessages(d),b(e)):f||p("'"+a+"' does not contain a UUID - ignoring.")})}var f=a.options,g=this,h=a.proxy,i=qq.getUniqueId(),j={},k={},l={},m=f.isCors,n=f.inputName,o=h.getUuid,p=h.log,q=new qq.WindowReceiveMessage({log:p});qq.extend(this,new qq.UploadHandler(a)),qq.override(this,function(a){return{add:function(b,c){a.add(b,{input:c}),c.setAttribute("name",n),c.parentNode&&qq(c).remove()},expunge:function(c){b(c),a.expunge(c)},isValid:function(b){return a.isValid(b)&&void 0!==g._getFileState(b).input}}}),qq.extend(this,{getInput:function(a){return g._getFileState(a).input},_attachLoadEvent:function(a,b){var c;m?e(a,b):k[a.id]=qq(a).attach("load",function(){if(p("Received response for "+a.id),a.parentNode){try{if(a.contentDocument&&a.contentDocument.body&&"false"==a.contentDocument.body.innerHTML)return}catch(d){p("Error when attempting to access iframe during handling of upload response ("+d.message+")","error"),c={success:!1}}b(c)}})},_createIframe:function(a){var b=g._getIframeName(a);return d(b)},_detachLoadEvent:function(a){void 0!==k[a]&&(k[a](),delete k[a])},_getIframeName:function(a){return a+"_"+i},_initFormForUpload:function(a){var b=a.method,c=a.endpoint,d=a.params,e=a.paramsInBody,f=a.targetName,g=qq.toElement("<form method='"+b+"' enctype='multipart/form-data'></form>"),h=c;return e?qq.obj2Inputs(d,g):h=qq.obj2url(d,c),g.setAttribute("action",h),g.setAttribute("target",f),g.style.display="none",document.body.appendChild(g),g
},_parseJsonResponse:function(a){var b={};try{b=qq.parseJson(a)}catch(c){p("Error when attempting to parse iframe upload response ("+c.message+")","error")}return b}})},qq.XhrUploadHandler=function(a){"use strict";function b(a){qq.each(c._getXhrs(a),function(b,d){var e=c._getAjaxRequester(a,b);d.onreadystatechange=null,d.upload.onprogress=null,d.abort(),e&&e.canceled&&e.canceled(a)})}var c=this,d=a.options.namespace,e=a.proxy,f=a.options.chunking,g=a.options.resume,h=f&&a.options.chunking.enabled&&qq.supportedFeatures.chunking,i=g&&a.options.resume.enabled&&h&&qq.supportedFeatures.resume,j=e.getName,k=e.getSize,l=e.getUuid,m=e.getEndpoint,n=e.getDataByUuid,o=e.onUuidChanged,p=e.onProgress,q=e.log;qq.extend(this,new qq.UploadHandler(a)),qq.override(this,function(a){return{add:function(b,d){if(qq.isFile(d)||qq.isBlob(d))a.add(b,{file:d});else{if(!(d instanceof qq.BlobProxy))throw new Error("Passed obj is not a File, Blob, or proxy");a.add(b,{proxy:d})}c._initTempState(b),i&&c._maybePrepareForResume(b)},expunge:function(d){b(d),c._maybeDeletePersistedChunkData(d),c._clearXhrs(d),a.expunge(d)}}}),qq.extend(this,{clearCachedChunk:function(a,b){delete c._getFileState(a).temp.cachedChunks[b]},clearXhr:function(a,b){var d=c._getFileState(a).temp;d.xhrs&&delete d.xhrs[b],d.ajaxRequesters&&delete d.ajaxRequesters[b]},finalizeChunks:function(a,b){var d=c._getTotalChunks(a)-1,e=c._getXhr(a,d);return b?(new qq.Promise).success(b(e),e):(new qq.Promise).success({},e)},getFile:function(a){return c.isValid(a)&&c._getFileState(a).file},getProxy:function(a){return c.isValid(a)&&c._getFileState(a).proxy},getResumableFilesData:function(){var a=[];return c._iterateResumeRecords(function(b,d){c.moveInProgressToRemaining(null,d.chunking.inProgress,d.chunking.remaining);var e={name:d.name,remaining:d.chunking.remaining,size:d.size,uuid:d.uuid};d.key&&(e.key=d.key),a.push(e)}),a},isResumable:function(a){return!!f&&c.isValid(a)&&!c._getFileState(a).notResumable},moveInProgressToRemaining:function(a,b,d){var e=b||c._getFileState(a).chunking.inProgress,f=d||c._getFileState(a).chunking.remaining;e&&(e.reverse(),qq.each(e,function(a,b){f.unshift(b)}),e.length=0)},pause:function(a){return c.isValid(a)?(q(qq.format("Aborting XHR upload for {} '{}' due to pause instruction.",a,j(a))),c._getFileState(a).paused=!0,b(a),!0):void 0},reevaluateChunking:function(a){if(f&&c.isValid(a)){var b,d,e=c._getFileState(a);if(delete e.chunking,e.chunking={},b=c._getTotalChunks(a),b>1||f.mandatory){for(e.chunking.enabled=!0,e.chunking.parts=b,e.chunking.remaining=[],d=0;b>d;d++)e.chunking.remaining.push(d);c._initTempState(a)}else e.chunking.enabled=!1}},updateBlob:function(a,b){c.isValid(a)&&(c._getFileState(a).file=b)},_clearXhrs:function(a){var b=c._getFileState(a).temp;qq.each(b.ajaxRequesters,function(a){delete b.ajaxRequesters[a]}),qq.each(b.xhrs,function(a){delete b.xhrs[a]})},_createXhr:function(a,b){return c._registerXhr(a,b,qq.createXhrInstance())},_getAjaxRequester:function(a,b){var d=null==b?-1:b;return c._getFileState(a).temp.ajaxRequesters[d]},_getChunkData:function(a,b){var d=f.partSize,e=k(a),g=c.getFile(a),h=d*b,i=h+d>=e?e:h+d,j=c._getTotalChunks(a),l=this._getFileState(a).temp.cachedChunks,m=l[b]||qq.sliceBlob(g,h,i);return l[b]=m,{part:b,start:h,end:i,count:j,blob:m,size:i-h}},_getChunkDataForCallback:function(a){return{partIndex:a.part,startByte:a.start+1,endByte:a.end,totalParts:a.count}},_getLocalStorageId:function(a){var b="5.0",c=j(a),e=k(a),g=f.partSize,h=m(a);return qq.format("qq{}resume{}-{}-{}-{}-{}",d,b,c,e,g,h)},_getMimeType:function(a){return c.getFile(a).type},_getPersistableData:function(a){return c._getFileState(a).chunking},_getTotalChunks:function(a){if(f){var b=k(a),c=f.partSize;return Math.ceil(b/c)}},_getXhr:function(a,b){var d=null==b?-1:b;return c._getFileState(a).temp.xhrs[d]},_getXhrs:function(a){return c._getFileState(a).temp.xhrs},_iterateResumeRecords:function(a){i&&qq.each(localStorage,function(b,c){if(0===b.indexOf(qq.format("qq{}resume-",d))){var e=JSON.parse(c);a(b,e)}})},_initTempState:function(a){c._getFileState(a).temp={ajaxRequesters:{},chunkProgress:{},xhrs:{},cachedChunks:{}}},_markNotResumable:function(a){c._getFileState(a).notResumable=!0},_maybeDeletePersistedChunkData:function(a){var b;return i&&c.isResumable(a)&&(b=c._getLocalStorageId(a),b&&localStorage.getItem(b))?(localStorage.removeItem(b),!0):!1},_maybePrepareForResume:function(a){var b,d,e=c._getFileState(a);i&&void 0===e.key&&(b=c._getLocalStorageId(a),d=localStorage.getItem(b),d&&(d=JSON.parse(d),n(d.uuid)?c._markNotResumable(a):(q(qq.format("Identified file with ID {} and name of {} as resumable.",a,j(a))),o(a,d.uuid),e.key=d.key,e.chunking=d.chunking,e.loaded=d.loaded,e.attemptingResume=!0,c.moveInProgressToRemaining(a))))},_maybePersistChunkedState:function(a){var b,d,e=c._getFileState(a);if(i&&c.isResumable(a)){b=c._getLocalStorageId(a),d={name:j(a),size:k(a),uuid:l(a),key:e.key,chunking:e.chunking,loaded:e.loaded,lastUpdated:Date.now()};try{localStorage.setItem(b,JSON.stringify(d))}catch(f){q(qq.format("Unable to save resume data for '{}' due to error: '{}'.",a,f.toString()),"warn")}}},_registerProgressHandler:function(a,b,d){var e=c._getXhr(a,b),f=j(a),g={simple:function(b,c){var d=k(a);b===c?p(a,f,d,d):p(a,f,b>=d?d-1:b,d)},chunked:function(e,g){var h=c._getFileState(a).temp.chunkProgress,i=c._getFileState(a).loaded,j=e,l=g,m=k(a),n=j-(l-d),o=i;h[b]=n,qq.each(h,function(a,b){o+=b}),p(a,f,o,m)}};e.upload.onprogress=function(a){if(a.lengthComputable){var b=null==d?"simple":"chunked";g[b](a.loaded,a.total)}}},_registerXhr:function(a,b,d,e){var f=null==b?-1:b,g=c._getFileState(a).temp;return g.xhrs=g.xhrs||{},g.ajaxRequesters=g.ajaxRequesters||{},g.xhrs[f]=d,e&&(g.ajaxRequesters[f]=e),d},_removeExpiredChunkingRecords:function(){var a=g.recordsExpireIn;c._iterateResumeRecords(function(b,c){var d=new Date(c.lastUpdated);d.setDate(d.getDate()+a),d.getTime()<=Date.now()&&(q("Removing expired resume record with key "+b),localStorage.removeItem(b))})},_shouldChunkThisFile:function(a){var b=c._getFileState(a);return b.chunking||c.reevaluateChunking(a),b.chunking.enabled}})},qq.WindowReceiveMessage=function(a){"use strict";var b={log:function(){}},c={};qq.extend(b,a),qq.extend(this,{receiveMessage:function(a,b){var d=function(a){b(a.data)};window.postMessage?c[a]=qq(window).attach("message",d):log("iframe message passing not supported in this browser!","error")},stopReceivingMessages:function(a){if(window.postMessage){var b=c[a];b&&b()}}})},function(){"use strict";qq.uiPublicApi={clearStoredFiles:function(){this._parent.prototype.clearStoredFiles.apply(this,arguments),this._templating.clearFiles()},addExtraDropzone:function(a){this._dnd&&this._dnd.setupExtraDropzone(a)},removeExtraDropzone:function(a){return this._dnd?this._dnd.removeDropzone(a):void 0},getItemByFileId:function(a){return this._templating.getFileContainer(a)},reset:function(){this._parent.prototype.reset.apply(this,arguments),this._templating.reset(),!this._options.button&&this._templating.getButton()&&(this._defaultButtonId=this._createUploadButton({element:this._templating.getButton()}).getButtonId()),this._dnd&&(this._dnd.dispose(),this._dnd=this._setupDragAndDrop()),this._totalFilesInBatch=0,this._filesInBatchAddedToUi=0,this._setupClickAndEditEventHandlers()},setName:function(a,b){var c=this._options.formatFileName(b);this._parent.prototype.setName.apply(this,arguments),this._templating.updateFilename(a,c)},pauseUpload:function(a){var b=this._parent.prototype.pauseUpload.apply(this,arguments);return b&&this._templating.uploadPaused(a),b},continueUpload:function(a){var b=this._parent.prototype.continueUpload.apply(this,arguments);return b&&this._templating.uploadContinued(a),b},getId:function(a){return this._templating.getFileId(a)},getDropTarget:function(a){var b=this.getFile(a);return b.qqDropTarget}},qq.uiPrivateApi={_getButton:function(a){var b=this._parent.prototype._getButton.apply(this,arguments);return b||a===this._defaultButtonId&&(b=this._templating.getButton()),b},_removeFileItem:function(a){this._templating.removeFile(a)},_setupClickAndEditEventHandlers:function(){this._fileButtonsClickHandler=qq.FileButtonsClickHandler&&this._bindFileButtonsClickEvent(),this._focusinEventSupported=!qq.firefox(),this._isEditFilenameEnabled()&&(this._filenameClickHandler=this._bindFilenameClickEvent(),this._filenameInputFocusInHandler=this._bindFilenameInputFocusInEvent(),this._filenameInputFocusHandler=this._bindFilenameInputFocusEvent())},_setupDragAndDrop:function(){var a=this,b=this._options.dragAndDrop.extraDropzones,c=this._templating,d=c.getDropZone();return d&&b.push(d),new qq.DragAndDrop({dropZoneElements:b,allowMultipleItems:this._options.multiple,classes:{dropActive:this._options.classes.dropActive},callbacks:{processingDroppedFiles:function(){c.showDropProcessing()},processingDroppedFilesComplete:function(b,d){c.hideDropProcessing(),qq.each(b,function(a,b){b.qqDropTarget=d}),b.length&&a.addFiles(b,null,null)},dropError:function(b,c){a._itemError(b,c)},dropLog:function(b,c){a.log(b,c)}}})},_bindFileButtonsClickEvent:function(){var a=this;return new qq.FileButtonsClickHandler({templating:this._templating,log:function(b,c){a.log(b,c)},onDeleteFile:function(b){a.deleteFile(b)},onCancel:function(b){a.cancel(b)},onRetry:function(b){qq(a._templating.getFileContainer(b)).removeClass(a._classes.retryable),a._templating.hideRetry(b),a.retry(b)},onPause:function(b){a.pauseUpload(b)},onContinue:function(b){a.continueUpload(b)},onGetName:function(b){return a.getName(b)}})},_isEditFilenameEnabled:function(){return this._templating.isEditFilenamePossible()&&!this._options.autoUpload&&qq.FilenameClickHandler&&qq.FilenameInputFocusHandler&&qq.FilenameInputFocusHandler},_filenameEditHandler:function(){var a=this,b=this._templating;return{templating:b,log:function(b,c){a.log(b,c)},onGetUploadStatus:function(b){return a.getUploads({id:b}).status},onGetName:function(b){return a.getName(b)},onSetName:function(b,c){a.setName(b,c)},onEditingStatusChange:function(a,c){var d=qq(b.getEditInput(a)),e=qq(b.getFileContainer(a));c?(d.addClass("qq-editing"),b.hideFilename(a),b.hideEditIcon(a)):(d.removeClass("qq-editing"),b.showFilename(a),b.showEditIcon(a)),e.addClass("qq-temp").removeClass("qq-temp")}}},_onUploadStatusChange:function(a,b,c){this._parent.prototype._onUploadStatusChange.apply(this,arguments),this._isEditFilenameEnabled()&&this._templating.getFileContainer(a)&&c!==qq.status.SUBMITTED&&(this._templating.markFilenameEditable(a),this._templating.hideEditIcon(a)),c===qq.status.UPLOAD_RETRYING?(this._templating.setStatusText(a),qq(this._templating.getFileContainer(a)).removeClass(this._classes.retrying)):c===qq.status.UPLOAD_FAILED&&this._templating.hidePause(a)},_bindFilenameInputFocusInEvent:function(){var a=qq.extend({},this._filenameEditHandler());return new qq.FilenameInputFocusInHandler(a)},_bindFilenameInputFocusEvent:function(){var a=qq.extend({},this._filenameEditHandler());return new qq.FilenameInputFocusHandler(a)},_bindFilenameClickEvent:function(){var a=qq.extend({},this._filenameEditHandler());return new qq.FilenameClickHandler(a)},_storeForLater:function(a){this._parent.prototype._storeForLater.apply(this,arguments),this._templating.hideSpinner(a)},_onAllComplete:function(){this._parent.prototype._onAllComplete.apply(this,arguments),this._templating.resetTotalProgress()},_onSubmit:function(a,b){var c=this.getFile(a);c&&c.qqPath&&this._options.dragAndDrop.reportDirectoryPaths&&this._paramsStore.addReadOnly(a,{qqpath:c.qqPath}),this._parent.prototype._onSubmit.apply(this,arguments),this._addToList(a,b)},_onSubmitted:function(a){this._isEditFilenameEnabled()&&(this._templating.markFilenameEditable(a),this._templating.showEditIcon(a),this._focusinEventSupported||this._filenameInputFocusHandler.addHandler(this._templating.getEditInput(a)))},_onProgress:function(a,b,c,d){this._parent.prototype._onProgress.apply(this,arguments),this._templating.updateProgress(a,c,d),100===Math.round(100*(c/d))?(this._templating.hideCancel(a),this._templating.hidePause(a),this._templating.hideProgress(a),this._templating.setStatusText(a,this._options.text.waitingForResponse),this._displayFileSize(a)):this._displayFileSize(a,c,d)},_onTotalProgress:function(a,b){this._parent.prototype._onTotalProgress.apply(this,arguments),this._templating.updateTotalProgress(a,b)},_onComplete:function(a,b,c){function d(b){g&&(f.setStatusText(a),qq(g).removeClass(h._classes.retrying),f.hideProgress(a),h.getUploads({id:a}).status!==qq.status.UPLOAD_FAILED&&f.hideCancel(a),f.hideSpinner(a),b.success?h._markFileAsSuccessful(a):(qq(g).addClass(h._classes.fail),f.showCancel(a),f.isRetryPossible()&&!h._preventRetries[a]&&(qq(g).addClass(h._classes.retryable),f.showRetry(a)),h._controlFailureTextDisplay(a,b)))}var e=this._parent.prototype._onComplete.apply(this,arguments),f=this._templating,g=f.getFileContainer(a),h=this;return e instanceof qq.Promise?e.done(function(a){d(a)}):d(c),e},_markFileAsSuccessful:function(a){var b=this._templating;this._isDeletePossible()&&b.showDeleteButton(a),qq(b.getFileContainer(a)).addClass(this._classes.success),this._maybeUpdateThumbnail(a)},_onUploadPrep:function(a){this._parent.prototype._onUploadPrep.apply(this,arguments),this._templating.showSpinner(a)},_onUpload:function(a){var b=this._parent.prototype._onUpload.apply(this,arguments);return this._templating.showSpinner(a),b},_onUploadChunk:function(a,b){this._parent.prototype._onUploadChunk.apply(this,arguments),b.partIndex>0&&this._handler.isResumable(a)&&this._templating.allowPause(a)},_onCancel:function(a){this._parent.prototype._onCancel.apply(this,arguments),this._removeFileItem(a),0===this._getNotFinished()&&this._templating.resetTotalProgress()},_onBeforeAutoRetry:function(a){var b,c,d;this._parent.prototype._onBeforeAutoRetry.apply(this,arguments),this._showCancelLink(a),this._options.retry.showAutoRetryNote&&(b=this._autoRetries[a],c=this._options.retry.maxAutoAttempts,d=this._options.retry.autoRetryNote.replace(/\{retryNum\}/g,b),d=d.replace(/\{maxAuto\}/g,c),this._templating.setStatusText(a,d),qq(this._templating.getFileContainer(a)).addClass(this._classes.retrying))},_onBeforeManualRetry:function(a){return this._parent.prototype._onBeforeManualRetry.apply(this,arguments)?(this._templating.resetProgress(a),qq(this._templating.getFileContainer(a)).removeClass(this._classes.fail),this._templating.setStatusText(a),this._templating.showSpinner(a),this._showCancelLink(a),!0):(qq(this._templating.getFileContainer(a)).addClass(this._classes.retryable),this._templating.showRetry(a),!1)},_onSubmitDelete:function(a){var b=qq.bind(this._onSubmitDeleteSuccess,this);this._parent.prototype._onSubmitDelete.call(this,a,b)},_onSubmitDeleteSuccess:function(){this._options.deleteFile.forceConfirm?this._showDeleteConfirm.apply(this,arguments):this._sendDeleteRequest.apply(this,arguments)},_onDeleteComplete:function(a,b,c){this._parent.prototype._onDeleteComplete.apply(this,arguments),this._templating.hideSpinner(a),c?(this._templating.setStatusText(a,this._options.deleteFile.deletingFailedText),this._templating.showDeleteButton(a)):this._removeFileItem(a)},_sendDeleteRequest:function(a){this._templating.hideDeleteButton(a),this._templating.showSpinner(a),this._templating.setStatusText(a,this._options.deleteFile.deletingStatusText),this._deleteHandler.sendDelete.apply(this,arguments)},_showDeleteConfirm:function(a){var b,c=this.getName(a),d=this._options.deleteFile.confirmMessage.replace(/\{filename\}/g,c),e=(this.getUuid(a),arguments),f=this;b=this._options.showConfirm(d),qq.isGenericPromise(b)?b.then(function(){f._sendDeleteRequest.apply(f,e)}):b!==!1&&f._sendDeleteRequest.apply(f,e)},_addToList:function(a,b,c){var d,e,f=0,g=this._handler.isProxied(a)&&this._options.scaling.hideScaled;g||(this._options.display.prependFiles&&(this._totalFilesInBatch>1&&this._filesInBatchAddedToUi>0&&(f=this._filesInBatchAddedToUi-1),d={index:f}),c||(this._options.disableCancelForFormUploads&&!qq.supportedFeatures.ajaxUploading&&this._templating.disableCancel(),this._options.multiple||(e=this.getUploads({id:a}),this._handledProxyGroup=this._handledProxyGroup||e.proxyGroupId,e.proxyGroupId===this._handledProxyGroup&&e.proxyGroupId||(this._handler.cancelAll(),this._clearList(),this._handledProxyGroup=null))),this._templating.addFile(a,this._options.formatFileName(b),d),c?this._thumbnailUrls[a]&&this._templating.updateThumbnail(a,this._thumbnailUrls[a],!0):this._templating.generatePreview(a,this.getFile(a)),this._filesInBatchAddedToUi+=1,(c||this._options.display.fileSizeOnSubmit&&qq.supportedFeatures.ajaxUploading)&&this._displayFileSize(a))},_clearList:function(){this._templating.clearFiles(),this.clearStoredFiles()},_displayFileSize:function(a,b,c){var d=this.getSize(a),e=this._formatSize(d);d>=0&&(void 0!==b&&void 0!==c&&(e=this._formatProgress(b,c)),this._templating.updateSize(a,e))},_formatProgress:function(a,b){function c(a,b){d=d.replace(a,b)}var d=this._options.text.formatProgress;return c("{percent}",Math.round(100*(a/b))),c("{total_size}",this._formatSize(b)),d},_controlFailureTextDisplay:function(a,b){var c,d,e;c=this._options.failedUploadTextDisplay.mode,d=this._options.failedUploadTextDisplay.responseProperty,"custom"===c?(e=b[d],e||(e=this._options.text.failUpload),this._templating.setStatusText(a,e),this._options.failedUploadTextDisplay.enableTooltip&&this._showTooltip(a,e)):"default"===c?this._templating.setStatusText(a,this._options.text.failUpload):"none"!==c&&this.log("failedUploadTextDisplay.mode value of '"+c+"' is not valid","warn")},_showTooltip:function(a,b){this._templating.getFileContainer(a).title=b},_showCancelLink:function(a){(!this._options.disableCancelForFormUploads||qq.supportedFeatures.ajaxUploading)&&this._templating.showCancel(a)},_itemError:function(){var a=this._parent.prototype._itemError.apply(this,arguments);this._options.showMessage(a)},_batchError:function(a){this._parent.prototype._batchError.apply(this,arguments),this._options.showMessage(a)},_setupPastePrompt:function(){var a=this;this._options.callbacks.onPasteReceived=function(){var b=a._options.paste.namePromptMessage,c=a._options.paste.defaultName;return a._options.showPrompt(b,c)}},_fileOrBlobRejected:function(){this._totalFilesInBatch-=1,this._parent.prototype._fileOrBlobRejected.apply(this,arguments)},_prepareItemsForUpload:function(a){this._totalFilesInBatch=a.length,this._filesInBatchAddedToUi=0,this._parent.prototype._prepareItemsForUpload.apply(this,arguments)},_maybeUpdateThumbnail:function(a){var b=this._thumbnailUrls[a];this._templating.updateThumbnail(a,b)},_addCannedFile:function(){var a=this._parent.prototype._addCannedFile.apply(this,arguments);return this._addToList(a,this.getName(a),!0),this._templating.hideSpinner(a),this._templating.hideCancel(a),this._markFileAsSuccessful(a),a},_setSize:function(a,b){this._parent.prototype._setSize.apply(this,arguments),this._templating.updateSize(a,this._formatSize(b))}}}(),qq.FineUploader=function(a,b){"use strict";var c=this;this._parent=b?qq[b].FineUploaderBasic:qq.FineUploaderBasic,this._parent.apply(this,arguments),qq.extend(this._options,{element:null,button:null,listElement:null,dragAndDrop:{extraDropzones:[],reportDirectoryPaths:!1},text:{formatProgress:"{percent}% of {total_size}",failUpload:"Upload failed",waitingForResponse:"Processing...",paused:"Paused"},template:"qq-template",classes:{retrying:"qq-upload-retrying",retryable:"qq-upload-retryable",success:"qq-upload-success",fail:"qq-upload-fail",editable:"qq-editable",hide:"qq-hide",dropActive:"qq-upload-drop-area-active"},failedUploadTextDisplay:{mode:"default",responseProperty:"error",enableTooltip:!0},messages:{tooManyFilesError:"You may only drop one file",unsupportedBrowser:"Unrecoverable error - this browser does not permit file uploading of any kind."},retry:{showAutoRetryNote:!0,autoRetryNote:"Retrying {retryNum}/{maxAuto}..."},deleteFile:{forceConfirm:!1,confirmMessage:"Are you sure you want to delete {filename}?",deletingStatusText:"Deleting...",deletingFailedText:"Delete failed"},display:{fileSizeOnSubmit:!1,prependFiles:!1},paste:{promptForName:!1,namePromptMessage:"Please name this image"},thumbnails:{maxCount:0,placeholders:{waitUntilResponse:!1,notAvailablePath:null,waitingPath:null},timeBetweenThumbs:750},scaling:{hideScaled:!1},showMessage:function(a){return c._templating.hasDialog("alert")?c._templating.showDialog("alert",a):(setTimeout(function(){window.alert(a)},0),void 0)},showConfirm:function(a){return c._templating.hasDialog("confirm")?c._templating.showDialog("confirm",a):window.confirm(a)},showPrompt:function(a,b){return c._templating.hasDialog("prompt")?c._templating.showDialog("prompt",a,b):window.prompt(a,b)}},!0),qq.extend(this._options,a,!0),this._templating=new qq.Templating({log:qq.bind(this.log,this),templateIdOrEl:this._options.template,containerEl:this._options.element,fileContainerEl:this._options.listElement,button:this._options.button,imageGenerator:this._imageGenerator,classes:{hide:this._options.classes.hide,editable:this._options.classes.editable},limits:{maxThumbs:this._options.thumbnails.maxCount,timeBetweenThumbs:this._options.thumbnails.timeBetweenThumbs},placeholders:{waitUntilUpdate:this._options.thumbnails.placeholders.waitUntilResponse,thumbnailNotAvailable:this._options.thumbnails.placeholders.notAvailablePath,waitingForThumbnail:this._options.thumbnails.placeholders.waitingPath},text:this._options.text}),this._options.workarounds.ios8SafariUploads&&qq.ios800()&&qq.iosSafari()?this._templating.renderFailure(this._options.messages.unsupportedBrowserIos8Safari):!qq.supportedFeatures.uploading||this._options.cors.expected&&!qq.supportedFeatures.uploadCors?this._templating.renderFailure(this._options.messages.unsupportedBrowser):(this._wrapCallbacks(),this._templating.render(),this._classes=this._options.classes,!this._options.button&&this._templating.getButton()&&(this._defaultButtonId=this._createUploadButton({element:this._templating.getButton()}).getButtonId()),this._setupClickAndEditEventHandlers(),qq.DragAndDrop&&qq.supportedFeatures.fileDrop&&(this._dnd=this._setupDragAndDrop()),this._options.paste.targetElement&&this._options.paste.promptForName&&(qq.PasteSupport?this._setupPastePrompt():this.log("Paste support module not found.","error")),this._totalFilesInBatch=0,this._filesInBatchAddedToUi=0)},qq.extend(qq.FineUploader.prototype,qq.basePublicApi),qq.extend(qq.FineUploader.prototype,qq.basePrivateApi),qq.extend(qq.FineUploader.prototype,qq.uiPublicApi),qq.extend(qq.FineUploader.prototype,qq.uiPrivateApi),qq.Templating=function(a){"use strict";var b,c,d,e,f,g,h,i,j="qq-file-id",k="qq-file-id-",l="qq-max-size",m="qq-server-scale",n="qq-hide-dropzone",o="qq-drop-area-text",p="qq-in-progress",q=!1,r=0,s=!1,t=[],u=-1,v={log:null,limits:{maxThumbs:0,timeBetweenThumbs:750},templateIdOrEl:"qq-template",containerEl:null,fileContainerEl:null,button:null,imageGenerator:null,classes:{hide:"qq-hide",editable:"qq-editable"},placeholders:{waitUntilUpdate:!1,thumbnailNotAvailable:null,waitingForThumbnail:null},text:{paused:"Paused"}},w={button:"qq-upload-button-selector",alertDialog:"qq-alert-dialog-selector",dialogCancelButton:"qq-cancel-button-selector",confirmDialog:"qq-confirm-dialog-selector",dialogMessage:"qq-dialog-message-selector",dialogOkButton:"qq-ok-button-selector",promptDialog:"qq-prompt-dialog-selector",uploader:"qq-uploader-selector",drop:"qq-upload-drop-area-selector",list:"qq-upload-list-selector",progressBarContainer:"qq-progress-bar-container-selector",progressBar:"qq-progress-bar-selector",totalProgressBarContainer:"qq-total-progress-bar-container-selector",totalProgressBar:"qq-total-progress-bar-selector",file:"qq-upload-file-selector",spinner:"qq-upload-spinner-selector",size:"qq-upload-size-selector",cancel:"qq-upload-cancel-selector",pause:"qq-upload-pause-selector",continueButton:"qq-upload-continue-selector",deleteButton:"qq-upload-delete-selector",retry:"qq-upload-retry-selector",statusText:"qq-upload-status-text-selector",editFilenameInput:"qq-edit-filename-selector",editNameIcon:"qq-edit-filename-icon-selector",dropText:"qq-upload-drop-area-text-selector",dropProcessing:"qq-drop-processing-selector",dropProcessingSpinner:"qq-drop-processing-spinner-selector",thumbnail:"qq-thumbnail-selector"},x={},y=new qq.Promise,z=new qq.Promise,A=function(){var a=v.placeholders.thumbnailNotAvailable,c=v.placeholders.waitingForThumbnail,d={maxSize:u,scale:i};h&&(a?v.imageGenerator.generate(a,new Image,d).then(function(a){y.success(a)},function(){y.failure(),b("Problem loading 'not available' placeholder image at "+a,"error")}):y.failure(),c?v.imageGenerator.generate(c,new Image,d).then(function(a){z.success(a)},function(){z.failure(),b("Problem loading 'waiting for thumbnail' placeholder image at "+c,"error")}):z.failure())},B=function(a){var b=new qq.Promise;return z.then(function(c){U(c,a),a.src?b.success():(a.src=c.src,a.onload=function(){a.onload=null,_(a),b.success()})},function(){T(a),b.success()}),b},C=function(a,c,d){var e=S(a);return b("Generating new thumbnail for "+a),c.qqThumbnailId=a,v.imageGenerator.generate(c,e,d).then(function(){r++,_(e),x[a].success()},function(){x[a].failure(),v.placeholders.waitUntilUpdate||V(a,e)})},D=function(){if(t.length){s=!0;var a=t.shift();a.update?Z(a):Y(a)}else s=!1},E=function(a){return R(K(a),w.cancel)},F=function(a){return R(K(a),w.continueButton)},G=function(a){return R(f,w[a+"Dialog"])},H=function(a){return R(K(a),w.deleteButton)},I=function(){return R(f,w.dropProcessing)},J=function(a){return R(K(a),w.editNameIcon)},K=function(a){return qq(g).getByClass(k+a)[0]},L=function(a){return R(K(a),w.file)},M=function(a){return R(K(a),w.pause)},N=function(a){return null==a?R(f,w.totalProgressBarContainer)||R(f,w.totalProgressBar):R(K(a),w.progressBarContainer)||R(K(a),w.progressBar)},O=function(a){return R(K(a),w.retry)},P=function(a){return R(K(a),w.size)},Q=function(a){return R(K(a),w.spinner)},R=function(a,b){return a&&qq(a).getByClass(b)[0]},S=function(a){return h&&R(K(a),w.thumbnail)},T=function(a){a&&qq(a).addClass(v.classes.hide)},U=function(a,b){var c=a.style.maxWidth,d=a.style.maxHeight;d&&c&&!b.style.maxWidth&&!b.style.maxHeight&&qq(b).css({maxWidth:c,maxHeight:d})},V=function(a,b){var c=x[a]||(new qq.Promise).failure(),d=new qq.Promise;return y.then(function(a){c.then(function(){d.success()},function(){U(a,b),b.onload=function(){b.onload=null,d.success()},b.src=a.src,_(b)})}),d},W=function(){var a,e,f,g,j,k,p,q,r,s,t;if(b("Parsing template"),null==v.templateIdOrEl)throw new Error("You MUST specify either a template element or ID!");if(qq.isString(v.templateIdOrEl)){if(a=document.getElementById(v.templateIdOrEl),null===a)throw new Error(qq.format("Cannot find template script at ID '{}'!",v.templateIdOrEl));e=a.innerHTML}else{if(void 0===v.templateIdOrEl.innerHTML)throw new Error("You have specified an invalid value for the template option!  It must be an ID or an Element.");e=v.templateIdOrEl.innerHTML}if(e=qq.trimStr(e),g=document.createElement("div"),g.appendChild(qq.toElement(e)),t=qq(g).getByClass(w.uploader)[0],v.button&&(k=qq(g).getByClass(w.button)[0],k&&qq(k).remove()),qq.DragAndDrop&&qq.supportedFeatures.fileDrop||(r=qq(g).getByClass(w.dropProcessing)[0],r&&qq(r).remove()),p=qq(g).getByClass(w.drop)[0],p&&!qq.DragAndDrop&&(b("DnD module unavailable.","info"),qq(p).remove()),qq.supportedFeatures.fileDrop?qq(t).hasAttribute(o)&&p&&(s=qq(p).getByClass(w.dropText)[0],s&&qq(s).remove()):(t.removeAttribute(o),p&&qq(p).hasAttribute(n)&&qq(p).css({display:"none"})),q=qq(g).getByClass(w.thumbnail)[0],h?q&&(u=parseInt(q.getAttribute(l)),u=u>0?u:null,i=qq(q).hasAttribute(m)):q&&qq(q).remove(),h=h&&q,c=qq(g).getByClass(w.editFilenameInput).length>0,d=qq(g).getByClass(w.retry).length>0,f=qq(g).getByClass(w.list)[0],null==f)throw new Error("Could not find the file list container in the template!");return j=f.innerHTML,f.innerHTML="",g.getElementsByTagName("DIALOG").length&&document.createElement("dialog"),b("Template parsing complete"),{template:qq.trimStr(g.innerHTML),fileTemplate:qq.trimStr(j)}},X=function(a,b){var c=g,d=c.firstChild;b>0&&(d=qq(c).children()[b].nextSibling),c.insertBefore(a,d)},Y=function(a){var b=a.id,c=a.optFileOrBlob,d=c&&c.qqThumbnailId,e=S(b),f={maxSize:u,scale:!0,orient:!0};qq.supportedFeatures.imagePreviews?e&&(v.limits.maxThumbs&&v.limits.maxThumbs<=r?(V(b,e),D()):B(e).done(function(){x[b]=new qq.Promise,x[b].done(function(){setTimeout(D,v.limits.timeBetweenThumbs)}),null!=d?ab(b,d):C(b,c,f)})):e&&(B(e),D())},Z=function(a){var b=a.id,c=a.thumbnailUrl,d=a.showWaitingImg,e=S(b),f={maxSize:u,scale:i};if(e)if(c){if(!(v.limits.maxThumbs&&v.limits.maxThumbs<=r))return d&&B(e),v.imageGenerator.generate(c,e,f).then(function(){_(e),r++,setTimeout(D,v.limits.timeBetweenThumbs)},function(){V(b,e),setTimeout(D,v.limits.timeBetweenThumbs)});V(b,e),D()}else V(b,e),D()},$=function(a,b){var c=N(a),d=null==a?w.totalProgressBar:w.progressBar;c&&!qq(c).hasClass(d)&&(c=qq(c).getByClass(d)[0]),c&&(qq(c).css({width:b+"%"}),c.setAttribute("aria-valuenow",b))},_=function(a){a&&qq(a).removeClass(v.classes.hide)},ab=function(a,c){var d=S(a),e=S(c);b(qq.format("ID {} is the same file as ID {}.  Will use generated thumbnail from ID {} instead.",a,c,c)),x[c].then(function(){r++,x[a].success(),b(qq.format("Now using previously generated thumbnail created for ID {} on ID {}.",c,a)),d.src=e.src,_(d)},function(){x[a].failure(),v.placeholders.waitUntilUpdate||V(a,d)})};qq.extend(v,a),b=v.log,qq.supportedFeatures.imagePreviews||(v.limits.timeBetweenThumbs=0,v.limits.maxThumbs=0),f=v.containerEl,h=void 0!==v.imageGenerator,e=W(),A(),qq.extend(this,{render:function(){b("Rendering template in DOM."),r=0,f.innerHTML=e.template,T(I()),this.hideTotalProgress(),g=v.fileContainerEl||R(f,w.list),b("Template rendering complete")},renderFailure:function(a){var b=qq.toElement(a);f.innerHTML="",f.appendChild(b)},reset:function(){this.render()},clearFiles:function(){g.innerHTML=""},disableCancel:function(){q=!0},addFile:function(a,b,c){var d,h=qq.toElement(e.fileTemplate),i=R(h,w.file),l=R(f,w.uploader);qq(h).addClass(k+a),l.removeAttribute(o),i&&(qq(i).setText(b),i.setAttribute("title",b)),h.setAttribute(j,a),c?X(h,c.index):g.appendChild(h),T(N(a)),T(P(a)),T(H(a)),T(O(a)),T(M(a)),T(F(a)),q&&this.hideCancel(a),d=S(a),d&&!d.src&&z.then(function(a){d.src=a.src,a.style.maxHeight&&a.style.maxWidth&&qq(d).css({maxHeight:a.style.maxHeight,maxWidth:a.style.maxWidth}),_(d)})},removeFile:function(a){qq(K(a)).remove()},getFileId:function(a){var b=a;if(b){for(;null==b.getAttribute(j);)b=b.parentNode;return parseInt(b.getAttribute(j))}},getFileList:function(){return g},markFilenameEditable:function(a){var b=L(a);b&&qq(b).addClass(v.classes.editable)},updateFilename:function(a,b){var c=L(a);c&&(qq(c).setText(b),c.setAttribute("title",b))},hideFilename:function(a){T(L(a))},showFilename:function(a){_(L(a))},isFileName:function(a){return qq(a).hasClass(w.file)},getButton:function(){return v.button||R(f,w.button)},hideDropProcessing:function(){T(I())},showDropProcessing:function(){_(I())},getDropZone:function(){return R(f,w.drop)},isEditFilenamePossible:function(){return c},hideRetry:function(a){T(O(a))},isRetryPossible:function(){return d},showRetry:function(a){_(O(a))},getFileContainer:function(a){return K(a)},showEditIcon:function(a){var b=J(a);b&&qq(b).addClass(v.classes.editable)},hideEditIcon:function(a){var b=J(a);b&&qq(b).removeClass(v.classes.editable)},isEditIcon:function(a){return qq(a).hasClass(w.editNameIcon,!0)},getEditInput:function(a){return R(K(a),w.editFilenameInput)},isEditInput:function(a){return qq(a).hasClass(w.editFilenameInput,!0)},updateProgress:function(a,b,c){var d,e=N(a);e&&c>0&&(d=Math.round(100*(b/c)),100===d?T(e):_(e),$(a,d))},updateTotalProgress:function(a,b){this.updateProgress(null,a,b)},hideProgress:function(a){var b=N(a);b&&T(b)
},hideTotalProgress:function(){this.hideProgress()},resetProgress:function(a){$(a,0),this.hideTotalProgress(a)},resetTotalProgress:function(){this.resetProgress()},showCancel:function(a){if(!q){var b=E(a);b&&qq(b).removeClass(v.classes.hide)}},hideCancel:function(a){T(E(a))},isCancel:function(a){return qq(a).hasClass(w.cancel,!0)},allowPause:function(a){_(M(a)),T(F(a))},uploadPaused:function(a){this.setStatusText(a,v.text.paused),this.allowContinueButton(a),T(Q(a))},hidePause:function(a){T(M(a))},isPause:function(a){return qq(a).hasClass(w.pause,!0)},isContinueButton:function(a){return qq(a).hasClass(w.continueButton,!0)},allowContinueButton:function(a){_(F(a)),T(M(a))},uploadContinued:function(a){this.setStatusText(a,""),this.allowPause(a),_(Q(a))},showDeleteButton:function(a){_(H(a))},hideDeleteButton:function(a){T(H(a))},isDeleteButton:function(a){return qq(a).hasClass(w.deleteButton,!0)},isRetry:function(a){return qq(a).hasClass(w.retry,!0)},updateSize:function(a,b){var c=P(a);c&&(_(c),qq(c).setText(b))},setStatusText:function(a,b){var c=R(K(a),w.statusText);c&&(null==b?qq(c).clearText():qq(c).setText(b))},hideSpinner:function(a){qq(K(a)).removeClass(p),T(Q(a))},showSpinner:function(a){qq(K(a)).addClass(p),_(Q(a))},generatePreview:function(a,b){t.push({id:a,optFileOrBlob:b}),!s&&D()},updateThumbnail:function(a,b,c){t.push({update:!0,id:a,thumbnailUrl:b,showWaitingImg:c}),!s&&D()},hasDialog:function(a){return qq.supportedFeatures.dialogElement&&!!G(a)},showDialog:function(a,b,c){var d=G(a),e=R(d,w.dialogMessage),f=d.getElementsByTagName("INPUT")[0],g=R(d,w.dialogCancelButton),h=R(d,w.dialogOkButton),i=new qq.Promise,j=function(){g.removeEventListener("click",k),h&&h.removeEventListener("click",l),i.failure()},k=function(){g.removeEventListener("click",k),d.close()},l=function(){d.removeEventListener("close",j),h.removeEventListener("click",l),d.close(),i.success(f&&f.value)};return d.addEventListener("close",j),g.addEventListener("click",k),h&&h.addEventListener("click",l),f&&(f.value=c),e.textContent=b,d.showModal(),i}})},qq.traditional=qq.traditional||{},qq.traditional.FormUploadHandler=function(a,b){"use strict";function c(a,b){var c,d,f;try{d=b.contentDocument||b.contentWindow.document,f=d.body.innerHTML,h("converting iframe's innerHTML to JSON"),h("innerHTML = "+f),f&&f.match(/^<pre/i)&&(f=d.body.firstChild.firstChild.nodeValue),c=e._parseJsonResponse(f)}catch(g){h("Error when attempting to parse form upload response ("+g.message+")","error"),c={success:!1}}return c}function d(b,c){var d=a.paramsStore.get(b),h="get"===a.method.toLowerCase()?"GET":"POST",i=a.endpointStore.get(b),j=f(b);return d[a.uuidName]=g(b),d[a.filenameParam]=j,e._initFormForUpload({method:h,endpoint:i,params:d,paramsInBody:a.paramsInBody,targetName:c.name})}var e=this,f=b.getName,g=b.getUuid,h=b.log;this.uploadFile=function(b){var f,g=e.getInput(b),i=e._createIframe(b),j=new qq.Promise;return f=d(b,i),f.appendChild(g),e._attachLoadEvent(i,function(d){h("iframe loaded");var f=d?d:c(b,i);e._detachLoadEvent(b),a.cors.expected||qq(i).remove(),f.success?j.success(f):j.failure(f)}),h("Sending upload request for "+b),f.submit(),qq(f).remove(),j},qq.extend(this,new qq.FormUploadHandler({options:{isCors:a.cors.expected,inputName:a.inputName},proxy:{onCancel:a.onCancel,getName:f,getUuid:g,log:h}}))},qq.traditional=qq.traditional||{},qq.traditional.XhrUploadHandler=function(a,b){"use strict";var c=this,d=b.getName,e=b.getSize,f=b.getUuid,g=b.log,h=a.forceMultipart||a.paramsInBody,i=function(b,c,f){var g=e(b),i=d(b);c[a.chunking.paramNames.partIndex]=f.part,c[a.chunking.paramNames.partByteOffset]=f.start,c[a.chunking.paramNames.chunkSize]=f.size,c[a.chunking.paramNames.totalParts]=f.count,c[a.totalFileSizeName]=g,h&&(c[a.filenameParam]=i)},j=new qq.traditional.AllChunksDoneAjaxRequester({cors:a.cors,endpoint:a.chunking.success.endpoint,log:g}),k=function(a,b){var c=new qq.Promise;return b.onreadystatechange=function(){if(4===b.readyState){var d=n(a,b);d.success?c.success(d.response,b):c.failure(d.response,b)}},c},l=function(b){var g=a.paramsStore.get(b),h=d(b),i=e(b);return g[a.uuidName]=f(b),g[a.filenameParam]=h,g[a.totalFileSizeName]=i,g[a.chunking.paramNames.totalParts]=c._getTotalChunks(b),g},m=function(a,b){return qq.indexOf([200,201,202,203,204],a.status)<0||!b.success||b.reset},n=function(a,b){var c;return g("xhr - server response received for "+a),g("responseText = "+b.responseText),c=o(!0,b),{success:!m(b,c),response:c}},o=function(a,b){var c={};try{g(qq.format("Received response status {} with body: {}",b.status,b.responseText)),c=qq.parseJson(b.responseText)}catch(d){a&&g("Error when attempting to parse xhr response text ("+d.message+")","error")}return c},p=function(b){var d=new qq.Promise;return j.complete(b,c._createXhr(b),l(b),a.customHeaders.get(b)).then(function(a){d.success(o(!1,a),a)},function(a){d.failure(o(!1,a),a)}),d},q=function(b,c,g,i){var j=new FormData,k=a.method,l=a.endpointStore.get(i),m=d(i),n=e(i);return b[a.uuidName]=f(i),b[a.filenameParam]=m,h&&(b[a.totalFileSizeName]=n),a.paramsInBody||(h||(b[a.inputName]=m),l=qq.obj2url(b,l)),c.open(k,l,!0),a.cors.expected&&a.cors.sendCredentials&&(c.withCredentials=!0),h?(a.paramsInBody&&qq.obj2FormData(b,j),j.append(a.inputName,g),j):g},r=function(b,d){var e=a.customHeaders.get(b),f=c.getFile(b);d.setRequestHeader("Accept","application/json"),d.setRequestHeader("X-Requested-With","XMLHttpRequest"),d.setRequestHeader("Cache-Control","no-cache"),h||(d.setRequestHeader("Content-Type","application/octet-stream"),d.setRequestHeader("X-Mime-Type",f.type)),qq.each(e,function(a,b){d.setRequestHeader(a,b)})};qq.extend(this,{uploadChunk:function(b,d,f){var g,h,j,l=c._getChunkData(b,d),m=c._createXhr(b,d);return e(b),g=k(b,m),c._registerProgressHandler(b,d,l.size),j=a.paramsStore.get(b),i(b,j,l),f&&(j[a.resume.paramNames.resuming]=!0),h=q(j,m,l.blob,b),r(b,m),m.send(h),g},uploadFile:function(b){var d,e,f,g,h=c.getFile(b);return e=c._createXhr(b),c._registerProgressHandler(b),d=k(b,e),f=a.paramsStore.get(b),g=q(f,e,h,b),r(b,e),e.send(g),d}}),qq.extend(this,new qq.XhrUploadHandler({options:qq.extend({namespace:"traditional"},a),proxy:qq.extend({getEndpoint:a.endpointStore.get},b)})),qq.override(this,function(b){return{finalizeChunks:function(c){return a.chunking.success.endpoint?p(c):b.finalizeChunks(c,qq.bind(o,this,!0))}}})},qq.traditional.AllChunksDoneAjaxRequester=function(a){"use strict";var b,c="POST",d={cors:{allowXdr:!1,expected:!1,sendCredentials:!1},endpoint:null,log:function(){}},e={},f={get:function(){return d.endpoint}};qq.extend(d,a),b=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",validMethods:[c],method:c,endpointStore:f,allowXRequestedWithAndCacheControl:!1,cors:d.cors,log:d.log,onComplete:function(a,b,c){var d=e[a];delete e[a],c?d.failure(b):d.success(b)}})),qq.extend(this,{complete:function(a,c,f,g){var h=new qq.Promise;return d.log("Submitting All Chunks Done request for "+a),e[a]=h,b.initTransport(a).withParams(f).withHeaders(g).send(c),h}})},qq.PasteSupport=function(a){"use strict";function b(a){return a.type&&0===a.type.indexOf("image/")}function c(){f=qq(e.targetElement).attach("paste",function(a){var c=a.clipboardData;c&&qq.each(c.items,function(a,c){if(b(c)){var d=c.getAsFile();e.callbacks.pasteReceived(d)}})})}function d(){f&&f()}var e,f;e={targetElement:null,callbacks:{log:function(){},pasteReceived:function(){}}},qq.extend(e,a),c(),qq.extend(this,{reset:function(){d()}})},qq.DragAndDrop=function(a){"use strict";function b(a,b){var c=Array.prototype.slice.call(a);j.callbacks.dropLog("Grabbed "+a.length+" dropped files."),b.dropDisabled(!1),j.callbacks.processingDroppedFilesComplete(c,b.getElement())}function c(a){var b=new qq.Promise;return a.isFile?a.file(function(c){var d=a.name,e=a.fullPath,f=e.indexOf(d);e=e.substr(0,f),"/"===e.charAt(0)&&(e=e.substr(1)),c.qqPath=e,n.push(c),b.success()},function(c){j.callbacks.dropLog("Problem parsing '"+a.fullPath+"'.  FileError code "+c.code+".","error"),b.failure()}):a.isDirectory&&d(a).then(function(a){var d=a.length;qq.each(a,function(a,e){c(e).done(function(){d-=1,0===d&&b.success()})}),a.length||b.success()},function(c){j.callbacks.dropLog("Problem parsing '"+a.fullPath+"'.  FileError code "+c.code+".","error"),b.failure()}),b}function d(a,b,c,e){var f=e||new qq.Promise,g=b||a.createReader();return g.readEntries(function(b){var e=c?c.concat(b):b;b.length?setTimeout(function(){d(a,g,e,f)},0):f.success(e)},f.failure),f}function e(a,b){var d=[],e=new qq.Promise;return j.callbacks.processingDroppedFiles(),b.dropDisabled(!0),a.files.length>1&&!j.allowMultipleItems?(j.callbacks.processingDroppedFilesComplete([]),j.callbacks.dropError("tooManyFilesError",""),b.dropDisabled(!1),e.failure()):(n=[],qq.isFolderDropSupported(a)?qq.each(a.items,function(a,b){var f=b.webkitGetAsEntry();f&&(f.isFile?n.push(b.getAsFile()):d.push(c(f).done(function(){d.pop(),0===d.length&&e.success()})))}):n=a.files,0===d.length&&e.success()),e}function f(a){var c=new qq.UploadDropZone({HIDE_ZONES_EVENT_NAME:k,element:a,onEnter:function(b){qq(a).addClass(j.classes.dropActive),b.stopPropagation()},onLeaveNotDescendants:function(){qq(a).removeClass(j.classes.dropActive)},onDrop:function(a){e(a.dataTransfer,c).then(function(){b(n,c)},function(){j.callbacks.dropLog("Drop event DataTransfer parsing failed.  No files will be uploaded.","error")})}});return o.addDisposer(function(){c.dispose()}),qq(a).hasAttribute(l)&&qq(a).hide(),m.push(c),c}function g(a){var b;return qq.each(a.dataTransfer.types,function(a,c){return"Files"===c?(b=!0,!1):void 0}),b}function h(a){return qq.firefox()?!a.relatedTarget:qq.safari()?a.x<0||a.y<0:0===a.x&&0===a.y}function i(){var a=j.dropZoneElements,b=function(){setTimeout(function(){qq.each(a,function(a,b){qq(b).hasAttribute(l)&&qq(b).hide(),qq(b).removeClass(j.classes.dropActive)})},10)};qq.each(a,function(b,c){var d=f(c);a.length&&qq.supportedFeatures.fileDrop&&o.attach(document,"dragenter",function(b){!d.dropDisabled()&&g(b)&&qq.each(a,function(a,b){b instanceof HTMLElement&&qq(b).hasAttribute(l)&&qq(b).css({display:"block"})})})}),o.attach(document,"dragleave",function(a){h(a)&&b()}),o.attach(qq(document).children()[0],"mouseenter",function(){b()}),o.attach(document,"drop",function(a){a.preventDefault(),b()}),o.attach(document,k,b)}var j,k="qq-hidezones",l="qq-hide-dropzone",m=[],n=[],o=new qq.DisposeSupport;j={dropZoneElements:[],allowMultipleItems:!0,classes:{dropActive:null},callbacks:new qq.DragAndDrop.callbacks},qq.extend(j,a,!0),i(),qq.extend(this,{setupExtraDropzone:function(a){j.dropZoneElements.push(a),f(a)},removeDropzone:function(a){var b,c=j.dropZoneElements;for(b in c)if(c[b]===a)return c.splice(b,1)},dispose:function(){o.dispose(),qq.each(m,function(a,b){b.dispose()})}})},qq.DragAndDrop.callbacks=function(){"use strict";return{processingDroppedFiles:function(){},processingDroppedFilesComplete:function(){},dropError:function(a,b){qq.log("Drag & drop error code '"+a+" with these specifics: '"+b+"'","error")},dropLog:function(a,b){qq.log(a,b)}}},qq.UploadDropZone=function(a){"use strict";function b(){return qq.safari()||qq.firefox()&&qq.windows()}function c(){k||(b?l.attach(document,"dragover",function(a){a.preventDefault()}):l.attach(document,"dragover",function(a){a.dataTransfer&&(a.dataTransfer.dropEffect="none",a.preventDefault())}),k=!0)}function d(a){if(!qq.supportedFeatures.fileDrop)return!1;var b,c=a.dataTransfer,d=qq.safari();return b=qq.ie()&&qq.supportedFeatures.fileDrop?!0:"none"!==c.effectAllowed,c&&b&&(c.files||!d&&c.types.contains&&c.types.contains("Files"))}function e(a){return void 0!==a&&(j=a),j}function f(){function a(){b=document.createEvent("Event"),b.initEvent(h.HIDE_ZONES_EVENT_NAME,!0,!0)}var b;if(window.CustomEvent)try{b=new CustomEvent(h.HIDE_ZONES_EVENT_NAME)}catch(c){a()}else a();document.dispatchEvent(b)}function g(){l.attach(i,"dragover",function(a){if(d(a)){var b=qq.ie()&&qq.supportedFeatures.fileDrop?null:a.dataTransfer.effectAllowed;a.dataTransfer.dropEffect="move"===b||"linkMove"===b?"move":"copy",a.stopPropagation(),a.preventDefault()}}),l.attach(i,"dragenter",function(a){if(!e()){if(!d(a))return;h.onEnter(a)}}),l.attach(i,"dragleave",function(a){if(d(a)){h.onLeave(a);var b=document.elementFromPoint(a.clientX,a.clientY);qq(this).contains(b)||h.onLeaveNotDescendants(a)}}),l.attach(i,"drop",function(a){if(!e()){if(!d(a))return;a.preventDefault(),a.stopPropagation(),h.onDrop(a),f()}})}var h,i,j,k,l=new qq.DisposeSupport;h={element:null,onEnter:function(){},onLeave:function(){},onLeaveNotDescendants:function(){},onDrop:function(){}},qq.extend(h,a),i=h.element,c(),g(),qq.extend(this,{dropDisabled:function(a){return e(a)},dispose:function(){l.dispose()},getElement:function(){return i}})},qq.DeleteFileAjaxRequester=function(a){"use strict";function b(){return"POST"===d.method.toUpperCase()?{_method:"DELETE"}:{}}var c,d={method:"DELETE",uuidParamName:"qquuid",endpointStore:{},maxConnections:3,customHeaders:function(){return{}},paramsStore:{},cors:{expected:!1,sendCredentials:!1},log:function(){},onDelete:function(){},onDeleteComplete:function(){}};qq.extend(d,a),c=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",validMethods:["POST","DELETE"],method:d.method,endpointStore:d.endpointStore,paramsStore:d.paramsStore,mandatedParams:b(),maxConnections:d.maxConnections,customHeaders:function(a){return d.customHeaders.get(a)},log:d.log,onSend:d.onDelete,onComplete:d.onDeleteComplete,cors:d.cors})),qq.extend(this,{sendDelete:function(a,b,e){var f=e||{};d.log("Submitting delete file request for "+a),"DELETE"===d.method?c.initTransport(a).withPath(b).withParams(f).send():(f[d.uuidParamName]=b,c.initTransport(a).withParams(f).send())}})},function(){function a(a){var b,c=a.naturalWidth,d=a.naturalHeight,e=document.createElement("canvas");return c*d>1048576?(e.width=e.height=1,b=e.getContext("2d"),b.drawImage(a,-c+1,0),0===b.getImageData(0,0,1,1).data[3]):!1}function b(a,b,c){var d,e,f,g,h=document.createElement("canvas"),i=0,j=c,k=c;for(h.width=1,h.height=c,d=h.getContext("2d"),d.drawImage(a,0,0),e=d.getImageData(0,0,1,c).data;k>i;)f=e[4*(k-1)+3],0===f?j=k:i=k,k=j+i>>1;return g=k/c,0===g?1:g}function c(a,b,c){var d=document.createElement("canvas"),f=b.mime||"image/jpeg";return e(a,d,b,c),d.toDataURL(f,b.quality||.8)}function d(a){var b=5241e3;if(!qq.ios())throw new qq.Error("Downsampled dimensions can only be reliably calculated for iOS!");return a.origHeight*a.origWidth>b?{newHeight:Math.round(Math.sqrt(b*(a.origHeight/a.origWidth))),newWidth:Math.round(Math.sqrt(b*(a.origWidth/a.origHeight)))}:void 0}function e(c,e,g,h){var i,j=c.naturalWidth,k=c.naturalHeight,l=g.width,m=g.height,n=e.getContext("2d");n.save(),qq.supportedFeatures.unlimitedScaledImageSize||(i=d({origWidth:l,origHeight:m}),i&&(qq.log(qq.format("Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h",l,m,i.newWidth,i.newHeight),"warn"),l=i.newWidth,m=i.newHeight)),f(e,l,m,g.orientation),qq.ios()?function(){a(c)&&(j/=2,k/=2);var d,e,f,g=1024,i=document.createElement("canvas"),o=h?b(c,j,k):1,p=Math.ceil(g*l/j),q=Math.ceil(g*m/k/o),r=0,s=0;for(i.width=i.height=g,d=i.getContext("2d");k>r;){for(e=0,f=0;j>e;)d.clearRect(0,0,g,g),d.drawImage(c,-e,-r),n.drawImage(i,0,0,g,g,f,s,p,q),e+=g,f+=p;r+=g,s+=q}n.restore(),i=d=null}():n.drawImage(c,0,0,l,m),e.qqImageRendered&&e.qqImageRendered()}function f(a,b,c,d){switch(d){case 5:case 6:case 7:case 8:a.width=c,a.height=b;break;default:a.width=b,a.height=c}var e=a.getContext("2d");switch(d){case 2:e.translate(b,0),e.scale(-1,1);break;case 3:e.translate(b,c),e.rotate(Math.PI);break;case 4:e.translate(0,c),e.scale(1,-1);break;case 5:e.rotate(.5*Math.PI),e.scale(1,-1);break;case 6:e.rotate(.5*Math.PI),e.translate(0,-c);break;case 7:e.rotate(.5*Math.PI),e.translate(b,-c),e.scale(-1,1);break;case 8:e.rotate(-.5*Math.PI),e.translate(-b,0)}}function g(a,b){var c=this;window.Blob&&a instanceof Blob&&function(){var b=new Image,d=window.URL&&window.URL.createObjectURL?window.URL:window.webkitURL&&window.webkitURL.createObjectURL?window.webkitURL:null;if(!d)throw Error("No createObjectURL function found to create blob url");b.src=d.createObjectURL(a),c.blob=a,a=b}(),a.naturalWidth||a.naturalHeight||(a.onload=function(){var a=c.imageLoadListeners;a&&(c.imageLoadListeners=null,setTimeout(function(){for(var b=0,c=a.length;c>b;b++)a[b]()},0))},a.onerror=b,this.imageLoadListeners=[]),this.srcImage=a}g.prototype.render=function(a,b){b=b||{};var d,f=this,g=this.srcImage.naturalWidth,h=this.srcImage.naturalHeight,i=b.width,j=b.height,k=b.maxWidth,l=b.maxHeight,m=!this.blob||"image/jpeg"===this.blob.type,n=a.tagName.toLowerCase();return this.imageLoadListeners?(this.imageLoadListeners.push(function(){f.render(a,b)}),void 0):(i&&!j?j=h*i/g<<0:j&&!i?i=g*j/h<<0:(i=g,j=h),k&&i>k&&(i=k,j=h*i/g<<0),l&&j>l&&(j=l,i=g*j/h<<0),d={width:i,height:j},qq.each(b,function(a,b){d[a]=b}),"img"===n?function(){var b=a.src;a.src=c(f.srcImage,d,m),b===a.src&&a.onload()}():"canvas"===n&&e(this.srcImage,a,d,m),"function"==typeof this.onrender&&this.onrender(a),void 0)},qq.MegaPixImage=g}(),qq.ImageGenerator=function(a){"use strict";function b(a){return"img"===a.tagName.toLowerCase()}function c(a){return"canvas"===a.tagName.toLowerCase()}function d(){return void 0!==(new Image).crossOrigin}function e(){var a=document.createElement("canvas");return a.getContext&&a.getContext("2d")}function f(a){var b=a.split("/"),c=b[b.length-1],d=qq.getExtension(c);switch(d=d&&d.toLowerCase()){case"jpeg":case"jpg":return"image/jpeg";case"png":return"image/png";case"bmp":return"image/bmp";case"gif":return"image/gif";case"tiff":case"tif":return"image/tiff"}}function g(a){var b,c,d,e=document.createElement("a");return e.href=a,b=e.protocol,d=e.port,c=e.hostname,b.toLowerCase()!==window.location.protocol.toLowerCase()?!0:c.toLowerCase()!==window.location.hostname.toLowerCase()?!0:d===window.location.port||qq.ie()?!1:!0}function h(b,c){b.onload=function(){b.onload=null,b.onerror=null,c.success(b)},b.onerror=function(){b.onload=null,b.onerror=null,a("Problem drawing thumbnail!","error"),c.failure(b,"Problem drawing thumbnail!")}}function i(a,b){a.qqImageRendered=function(){b.success(a)}}function j(d,e){var f=b(d)||c(d);return b(d)?h(d,e):c(d)?i(d,e):(e.failure(d),a(qq.format("Element container of type {} is not supported!",d.tagName),"error")),f}function k(b,c,d){var e=new qq.Promise,f=new qq.Identify(b,a),g=d.maxSize,h=null==d.orient?!0:d.orient,i=function(){c.onerror=null,c.onload=null,a("Could not render preview, file may be too large!","error"),e.failure(c,"Browser cannot render image!")};return f.isPreviewable().then(function(d){var f={parse:function(){return(new qq.Promise).success()}},k=h?new qq.Exif(b,a):f,l=new qq.MegaPixImage(b,i);j(c,e)&&k.parse().then(function(a){var b=a&&a.Orientation;l.render(c,{maxWidth:g,maxHeight:g,orientation:b,mime:d})},function(b){a(qq.format("EXIF data could not be parsed ({}).  Assuming orientation = 1.",b)),l.render(c,{maxWidth:g,maxHeight:g,mime:d})})},function(){a("Not previewable"),e.failure(c,"Not previewable")}),e}function l(a,b,c,d){var e=new Image,h=new qq.Promise;j(e,h),g(a)&&(e.crossOrigin="anonymous"),e.src=a,h.then(function(){j(b,c);var g=new qq.MegaPixImage(e);g.render(b,{maxWidth:d,maxHeight:d,mime:f(a)})},c.failure)}function m(a,b,c,d){j(b,c),qq(b).css({maxWidth:d+"px",maxHeight:d+"px"}),b.src=a}function n(a,f,h){var i=new qq.Promise,k=h.scale,n=k?h.maxSize:null;return k&&b(f)?e()?g(a)&&!d()?m(a,f,i,n):l(a,f,i,n):m(a,f,i,n):c(f)?l(a,f,i,n):j(f,i)&&(f.src=a),i}qq.extend(this,{generate:function(b,c,d){return qq.isString(b)?(a("Attempting to update thumbnail based on server response."),n(b,c,d||{})):(a("Attempting to draw client-side image preview."),k(b,c,d||{}))}})},qq.Exif=function(a,b){"use strict";function c(a){for(var b=0,c=0;a.length>0;)b+=parseInt(a.substring(0,2),16)*Math.pow(2,c),a=a.substring(2,a.length),c+=8;return b}function d(b,c){var e=b,f=c;return void 0===e&&(e=2,f=new qq.Promise),qq.readBlobToHex(a,e,4).then(function(a){var b,c=/^ffe([0-9])/.exec(a);c?"1"!==c[1]?(b=parseInt(a.slice(4,8),16),d(e+b+2,f)):f.success(e):f.failure("No EXIF header to be found!")}),f}function e(){var b=new qq.Promise;return qq.readBlobToHex(a,0,6).then(function(a){0!==a.indexOf("ffd8")?b.failure("Not a valid JPEG!"):d().then(function(a){b.success(a)},function(a){b.failure(a)})}),b}function f(b){var c=new qq.Promise;return qq.readBlobToHex(a,b+10,2).then(function(a){c.success("4949"===a)}),c}function g(b,d){var e=new qq.Promise;return qq.readBlobToHex(a,b+18,2).then(function(a){return d?e.success(c(a)):(e.success(parseInt(a,16)),void 0)}),e}function h(b,c){var d=b+20,e=12*c;return qq.readBlobToHex(a,d,e)}function i(a){for(var b=[],c=0;c+24<=a.length;)b.push(a.slice(c,c+24)),c+=24;return b}function j(a,b){var d=16,e=qq.extend([],k),f={};return qq.each(b,function(b,g){var h,i,j,k=g.slice(0,4),m=a?c(k):parseInt(k,16),n=e.indexOf(m);return n>=0&&(i=l[m].name,j=l[m].bytes,h=g.slice(d,d+2*j),f[i]=a?c(h):parseInt(h,16),e.splice(n,1)),0===e.length?!1:void 0}),f}var k=[274],l={274:{name:"Orientation",bytes:2}};qq.extend(this,{parse:function(){var c=new qq.Promise,d=function(a){b(qq.format("EXIF header parse failed: '{}' ",a)),c.failure(a)};return e().then(function(e){b(qq.format("Moving forward with EXIF header parsing for '{}'",void 0===a.name?"blob":a.name)),f(e).then(function(a){b(qq.format("EXIF Byte order is {} endian",a?"little":"big")),g(e,a).then(function(f){b(qq.format("Found {} APP1 directory entries",f)),h(e,f).then(function(d){var e=i(d),f=j(a,e);b("Successfully parsed some EXIF tags"),c.success(f)},d)},d)},d)},d),c}})},qq.Identify=function(a,b){"use strict";function c(a,b){var c=!1,d=[].concat(a);return qq.each(d,function(a,d){return 0===b.indexOf(d)?(c=!0,!1):void 0}),c}qq.extend(this,{isPreviewable:function(){var d=this,e=new qq.Promise,f=!1,g=void 0===a.name?"blob":a.name;return b(qq.format("Attempting to determine if {} can be rendered in this browser",g)),b("First pass: check type attribute of blob object."),this.isPreviewableSync()?(b("Second pass: check for magic bytes in file header."),qq.readBlobToHex(a,0,4).then(function(a){qq.each(d.PREVIEWABLE_MIME_TYPES,function(b,d){return c(d,a)?(("image/tiff"!==b||qq.supportedFeatures.tiffPreviews)&&(f=!0,e.success(b)),!1):void 0}),b(qq.format("'{}' is {} able to be rendered in this browser",g,f?"":"NOT")),f||e.failure()},function(){b("Error reading file w/ name '"+g+"'.  Not able to be rendered in this browser."),e.failure()})):e.failure(),e},isPreviewableSync:function(){var c=a.type,d=qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES),c)>=0,e=!1,f=void 0===a.name?"blob":a.name;return d&&(e="image/tiff"===c?qq.supportedFeatures.tiffPreviews:!0),!e&&b(f+" is not previewable in this browser per the blob's type attr"),e}})},qq.Identify.prototype.PREVIEWABLE_MIME_TYPES={"image/jpeg":"ffd8ff","image/gif":"474946","image/png":"89504e","image/bmp":"424d","image/tiff":["49492a00","4d4d002a"]},qq.ImageValidation=function(a,b){"use strict";function c(a){var b=!1;return qq.each(a,function(a,c){return c>0?(b=!0,!1):void 0}),b}function d(){var c=new qq.Promise;return new qq.Identify(a,b).isPreviewable().then(function(){var d=new Image,e=window.URL&&window.URL.createObjectURL?window.URL:window.webkitURL&&window.webkitURL.createObjectURL?window.webkitURL:null;e?(d.onerror=function(){b("Cannot determine dimensions for image.  May be too large.","error"),c.failure()},d.onload=function(){c.success({width:this.width,height:this.height})},d.src=e.createObjectURL(a)):(b("No createObjectURL function available to generate image URL!","error"),c.failure())},c.failure),c}function e(a,b){var c;return qq.each(a,function(a,d){if(d>0){var e=/(max|min)(Width|Height)/.exec(a),f=e[2].charAt(0).toLowerCase()+e[2].slice(1),g=b[f];switch(e[1]){case"min":if(d>g)return c=a,!1;break;case"max":if(g>d)return c=a,!1}}}),c}this.validate=function(a){var f=new qq.Promise;return b("Attempting to validate image."),c(a)?d().then(function(b){var c=e(a,b);c?f.failure(c):f.success()},f.success):f.success(),f}},qq.Session=function(a){"use strict";function b(a){return qq.isArray(a)?!0:(d.log("Session response is not an array.","error"),void 0)}function c(a,c,e,f){var g=!1;c=c&&b(a),c&&qq.each(a,function(a,b){if(null==b.uuid)g=!0,d.log(qq.format("Session response item {} did not include a valid UUID - ignoring.",a),"error");else if(null==b.name)g=!0,d.log(qq.format("Session response item {} did not include a valid name - ignoring.",a),"error");else try{return d.addFileRecord(b),!0}catch(c){g=!0,d.log(c.message,"error")}return!1}),f[c&&!g?"success":"failure"](a,e)}var d={endpoint:null,params:{},customHeaders:{},cors:{},addFileRecord:function(){},log:function(){}};qq.extend(d,a,!0),this.refresh=function(){var a=new qq.Promise,b=function(b,d,e){c(b,d,e,a)},e=qq.extend({},d),f=new qq.SessionAjaxRequester(qq.extend(e,{onComplete:b}));return f.queryServer(),a}},qq.SessionAjaxRequester=function(a){"use strict";function b(a,b,c){var e=null;if(null!=b.responseText)try{e=qq.parseJson(b.responseText)}catch(f){d.log("Problem parsing session response: "+f.message,"error"),c=!0}d.onComplete(e,!c,b)}var c,d={endpoint:null,customHeaders:{},params:{},cors:{expected:!1,sendCredentials:!1},onComplete:function(){},log:function(){}};qq.extend(d,a),c=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",validMethods:["GET"],method:"GET",endpointStore:{get:function(){return d.endpoint}},customHeaders:d.customHeaders,log:d.log,onComplete:b,cors:d.cors})),qq.extend(this,{queryServer:function(){var a=qq.extend({},d.params);d.log("Session query request."),c.initTransport("sessionRefresh").withParams(a).withCacheBuster().send()}})},qq.FormSupport=function(a,b,c){"use strict";function d(a){a.getAttribute("action")&&(h.newEndpoint=a.getAttribute("action"))}function e(a,b){return!a.checkValidity||a.checkValidity()?!0:(c("Form did not pass validation checks - will not upload.","error"),b(),void 0)}function f(a){var c=a.submit;qq(a).attach("submit",function(d){d=d||window.event,d.preventDefault?d.preventDefault():d.returnValue=!1,e(a,c)&&b()}),a.submit=function(){e(a,c)&&b()}}function g(a){return a&&(qq.isString(a)&&(a=document.getElementById(a)),a&&(c("Attaching to form element."),d(a),i&&f(a))),a}var h=this,i=a.interceptSubmit,j=a.element,k=a.autoUpload;qq.extend(this,{newEndpoint:null,newAutoUpload:k,attachedToForm:!1,getFormInputsAsObject:function(){return null==j?null:h._form2Obj(j)}}),j=g(j),this.attachedToForm=!!j},qq.extend(qq.FormSupport.prototype,{_form2Obj:function(a){"use strict";var b={},c=function(a){var b=["button","image","reset","submit"];return qq.indexOf(b,a.toLowerCase())<0},d=function(a){return qq.indexOf(["checkbox","radio"],a.toLowerCase())>=0},e=function(a){return d(a.type)&&!a.checked?!0:a.disabled&&"hidden"!==a.type.toLowerCase()},f=function(a){var b=null;return qq.each(qq(a).children(),function(a,c){return"option"===c.tagName.toLowerCase()&&c.selected?(b=c.value,!1):void 0}),b};return qq.each(a.elements,function(a,d){if(!qq.isInput(d,!0)&&"textarea"!==d.tagName.toLowerCase()||!c(d.type)||e(d)){if("select"===d.tagName.toLowerCase()&&!e(d)){var g=f(d);null!==g&&(b[d.name]=g)}}else b[d.name]=d.value}),b}}),qq.Scaler=function(a,b){"use strict";var c=a.sendOriginal,d=a.orient,e=a.defaultType,f=a.defaultQuality/100,g=a.failureText,h=a.includeExif,i=this._getSortedSizes(a.sizes);qq.extend(this,{enabled:qq.supportedFeatures.scaling&&i.length>0,getFileRecords:function(a,j,k){var l=this,m=[],n=k.blob?k.blob:k,o=new qq.Identify(n,b);return o.isPreviewableSync()?(qq.each(i,function(a,c){var i=l._determineOutputType({defaultType:e,requestedType:c.type,refType:n.type});m.push({uuid:qq.getUniqueId(),name:l._getName(j,{name:c.name,type:i,refType:n.type}),blob:new qq.BlobProxy(n,qq.bind(l._generateScaledImage,l,{maxSize:c.maxSize,orient:d,type:i,quality:f,failedText:g,includeExif:h,log:b}))})}),c&&m.push({uuid:a,name:j,blob:n})):m.push({uuid:a,name:j,blob:n}),m},handleNewFile:function(a,b,c,d,e,f,g,h){var i=this,j=(a.qqButtonId||a.blob&&a.blob.qqButtonId,[]),k=null,l=h.addFileToHandler,m=h.uploadData,n=h.paramsStore,o=qq.getUniqueId();qq.each(i.getFileRecords(c,b,a),function(b,c){var g,h=a,i=d;c.blob instanceof qq.BlobProxy&&(h=c.blob,i=-1),g=m.addFile({uuid:c.uuid,name:c.name,size:i,batchId:f,proxyGroupId:o}),c.blob instanceof qq.BlobProxy?j.push(g):k=g,l(g,h),e.push({id:g,file:h})}),null!==k&&(qq.each(j,function(a,b){var c={qqparentuuid:m.retrieve({id:k}).uuid,qqparentsize:m.retrieve({id:k}).size};c[g]=m.retrieve({id:b}).uuid,m.setParentId(b,k),n.addReadOnly(b,c)}),j.length&&function(){var a={};a[g]=m.retrieve({id:k}).uuid,n.addReadOnly(k,a)}())}})},qq.extend(qq.Scaler.prototype,{scaleImage:function(a,b,c){"use strict";if(!qq.supportedFeatures.scaling)throw new qq.Error("Scaling is not supported in this browser!");var d=new qq.Promise,e=c.log,f=c.getFile(a),g=c.uploadData.retrieve({id:a}),h=g&&g.name,i=g&&g.uuid,j={sendOriginal:!1,orient:b.orient,defaultType:b.type||null,defaultQuality:b.quality,failedToScaleText:"Unable to scale",sizes:[{name:"",maxSize:b.maxSize}]},k=new qq.Scaler(j,e);return qq.Scaler&&qq.supportedFeatures.imagePreviews&&f?qq.bind(function(){var b=k.getFileRecords(i,h,f)[0];b&&b.blob instanceof qq.BlobProxy?b.blob.create().then(d.success,d.failure):(e(a+" is not a scalable image!","error"),d.failure())},this)():(d.failure(),e("Could not generate requested scaled image for "+a+".  "+"Scaling is either not possible in this browser, or the file could not be located.","error")),d},_determineOutputType:function(a){"use strict";var b=a.requestedType,c=a.defaultType,d=a.refType;return c||b?b?qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES),b)>=0?"image/tiff"===b?qq.supportedFeatures.tiffPreviews?b:c:b:c:c:"image/jpeg"!==d?"image/png":d},_getName:function(a,b){"use strict";var c=a.lastIndexOf("."),d=b.type||"image/png",e=b.refType,f="",g=qq.getExtension(a),h="";return b.name&&b.name.trim().length&&(h=" ("+b.name+")"),c>=0?(f=a.substr(0,c),e!==d&&(g=d.split("/")[1]),f+=h+"."+g):f=a+h,f},_getSortedSizes:function(a){"use strict";return a=qq.extend([],a),a.sort(function(a,b){return a.maxSize>b.maxSize?1:a.maxSize<b.maxSize?-1:0})},_generateScaledImage:function(a,b){"use strict";var c=this,d=a.log,e=a.maxSize,f=a.orient,g=a.type,h=a.quality,i=a.failedText,j=a.includeExif&&"image/jpeg"===b.type&&"image/jpeg"===g,k=new qq.Promise,l=new qq.ImageGenerator(d),m=document.createElement("canvas");return d("Attempting to generate scaled version for "+b.name),l.generate(b,m,{maxSize:e,orient:f}).then(function(){var a=m.toDataURL(g,h),e=function(){d("Success generating scaled version for "+b.name);var c=qq.dataUriToBlob(a);k.success(c)};j?c._insertExifHeader(b,a,d).then(function(b){a=b,e()},function(){d("Problem inserting EXIF header into scaled image.  Using scaled image w/out EXIF data.","error"),e()}):e()},function(){d("Failed attempt to generate scaled version for "+b.name,"error"),k.failure(i)}),k},_insertExifHeader:function(a,b,c){"use strict";var d=new FileReader,e=new qq.Promise,f="";return d.onload=function(){f=d.result,e.success(ExifRestorer.restore(f,b))},d.onerror=function(){c("Problem reading "+a.name+" during attempt to transfer EXIF data to scaled version.","error"),e.failure()},d.readAsDataURL(a),e},_dataUriToBlob:function(a){"use strict";var b,c,d,e;return b=a.split(",")[0].indexOf("base64")>=0?atob(a.split(",")[1]):decodeURI(a.split(",")[1]),c=a.split(",")[0].split(":")[1].split(";")[0],d=new ArrayBuffer(b.length),e=new Uint8Array(d),qq.each(b,function(a,b){e[a]=b.charCodeAt(0)}),this._createBlob(d,c)},_createBlob:function(a,b){"use strict";var c=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,d=c&&new c;return d?(d.append(a),d.getBlob(b)):new Blob([a],{type:b})}});var ExifRestorer=function(){var a={};return a.KEY_STR="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",a.encode64=function(a){var b,c,d,e,f,g="",h="",i="",j=0;
do b=a[j++],c=a[j++],h=a[j++],d=b>>2,e=(3&b)<<4|c>>4,f=(15&c)<<2|h>>6,i=63&h,isNaN(c)?f=i=64:isNaN(h)&&(i=64),g=g+this.KEY_STR.charAt(d)+this.KEY_STR.charAt(e)+this.KEY_STR.charAt(f)+this.KEY_STR.charAt(i),b=c=h="",d=e=f=i="";while(j<a.length);return g},a.restore=function(a,b){var c="data:image/jpeg;base64,";if(!a.match(c))return b;var d=this.decode64(a.replace(c,"")),e=this.slice2Segments(d),f=this.exifManipulation(b,e);return c+this.encode64(f)},a.exifManipulation=function(a,b){var c=this.getExifArray(b),d=this.insertExif(a,c),e=new Uint8Array(d);return e},a.getExifArray=function(a){for(var b,c=0;c<a.length;c++)if(b=a[c],255==b[0]&225==b[1])return b;return[]},a.insertExif=function(a,b){var c=a.replace("data:image/jpeg;base64,",""),d=this.decode64(c),e=d.indexOf(255,3),f=d.slice(0,e),g=d.slice(e),h=f;return h=h.concat(b),h=h.concat(g)},a.slice2Segments=function(a){for(var b=0,c=[];;){if(255==a[b]&218==a[b+1])break;if(255==a[b]&216==a[b+1])b+=2;else{var d=256*a[b+2]+a[b+3],e=b+d+2,f=a.slice(b,e);c.push(f),b=e}if(b>a.length)break}return c},a.decode64=function(a){var b,c,d,e,f,g="",h="",i=0,j=[],k=/[^A-Za-z0-9\+\/\=]/g;if(k.exec(a))throw new Error("There were invalid base64 characters in the input text.  Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='");a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");do d=this.KEY_STR.indexOf(a.charAt(i++)),e=this.KEY_STR.indexOf(a.charAt(i++)),f=this.KEY_STR.indexOf(a.charAt(i++)),h=this.KEY_STR.indexOf(a.charAt(i++)),b=d<<2|e>>4,c=(15&e)<<4|f>>2,g=(3&f)<<6|h,j.push(b),64!=f&&j.push(c),64!=h&&j.push(g),b=c=g="",d=e=f=h="";while(i<a.length);return j},a}();qq.TotalProgress=function(a,b){"use strict";var c={},d=0,e=0,f=-1,g=-1,h=function(b,c){(b!==f||c!==g)&&a(b,c),f=b,g=c},i=function(a,b){var c=!0;return qq.each(a,function(a,d){return qq.indexOf(b,d)>=0?(c=!1,!1):void 0}),c},j=function(a){m(a,-1,-1),delete c[a]},k=function(a,b,c){(0===b.length||i(b,c))&&(h(e,e),this.reset())},l=function(a){var d=b(a);d>0&&(m(a,0,d),c[a]={loaded:0,total:d})},m=function(a,b,f){var g=c[a]?c[a].loaded:0,i=c[a]?c[a].total:0;-1===b&&-1===f?(d-=g,e-=i):(b&&(d+=b-g),f&&(e+=f-i)),h(d,e)};qq.extend(this,{onAllComplete:k,onStatusChange:function(a,b,c){c===qq.status.CANCELED||c===qq.status.REJECTED?j(a):c===qq.status.SUBMITTING&&l(a)},onIndividualProgress:function(a,b,d){m(a,b,d),c[a]={loaded:b,total:d}},onNewSize:function(a){l(a)},reset:function(){c={},d=0,e=0}})},qq.UiEventHandler=function(a,b){"use strict";function c(a){d.attach(a,e.eventType,function(a){a=a||window.event;var b=a.target||a.srcElement;e.onHandled(b,a)})}var d=new qq.DisposeSupport,e={eventType:"click",attachTo:null,onHandled:function(){}};qq.extend(this,{addHandler:function(a){c(a)},dispose:function(){d.dispose()}}),qq.extend(b,{getFileIdFromItem:function(a){return a.qqFileId},getDisposeSupport:function(){return d}}),qq.extend(e,a),e.attachTo&&c(e.attachTo)},qq.FileButtonsClickHandler=function(a){"use strict";function b(a,b){qq.each(e,function(c,e){var f,g=c.charAt(0).toUpperCase()+c.slice(1);return d.templating["is"+g](a)?(f=d.templating.getFileId(a),qq.preventDefault(b),d.log(qq.format("Detected valid file button click event on file '{}', ID: {}.",d.onGetName(f),f)),e(f),!1):void 0})}var c={},d={templating:null,log:function(){},onDeleteFile:function(){},onCancel:function(){},onRetry:function(){},onPause:function(){},onContinue:function(){},onGetName:function(){}},e={cancel:function(a){d.onCancel(a)},retry:function(a){d.onRetry(a)},deleteButton:function(a){d.onDeleteFile(a)},pause:function(a){d.onPause(a)},continueButton:function(a){d.onContinue(a)}};qq.extend(d,a),d.eventType="click",d.onHandled=b,d.attachTo=d.templating.getFileList(),qq.extend(this,new qq.UiEventHandler(d,c))},qq.FilenameClickHandler=function(a){"use strict";function b(a,b){if(d.templating.isFileName(a)||d.templating.isEditIcon(a)){var e=d.templating.getFileId(a),f=d.onGetUploadStatus(e);f===qq.status.SUBMITTED&&(d.log(qq.format("Detected valid filename click event on file '{}', ID: {}.",d.onGetName(e),e)),qq.preventDefault(b),c.handleFilenameEdit(e,a,!0))}}var c={},d={templating:null,log:function(){},classes:{file:"qq-upload-file",editNameIcon:"qq-edit-filename-icon"},onGetUploadStatus:function(){},onGetName:function(){}};qq.extend(d,a),d.eventType="click",d.onHandled=b,qq.extend(this,new qq.FilenameEditHandler(d,c))},qq.FilenameInputFocusInHandler=function(a,b){"use strict";function c(a){if(d.templating.isEditInput(a)){var c=d.templating.getFileId(a),e=d.onGetUploadStatus(c);e===qq.status.SUBMITTED&&(d.log(qq.format("Detected valid filename input focus event on file '{}', ID: {}.",d.onGetName(c),c)),b.handleFilenameEdit(c,a))}}var d={templating:null,onGetUploadStatus:function(){},log:function(){}};b||(b={}),d.eventType="focusin",d.onHandled=c,qq.extend(d,a),qq.extend(this,new qq.FilenameEditHandler(d,b))},qq.FilenameInputFocusHandler=function(a){"use strict";a.eventType="focus",a.attachTo=null,qq.extend(this,new qq.FilenameInputFocusInHandler(a,{}))},qq.FilenameEditHandler=function(a,b){"use strict";function c(a){var b=h.onGetName(a),c=b.lastIndexOf(".");return c>0&&(b=b.substr(0,c)),b}function d(a){var b=h.onGetName(a);return qq.getExtension(b)}function e(a,b){var c,e=a.value;void 0!==e&&qq.trimStr(e).length>0&&(c=d(b),void 0!==c&&(e=e+"."+c),h.onSetName(b,e)),h.onEditingStatusChange(b,!1)}function f(a,c){b.getDisposeSupport().attach(a,"blur",function(){e(a,c)})}function g(a,c){b.getDisposeSupport().attach(a,"keyup",function(b){var d=b.keyCode||b.which;13===d&&e(a,c)})}var h={templating:null,log:function(){},onGetUploadStatus:function(){},onGetName:function(){},onSetName:function(){},onEditingStatusChange:function(){}};qq.extend(h,a),h.attachTo=h.templating.getFileList(),qq.extend(this,new qq.UiEventHandler(h,b)),qq.extend(b,{handleFilenameEdit:function(a,b,d){var e=h.templating.getEditInput(a);h.onEditingStatusChange(a,!0),e.value=c(a),d&&e.focus(),f(e,a),g(e,a)}})},function(a){"use strict";function b(a){var b=h(a||{}),d=c(b);return e(d),g(b,d),l}function c(a){var b=f("uploaderType"),c=f("endpointType");return b?(b=b.charAt(0).toUpperCase()+b.slice(1).toLowerCase(),c?new qq[c]["FineUploader"+b](a):new qq["FineUploader"+b](a)):c?new qq[c].FineUploader(a):new qq.FineUploader(a)}function d(a,b){var c=l.data("fineuploader");return b?(void 0===c&&(c={}),c[a]=b,l.data("fineuploader",c),void 0):void 0===c?null:c[a]}function e(a){return d("uploader",a)}function f(a,b){return d(a,b)}function g(b,c){var d=b.callbacks={};a.each(c._options.callbacks,function(b,c){var e,f;e=/^on(\w+)/.exec(b)[1],e=e.substring(0,1).toLowerCase()+e.substring(1),f=l,d[b]=function(){var b,d,g=Array.prototype.slice.call(arguments),h=[];a.each(g,function(a,b){h.push(k(b))}),b=c.apply(this,g);try{d=f.triggerHandler(e,h)}catch(i){qq.log("Caught error in Fine Uploader jQuery event handler: "+i.message,"error")}return null!=b?b:d}}),c._options.callbacks=d}function h(b,c){var d,e;return d=void 0===c?"basic"!==b.uploaderType?{element:l[0]}:{}:c,a.each(b,function(b,c){a.inArray(b,m)>=0?f(b,c):c instanceof a?d[b]=c[0]:a.isPlainObject(c)?(d[b]={},h(c,d[b])):a.isArray(c)?(e=[],a.each(c,function(b,c){var d={};c instanceof a?a.merge(e,c):a.isPlainObject(c)?(h(c,d),e.push(d)):e.push(c)}),d[b]=e):d[b]=c}),void 0===c?d:void 0}function i(b){return"string"===a.type(b)&&!b.match(/^_/)&&void 0!==e()[b]}function j(a){var b,c=[],d=Array.prototype.slice.call(arguments,1);return h(d,c),b=e()[a].apply(e(),c),k(b)}function k(b){var c=b;return null==b||"object"!=typeof b||1!==b.nodeType&&9!==b.nodeType||!b.cloneNode||(c=a(b)),c}var l,m=["uploaderType","endpointType"];a.fn.fineUploader=function(c){var d=this,f=arguments,g=[];return this.each(function(h,k){if(l=a(k),e()&&i(c)){if(g.push(j.apply(d,f)),1===d.length)return!1}else"object"!=typeof c&&c?a.error("Method "+c+" does not exist on jQuery.fineUploader"):b.apply(d,f)}),1===g.length?g[0]:g.length>1?g:this}}(jQuery),function(a){"use strict";function b(a){a||(a={}),a.dropZoneElements=[i];var b=f(a);return e(b),d(new qq.DragAndDrop(b)),i}function c(a,b){var c=i.data(j);return b?(void 0===c&&(c={}),c[a]=b,i.data(j,c),void 0):void 0===c?null:c[a]}function d(a){return c("dndInstance",a)}function e(b){var c=b.callbacks={};a.each(new qq.DragAndDrop.callbacks,function(a){var b,d=a;b=i,c[a]=function(){var a=Array.prototype.slice.call(arguments),c=b.triggerHandler(d,a);return c}})}function f(b,c){var d,e;return d=void 0===c?{}:c,a.each(b,function(b,c){c instanceof a?d[b]=c[0]:a.isPlainObject(c)?(d[b]={},f(c,d[b])):a.isArray(c)?(e=[],a.each(c,function(b,c){c instanceof a?a.merge(e,c):e.push(c)}),d[b]=e):d[b]=c}),void 0===c?d:void 0}function g(b){return"string"===a.type(b)&&"dispose"===b&&void 0!==d()[b]}function h(a){var b=[],c=Array.prototype.slice.call(arguments,1);return f(c,b),d()[a].apply(d(),b)}var i,j="fineUploaderDnd";a.fn.fineUploaderDnd=function(c){var e=this,f=arguments,j=[];return this.each(function(k,l){if(i=a(l),d()&&g(c)){if(j.push(h.apply(e,f)),1===e.length)return!1}else"object"!=typeof c&&c?a.error("Method "+c+" does not exist in Fine Uploader's DnD module."):b.apply(e,f)}),1===j.length?j[0]:j.length>1?j:this}}(jQuery);
/*! 2015-04-21 */
;
/**
 * TableDnD plug-in for JQuery, allows you to drag and drop table rows
 * You can set up various options to control how the system will work
 * Copyright (c) Denis Howlett <denish@isocra.com>
 * Licensed like jQuery, see http://docs.jquery.com/License.
 *
 * Configuration options:
 *
 * onDragStyle
 *     This is the style that is assigned to the row during drag. There are limitations to the styles that can be
 *     associated with a row (such as you can't assign a border--well you can, but it won't be
 *     displayed). (So instead consider using onDragClass.) The CSS style to apply is specified as
 *     a map (as used in the jQuery css(...) function).
 * onDropStyle
 *     This is the style that is assigned to the row when it is dropped. As for onDragStyle, there are limitations
 *     to what you can do. Also this replaces the original style, so again consider using onDragClass which
 *     is simply added and then removed on drop.
 * onDragClass
 *     This class is added for the duration of the drag and then removed when the row is dropped. It is more
 *     flexible than using onDragStyle since it can be inherited by the row cells and other content. The default
 *     is class is tDnD_whileDrag. So to use the default, simply customise this CSS class in your
 *     stylesheet.
 * onDrop
 *     Pass a function that will be called when the row is dropped. The function takes 2 parameters: the table
 *     and the row that was dropped. You can work out the new order of the rows by using
 *     table.rows.
 * onDragStart
 *     Pass a function that will be called when the user starts dragging. The function takes 2 parameters: the
 *     table and the row which the user has started to drag.
 * onDragStop
 *     Pass a function that will be called when the user stops dragging regardless of if the rows have been
 *     rearranged. The function takes 2 parameters: the table and the row which the user was dragging.
 * onAllowDrop
 *     Pass a function that will be called as a row is over another row. If the function returns true, allow
 *     dropping on that row, otherwise not. The function takes 2 parameters: the dragged row and the row under
 *     the cursor. It returns a boolean: true allows the drop, false doesn't allow it.
 * scrollAmount
 *     This is the number of pixels to scroll if the user moves the mouse cursor to the top or bottom of the
 *     window. The page should automatically scroll up or down as appropriate (tested in IE6, IE7, Safari, FF2,
 *     FF3 beta
 * dragHandle
 *     This is a jQuery mach string for one or more cells in each row that is draggable. If you
 *     specify this, then you are responsible for setting cursor: move in the CSS and only these cells
 *     will have the drag behaviour. If you do not specify a dragHandle, then you get the old behaviour where
 *     the whole row is draggable.
 *
 * Other ways to control behaviour:
 *
 * Add class="nodrop" to any rows for which you don't want to allow dropping, and class="nodrag" to any rows
 * that you don't want to be draggable.
 *
 * Inside the onDrop method you can also call $.tableDnD.serialize() this returns a string of the form
 * <tableID>[]=<rowID1>&<tableID>[]=<rowID2> so that you can send this back to the server. The table must have
 * an ID as must all the rows.
 *
 * Other methods:
 *
 * $("...").tableDnDUpdate()
 * Will update all the matching tables, that is it will reapply the mousedown method to the rows (or handle cells).
 * This is useful if you have updated the table rows using Ajax and you want to make the table draggable again.
 * The table maintains the original configuration (so you don't have to specify it again).
 *
 * $("...").tableDnDSerialize()
 * Will serialize and return the serialized string as above, but for each of the matching tables--so it can be
 * called from anywhere and isn't dependent on the currentTable being set up correctly before calling
 *
 * Known problems:
 * - Auto-scoll has some problems with IE7  (it scrolls even when it shouldn't), work-around: set scrollAmount to 0
 *
 * Version 0.2: 2008-02-20 First public version
 * Version 0.3: 2008-02-07 Added onDragStart option
 *                         Made the scroll amount configurable (default is 5 as before)
 * Version 0.4: 2008-03-15 Changed the noDrag/noDrop attributes to nodrag/nodrop classes
 *                         Added onAllowDrop to control dropping
 *                         Fixed a bug which meant that you couldn't set the scroll amount in both directions
 *                         Added serialize method
 * Version 0.5: 2008-05-16 Changed so that if you specify a dragHandle class it doesn't make the whole row
 *                         draggable
 *                         Improved the serialize method to use a default (and settable) regular expression.
 *                         Added tableDnDupate() and tableDnDSerialize() to be called when you are outside the table
 * Version 0.6: 2011-12-02 Added support for touch devices
 * Version 0.7  2012-04-09 Now works with jQuery 1.7 and supports touch, tidied up tabs and spaces
 */
!function ($, window, document, undefined) {
    // Determine if this is a touch device
    var hasTouch = 'ontouchstart' in document.documentElement,
        startEvent = 'touchstart mousedown',
        moveEvent = 'touchmove mousemove',
        endEvent = 'touchend mouseup';

    // If we're on a touch device, then wire up the events
    // see http://stackoverflow.com/a/8456194/1316086
    hasTouch
        && $.each("touchstart touchmove touchend".split(" "), function (i, name) {
            $.event.fixHooks[name] = $.event.mouseHooks;
        });


    $(document).ready(function () {
        function parseStyle(css) {
            var objMap = {},
                parts = css.match(/([^;:]+)/g) || [];
            while (parts.length)
                objMap[parts.shift()] = parts.shift().trim();

            return objMap;
        }
        $('table').each(function () {
            if ($(this).data('table') == 'dnd') {

                $(this).tableDnD({
                    onDragStyle: $(this).data('ondragstyle') && parseStyle($(this).data('ondragstyle')) || null,
                    onDropStyle: $(this).data('ondropstyle') && parseStyle($(this).data('ondropstyle')) || null,
                    onDragClass: $(this).data('ondragclass') == undefined && "tDnD_whileDrag" || $(this).data('ondragclass'),
                    onDrop: $(this).data('ondrop') && new Function('table', 'row', $(this).data('ondrop')), // 'return eval("'+$(this).data('ondrop')+'");') || null,
                    onDragStart: $(this).data('ondragstart') && new Function('table', 'row', $(this).data('ondragstart')), // 'return eval("'+$(this).data('ondragstart')+'");') || null,
                    onDragStop: $(this).data('ondragstop') && new Function('table', 'row', $(this).data('ondragstop')),
                    scrollAmount: $(this).data('scrollamount') || 5,
                    sensitivity: $(this).data('sensitivity') || 10,
                    hierarchyLevel: $(this).data('hierarchylevel') || 0,
                    indentArtifact: $(this).data('indentartifact') || '<div class="indent">&nbsp;</div>',
                    autoWidthAdjust: $(this).data('autowidthadjust') || true,
                    autoCleanRelations: $(this).data('autocleanrelations') || true,
                    jsonPretifySeparator: $(this).data('jsonpretifyseparator') || '\t',
                    serializeRegexp: $(this).data('serializeregexp') && new RegExp($(this).data('serializeregexp')) || /[^\-]*$/,
                    serializeParamName: $(this).data('serializeparamname') || false,
                    dragHandle: $(this).data('draghandle') || null
                });
            }


        });
    });

    jQuery.tableDnD = {
        /** Keep hold of the current table being dragged */
        currentTable: null,
        /** Keep hold of the current drag object if any */
        dragObject: null,
        /** The current mouse offset */
        mouseOffset: null,
        /** Remember the old value of X and Y so that we don't do too much processing */
        oldX: 0,
        oldY: 0,

        /** Actually build the structure */
        build: function (options) {
            // Set up the defaults if any

            this.each(function () {
                // This is bound to each matching table, set up the defaults and override with user options
                this.tableDnDConfig = $.extend({
                    onDragStyle: null,
                    onDropStyle: null,
                    // Add in the default class for whileDragging
                    onDragClass: "tDnD_whileDrag",
                    onDrop: null,
                    onDragStart: null,
                    onDragStop: null,
                    scrollAmount: 5,
                    /** Sensitivity setting will throttle the trigger rate for movement detection */
                    sensitivity: 10,
                    /** Hierarchy level to support parent child. 0 switches this functionality off */
                    hierarchyLevel: 0,
                    /** The html artifact to prepend the first cell with as indentation */
                    indentArtifact: '<div class="indent">&nbsp;</div>',
                    /** Automatically adjust width of first cell */
                    autoWidthAdjust: true,
                    /** Automatic clean-up to ensure relationship integrity */
                    autoCleanRelations: true,
                    /** Specify a number (4) as number of spaces or any indent string for JSON.stringify */
                    jsonPretifySeparator: '\t',
                    /** The regular expression to use to trim row IDs */
                    serializeRegexp: /[^\-]*$/,
                    /** If you want to specify another parameter name instead of the table ID */
                    serializeParamName: false,
                    /** If you give the name of a class here, then only Cells with this class will be draggable */
                    dragHandle: null
                }, options || {});

                // Now make the rows draggable
                $.tableDnD.makeDraggable(this);
                // Prepare hierarchy support
                this.tableDnDConfig.hierarchyLevel
                    && $.tableDnD.makeIndented(this);
            });

            // Don't break the chain
            return this;
        },
        makeIndented: function (table) {
            var config = table.tableDnDConfig,
                rows = table.rows,
                firstCell = $(rows).first().find('td:first')[0],
                indentLevel = 0,
                cellWidth = 0,
                longestCell,
                tableStyle;

            if ($(table).hasClass('indtd'))
                return null;

            tableStyle = $(table).addClass('indtd').attr('style');
            $(table).css({ whiteSpace: "nowrap" });

            for (var w = 0; w < rows.length; w++) {
                if (cellWidth < $(rows[w]).find('td:first').text().length) {
                    cellWidth = $(rows[w]).find('td:first').text().length;
                    longestCell = w;
                }
            }
            $(firstCell).css({ width: 'auto' });
            for (w = 0; w < config.hierarchyLevel; w++)
                $(rows[longestCell]).find('td:first').prepend(config.indentArtifact);
            firstCell && $(firstCell).css({ width: firstCell.offsetWidth });
            tableStyle && $(table).css(tableStyle);

            for (w = 0; w < config.hierarchyLevel; w++)
                $(rows[longestCell]).find('td:first').children(':first').remove();

            config.hierarchyLevel
                && $(rows).each(function () {
                    indentLevel = $(this).data('level') || 0;
                    indentLevel <= config.hierarchyLevel
                        && $(this).data('level', indentLevel)
                        || $(this).data('level', 0);
                    for (var i = 0; i < $(this).data('level') ; i++)
                        $(this).find('td:first').prepend(config.indentArtifact);
                });

            return this;
        },
        /** This function makes all the rows on the table draggable apart from those marked as "NoDrag" */
        makeDraggable: function (table) {
            var config = table.tableDnDConfig;

            config.dragHandle
            // We only need to add the event to the specified cells
                && $(config.dragHandle, table).each(function () {
                    // The cell is bound to "this"
                    $(this).bind(startEvent, function (e) {
                        $.tableDnD.initialiseDrag($(this).parents('tr')[0], table, this, e, config);
                        return false;
                    });
                })
            // For backwards compatibility, we add the event to the whole row
            // get all the rows as a wrapped set
                || $(table.rows).each(function () {
                    // Iterate through each row, the row is bound to "this"
                    if (!$(this).hasClass("nodrag")) {
                        $(this).bind(startEvent, function (e) {
                            if (e.target.tagName == "TD") {
                                $.tableDnD.initialiseDrag(this, table, this, e, config);
                                return false;
                            }
                        }).css("cursor", "move"); // Store the tableDnD object
                    } else {
                        $(this).css("cursor", ""); // Remove the cursor if we don't have the nodrag class
                    }
                });
        },
        currentOrder: function () {
            var rows = this.currentTable.rows;
            return $.map(rows, function (val) {
                return ($(val).data('level') + val.id).replace(/\s/g, '');
            }).join('');
        },
        initialiseDrag: function (dragObject, table, target, e, config) {
            this.dragObject = dragObject;
            this.currentTable = table;
            this.mouseOffset = this.getMouseOffset(target, e);
            this.originalOrder = this.currentOrder();

            // Now we need to capture the mouse up and mouse move event
            // We can use bind so that we don't interfere with other event handlers
            $(document)
                .bind(moveEvent, this.mousemove)
                .bind(endEvent, this.mouseup);

            // Call the onDragStart method if there is one
            config.onDragStart
                && config.onDragStart(table, target);
        },
        updateTables: function () {
            this.each(function () {
                // this is now bound to each matching table
                if (this.tableDnDConfig)
                    $.tableDnD.makeDraggable(this);
            });
        },
        /** Get the mouse coordinates from the event (allowing for browser differences) */
        mouseCoords: function (e) {
            if (e.originalEvent.changedTouches)
                return {
                    x: e.originalEvent.changedTouches[0].clientX,
                    y: e.originalEvent.changedTouches[0].clientY
                };

            if (e.pageX || e.pageY)
                return {
                    x: e.pageX,
                    y: e.pageY
                };

            return {
                x: e.clientX + document.body.scrollLeft - document.body.clientLeft,
                y: e.clientY + document.body.scrollTop - document.body.clientTop
            };
        },
        /** Given a target element and a mouse eent, get the mouse offset from that element.
         To do this we need the element's position and the mouse position */
        getMouseOffset: function (target, e) {
            var mousePos,
                docPos;

            e = e || window.event;

            docPos = this.getPosition(target);
            mousePos = this.mouseCoords(e);

            return {
                x: mousePos.x - docPos.x,
                y: mousePos.y - docPos.y
            };
        },
        /** Get the position of an element by going up the DOM tree and adding up all the offsets */
        getPosition: function (element) {
            var left = 0,
                top = 0;

            // Safari fix -- thanks to Luis Chato for this!
            // Safari 2 doesn't correctly grab the offsetTop of a table row
            // this is detailed here:
            // http://jacob.peargrove.com/blog/2006/technical/table-row-offsettop-bug-in-safari/
            // the solution is likewise noted there, grab the offset of a table cell in the row - the firstChild.
            // note that firefox will return a text node as a first child, so designing a more thorough
            // solution may need to take that into account, for now this seems to work in firefox, safari, ie
            if (element.offsetHeight == 0)
                element = element.firstChild; // a table cell

            while (element.offsetParent) {
                left += element.offsetLeft;
                top += element.offsetTop;
                element = element.offsetParent;
            }

            left += element.offsetLeft;
            top += element.offsetTop;

            return {
                x: left,
                y: top
            };
        },
        autoScroll: function (mousePos) {
            var config = this.currentTable.tableDnDConfig,
                yOffset = window.pageYOffset,
                windowHeight = window.innerHeight
                  ? window.innerHeight
                  : document.documentElement.clientHeight
                  ? document.documentElement.clientHeight
                  : document.body.clientHeight;

            // Windows version
            // yOffset=document.body.scrollTop;
            if (document.all)
                if (typeof document.compatMode != 'undefined'
                    && document.compatMode != 'BackCompat')
                    yOffset = document.documentElement.scrollTop;
                else if (typeof document.body != 'undefined')
                    yOffset = document.body.scrollTop;

            mousePos.y - yOffset < config.scrollAmount
                && window.scrollBy(0, -config.scrollAmount)
            || windowHeight - (mousePos.y - yOffset) < config.scrollAmount
                && window.scrollBy(0, config.scrollAmount);

        },
        moveVerticle: function (moving, currentRow) {

            if (0 != moving.vertical
                // If we're over a row then move the dragged row to there so that the user sees the
                // effect dynamically
                && currentRow
                && this.dragObject != currentRow
                && this.dragObject.parentNode == currentRow.parentNode)
                0 > moving.vertical
                    && this.dragObject.parentNode.insertBefore(this.dragObject, currentRow.nextSibling)
                || 0 < moving.vertical
                    && this.dragObject.parentNode.insertBefore(this.dragObject, currentRow);

        },
        moveHorizontal: function (moving, currentRow) {
            var config = this.currentTable.tableDnDConfig,
                currentLevel;

            if (!config.hierarchyLevel
                || 0 == moving.horizontal
                // We only care if moving left or right on the current row
                || !currentRow
                || this.dragObject != currentRow)
                return null;

            currentLevel = $(currentRow).data('level');

            0 < moving.horizontal
                && currentLevel > 0
                && $(currentRow).find('td:first').children(':first').remove()
                && $(currentRow).data('level', --currentLevel);

            0 > moving.horizontal
                && currentLevel < config.hierarchyLevel
                && $(currentRow).prev().data('level') >= currentLevel
                && $(currentRow).children(':first').prepend(config.indentArtifact)
                && $(currentRow).data('level', ++currentLevel);

        },
        mousemove: function (e) {
            var dragObj = $($.tableDnD.dragObject),
                config = $.tableDnD.currentTable.tableDnDConfig,
                currentRow,
                mousePos,
                moving,
                x,
                y;

            e && e.preventDefault();

            if (!$.tableDnD.dragObject)
                return false;

            // prevent touch device screen scrolling
            e.type == 'touchmove'
                && event.preventDefault(); // TODO verify this is event and not really e

            // update the style to show we're dragging
            config.onDragClass
                && dragObj.addClass(config.onDragClass)
                || dragObj.css(config.onDragStyle);

            mousePos = $.tableDnD.mouseCoords(e);
            x = mousePos.x - $.tableDnD.mouseOffset.x;
            y = mousePos.y - $.tableDnD.mouseOffset.y;

            // auto scroll the window
            $.tableDnD.autoScroll(mousePos);

            currentRow = $.tableDnD.findDropTargetRow(dragObj, y);
            moving = $.tableDnD.findDragDirection(x, y);

            $.tableDnD.moveVerticle(moving, currentRow);
            $.tableDnD.moveHorizontal(moving, currentRow);

            return false;
        },
        findDragDirection: function (x, y) {
            var sensitivity = this.currentTable.tableDnDConfig.sensitivity,
                oldX = this.oldX,
                oldY = this.oldY,
                xMin = oldX - sensitivity,
                xMax = oldX + sensitivity,
                yMin = oldY - sensitivity,
                yMax = oldY + sensitivity,
                moving = {
                    horizontal: x >= xMin && x <= xMax ? 0 : x > oldX ? -1 : 1,
                    vertical: y >= yMin && y <= yMax ? 0 : y > oldY ? -1 : 1
                };

            // update the old value
            if (moving.horizontal != 0)
                this.oldX = x;
            if (moving.vertical != 0)
                this.oldY = y;

            return moving;
        },
        /** We're only worried about the y position really, because we can only move rows up and down */
        findDropTargetRow: function (draggedRow, y) {
            var rowHeight = 0,
                rows = this.currentTable.rows,
                config = this.currentTable.tableDnDConfig,
                rowY = 0,
                row = null;

            for (var i = 0; i < rows.length; i++) {
                row = rows[i];
                rowY = this.getPosition(row).y;
                rowHeight = parseInt(row.offsetHeight) / 2;
                if (row.offsetHeight == 0) {
                    rowY = this.getPosition(row.firstChild).y;
                    rowHeight = parseInt(row.firstChild.offsetHeight) / 2;
                }
                // Because we always have to insert before, we need to offset the height a bit
                if (y > (rowY - rowHeight) && y < (rowY + rowHeight))
                    // that's the row we're over
                    // If it's the same as the current row, ignore it
                    if (draggedRow.is(row)
                        || (config.onAllowDrop
                        && !config.onAllowDrop(draggedRow, row))
                        // If a row has nodrop class, then don't allow dropping (inspired by John Tarr and Famic)
                        || $(row).hasClass("nodrop"))
                        return null;
                    else
                        return row;
            }
            return null;
        },
        processMouseup: function () {
            if (!this.currentTable || !this.dragObject)
                return null;

            var config = this.currentTable.tableDnDConfig,
                droppedRow = this.dragObject,
                parentLevel = 0,
                myLevel = 0;

            // Unbind the event handlers
            $(document)
                .unbind(moveEvent, this.mousemove)
                .unbind(endEvent, this.mouseup);

            config.hierarchyLevel
                && config.autoCleanRelations
                && $(this.currentTable.rows).first().find('td:first').children().each(function () {
                    myLevel = $(this).parents('tr:first').data('level');
                    myLevel
                        && $(this).parents('tr:first').data('level', --myLevel)
                        && $(this).remove();
                })
                && config.hierarchyLevel > 1
                && $(this.currentTable.rows).each(function () {
                    myLevel = $(this).data('level');
                    if (myLevel > 1) {
                        parentLevel = $(this).prev().data('level');
                        while (myLevel > parentLevel + 1) {
                            $(this).find('td:first').children(':first').remove();
                            $(this).data('level', --myLevel);
                        }
                    }
                });

            // If we have a dragObject, then we need to release it,
            // The row will already have been moved to the right place so we just reset stuff
            config.onDragClass
                && $(droppedRow).removeClass(config.onDragClass)
                || $(droppedRow).css(config.onDropStyle);

            this.dragObject = null;
            // Call the onDrop method if there is one
            config.onDrop
                && this.originalOrder != this.currentOrder()
                && $(droppedRow).hide().fadeIn('fast')
                && config.onDrop(this.currentTable, droppedRow);

            // Call the onDragStop method if there is one
            config.onDragStop
                && config.onDragStop(this.currentTable, droppedRow);

            this.currentTable = null; // let go of the table too
        },
        mouseup: function (e) {
            e && e.preventDefault();
            $.tableDnD.processMouseup();
            return false;
        },
        jsonize: function (pretify) {
            var table = this.currentTable;
            if (pretify)
                return JSON.stringify(
                    this.tableData(table),
                    null,
                    table.tableDnDConfig.jsonPretifySeparator
                );
            return JSON.stringify(this.tableData(table));
        },
        serialize: function () {
            return $.param(this.tableData(this.currentTable));
        },
        serializeTable: function (table) {
            var result = "";
            var paramName = table.tableDnDConfig.serializeParamName || table.id;
            var rows = table.rows;
            for (var i = 0; i < rows.length; i++) {
                if (result.length > 0) result += "&";
                var rowId = rows[i].id;
                if (rowId && table.tableDnDConfig && table.tableDnDConfig.serializeRegexp) {
                    rowId = rowId.match(table.tableDnDConfig.serializeRegexp)[0];
                    result += paramName + '[]=' + rowId;
                }
            }
            return result;
        },
        serializeTables: function () {
            var result = [];
            $('table').each(function () {
                this.id && result.push($.param(this.tableData(this)));
            });
            return result.join('&');
        },
        tableData: function (table) {
            var config = table.tableDnDConfig,
                previousIDs = [],
                currentLevel = 0,
                indentLevel = 0,
                rowID = null,
                data = {},
                getSerializeRegexp,
                paramName,
                currentID,
                rows;

            if (!table)
                table = this.currentTable;
            if (!table || !table.rows || !table.rows.length)
                return { error: { code: 500, message: "Not a valid table." } };
            if (!table.id && !config.serializeParamName)
                return { error: { code: 500, message: "No serializable unique id provided." } };

            rows = config.autoCleanRelations
                            && table.rows
                            || $.makeArray(table.rows);
            paramName = config.serializeParamName || table.id;
            currentID = paramName;

            getSerializeRegexp = function (rowId) {
                if (rowId && config && config.serializeRegexp)
                    return rowId.match(config.serializeRegexp)[0];
                return rowId;
            };

            data[currentID] = [];
            !config.autoCleanRelations
                && $(rows[0]).data('level')
                && rows.unshift({ id: 'undefined' });



            for (var i = 0; i < rows.length; i++) {
                if (config.hierarchyLevel) {
                    indentLevel = $(rows[i]).data('level') || 0;
                    if (indentLevel == 0) {
                        currentID = paramName;
                        previousIDs = [];
                    }
                    else if (indentLevel > currentLevel) {
                        previousIDs.push([currentID, currentLevel]);
                        currentID = getSerializeRegexp(rows[i - 1].id);
                    }
                    else if (indentLevel < currentLevel) {
                        for (var h = 0; h < previousIDs.length; h++) {
                            if (previousIDs[h][1] == indentLevel)
                                currentID = previousIDs[h][0];
                            if (previousIDs[h][1] >= currentLevel)
                                previousIDs[h][1] = 0;
                        }
                    }
                    currentLevel = indentLevel;

                    if (!$.isArray(data[currentID]))
                        data[currentID] = [];
                    rowID = getSerializeRegexp(rows[i].id);
                    rowID && data[currentID].push(rowID);
                }
                else {
                    rowID = getSerializeRegexp(rows[i].id);
                    rowID && data[currentID].push(rowID);
                }
            }
            return data;
        }
    };

    jQuery.fn.extend(
        {
            tableDnD: $.tableDnD.build,
            tableDnDUpdate: $.tableDnD.updateTables,
            tableDnDSerialize: $.proxy($.tableDnD.serialize, $.tableDnD),
            tableDnDSerializeAll: $.tableDnD.serializeTables,
            tableDnDData: $.proxy($.tableDnD.tableData, $.tableDnD)
        }
    );

}(jQuery, window, window.document);;
var PDFObject = function (e) { if (!e || !e.url) { return false } var t = "1.2", n = e.id || false, r = e.width || "100%", i = e.height || "100%", s = e.pdfOpenParams, o, u, a, f, l, c, h, p, d, v, m; a = function (e) { var t; try { t = new ActiveXObject(e) } catch (n) { t = null } return t }; f = function () { var e = null; try { e = new ActiveXObject("AcroPDF.PDF") } catch (t) { } if (e != null || window.ActiveXObject) { e = a("AcroPDF.PDF"); if (!e) { e = a("PDF.PdfCtrl") } if (e !== null) { return true } } return false }; l = function () { var e, t = navigator.plugins, n = t.length, r = /Adobe Reader|Adobe PDF|Acrobat/gi; for (e = 0; e < n; e++) { if (r.test(t[e].name)) { return true } } return false }; c = function () { var e = navigator.mimeTypes["application/pdf"]; return e && e.enabledPlugin }; h = function () { var e = null; if (l() || f()) { e = "Adobe" } else if (c()) { e = "generic" } return e }; p = function () { var e = document.getElementsByTagName("html"), t, n; if (!e) { return false } t = e[0].style; n = document.body.style; t.height = "100%"; t.overflow = "hidden"; n.margin = "0"; n.padding = "0"; n.height = "100%"; n.overflow = "hidden" }; d = function (e) { var t = "", n; if (!e) { return t } for (n in e) { if (e.hasOwnProperty(n)) { t += n + "="; if (n === "search") { t += encodeURI(e[n]) } else { t += e[n] } t += "&" } } return t.slice(0, t.length - 1) }; v = function (e) { var a = null; switch (e) { case "url": a = o; break; case "id": a = n; break; case "width": a = r; break; case "height": a = i; break; case "pdfOpenParams": a = s; break; case "pluginTypeFound": a = u; break; case "pdfobjectversion": a = t; break } return a }; m = function (e) { if (!u) { return false } var t = null; if (e) { t = e.nodeType && e.nodeType === 1 ? e : document.getElementById(e); if (!t) { return false } } else { t = document.body; p(); r = "100%"; i = "100%" } t.innerHTML = '<object    data="' + o + '" type="application/pdf" width="' + r + '" height="' + i + '"></object>'; return t.getElementsByTagName("object")[0] }; o = encodeURI(e.url) + "#" + d(s); u = h(); this.get = function (e) { return v(e) }; this.embed = function (e) { return m(e) }; this.pdfobjectversion = t; return this };
/*!
  * Bowser - a browser detector
  * https://github.com/ded/bowser
  * MIT License | (c) Dustin Diaz 2014
  */
!function(e,t){typeof module!="undefined"&&module.exports?module.exports.browser=t():typeof define=="function"?define(t):this[e]=t()}("bowser",function(){function t(t){function n(e){var n=t.match(e);return n&&n.length>1&&n[1]||""}var r=n(/(ipod|iphone|ipad)/i).toLowerCase(),i=/like android/i.test(t),s=!i&&/android/i.test(t),o=n(/version\/(\d+(\.\d+)?)/i),u=/tablet/i.test(t),a=!u&&/[^-]mobi/i.test(t),f;/opera|opr/i.test(t)?f={name:"Opera",opera:e,version:o||n(/(?:opera|opr)[\s\/](\d+(\.\d+)?)/i)}:/windows phone/i.test(t)?f={name:"Windows Phone",windowsphone:e,msie:e,version:n(/iemobile\/(\d+(\.\d+)?)/i)}:/msie|trident/i.test(t)?f={name:"Internet Explorer",msie:e,version:n(/(?:msie |rv:)(\d+(\.\d+)?)/i)}:/chrome|crios|crmo/i.test(t)?f={name:"Chrome",chrome:e,version:n(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i)}:r?(f={name:r=="iphone"?"iPhone":r=="ipad"?"iPad":"iPod"},o&&(f.version=o)):/sailfish/i.test(t)?f={name:"Sailfish",sailfish:e,version:n(/sailfish\s?browser\/(\d+(\.\d+)?)/i)}:/seamonkey\//i.test(t)?f={name:"SeaMonkey",seamonkey:e,version:n(/seamonkey\/(\d+(\.\d+)?)/i)}:/firefox|iceweasel/i.test(t)?(f={name:"Firefox",firefox:e,version:n(/(?:firefox|iceweasel)[ \/](\d+(\.\d+)?)/i)},/\((mobile|tablet);[^\)]*rv:[\d\.]+\)/i.test(t)&&(f.firefoxos=e)):/silk/i.test(t)?f={name:"Amazon Silk",silk:e,version:n(/silk\/(\d+(\.\d+)?)/i)}:s?f={name:"Android",version:o}:/phantom/i.test(t)?f={name:"PhantomJS",phantom:e,version:n(/phantomjs\/(\d+(\.\d+)?)/i)}:/blackberry|\bbb\d+/i.test(t)||/rim\stablet/i.test(t)?f={name:"BlackBerry",blackberry:e,version:o||n(/blackberry[\d]+\/(\d+(\.\d+)?)/i)}:/(web|hpw)os/i.test(t)?(f={name:"WebOS",webos:e,version:o||n(/w(?:eb)?osbrowser\/(\d+(\.\d+)?)/i)},/touchpad\//i.test(t)&&(f.touchpad=e)):/bada/i.test(t)?f={name:"Bada",bada:e,version:n(/dolfin\/(\d+(\.\d+)?)/i)}:/tizen/i.test(t)?f={name:"Tizen",tizen:e,version:n(/(?:tizen\s?)?browser\/(\d+(\.\d+)?)/i)||o}:/safari/i.test(t)?f={name:"Safari",safari:e,version:o}:f={},/(apple)?webkit/i.test(t)?(f.name=f.name||"Webkit",f.webkit=e,!f.version&&o&&(f.version=o)):!f.opera&&/gecko\//i.test(t)&&(f.name=f.name||"Gecko",f.gecko=e,f.version=f.version||n(/gecko\/(\d+(\.\d+)?)/i)),s||f.silk?f.android=e:r&&(f[r]=e,f.ios=e);var l="";r?(l=n(/os (\d+([_\s]\d+)*) like mac os x/i),l=l.replace(/[_\s]/g,".")):s?l=n(/android[ \/-](\d+(\.\d+)*)/i):f.windowsphone?l=n(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i):f.webos?l=n(/(?:web|hpw)os\/(\d+(\.\d+)*)/i):f.blackberry?l=n(/rim\stablet\sos\s(\d+(\.\d+)*)/i):f.bada?l=n(/bada\/(\d+(\.\d+)*)/i):f.tizen&&(l=n(/tizen[\/\s](\d+(\.\d+)*)/i)),l&&(f.osversion=l);var c=l.split(".")[0];if(u||r=="ipad"||s&&(c==3||c==4&&!a)||f.silk)f.tablet=e;else if(a||r=="iphone"||r=="ipod"||s||f.blackberry||f.webos||f.bada)f.mobile=e;return f.msie&&f.version>=10||f.chrome&&f.version>=20||f.firefox&&f.version>=20||f.safari&&f.version>=6||f.opera&&f.version>=10||f.ios&&f.osversion&&f.osversion.split(".")[0]>=6?f.a=e:f.msie&&f.version<10||f.chrome&&f.version<20||f.firefox&&f.version<20||f.safari&&f.version<6||f.opera&&f.version<10||f.ios&&f.osversion&&f.osversion.split(".")[0]<6?f.c=e:f.x=e,f}var e=!0,n=t(typeof navigator!="undefined"?navigator.userAgent:"");return n._detect=t,n});
/**
 * A Javascript object to encode and/or decode html characters using HTML or Numeric entities that handles double or partial encoding
 * Author: R Reid
 * source: http://www.strictly-software.com/htmlencode
 * Licences: GPL, The MIT License (MIT)
 * Copyright: (c) 2011 Robert Reid - Strictly-Software.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * 
 * Revision:
 *  2011-07-14, Jacques-Yves Bleau: 
 *       - fixed conversion error with capitalized accentuated characters
 *       + converted arr1 and arr2 to object property to remove redundancy
 *
 * Revision:
 *  2011-11-10, Ce-Yi Hio: 
 *       - fixed conversion error with a number of capitalized entity characters
 *
 * Revision:
 *  2011-11-10, Rob Reid: 
 *		 - changed array format
 *
 * Revision:
 *  2012-09-23, Alex Oss: 
 *		 - replaced string concatonation in numEncode with string builder, push and join for peformance with ammendments by Rob Reid
 */

Encoder = {

    // When encoding do we convert characters into html or numerical entities
    EncodeType: "entity",  // entity OR numerical

    isEmpty: function (val) {
        if (val) {
            return ((val === null) || val.length == 0 || /^\s+$/.test(val));
        } else {
            return true;
        }
    },

    // arrays for conversion from HTML Entities to Numerical values
    arr1: ['&nbsp;', '&iexcl;', '&cent;', '&pound;', '&curren;', '&yen;', '&brvbar;', '&sect;', '&uml;', '&copy;', '&ordf;', '&laquo;', '&not;', '&shy;', '&reg;', '&macr;', '&deg;', '&plusmn;', '&sup2;', '&sup3;', '&acute;', '&micro;', '&para;', '&middot;', '&cedil;', '&sup1;', '&ordm;', '&raquo;', '&frac14;', '&frac12;', '&frac34;', '&iquest;', '&Agrave;', '&Aacute;', '&Acirc;', '&Atilde;', '&Auml;', '&Aring;', '&AElig;', '&Ccedil;', '&Egrave;', '&Eacute;', '&Ecirc;', '&Euml;', '&Igrave;', '&Iacute;', '&Icirc;', '&Iuml;', '&ETH;', '&Ntilde;', '&Ograve;', '&Oacute;', '&Ocirc;', '&Otilde;', '&Ouml;', '&times;', '&Oslash;', '&Ugrave;', '&Uacute;', '&Ucirc;', '&Uuml;', '&Yacute;', '&THORN;', '&szlig;', '&agrave;', '&aacute;', '&acirc;', '&atilde;', '&auml;', '&aring;', '&aelig;', '&ccedil;', '&egrave;', '&eacute;', '&ecirc;', '&euml;', '&igrave;', '&iacute;', '&icirc;', '&iuml;', '&eth;', '&ntilde;', '&ograve;', '&oacute;', '&ocirc;', '&otilde;', '&ouml;', '&divide;', '&oslash;', '&ugrave;', '&uacute;', '&ucirc;', '&uuml;', '&yacute;', '&thorn;', '&yuml;', '&quot;', '&amp;', '&lt;', '&gt;', '&OElig;', '&oelig;', '&Scaron;', '&scaron;', '&Yuml;', '&circ;', '&tilde;', '&ensp;', '&emsp;', '&thinsp;', '&zwnj;', '&zwj;', '&lrm;', '&rlm;', '&ndash;', '&mdash;', '&lsquo;', '&rsquo;', '&sbquo;', '&ldquo;', '&rdquo;', '&bdquo;', '&dagger;', '&Dagger;', '&permil;', '&lsaquo;', '&rsaquo;', '&euro;', '&fnof;', '&Alpha;', '&Beta;', '&Gamma;', '&Delta;', '&Epsilon;', '&Zeta;', '&Eta;', '&Theta;', '&Iota;', '&Kappa;', '&Lambda;', '&Mu;', '&Nu;', '&Xi;', '&Omicron;', '&Pi;', '&Rho;', '&Sigma;', '&Tau;', '&Upsilon;', '&Phi;', '&Chi;', '&Psi;', '&Omega;', '&alpha;', '&beta;', '&gamma;', '&delta;', '&epsilon;', '&zeta;', '&eta;', '&theta;', '&iota;', '&kappa;', '&lambda;', '&mu;', '&nu;', '&xi;', '&omicron;', '&pi;', '&rho;', '&sigmaf;', '&sigma;', '&tau;', '&upsilon;', '&phi;', '&chi;', '&psi;', '&omega;', '&thetasym;', '&upsih;', '&piv;', '&bull;', '&hellip;', '&prime;', '&Prime;', '&oline;', '&frasl;', '&weierp;', '&image;', '&real;', '&trade;', '&alefsym;', '&larr;', '&uarr;', '&rarr;', '&darr;', '&harr;', '&crarr;', '&lArr;', '&uArr;', '&rArr;', '&dArr;', '&hArr;', '&forall;', '&part;', '&exist;', '&empty;', '&nabla;', '&isin;', '&notin;', '&ni;', '&prod;', '&sum;', '&minus;', '&lowast;', '&radic;', '&prop;', '&infin;', '&ang;', '&and;', '&or;', '&cap;', '&cup;', '&int;', '&there4;', '&sim;', '&cong;', '&asymp;', '&ne;', '&equiv;', '&le;', '&ge;', '&sub;', '&sup;', '&nsub;', '&sube;', '&supe;', '&oplus;', '&otimes;', '&perp;', '&sdot;', '&lceil;', '&rceil;', '&lfloor;', '&rfloor;', '&lang;', '&rang;', '&loz;', '&spades;', '&clubs;', '&hearts;', '&diams;'],
    arr2: ['&#160;', '&#161;', '&#162;', '&#163;', '&#164;', '&#165;', '&#166;', '&#167;', '&#168;', '&#169;', '&#170;', '&#171;', '&#172;', '&#173;', '&#174;', '&#175;', '&#176;', '&#177;', '&#178;', '&#179;', '&#180;', '&#181;', '&#182;', '&#183;', '&#184;', '&#185;', '&#186;', '&#187;', '&#188;', '&#189;', '&#190;', '&#191;', '&#192;', '&#193;', '&#194;', '&#195;', '&#196;', '&#197;', '&#198;', '&#199;', '&#200;', '&#201;', '&#202;', '&#203;', '&#204;', '&#205;', '&#206;', '&#207;', '&#208;', '&#209;', '&#210;', '&#211;', '&#212;', '&#213;', '&#214;', '&#215;', '&#216;', '&#217;', '&#218;', '&#219;', '&#220;', '&#221;', '&#222;', '&#223;', '&#224;', '&#225;', '&#226;', '&#227;', '&#228;', '&#229;', '&#230;', '&#231;', '&#232;', '&#233;', '&#234;', '&#235;', '&#236;', '&#237;', '&#238;', '&#239;', '&#240;', '&#241;', '&#242;', '&#243;', '&#244;', '&#245;', '&#246;', '&#247;', '&#248;', '&#249;', '&#250;', '&#251;', '&#252;', '&#253;', '&#254;', '&#255;', '&#34;', '&#38;', '&#60;', '&#62;', '&#338;', '&#339;', '&#352;', '&#353;', '&#376;', '&#710;', '&#732;', '&#8194;', '&#8195;', '&#8201;', '&#8204;', '&#8205;', '&#8206;', '&#8207;', '&#8211;', '&#8212;', '&#8216;', '&#8217;', '&#8218;', '&#8220;', '&#8221;', '&#8222;', '&#8224;', '&#8225;', '&#8240;', '&#8249;', '&#8250;', '&#8364;', '&#402;', '&#913;', '&#914;', '&#915;', '&#916;', '&#917;', '&#918;', '&#919;', '&#920;', '&#921;', '&#922;', '&#923;', '&#924;', '&#925;', '&#926;', '&#927;', '&#928;', '&#929;', '&#931;', '&#932;', '&#933;', '&#934;', '&#935;', '&#936;', '&#937;', '&#945;', '&#946;', '&#947;', '&#948;', '&#949;', '&#950;', '&#951;', '&#952;', '&#953;', '&#954;', '&#955;', '&#956;', '&#957;', '&#958;', '&#959;', '&#960;', '&#961;', '&#962;', '&#963;', '&#964;', '&#965;', '&#966;', '&#967;', '&#968;', '&#969;', '&#977;', '&#978;', '&#982;', '&#8226;', '&#8230;', '&#8242;', '&#8243;', '&#8254;', '&#8260;', '&#8472;', '&#8465;', '&#8476;', '&#8482;', '&#8501;', '&#8592;', '&#8593;', '&#8594;', '&#8595;', '&#8596;', '&#8629;', '&#8656;', '&#8657;', '&#8658;', '&#8659;', '&#8660;', '&#8704;', '&#8706;', '&#8707;', '&#8709;', '&#8711;', '&#8712;', '&#8713;', '&#8715;', '&#8719;', '&#8721;', '&#8722;', '&#8727;', '&#8730;', '&#8733;', '&#8734;', '&#8736;', '&#8743;', '&#8744;', '&#8745;', '&#8746;', '&#8747;', '&#8756;', '&#8764;', '&#8773;', '&#8776;', '&#8800;', '&#8801;', '&#8804;', '&#8805;', '&#8834;', '&#8835;', '&#8836;', '&#8838;', '&#8839;', '&#8853;', '&#8855;', '&#8869;', '&#8901;', '&#8968;', '&#8969;', '&#8970;', '&#8971;', '&#9001;', '&#9002;', '&#9674;', '&#9824;', '&#9827;', '&#9829;', '&#9830;'],

    // Convert HTML entities into numerical entities
    HTML2Numerical: function (s) {
        return this.swapArrayVals(s, this.arr1, this.arr2);
    },

    // Convert Numerical entities into HTML entities
    NumericalToHTML: function (s) {
        return this.swapArrayVals(s, this.arr2, this.arr1);
    },


    // Numerically encodes all unicode characters
    numEncode: function (s) {
        if (this.isEmpty(s)) return "";

        var a = [],
			l = s.length;

        for (var i = 0; i < l; i++) {
            var c = s.charAt(i);
            if (c < " " || c > "~") {
                a.push("&#");
                a.push(c.charCodeAt()); //numeric value of code point 
                a.push(";");
            } else {
                a.push(c);
            }
        }

        return a.join("");
    },

    // HTML Decode numerical and HTML entities back to original values
    htmlDecode: function (s) {

        var c, m, d = s;

        if (this.isEmpty(d)) return "";

        // convert HTML entites back to numerical entites first
        d = this.HTML2Numerical(d);

        // look for numerical entities &#34;
        arr = d.match(/&#[0-9]{1,5};/g);

        // if no matches found in string then skip
        if (arr != null) {
            for (var x = 0; x < arr.length; x++) {
                m = arr[x];
                c = m.substring(2, m.length - 1); //get numeric part which is refernce to unicode character
                // if its a valid number we can decode
                if (c >= -32768 && c <= 65535) {
                    // decode every single match within string
                    d = d.replace(m, String.fromCharCode(c));
                } else {
                    d = d.replace(m, ""); //invalid so replace with nada
                }
            }
        }

        return d;
    },

    // encode an input string into either numerical or HTML entities
    htmlEncode: function (s, dbl) {

        if (this.isEmpty(s)) return "";

        // do we allow double encoding? E.g will &amp; be turned into &amp;amp;
        dbl = dbl || false; //default to prevent double encoding

        // if allowing double encoding we do ampersands first
        if (dbl) {
            if (this.EncodeType == "numerical") {
                s = s.replace(/&/g, "&#38;");
            } else {
                s = s.replace(/&/g, "&amp;");
            }
        }

        // convert the xss chars to numerical entities ' " < >
        s = this.XSSEncode(s, false);

        if (this.EncodeType == "numerical" || !dbl) {
            // Now call function that will convert any HTML entities to numerical codes
            s = this.HTML2Numerical(s);
        }

        // Now encode all chars above 127 e.g unicode
        s = this.numEncode(s);

        // now we know anything that needs to be encoded has been converted to numerical entities we
        // can encode any ampersands & that are not part of encoded entities
        // to handle the fact that I need to do a negative check and handle multiple ampersands &&&
        // I am going to use a placeholder

        // if we don't want double encoded entities we ignore the & in existing entities
        if (!dbl) {
            s = s.replace(/&#/g, "##AMPHASH##");

            if (this.EncodeType == "numerical") {
                s = s.replace(/&/g, "&#38;");
            } else {
                s = s.replace(/&/g, "&amp;");
            }

            s = s.replace(/##AMPHASH##/g, "&#");
        }

        // replace any malformed entities
        s = s.replace(/&#\d*([^\d;]|$)/g, "$1");

        if (!dbl) {
            // safety check to correct any double encoded &amp;
            s = this.correctEncoding(s);
        }

        // now do we need to convert our numerical encoded string into entities
        if (this.EncodeType == "entity") {
            s = this.NumericalToHTML(s);
        }

        return s;
    },

    // Encodes the basic 4 characters used to malform HTML in XSS hacks
    XSSEncode: function (s, en) {
        if (!this.isEmpty(s)) {
            en = en || true;
            // do we convert to numerical or html entity?
            if (en) {
                s = s.replace(/\'/g, "&#39;"); //no HTML equivalent as &apos is not cross browser supported
                s = s.replace(/\"/g, "&quot;");
                s = s.replace(/</g, "&lt;");
                s = s.replace(/>/g, "&gt;");
            } else {
                s = s.replace(/\'/g, "&#39;"); //no HTML equivalent as &apos is not cross browser supported
                s = s.replace(/\"/g, "&#34;");
                s = s.replace(/</g, "&#60;");
                s = s.replace(/>/g, "&#62;");
            }
            return s;
        } else {
            return "";
        }
    },

    // returns true if a string contains html or numerical encoded entities
    hasEncoded: function (s) {
        if (/&#[0-9]{1,5};/g.test(s)) {
            return true;
        } else if (/&[A-Z]{2,6};/gi.test(s)) {
            return true;
        } else {
            return false;
        }
    },

    // will remove any unicode characters
    stripUnicode: function (s) {
        return s.replace(/[^\x20-\x7E]/g, "");

    },

    // corrects any double encoded &amp; entities e.g &amp;amp;
    correctEncoding: function (s) {
        return s.replace(/(&amp;)(amp;)+/, "$1");
    },


    // Function to loop through an array swaping each item with the value from another array e.g swap HTML entities with Numericals
    swapArrayVals: function (s, arr1, arr2) {
        if (this.isEmpty(s)) return "";
        var re;
        if (arr1 && arr2) {
            //ShowDebug("in swapArrayVals arr1.length = " + arr1.length + " arr2.length = " + arr2.length)
            // array lengths must match
            if (arr1.length == arr2.length) {
                for (var x = 0, i = arr1.length; x < i; x++) {
                    re = new RegExp(arr1[x], 'g');
                    s = s.replace(re, arr2[x]); //swap arr1 item with matching item from arr2	
                }
            }
        }
        return s;
    },

    inArray: function (item, arr) {
        for (var i = 0, x = arr.length; i < x; i++) {
            if (arr[i] === item) {
                return i;
            }
        }
        return -1;
    }

};
/**
 * Bootstrap Multiselect (https://github.com/davidstutz/bootstrap-multiselect)
 *
 * Apache License, Version 2.0:
 * Copyright (c) 2012 - 2015 David Stutz
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a
 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 * BSD 3-Clause License:
 * Copyright (c) 2012 - 2015 David Stutz
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *    - Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *    - Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *    - Neither the name of David Stutz nor the names of its contributors may be
 *      used to endorse or promote products derived from this software without
 *      specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
!function ($) {
    "use strict";// jshint ;_;

    if (typeof ko !== 'undefined' && ko.bindingHandlers && !ko.bindingHandlers.multiselect) {
        ko.bindingHandlers.multiselect = {
            after: ['options', 'value', 'selectedOptions', 'enable', 'disable'],

            init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
                var $element = $(element);
                var config = ko.toJS(valueAccessor());

                $element.multiselect(config);

                if (allBindings.has('options')) {
                    var options = allBindings.get('options');
                    if (ko.isObservable(options)) {
                        ko.computed({
                            read: function () {
                                options();
                                setTimeout(function () {
                                    var ms = $element.data('multiselect');
                                    if (ms)
                                        ms.updateOriginalOptions();//Not sure how beneficial this is.
                                    $element.multiselect('rebuild');
                                }, 1);
                            },
                            disposeWhenNodeIsRemoved: element
                        });
                    }
                }

                //value and selectedOptions are two-way, so these will be triggered even by our own actions.
                //It needs some way to tell if they are triggered because of us or because of outside change.
                //It doesn't loop but it's a waste of processing.
                if (allBindings.has('value')) {
                    var value = allBindings.get('value');
                    if (ko.isObservable(value)) {
                        ko.computed({
                            read: function () {
                                value();
                                setTimeout(function () {
                                    $element.multiselect('refresh');
                                }, 1);
                            },
                            disposeWhenNodeIsRemoved: element
                        }).extend({ rateLimit: 100, notifyWhenChangesStop: true });
                    }
                }

                //Switched from arrayChange subscription to general subscription using 'refresh'.
                //Not sure performance is any better using 'select' and 'deselect'.
                if (allBindings.has('selectedOptions')) {
                    var selectedOptions = allBindings.get('selectedOptions');
                    if (ko.isObservable(selectedOptions)) {
                        ko.computed({
                            read: function () {
                                selectedOptions();

                                // Added to handle knockout binding to an object...not just a value
                                // multiselect needs the selected property on the options, else it wont show them on refresh
                                if ((config.optionsKey !== undefined) &&
                                    (config.optionsKey !== null) &&
                                    (config.optionsKey.length > 0) &&
                                    (config.observableKey !== undefined) &&
                                    (config.observableKey !== null) &&
                                    (config.observableKey.length > 0)) {
                                    var _optionsKey = config.optionsKey;
                                    var _observableKey = config.observableKey;
                                    ko.utils.arrayForEach(selectedOptions(),
                                        function (selectedOption) {
                                            var observableKeyValue;
                                            if (typeof selectedOption[_observableKey] === "function") {
                                                observableKeyValue = selectedOption[_observableKey]();
                                            } else {
                                                observableKeyValue = selectedOption[_observableKey];
                                            }

                                            $("option[" + _optionsKey + "='" + observableKeyValue + "']",
                                                    $element)
                                                .prop('selected', true);
                                        });
                                }

                                setTimeout(function () {
                                    $element.multiselect('refresh');
                                }, 1);
                            },
                            disposeWhenNodeIsRemoved: element
                        }).extend({ rateLimit: 100, notifyWhenChangesStop: true });
                    }
                }

                var setEnabled = function (enable) {
                    setTimeout(function () {
                        if (enable)
                            $element.multiselect('enable');
                        else
                            $element.multiselect('disable');
                    });
                };

                if (allBindings.has('enable')) {
                    var enable = allBindings.get('enable');
                    if (ko.isObservable(enable)) {
                        ko.computed({
                            read: function () {
                                setEnabled(enable());
                            },
                            disposeWhenNodeIsRemoved: element
                        }).extend({ rateLimit: 100, notifyWhenChangesStop: true });
                    } else {
                        setEnabled(enable);
                    }
                }

                if (allBindings.has('disable')) {
                    var disable = allBindings.get('disable');
                    if (ko.isObservable(disable)) {
                        ko.computed({
                            read: function () {
                                setEnabled(!disable());
                            },
                            disposeWhenNodeIsRemoved: element
                        }).extend({ rateLimit: 100, notifyWhenChangesStop: true });
                    } else {
                        setEnabled(!disable);
                    }
                }

                ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
                    $element.multiselect('destroy');
                });
            },

            update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
                var $element = $(element);
                var config = ko.toJS(valueAccessor());

                $element.multiselect('setOptions', config);
                $element.multiselect('rebuild');
            }
        };
    }

    function forEach(array, callback) {
        for (var index = 0; index < array.length; ++index) {
            callback(array[index], index);
        }
    }

    /**
     * Constructor to create a new multiselect using the given select.
     *
     * @param {jQuery} select
     * @param {Object} options
     * @returns {Multiselect}
     */
    function Multiselect(select, options) {

        this.$select = $(select);
        this.options = this.mergeOptions($.extend({}, options, this.$select.data()));

        // Placeholder via data attributes
        if (this.$select.attr("data-placeholder")) {
            this.options.nonSelectedText = this.$select.data("placeholder");
        }

        // Initialization.
        // We have to clone to create a new reference.
        this.originalOptions = this.$select.clone()[0].options;
        this.query = '';
        this.searchTimeout = null;
        this.lastToggledInput = null;

        this.options.multiple = this.$select.attr('multiple') === "multiple";
        this.options.onChange = $.proxy(this.options.onChange, this);
        this.options.onSelectAll = $.proxy(this.options.onSelectAll, this);
        this.options.onDeselectAll = $.proxy(this.options.onDeselectAll, this);
        this.options.onDropdownShow = $.proxy(this.options.onDropdownShow, this);
        this.options.onDropdownHide = $.proxy(this.options.onDropdownHide, this);
        this.options.onDropdownShown = $.proxy(this.options.onDropdownShown, this);
        this.options.onDropdownHidden = $.proxy(this.options.onDropdownHidden, this);
        this.options.onInitialized = $.proxy(this.options.onInitialized, this);
        this.options.onFiltering = $.proxy(this.options.onFiltering, this);

        // Build select all if enabled.
        this.buildContainer();
        this.buildButton();
        this.buildDropdown();
        this.buildSelectAll();
        this.buildDropdownOptions();
        this.buildFilter();

        this.updateButtonText();
        this.updateSelectAll(true);

        if (this.options.enableClickableOptGroups && this.options.multiple) {
            this.updateOptGroups();
        }

        this.options.wasDisabled = this.$select.prop('disabled');
        if (this.options.disableIfEmpty && $('option', this.$select).length <= 0) {
            this.disable();
        }

        this.$select.wrap('<span class="multiselect-native-select" />').after(this.$container);
        this.options.onInitialized(this.$select, this.$container);
    }

    Multiselect.prototype = {

        defaults: {
            /**
             * Default text function will either print 'None selected' in case no
             * option is selected or a list of the selected options up to a length
             * of 3 selected options.
             *
             * @param {jQuery} options
             * @param {jQuery} select
             * @returns {String}
             */
            buttonText: function (options, select) {
                if (this.disabledText.length > 0
                        && (select.prop('disabled') || (options.length == 0 && this.disableIfEmpty))) {

                    return this.disabledText;
                }
                else if (options.length === 0) {
                    return this.nonSelectedText;
                }
                else if (this.allSelectedText
                        && options.length === $('option', $(select)).length
                        && $('option', $(select)).length !== 1
                        && this.multiple) {

                    if (this.selectAllNumber) {
                        return this.allSelectedText + ' (' + options.length + ')';
                    }
                    else {
                        return this.allSelectedText;
                    }
                }
                else if (options.length > this.numberDisplayed) {
                    return options.length + ' ' + this.nSelectedText;
                }
                else {
                    var selected = '';
                    var delimiter = this.delimiterText;

                    options.each(function () {
                        var label = ($(this).attr('label') !== undefined) ? $(this).attr('label') : $(this).text();
                        selected += label + delimiter;
                    });

                    return selected.substr(0, selected.length - this.delimiterText.length);
                }
            },
            /**
             * Updates the title of the button similar to the buttonText function.
             *
             * @param {jQuery} options
             * @param {jQuery} select
             * @returns {@exp;selected@call;substr}
             */
            buttonTitle: function (options, select) {
                if (options.length === 0) {
                    return this.nonSelectedText;
                }
                else {
                    var selected = '';
                    var delimiter = this.delimiterText;

                    options.each(function () {
                        var label = ($(this).attr('label') !== undefined) ? $(this).attr('label') : $(this).text();
                        selected += label + delimiter;
                    });
                    return selected.substr(0, selected.length - this.delimiterText.length);
                }
            },
            checkboxName: function (option) {
                return false; // no checkbox name
            },
            /**
             * Create a label.
             *
             * @param {jQuery} element
             * @returns {String}
             */
            optionLabel: function (element) {
                return $(element).attr('label') || $(element).text();
            },
            /**
             * Create a class.
             *
             * @param {jQuery} element
             * @returns {String}
             */
            optionClass: function (element) {
                return $(element).attr('class') || '';
            },
            /**
             * Triggered on change of the multiselect.
             *
             * Not triggered when selecting/deselecting options manually.
             *
             * @param {jQuery} option
             * @param {Boolean} checked
             */
            onChange: function (option, checked) {

            },
            /**
             * Triggered when the dropdown is shown.
             *
             * @param {jQuery} event
             */
            onDropdownShow: function (event) {

            },
            /**
             * Triggered when the dropdown is hidden.
             *
             * @param {jQuery} event
             */
            onDropdownHide: function (event) {

            },
            /**
             * Triggered after the dropdown is shown.
             *
             * @param {jQuery} event
             */
            onDropdownShown: function (event) {

            },
            /**
             * Triggered after the dropdown is hidden.
             *
             * @param {jQuery} event
             */
            onDropdownHidden: function (event) {

            },
            /**
             * Triggered on select all.
             */
            onSelectAll: function () {

            },
            /**
             * Triggered on deselect all.
             */
            onDeselectAll: function () {

            },
            /**
             * Triggered after initializing.
             *
             * @param {jQuery} $select
             * @param {jQuery} $container
             */
            onInitialized: function ($select, $container) {

            },
            /**
             * Triggered on filtering.
             *
             * @param {jQuery} $filter
             */
            onFiltering: function ($filter) {

            },
            enableHTML: false,
            buttonClass: 'btn btn-default',
            inheritClass: false,
            buttonWidth: 'auto',
            buttonContainer: '<div class="btn-group" />',
            dropRight: false,
            dropUp: false,
            selectedClass: 'active',
            // Maximum height of the dropdown menu.
            // If maximum height is exceeded a scrollbar will be displayed.
            maxHeight: false,
            includeSelectAllOption: false,
            includeSelectAllIfMoreThan: 0,
            selectAllText: ' Select all',
            selectAllValue: 'multiselect-all',
            selectAllName: false,
            selectAllNumber: true,
            selectAllJustVisible: true,
            enableFiltering: false,
            enableCaseInsensitiveFiltering: false,
            enableFullValueFiltering: false,
            enableClickableOptGroups: false,
            enableCollapsibleOptGroups: false,
            filterPlaceholder: 'Search',
            // possible options: 'text', 'value', 'both'
            filterBehavior: 'text',
            includeFilterClearBtn: true,
            preventInputChangeEvent: false,
            nonSelectedText: 'None selected',
            nSelectedText: 'selected',
            allSelectedText: 'All selected',
            numberDisplayed: 3,
            disableIfEmpty: false,
            disabledText: '',
            delimiterText: ', ',
            templates: {
                button: '<button type="button" class="multiselect dropdown-toggle" data-toggle="dropdown"><span class="multiselect-selected-text"></span> <b class="caret"></b></button>',
                ul: '<ul class="multiselect-container dropdown-menu"></ul>',
                filter: '<li class="multiselect-item multiselect-filter"><div class="input-group"><span class="input-group-addon"><i class="glyphicon glyphicon-search"></i></span><input class="form-control multiselect-search" type="text"></div></li>',
                filterClearBtn: '<span class="input-group-btn"><button class="btn btn-default multiselect-clear-filter" type="button"><i class="glyphicon glyphicon-remove-circle"></i></button></span>',
                li: '<li><a tabindex="0"><label></label></a></li>',
                divider: '<li class="multiselect-item divider"></li>',
                liGroup: '<li class="multiselect-item multiselect-group"><label></label></li>'
            }
        },

        constructor: Multiselect,

        /**
         * Builds the container of the multiselect.
         */
        buildContainer: function () {
            this.$container = $(this.options.buttonContainer);
            this.$container.on('show.bs.dropdown', this.options.onDropdownShow);
            this.$container.on('hide.bs.dropdown', this.options.onDropdownHide);
            this.$container.on('shown.bs.dropdown', this.options.onDropdownShown);
            this.$container.on('hidden.bs.dropdown', this.options.onDropdownHidden);
        },

        /**
         * Builds the button of the multiselect.
         */
        buildButton: function () {
            this.$button = $(this.options.templates.button).addClass(this.options.buttonClass);
            if (this.$select.attr('class') && this.options.inheritClass) {
                this.$button.addClass(this.$select.attr('class'));
            }
            // Adopt active state.
            if (this.$select.prop('disabled')) {
                this.disable();
            }
            else {
                this.enable();
            }

            // Manually add button width if set.
            if (this.options.buttonWidth && this.options.buttonWidth !== 'auto') {
                this.$button.css({
                    'width': '100%', //this.options.buttonWidth,
                    'overflow': 'hidden',
                    'text-overflow': 'ellipsis'
                });
                this.$container.css({
                    'width': this.options.buttonWidth
                });
            }

            // Keep the tab index from the select.
            var tabindex = this.$select.attr('tabindex');
            if (tabindex) {
                this.$button.attr('tabindex', tabindex);
            }

            this.$container.prepend(this.$button);
        },

        /**
         * Builds the ul representing the dropdown menu.
         */
        buildDropdown: function () {

            // Build ul.
            this.$ul = $(this.options.templates.ul);

            if (this.options.dropRight) {
                this.$ul.addClass('pull-right');
            }

            // Set max height of dropdown menu to activate auto scrollbar.
            if (this.options.maxHeight) {
                // TODO: Add a class for this option to move the css declarations.
                this.$ul.css({
                    'max-height': this.options.maxHeight + 'px',
                    'overflow-y': 'auto',
                    'overflow-x': 'hidden'
                });
            }

            if (this.options.dropUp) {

                var height = Math.min(this.options.maxHeight, $('option[data-role!="divider"]', this.$select).length * 26 + $('option[data-role="divider"]', this.$select).length * 19 + (this.options.includeSelectAllOption ? 26 : 0) + (this.options.enableFiltering || this.options.enableCaseInsensitiveFiltering ? 44 : 0));
                var moveCalc = height + 34;

                this.$ul.css({
                    'max-height': height + 'px',
                    'overflow-y': 'auto',
                    'overflow-x': 'hidden',
                    'margin-top': "-" + moveCalc + 'px'
                });
            }

            this.$container.append(this.$ul);
        },

        /**
         * Build the dropdown options and binds all necessary events.
         *
         * Uses createDivider and createOptionValue to create the necessary options.
         */
        buildDropdownOptions: function () {

            this.$select.children().each($.proxy(function (index, element) {

                var $element = $(element);
                // Support optgroups and options without a group simultaneously.
                var tag = $element.prop('tagName')
                    .toLowerCase();

                if ($element.prop('value') === this.options.selectAllValue) {
                    return;
                }

                if (tag === 'optgroup') {
                    this.createOptgroup(element);
                }
                else if (tag === 'option') {

                    if ($element.data('role') === 'divider') {
                        this.createDivider();
                    }
                    else {
                        this.createOptionValue(element);
                    }

                }

                // Other illegal tags will be ignored.
            }, this));

            // Bind the change event on the dropdown elements.
            $('li:not(.multiselect-group) input', this.$ul).on('change', $.proxy(function (event) {
                var $target = $(event.target);

                var checked = $target.prop('checked') || false;
                var isSelectAllOption = $target.val() === this.options.selectAllValue;

                // Apply or unapply the configured selected class.
                if (this.options.selectedClass) {
                    if (checked) {
                        $target.closest('li')
                            .addClass(this.options.selectedClass);
                    }
                    else {
                        $target.closest('li')
                            .removeClass(this.options.selectedClass);
                    }
                }

                // Get the corresponding option.
                var value = $target.val();
                var $option = this.getOptionByValue(value);

                var $optionsNotThis = $('option', this.$select).not($option);
                var $checkboxesNotThis = $('input', this.$container).not($target);

                if (isSelectAllOption) {

                    if (checked) {
                        this.selectAll(this.options.selectAllJustVisible, true);
                    }
                    else {
                        this.deselectAll(this.options.selectAllJustVisible, true);
                    }
                }
                else {
                    if (checked) {
                        $option.prop('selected', true);

                        if (this.options.multiple) {
                            // Simply select additional option.
                            $option.prop('selected', true);
                        }
                        else {
                            // Unselect all other options and corresponding checkboxes.
                            if (this.options.selectedClass) {
                                $($checkboxesNotThis).closest('li').removeClass(this.options.selectedClass);
                            }

                            $($checkboxesNotThis).prop('checked', false);
                            $optionsNotThis.prop('selected', false);

                            // It's a single selection, so close.
                            this.$button.click();
                        }

                        if (this.options.selectedClass === "active") {
                            $optionsNotThis.closest("a").css("outline", "");
                        }
                    }
                    else {
                        // Unselect option.
                        $option.prop('selected', false);
                    }

                    // To prevent select all from firing onChange: #575
                    this.options.onChange($option, checked);

                    // Do not update select all or optgroups on select all change!
                    this.updateSelectAll();

                    if (this.options.enableClickableOptGroups && this.options.multiple) {
                        this.updateOptGroups();
                    }
                }

                this.$select.change();
                this.updateButtonText();

                if (this.options.preventInputChangeEvent) {
                    return false;
                }
            }, this));

            $('li a', this.$ul).on('mousedown', function (e) {
                if (e.shiftKey) {
                    // Prevent selecting text by Shift+click
                    return false;
                }
            });

            $('li a', this.$ul).on('touchstart click', $.proxy(function (event) {
                event.stopPropagation();

                var $target = $(event.target);

                if (event.shiftKey && this.options.multiple) {
                    if ($target.is("label")) { // Handles checkbox selection manually (see https://github.com/davidstutz/bootstrap-multiselect/issues/431)
                        event.preventDefault();
                        $target = $target.find("input");
                        $target.prop("checked", !$target.prop("checked"));
                    }
                    var checked = $target.prop('checked') || false;

                    if (this.lastToggledInput !== null && this.lastToggledInput !== $target) { // Make sure we actually have a range
                        var from = $target.closest("li").index();
                        var to = this.lastToggledInput.closest("li").index();

                        if (from > to) { // Swap the indices
                            var tmp = to;
                            to = from;
                            from = tmp;
                        }

                        // Make sure we grab all elements since slice excludes the last index
                        ++to;

                        // Change the checkboxes and underlying options
                        var range = this.$ul.find("li").slice(from, to).find("input");

                        range.prop('checked', checked);

                        if (this.options.selectedClass) {
                            range.closest('li')
                                .toggleClass(this.options.selectedClass, checked);
                        }

                        for (var i = 0, j = range.length; i < j; i++) {
                            var $checkbox = $(range[i]);

                            var $option = this.getOptionByValue($checkbox.val());

                            $option.prop('selected', checked);
                        }
                    }

                    // Trigger the select "change" event
                    $target.trigger("change");
                }

                // Remembers last clicked option
                if ($target.is("input") && !$target.closest("li").is(".multiselect-item")) {
                    this.lastToggledInput = $target;
                }

                $target.blur();
            }, this));

            // Keyboard support.
            this.$container.off('keydown.multiselect').on('keydown.multiselect', $.proxy(function (event) {
                if ($('input[type="text"]', this.$container).is(':focus')) {
                    return;
                }

                if (event.keyCode === 9 && this.$container.hasClass('open')) {
                    this.$button.click();
                }
                else {
                    var $items = $(this.$container).find("li:not(.divider):not(.disabled) a").filter(":visible");

                    if (!$items.length) {
                        return;
                    }

                    var index = $items.index($items.filter(':focus'));

                    // Navigation up.
                    if (event.keyCode === 38 && index > 0) {
                        index--;
                    }
                        // Navigate down.
                    else if (event.keyCode === 40 && index < $items.length - 1) {
                        index++;
                    }
                    else if (!~index) {
                        index = 0;
                    }

                    var $current = $items.eq(index);
                    $current.focus();

                    if (event.keyCode === 32 || event.keyCode === 13) {
                        var $checkbox = $current.find('input');

                        $checkbox.prop("checked", !$checkbox.prop("checked"));
                        $checkbox.change();
                    }

                    event.stopPropagation();
                    event.preventDefault();
                }
            }, this));

            if (this.options.enableClickableOptGroups && this.options.multiple) {
                $("li.multiselect-group input", this.$ul).on("change", $.proxy(function (event) {
                    event.stopPropagation();

                    var $target = $(event.target);
                    var checked = $target.prop('checked') || false;

                    var $li = $(event.target).closest('li');
                    var $group = $li.nextUntil("li.multiselect-group")
                        .not('.multiselect-filter-hidden')
                        .not('.disabled');

                    var $inputs = $group.find("input");

                    var values = [];
                    var $options = [];

                    if (this.options.selectedClass) {
                        if (checked) {
                            $li.addClass(this.options.selectedClass);
                        }
                        else {
                            $li.removeClass(this.options.selectedClass);
                        }
                    }

                    $.each($inputs, $.proxy(function (index, input) {
                        var value = $(input).val();
                        var $option = this.getOptionByValue(value);

                        if (checked) {
                            $(input).prop('checked', true);
                            $(input).closest('li')
                                .addClass(this.options.selectedClass);

                            $option.prop('selected', true);
                        }
                        else {
                            $(input).prop('checked', false);
                            $(input).closest('li')
                                .removeClass(this.options.selectedClass);

                            $option.prop('selected', false);
                        }

                        $options.push(this.getOptionByValue(value));
                    }, this))

                    // Cannot use select or deselect here because it would call updateOptGroups again.

                    this.options.onChange($options, checked);

                    this.$select.change();
                    this.updateButtonText();
                    this.updateSelectAll();
                }, this));
            }

            if (this.options.enableCollapsibleOptGroups && this.options.multiple) {
                $("li.multiselect-group .caret-container", this.$ul).on("click", $.proxy(function (event) {
                    var $li = $(event.target).closest('li');
                    var $inputs = $li.nextUntil("li.multiselect-group")
                            .not('.multiselect-filter-hidden');

                    var visible = true;
                    $inputs.each(function () {
                        visible = visible && $(this).is(':visible');
                    });

                    if (visible) {
                        $inputs.hide()
                            .addClass('multiselect-collapsible-hidden');
                    }
                    else {
                        $inputs.show()
                            .removeClass('multiselect-collapsible-hidden');
                    }
                }, this));

                $("li.multiselect-all", this.$ul).css('background', '#f3f3f3').css('border-bottom', '1px solid #eaeaea');
                $("li.multiselect-all > a > label.checkbox", this.$ul).css('padding', '3px 20px 3px 35px');
                $("li.multiselect-group > a > input", this.$ul).css('margin', '4px 0px 5px -20px');
            }
        },

        /**
         * Create an option using the given select option.
         *
         * @param {jQuery} element
         */
        createOptionValue: function (element) {
            var $element = $(element);
            if ($element.is(':selected')) {
                $element.prop('selected', true);
            }

            // Support the label attribute on options.
            var label = this.options.optionLabel(element);
            var classes = this.options.optionClass(element);
            var value = $element.val();

            // Added to handle knockout binding to an object...not just a value
            if ((this.options.optionsKey !== undefined) && (this.options.optionsKey !== null) && (this.options.optionsKey.length > 0)) {
                var key = $element.attr(this.options.optionsKey);
                if ((key !== undefined) && (key !== null) && (key.length > 0)) {
                    value = key;
                }
            }

            var inputType = this.options.multiple ? "checkbox" : "radio";

            var $li = $(this.options.templates.li);
            var $label = $('label', $li);
            $label.addClass(inputType);
            $li.addClass(classes);

            if (this.options.enableHTML) {
                $label.html(" " + label);
            }
            else {
                $label.text(" " + label);
            }

            var $checkbox = $('<input/>').attr('type', inputType);

            var name = this.options.checkboxName($element);
            if (name) {
                $checkbox.attr('name', name);
            }

            $label.prepend($checkbox);

            var selected = $element.prop('selected') || false;
            $checkbox.val(value);

            if (value === this.options.selectAllValue) {
                $li.addClass("multiselect-item multiselect-all");
                $checkbox.parent().parent()
                    .addClass('multiselect-all');
            }

            $label.attr('title', $element.attr('title'));

            this.$ul.append($li);

            if ($element.is(':disabled')) {
                $checkbox.attr('disabled', 'disabled')
                    .prop('disabled', true)
                    .closest('a')
                    .attr("tabindex", "-1")
                    .closest('li')
                    .addClass('disabled');
            }

            $checkbox.prop('checked', selected);

            if (selected && this.options.selectedClass) {
                $checkbox.closest('li')
                    .addClass(this.options.selectedClass);
            }
        },

        /**
         * Creates a divider using the given select option.
         *
         * @param {jQuery} element
         */
        createDivider: function (element) {
            var $divider = $(this.options.templates.divider);
            this.$ul.append($divider);
        },

        /**
         * Creates an optgroup.
         *
         * @param {jQuery} group
         */
        createOptgroup: function (group) {
            var label = $(group).attr("label");
            var value = $(group).attr("value");
            var $li = $('<li class="multiselect-item multiselect-group"><a href="javascript:void(0);"><label><b></b></label></a></li>');

            var classes = this.options.optionClass(group);
            $li.addClass(classes);

            if (this.options.enableHTML) {
                $('label b', $li).html(" " + label);
            }
            else {
                $('label b', $li).text(" " + label);
            }

            if (this.options.enableCollapsibleOptGroups && this.options.multiple) {
                $('a', $li).append('<span class="caret-container"><b class="caret"></b></span>');
            }

            if (this.options.enableClickableOptGroups && this.options.multiple) {
                $('a label', $li).prepend('<input type="checkbox" value="' + value + '"/>');
            }

            if ($(group).is(':disabled')) {
                $li.addClass('disabled');
            }

            this.$ul.append($li);

            $("option", group).each($.proxy(function ($, group) {
                this.createOptionValue(group);
            }, this))
        },

        /**
         * Build the select all.
         *
         * Checks if a select all has already been created.
         */
        buildSelectAll: function () {
            if (typeof this.options.selectAllValue === 'number') {
                this.options.selectAllValue = this.options.selectAllValue.toString();
            }

            var alreadyHasSelectAll = this.hasSelectAll();

            if (!alreadyHasSelectAll && this.options.includeSelectAllOption && this.options.multiple
                    && $('option', this.$select).length > this.options.includeSelectAllIfMoreThan) {

                // Check whether to add a divider after the select all.
                if (this.options.includeSelectAllDivider) {
                    this.$ul.prepend($(this.options.templates.divider));
                }

                var $li = $(this.options.templates.li);
                $('label', $li).addClass("checkbox");

                if (this.options.enableHTML) {
                    $('label', $li).html(" " + this.options.selectAllText);
                }
                else {
                    $('label', $li).text(" " + this.options.selectAllText);
                }

                if (this.options.selectAllName) {
                    $('label', $li).prepend('<input type="checkbox" name="' + this.options.selectAllName + '" />');
                }
                else {
                    $('label', $li).prepend('<input type="checkbox" />');
                }

                var $checkbox = $('input', $li);
                $checkbox.val(this.options.selectAllValue);

                $li.addClass("multiselect-item multiselect-all");
                $checkbox.parent().parent()
                    .addClass('multiselect-all');

                this.$ul.prepend($li);

                $checkbox.prop('checked', false);
            }
        },

        /**
         * Builds the filter.
         */
        buildFilter: function () {

            // Build filter if filtering OR case insensitive filtering is enabled and the number of options exceeds (or equals) enableFilterLength.
            if (this.options.enableFiltering || this.options.enableCaseInsensitiveFiltering) {
                var enableFilterLength = Math.max(this.options.enableFiltering, this.options.enableCaseInsensitiveFiltering);

                if (this.$select.find('option').length >= enableFilterLength) {

                    this.$filter = $(this.options.templates.filter);
                    $('input', this.$filter).attr('placeholder', this.options.filterPlaceholder);

                    // Adds optional filter clear button
                    if (this.options.includeFilterClearBtn) {
                        var clearBtn = $(this.options.templates.filterClearBtn);
                        clearBtn.on('click', $.proxy(function (event) {
                            clearTimeout(this.searchTimeout);

                            this.$filter.find('.multiselect-search').val('');
                            $('li', this.$ul).show().removeClass('multiselect-filter-hidden');

                            this.updateSelectAll();

                            if (this.options.enableClickableOptGroups && this.options.multiple) {
                                this.updateOptGroups();
                            }

                        }, this));
                        this.$filter.find('.input-group').append(clearBtn);
                    }

                    this.$ul.prepend(this.$filter);

                    this.$filter.val(this.query).on('click', function (event) {
                        event.stopPropagation();
                    }).on('input keydown', $.proxy(function (event) {
                        // Cancel enter key default behaviour
                        if (event.which === 13) {
                            event.preventDefault();
                        }

                        // This is useful to catch "keydown" events after the browser has updated the control.
                        clearTimeout(this.searchTimeout);

                        this.searchTimeout = this.asyncFunction($.proxy(function () {

                            if (this.query !== event.target.value) {
                                this.query = event.target.value;

                                var currentGroup, currentGroupVisible;
                                $.each($('li', this.$ul), $.proxy(function (index, element) {
                                    var value = $('input', element).length > 0 ? $('input', element).val() : "";
                                    var text = $('label', element).text();

                                    var filterCandidate = '';
                                    if ((this.options.filterBehavior === 'text')) {
                                        filterCandidate = text;
                                    }
                                    else if ((this.options.filterBehavior === 'value')) {
                                        filterCandidate = value;
                                    }
                                    else if (this.options.filterBehavior === 'both') {
                                        filterCandidate = text + '\n' + value;
                                    }

                                    if (value !== this.options.selectAllValue && text) {

                                        // By default lets assume that element is not
                                        // interesting for this search.
                                        var showElement = false;

                                        if (this.options.enableCaseInsensitiveFiltering) {
                                            filterCandidate = filterCandidate.toLowerCase();
                                            this.query = this.query.toLowerCase();
                                        }

                                        if (this.options.enableFullValueFiltering && this.options.filterBehavior !== 'both') {
                                            var valueToMatch = filterCandidate.trim().substring(0, this.query.length);
                                            if (this.query.indexOf(valueToMatch) > -1) {
                                                showElement = true;
                                            }
                                        }
                                        else if (filterCandidate.indexOf(this.query) > -1) {
                                            showElement = true;
                                        }

                                        // Toggle current element (group or group item) according to showElement boolean.
                                        $(element).toggle(showElement)
                                            .toggleClass('multiselect-filter-hidden', !showElement);

                                        // Differentiate groups and group items.
                                        if ($(element).hasClass('multiselect-group')) {
                                            // Remember group status.
                                            currentGroup = element;
                                            currentGroupVisible = showElement;
                                        }
                                        else {
                                            // Show group name when at least one of its items is visible.
                                            if (showElement) {
                                                $(currentGroup).show()
                                                    .removeClass('multiselect-filter-hidden');
                                            }

                                            // Show all group items when group name satisfies filter.
                                            if (!showElement && currentGroupVisible) {
                                                $(element).show()
                                                    .removeClass('multiselect-filter-hidden');
                                            }
                                        }
                                    }
                                }, this));
                            }

                            this.updateSelectAll();

                            if (this.options.enableClickableOptGroups && this.options.multiple) {
                                this.updateOptGroups();
                            }

                            this.options.onFiltering(event.target);

                        }, this), 300, this);
                    }, this));
                }
            }
        },

        /**
         * Unbinds the whole plugin.
         */
        destroy: function () {
            this.$container.remove();
            this.$select.show();

            // reset original state
            this.$select.prop('disabled', this.options.wasDisabled);

            this.$select.data('multiselect', null);
        },

        /**
         * Refreshs the multiselect based on the selected options of the select.
         */
        refresh: function () {
            var inputs = $.map($('li input', this.$ul), $);

            $('option', this.$select).each($.proxy(function (index, element) {
                var $elem = $(element);
                var value = $elem.val();
                var $input;
                for (var i = inputs.length; 0 < i--; /**/) {
                    if (value !== ($input = inputs[i]).val())
                        continue; // wrong li

                    if ($elem.is(':selected')) {
                        $input.prop('checked', true);

                        if (this.options.selectedClass) {
                            $input.closest('li')
                                .addClass(this.options.selectedClass);
                        }
                    }
                    else {
                        $input.prop('checked', false);

                        if (this.options.selectedClass) {
                            $input.closest('li')
                                .removeClass(this.options.selectedClass);
                        }
                    }

                    if ($elem.is(":disabled")) {
                        $input.attr('disabled', 'disabled')
                            .prop('disabled', true)
                            .closest('li')
                            .addClass('disabled');
                    }
                    else {
                        $input.prop('disabled', false)
                            .closest('li')
                            .removeClass('disabled');
                    }
                    break; // assumes unique values
                }
            }, this));

            this.updateButtonText();
            this.updateSelectAll();

            if (this.options.enableClickableOptGroups && this.options.multiple) {
                this.updateOptGroups();
            }
        },

        /**
         * Select all options of the given values.
         *
         * If triggerOnChange is set to true, the on change event is triggered if
         * and only if one value is passed.
         *
         * @param {Array} selectValues
         * @param {Boolean} triggerOnChange
         */
        select: function (selectValues, triggerOnChange) {
            if (!$.isArray(selectValues)) {
                selectValues = [selectValues];
            }

            for (var i = 0; i < selectValues.length; i++) {
                var value = selectValues[i];

                if (value === null || value === undefined) {
                    continue;
                }

                var $option = this.getOptionByValue(value);
                var $checkbox = this.getInputByValue(value);

                if ($option === undefined || $checkbox === undefined) {
                    continue;
                }

                if (!this.options.multiple) {
                    this.deselectAll(false);
                }

                if (this.options.selectedClass) {
                    $checkbox.closest('li')
                        .addClass(this.options.selectedClass);
                }

                $checkbox.prop('checked', true);
                $option.prop('selected', true);

                if (triggerOnChange) {
                    this.options.onChange($option, true);
                }
            }

            this.updateButtonText();
            this.updateSelectAll();

            if (this.options.enableClickableOptGroups && this.options.multiple) {
                this.updateOptGroups();
            }
        },

        /**
         * Clears all selected items.
         */
        clearSelection: function () {
            this.deselectAll(false);
            this.updateButtonText();
            this.updateSelectAll();

            if (this.options.enableClickableOptGroups && this.options.multiple) {
                this.updateOptGroups();
            }
        },

        /**
         * Deselects all options of the given values.
         *
         * If triggerOnChange is set to true, the on change event is triggered, if
         * and only if one value is passed.
         *
         * @param {Array} deselectValues
         * @param {Boolean} triggerOnChange
         */
        deselect: function (deselectValues, triggerOnChange) {
            if (!$.isArray(deselectValues)) {
                deselectValues = [deselectValues];
            }

            for (var i = 0; i < deselectValues.length; i++) {
                var value = deselectValues[i];

                if (value === null || value === undefined) {
                    continue;
                }

                var $option = this.getOptionByValue(value);
                var $checkbox = this.getInputByValue(value);

                if ($option === undefined || $checkbox === undefined) {
                    continue;
                }

                if (this.options.selectedClass) {
                    $checkbox.closest('li')
                        .removeClass(this.options.selectedClass);
                }

                $checkbox.prop('checked', false);
                $option.prop('selected', false);

                if (triggerOnChange) {
                    this.options.onChange($option, false);
                }
            }

            this.updateButtonText();
            this.updateSelectAll();

            if (this.options.enableClickableOptGroups && this.options.multiple) {
                this.updateOptGroups();
            }
        },

        /**
         * Selects all enabled & visible options.
         *
         * If justVisible is true or not specified, only visible options are selected.
         *
         * @param {Boolean} justVisible
         * @param {Boolean} triggerOnSelectAll
         */
        selectAll: function (justVisible, triggerOnSelectAll) {

            var justVisible = typeof justVisible === 'undefined' ? true : justVisible;
            var allLis = $("li:not(.divider):not(.disabled):not(.multiselect-group)", this.$ul);
            var visibleLis = $("li:not(.divider):not(.disabled):not(.multiselect-group):not(.multiselect-filter-hidden):not(.multiselect-collapisble-hidden)", this.$ul).filter(':visible');

            if (justVisible) {
                $('input:enabled', visibleLis).prop('checked', true);
                visibleLis.addClass(this.options.selectedClass);

                $('input:enabled', visibleLis).each($.proxy(function (index, element) {
                    var value = $(element).val();
                    var option = this.getOptionByValue(value);
                    $(option).prop('selected', true);
                }, this));
            }
            else {
                $('input:enabled', allLis).prop('checked', true);
                allLis.addClass(this.options.selectedClass);

                $('input:enabled', allLis).each($.proxy(function (index, element) {
                    var value = $(element).val();
                    var option = this.getOptionByValue(value);
                    $(option).prop('selected', true);
                }, this));
            }

            $('li input[value="' + this.options.selectAllValue + '"]', this.$ul).prop('checked', true);

            if (this.options.enableClickableOptGroups && this.options.multiple) {
                this.updateOptGroups();
            }

            if (triggerOnSelectAll) {
                this.options.onSelectAll();
            }
        },

        /**
         * Deselects all options.
         *
         * If justVisible is true or not specified, only visible options are deselected.
         *
         * @param {Boolean} justVisible
         */
        deselectAll: function (justVisible, triggerOnDeselectAll) {

            var justVisible = typeof justVisible === 'undefined' ? true : justVisible;
            var allLis = $("li:not(.divider):not(.disabled):not(.multiselect-group)", this.$ul);
            var visibleLis = $("li:not(.divider):not(.disabled):not(.multiselect-group):not(.multiselect-filter-hidden):not(.multiselect-collapisble-hidden)", this.$ul).filter(':visible');

            if (justVisible) {
                $('input[type="checkbox"]:enabled', visibleLis).prop('checked', false);
                visibleLis.removeClass(this.options.selectedClass);

                $('input[type="checkbox"]:enabled', visibleLis).each($.proxy(function (index, element) {
                    var value = $(element).val();
                    var option = this.getOptionByValue(value);
                    $(option).prop('selected', false);
                }, this));
            }
            else {
                $('input[type="checkbox"]:enabled', allLis).prop('checked', false);
                allLis.removeClass(this.options.selectedClass);

                $('input[type="checkbox"]:enabled', allLis).each($.proxy(function (index, element) {
                    var value = $(element).val();
                    var option = this.getOptionByValue(value);
                    $(option).prop('selected', false);
                }, this));
            }

            $('li input[value="' + this.options.selectAllValue + '"]', this.$ul).prop('checked', false);

            if (this.options.enableClickableOptGroups && this.options.multiple) {
                this.updateOptGroups();
            }

            if (triggerOnDeselectAll) {
                this.options.onDeselectAll();
            }
        },

        /**
         * Rebuild the plugin.
         *
         * Rebuilds the dropdown, the filter and the select all option.
         */
        rebuild: function () {
            this.$ul.html('');

            // Important to distinguish between radios and checkboxes.
            this.options.multiple = this.$select.attr('multiple') === "multiple";

            this.buildSelectAll();
            this.buildDropdownOptions();
            this.buildFilter();

            this.updateButtonText();
            this.updateSelectAll(true);

            if (this.options.enableClickableOptGroups && this.options.multiple) {
                this.updateOptGroups();
            }

            if (this.options.disableIfEmpty && $('option', this.$select).length <= 0) {
                this.disable();
            }
            else {
                this.enable();
            }

            if (this.options.dropRight) {
                this.$ul.addClass('pull-right');
            }
        },

        /**
         * The provided data will be used to build the dropdown.
         */
        dataprovider: function (dataprovider) {

            var groupCounter = 0;
            var $select = this.$select.empty();

            $.each(dataprovider, function (index, option) {
                var $tag;

                if ($.isArray(option.children)) { // create optiongroup tag
                    groupCounter++;

                    $tag = $('<optgroup/>').attr({
                        label: option.label || 'Group ' + groupCounter,
                        disabled: !!option.disabled
                    });

                    forEach(option.children, function (subOption) { // add children option tags
                        var attributes = {
                            value: subOption.value,
                            label: subOption.label || subOption.value,
                            title: subOption.title,
                            selected: !!subOption.selected,
                            disabled: !!subOption.disabled
                        };

                        //Loop through attributes object and add key-value for each attribute
                        for (var key in subOption.attributes) {
                            attributes['data-' + key] = subOption.attributes[key];
                        }
                        //Append original attributes + new data attributes to option
                        $tag.append($('<option/>').attr(attributes));
                    });
                }
                else {

                    var attributes = {
                        'value': option.value,
                        'label': option.label || option.value,
                        'title': option.title,
                        'class': option.class,
                        'selected': !!option.selected,
                        'disabled': !!option.disabled
                    };
                    //Loop through attributes object and add key-value for each attribute
                    for (var key in option.attributes) {
                        attributes['data-' + key] = option.attributes[key];
                    }
                    //Append original attributes + new data attributes to option
                    $tag = $('<option/>').attr(attributes);

                    $tag.text(option.label || option.value);
                }

                $select.append($tag);
            });

            this.rebuild();
        },

        /**
         * Enable the multiselect.
         */
        enable: function () {
            this.$select.prop('disabled', false);
            this.$button.prop('disabled', false)
                .removeClass('disabled');
        },

        /**
         * Disable the multiselect.
         */
        disable: function () {
            this.$select.prop('disabled', true);
            this.$button.prop('disabled', true)
                .addClass('disabled');
        },

        /**
         * Set the options.
         *
         * @param {Array} options
         */
        setOptions: function (options) {
            this.options = this.mergeOptions(options);
        },

        /**
         * Merges the given options with the default options.
         *
         * @param {Array} options
         * @returns {Array}
         */
        mergeOptions: function (options) {
            return $.extend(true, {}, this.defaults, this.options, options);
        },

        /**
         * Checks whether a select all checkbox is present.
         *
         * @returns {Boolean}
         */
        hasSelectAll: function () {
            return $('li.multiselect-all', this.$ul).length > 0;
        },

        /**
         * Update opt groups.
         */
        updateOptGroups: function () {
            var $groups = $('li.multiselect-group', this.$ul)
            var selectedClass = this.options.selectedClass;

            $groups.each(function () {
                var $options = $(this).nextUntil('li.multiselect-group')
                    .not('.multiselect-filter-hidden')
                    .not('.disabled');

                var checked = true;
                $options.each(function () {
                    var $input = $('input', this);

                    if (!$input.prop('checked')) {
                        checked = false;
                    }
                });

                if (selectedClass) {
                    if (checked) {
                        $(this).addClass(selectedClass);
                    }
                    else {
                        $(this).removeClass(selectedClass);
                    }
                }

                $('input', this).prop('checked', checked);
            });
        },

        /**
         * Updates the select all checkbox based on the currently displayed and selected checkboxes.
         */
        updateSelectAll: function (notTriggerOnSelectAll) {
            if (this.hasSelectAll()) {
                var allBoxes = $("li:not(.multiselect-item):not(.multiselect-filter-hidden):not(.multiselect-group):not(.disabled) input:enabled", this.$ul);
                var allBoxesLength = allBoxes.length;
                var checkedBoxesLength = allBoxes.filter(":checked").length;
                var selectAllLi = $("li.multiselect-all", this.$ul);
                var selectAllInput = selectAllLi.find("input");

                if (checkedBoxesLength > 0 && checkedBoxesLength === allBoxesLength) {
                    selectAllInput.prop("checked", true);
                    selectAllLi.addClass(this.options.selectedClass);
                }
                else {
                    selectAllInput.prop("checked", false);
                    selectAllLi.removeClass(this.options.selectedClass);
                }
            }
        },

        /**
         * Update the button text and its title based on the currently selected options.
         */
        updateButtonText: function () {
            var options = this.getSelected();

            // First update the displayed button text.
            if (this.options.enableHTML) {
                $('.multiselect .multiselect-selected-text', this.$container).html(this.options.buttonText(options, this.$select));
            }
            else {
                $('.multiselect .multiselect-selected-text', this.$container).text(this.options.buttonText(options, this.$select));
            }

            // Now update the title attribute of the button.
            $('.multiselect', this.$container).attr('title', this.options.buttonTitle(options, this.$select));
        },

        /**
         * Get all selected options.
         *
         * @returns {jQUery}
         */
        getSelected: function () {
            return $('option', this.$select).filter(":selected");
        },

        /**
         * Gets a select option by its value.
         *
         * @param {String} value
         * @returns {jQuery}
         */
        getOptionByValue: function (value) {

            var valueToCompare = value.toString();

            // Added to handle knockout binding to an object...not just a value
            if ((this.options.optionsKey !== undefined) && (this.options.optionsKey !== null) && (this.options.optionsKey.length > 0)) {
                var opt = $("option[" + this.options.optionsKey + "='" + valueToCompare + "']", this.$select).first();
                if ((opt !== undefined) && (opt !== null)) {
                    return $(opt);
                }
            }

            var options = $('option', this.$select);

            for (var i = 0; i < options.length; i = i + 1) {
                var option = options[i];
                if (option.value === valueToCompare) {
                    return $(option);
                }
            }
        },

        /**
         * Get the input (radio/checkbox) by its value.
         *
         * @param {String} value
         * @returns {jQuery}
         */
        getInputByValue: function (value) {

            var checkboxes = $('li input:not(.multiselect-search)', this.$ul);
            var valueToCompare = value.toString();

            for (var i = 0; i < checkboxes.length; i = i + 1) {
                var checkbox = checkboxes[i];
                if (checkbox.value === valueToCompare) {
                    return $(checkbox);
                }
            }
        },

        /**
         * Used for knockout integration.
         */
        updateOriginalOptions: function () {
            this.originalOptions = this.$select.clone()[0].options;
        },

        asyncFunction: function (callback, timeout, self) {
            var args = Array.prototype.slice.call(arguments, 3);
            return setTimeout(function () {
                callback.apply(self || window, args);
            }, timeout);
        },

        setAllSelectedText: function (allSelectedText) {
            this.options.allSelectedText = allSelectedText;
            this.updateButtonText();
        }
    };

    $.fn.multiselect = function (option, parameter, extraOptions) {
        return this.each(function () {
            var data = $(this).data('multiselect');
            var options = typeof option === 'object' && option;

            // Initialize the multiselect.
            if (!data) {
                data = new Multiselect(this, options);
                $(this).data('multiselect', data);
            }

            // Call multiselect method.
            if (typeof option === 'string') {
                data[option](parameter, extraOptions);

                if (option === 'destroy') {
                    $(this).data('multiselect', false);
                }
            }
        });
    };

    $.fn.multiselect.Constructor = Multiselect;

    $(function () {
        $("select[data-role=multiselect]").multiselect();
    });

}(window.jQuery);;
/*!
* inputmask.min.js
* http://github.com/RobinHerbots/jquery.inputmask
* Copyright (c) 2010 - 2015 Robin Herbots
* Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
* Version: 3.1.64-86
*/
!function (a) { "function" == typeof define && define.amd ? define(["jquery"], a) : "object" == typeof exports ? module.exports = a(require("jquery")) : a(jQuery) }(function (a) {
    function b(b) { this.el = void 0, this.opts = a.extend(!0, {}, this.defaults, b), this.noMasksCache = b && void 0 !== b.definitions, this.userOptions = b || {}, e(this.opts.alias, b, this.opts) } function c(a) { var b = document.createElement("input"), c = "on" + a, d = c in b; return d || (b.setAttribute(c, "return;"), d = "function" == typeof b[c]), b = null, d } function d(a) { var b = "text" == a || "tel" == a || "password" == a; if (!b) { var c = document.createElement("input"); c.setAttribute("type", a), b = "text" === c.type, c = null } return b } function e(b, c, d) { var f = d.aliases[b]; return f ? (f.alias && e(f.alias, void 0, d), a.extend(!0, d, f), a.extend(!0, d, c), !0) : (void 0 == d.mask && (d.mask = b), !1) } function f(b, c, d) { var f = a(b), g = f.data("inputmask"); if (g && "" != g) try { g = g.replace(new RegExp("'", "g"), '"'); var h = a.parseJSON("{" + g + "}"); a.extend(!0, d, h) } catch (i) { } for (var j in c) { var k = f.data("inputmask-" + j.toLowerCase()); void 0 != k && (k = "boolean" == typeof k ? k : k.toString(), "mask" == j && 0 == k.indexOf("[") ? (d[j] = k.replace(/[\s[\]]/g, "").split("','"), d[j][0] = d[j][0].replace("'", ""), d[j][d[j].length - 1] = d[j][d[j].length - 1].replace("'", "")) : d[j] = k) } return d.alias ? e(d.alias, d, c) : a.extend(!0, c, d), c } function g(c, d) { function e(b) { function d(a, b, c, d) { this.matches = [], this.isGroup = a || !1, this.isOptional = b || !1, this.isQuantifier = c || !1, this.isAlternator = d || !1, this.quantifier = { min: 1, max: 1 } } function e(b, d, e) { var f = c.definitions[d], g = 0 == b.matches.length; if (e = void 0 != e ? e : b.matches.length, f && !o) { f.placeholder = a.isFunction(f.placeholder) ? f.placeholder.call(this, c) : f.placeholder; for (var h = f.prevalidator, i = h ? h.length : 0, j = 1; j < f.cardinality; j++) { var k = i >= j ? h[j - 1] : [], l = k.validator, m = k.cardinality; b.matches.splice(e++, 0, { fn: l ? "string" == typeof l ? new RegExp(l) : new function () { this.test = l } : new RegExp("."), cardinality: m ? m : 1, optionality: b.isOptional, newBlockMarker: g, casing: f.casing, def: f.definitionSymbol || d, placeholder: f.placeholder, mask: d }) } b.matches.splice(e++, 0, { fn: f.validator ? "string" == typeof f.validator ? new RegExp(f.validator) : new function () { this.test = f.validator } : new RegExp("."), cardinality: f.cardinality, optionality: b.isOptional, newBlockMarker: g, casing: f.casing, def: f.definitionSymbol || d, placeholder: f.placeholder, mask: d }) } else b.matches.splice(e++, 0, { fn: null, cardinality: 0, optionality: b.isOptional, newBlockMarker: g, casing: null, def: d, placeholder: void 0, mask: d }), o = !1 } function f(a) { a.isGroup && (a.isGroup = !1, e(a, c.groupmarker.start, 0), e(a, c.groupmarker.end)) } function g(a, b, c, d) { b.matches.length > 0 && (void 0 == d || d) && (c = b.matches[b.matches.length - 1], f(c)), e(b, a) } for (var h, i, j, k, l, m, n = /(?:[?*+]|\{[0-9\+\*]+(?:,[0-9\+\*]*)?\})\??|[^.?*+^${[]()|\\]+|./g, o = !1, p = new d, q = [], r = []; h = n.exec(b) ;) if (i = h[0], o) g(i, p, m); else switch (i.charAt(0)) { case c.escapeChar: o = !0; break; case c.optionalmarker.end: case c.groupmarker.end: if (j = q.pop(), q.length > 0) { if (k = q[q.length - 1], k.matches.push(j), k.isAlternator) { l = q.pop(); for (var s = 0; s < l.matches.length; s++) l.matches[s].isGroup = !1; q.length > 0 ? (k = q[q.length - 1], k.matches.push(l)) : p.matches.push(l) } } else p.matches.push(j); break; case c.optionalmarker.start: q.push(new d(!1, !0)); break; case c.groupmarker.start: q.push(new d(!0)); break; case c.quantifiermarker.start: var t = new d(!1, !1, !0); i = i.replace(/[{}]/g, ""); var u = i.split(","), v = isNaN(u[0]) ? u[0] : parseInt(u[0]), w = 1 == u.length ? v : isNaN(u[1]) ? u[1] : parseInt(u[1]); if (("*" == w || "+" == w) && (v = "*" == w ? 0 : 1), t.quantifier = { min: v, max: w }, q.length > 0) { var x = q[q.length - 1].matches; if (h = x.pop(), !h.isGroup) { var y = new d(!0); y.matches.push(h), h = y } x.push(h), x.push(t) } else { if (h = p.matches.pop(), !h.isGroup) { var y = new d(!0); y.matches.push(h), h = y } p.matches.push(h), p.matches.push(t) } break; case c.alternatormarker: q.length > 0 ? (k = q[q.length - 1], m = k.matches.pop()) : m = p.matches.pop(), m.isAlternator ? q.push(m) : (l = new d(!1, !1, !1, !0), l.matches.push(m), q.push(l)); break; default: if (q.length > 0) { if (k = q[q.length - 1], g(i, k, m, !k.isAlternator), k.isAlternator) { l = q.pop(); for (var s = 0; s < l.matches.length; s++) l.matches[s].isGroup = !1; q.length > 0 ? (k = q[q.length - 1], k.matches.push(l)) : p.matches.push(l) } } else g(i, p, m) } return p.matches.length > 0 && (m = p.matches[p.matches.length - 1], f(m), r.push(p)), r } function f(f, g) { if (void 0 == f || "" == f) return void 0; if (1 == f.length && 0 == c.greedy && 0 != c.repeat && (c.placeholder = ""), c.repeat > 0 || "*" == c.repeat || "+" == c.repeat) { var h = "*" == c.repeat ? 0 : "+" == c.repeat ? 1 : c.repeat; f = c.groupmarker.start + f + c.groupmarker.end + c.quantifiermarker.start + h + "," + c.repeat + c.quantifiermarker.end } var i; return void 0 == b.prototype.masksCache[f] || d === !0 ? (i = { mask: f, maskToken: e(f), validPositions: {}, _buffer: void 0, buffer: void 0, tests: {}, metadata: g }, d !== !0 && (b.prototype.masksCache[f] = i)) : i = a.extend(!0, {}, b.prototype.masksCache[f]), i } function g(a) { if (a = a.toString(), c.numericInput) { a = a.split("").reverse(); for (var b = 0; b < a.length; b++) a[b] == c.optionalmarker.start ? a[b] = c.optionalmarker.end : a[b] == c.optionalmarker.end ? a[b] = c.optionalmarker.start : a[b] == c.groupmarker.start ? a[b] = c.groupmarker.end : a[b] == c.groupmarker.end && (a[b] = c.groupmarker.start); a = a.join("") } return a } var h = void 0; if (a.isFunction(c.mask) && (c.mask = c.mask.call(this, c)), a.isArray(c.mask)) { if (c.mask.length > 1) { c.keepStatic = void 0 == c.keepStatic ? !0 : c.keepStatic; var i = "("; return a.each(c.mask, function (b, c) { i.length > 1 && (i += ")|("), i += g(void 0 == c.mask || a.isFunction(c.mask) ? c : c.mask) }), i += ")", f(i, c.mask) } c.mask = c.mask.pop() } return c.mask && (h = void 0 == c.mask.mask || a.isFunction(c.mask.mask) ? f(g(c.mask), c.mask) : f(g(c.mask.mask), c.mask)), h } function h(e, f, g) {
        function h(a, b, c) { b = b || 0; var d, e, f, g = [], h = 0; do { if (a === !0 && i().validPositions[h]) { var j = i().validPositions[h]; e = j.match, d = j.locator.slice(), g.push(c === !0 ? j.input : H(h, e)) } else f = r(h, d, h - 1), e = f.match, d = f.locator.slice(), g.push(H(h, e)); h++ } while ((void 0 == da || da > h - 1) && null != e.fn || null == e.fn && "" != e.def || b >= h); return g.pop(), g } function i() { return f } function n(a) { var b = i(); b.buffer = void 0, b.tests = {}, a !== !0 && (b._buffer = void 0, b.validPositions = {}, b.p = 0) } function o(a, b) { var c = i(), d = -1, e = c.validPositions; void 0 == a && (a = -1); var f = d, g = d; for (var h in e) { var j = parseInt(h); e[j] && (b || null != e[j].match.fn) && (a >= j && (f = j), j >= a && (g = j)) } return d = -1 != f && a - f > 1 || a > g ? f : g } function p(b, c, d) { if (g.insertMode && void 0 != i().validPositions[b] && void 0 == d) { var e, f = a.extend(!0, {}, i().validPositions), h = o(); for (e = b; h >= e; e++) delete i().validPositions[e]; i().validPositions[b] = c; var j, k = !0, l = i().validPositions; for (e = j = b; h >= e; e++) { var m = f[e]; if (void 0 != m) for (var n = j, p = -1; n < C() && (null == m.match.fn && l[e] && (l[e].match.optionalQuantifier === !0 || l[e].match.optionality === !0) || null != m.match.fn) ;) { if (null == m.match.fn || !g.keepStatic && l[e] && (void 0 != l[e + 1] && u(e + 1, l[e].locator.slice(), e).length > 1 || void 0 != l[e].alternation) ? n++ : n = D(j), t(n, m.match.def)) { k = A(n, m.input, !0, !0) !== !1, j = n; break } if (k = null == m.match.fn, p == n) break; p = n } if (!k) break } if (!k) return i().validPositions = a.extend(!0, {}, f), !1 } else i().validPositions[b] = c; return !0 } function q(a, b, c, d) { var e, f = a; i().p = a; for (e = f; b > e; e++) void 0 != i().validPositions[e] && (c === !0 || 0 != g.canClearPosition(i(), e, o(), d, g)) && delete i().validPositions[e]; for (n(!0), e = f + 1; e <= o() ;) { for (; void 0 != i().validPositions[f];) f++; var h = i().validPositions[f]; f > e && (e = f + 1); var j = i().validPositions[e]; void 0 != j && void 0 == h ? (t(f, j.match.def) && A(f, j.input, !0) !== !1 && (delete i().validPositions[e], e++), f++) : e++ } var k = o(), l = C(); for (c !== !0 && void 0 != i().validPositions[k] && i().validPositions[k].input == g.radixPoint && delete i().validPositions[k], e = k + 1; l >= e; e++) i().validPositions[e] && delete i().validPositions[e]; n(!0) } function r(a, b, c) { var d = i().validPositions[a]; if (void 0 == d) for (var e = u(a, b, c), f = o(), h = i().validPositions[f] || u(0)[0], j = void 0 != h.alternation ? h.locator[h.alternation].toString().split(",") : [], k = 0; k < e.length && (d = e[k], !(d.match && (g.greedy && d.match.optionalQuantifier !== !0 || (d.match.optionality === !1 || d.match.newBlockMarker === !1) && d.match.optionalQuantifier !== !0) && (void 0 == h.alternation || h.alternation != d.alternation || void 0 != d.locator[h.alternation] && z(d.locator[h.alternation].toString().split(","), j)))) ; k++); return d } function s(a) { return i().validPositions[a] ? i().validPositions[a].match : u(a)[0].match } function t(a, b) { for (var c = !1, d = u(a), e = 0; e < d.length; e++) if (d[e].match && d[e].match.def == b) { c = !0; break } return c } function u(b, c, d, e) { function f(c, d, e, g) { function j(e, g, n) { if (h > 1e4) return alert("jquery.inputmask: There is probably an error in your mask definition or in the code. Create an issue on github with an example of the mask you are using. " + i().mask), !0; if (h == b && void 0 == e.matches) return k.push({ match: e, locator: g.reverse() }), !0; if (void 0 != e.matches) { if (e.isGroup && n !== !0) { if (e = j(c.matches[m + 1], g)) return !0 } else if (e.isOptional) { var o = e; if (e = f(e, d, g, n)) { var p = k[k.length - 1].match, q = 0 == a.inArray(p, o.matches); if (!q) return !0; l = !0, h = b } } else if (e.isAlternator) { var r, s = e, t = [], u = k.slice(), v = g.length, w = d.length > 0 ? d.shift() : -1; if (-1 == w || "string" == typeof w) { var x = h, y = d.slice(), z = []; "string" == typeof w && (z = w.split(",")); for (var A = 0; A < s.matches.length; A++) { if (k = [], e = j(s.matches[A], [A].concat(g), n) || e, e !== !0 && void 0 != e && z[z.length - 1] < s.matches.length) { var B = c.matches.indexOf(e) + 1; c.matches.length > B && (e = j(c.matches[B], [B].concat(g.slice(1, g.length)), n), e && (z.push(B.toString()), a.each(k, function (a, b) { b.alternation = g.length - 1 }))) } r = k.slice(), h = x, k = []; for (var C = 0; C < y.length; C++) d[C] = y[C]; for (var D = 0; D < r.length; D++) { var E = r[D]; E.alternation = E.alternation || v; for (var F = 0; F < t.length; F++) { var G = t[F]; if (E.match.mask == G.match.mask && ("string" != typeof w || -1 != a.inArray(E.locator[E.alternation].toString(), z))) { r.splice(D, 1), D--, G.locator[E.alternation] = G.locator[E.alternation] + "," + E.locator[E.alternation], G.alternation = E.alternation; break } } } t = t.concat(r) } "string" == typeof w && (t = a.map(t, function (b, c) { if (isFinite(c)) { var d, e = b.alternation, f = b.locator[e].toString().split(","); b.locator[e] = void 0, b.alternation = void 0; for (var g = 0; g < f.length; g++) d = -1 != a.inArray(f[g], z), d && (void 0 != b.locator[e] ? (b.locator[e] += ",", b.locator[e] += f[g]) : b.locator[e] = parseInt(f[g]), b.alternation = e); if (void 0 != b.locator[e]) return b } })), k = u.concat(t), h = b, l = k.length > 0 } else e = s.matches[w] ? j(s.matches[w], [w].concat(g), n) : !1; if (e) return !0 } else if (e.isQuantifier && n !== !0) for (var H = e, I = d.length > 0 && n !== !0 ? d.shift() : 0; I < (isNaN(H.quantifier.max) ? I + 1 : H.quantifier.max) && b >= h; I++) { var J = c.matches[a.inArray(H, c.matches) - 1]; if (e = j(J, [I].concat(g), !0)) { var p = k[k.length - 1].match; p.optionalQuantifier = I > H.quantifier.min - 1; var q = 0 == a.inArray(p, J.matches); if (q) { if (I > H.quantifier.min - 1) { l = !0, h = b; break } return !0 } return !0 } } else if (e = f(e, d, g, n)) return !0 } else h++ } for (var m = d.length > 0 ? d.shift() : 0; m < c.matches.length; m++) if (c.matches[m].isQuantifier !== !0) { var n = j(c.matches[m], [m].concat(e), g); if (n && h == b) return n; if (h > b) break } } var g = i().maskToken, h = c ? d : 0, j = c || [0], k = [], l = !1; if (e === !0 && i().tests[b]) return i().tests[b]; if (void 0 == c) { for (var m, n = b - 1; void 0 == (m = i().validPositions[n]) && n > -1 && (!i().tests[n] || void 0 == (m = i().tests[n][0])) ;) n--; void 0 != m && n > -1 && (h = n, j = m.locator.slice()) } for (var o = j.shift() ; o < g.length; o++) { var p = f(g[o], j, [o]); if (p && h == b || h > b) break } return (0 == k.length || l) && k.push({ match: { fn: null, cardinality: 0, optionality: !0, casing: null, def: "" }, locator: [] }), i().tests[b] = a.extend(!0, [], k), i().tests[b] } function v() { return void 0 == i()._buffer && (i()._buffer = h(!1, 1)), i()._buffer } function w() { return void 0 == i().buffer && (i().buffer = h(!0, o(), !0)), i().buffer } function x(a, b, c) { if (c = c || w().slice(), a === !0) n(), a = 0, b = c.length; else for (var d = a; b > d; d++) delete i().validPositions[d], delete i().tests[d]; for (var d = a; b > d; d++) c[d] != g.skipOptionalPartCharacter && A(d, c[d], !0, !0) } function y(a, b) { switch (b.casing) { case "upper": a = a.toUpperCase(); break; case "lower": a = a.toLowerCase() } return a } function z(b, c) { for (var d = g.greedy ? c : c.slice(0, 1), e = !1, f = 0; f < b.length; f++) if (-1 != a.inArray(b[f], d)) { e = !0; break } return e } function A(b, c, d, e) { function f(b, c, d, e) { var f = !1; return a.each(u(b), function (h, j) { for (var k = j.match, l = c ? 1 : 0, m = "", r = (w(), k.cardinality) ; r > l; r--) m += F(b - (r - 1)); if (c && (m += c), f = null != k.fn ? k.fn.test(m, i(), b, d, g) : c != k.def && c != g.skipOptionalPartCharacter || "" == k.def ? !1 : { c: k.def, pos: b }, f !== !1) { var s = void 0 != f.c ? f.c : c; s = s == g.skipOptionalPartCharacter && null === k.fn ? k.def : s; var t = b, u = w(); if (void 0 != f.remove && (a.isArray(f.remove) || (f.remove = [f.remove]), a.each(f.remove.sort(function (a, b) { return b - a }), function (a, b) { q(b, b + 1, !0) })), void 0 != f.insert && (a.isArray(f.insert) || (f.insert = [f.insert]), a.each(f.insert.sort(function (a, b) { return a - b }), function (a, b) { A(b.pos, b.c, !0) })), f.refreshFromBuffer) { var v = f.refreshFromBuffer; if (d = !0, x(v === !0 ? v : v.start, v.end, u), void 0 == f.pos && void 0 == f.c) return f.pos = o(), !1; if (t = void 0 != f.pos ? f.pos : b, t != b) return f = a.extend(f, A(t, s, !0)), !1 } else if (f !== !0 && void 0 != f.pos && f.pos != b && (t = f.pos, x(b, t), t != b)) return f = a.extend(f, A(t, s, !0)), !1; return 1 != f && void 0 == f.pos && void 0 == f.c ? !1 : (h > 0 && n(!0), p(t, a.extend({}, j, { input: y(s, k) }), e) || (f = !1), !1) } }), f } function h(b, c, d, e) { for (var f, h, j, k, l = a.extend(!0, {}, i().validPositions), m = o() ; m >= 0 && (k = i().validPositions[m], !k || void 0 == k.alternation || (f = m, h = i().validPositions[f].alternation, r(f).locator[k.alternation] == k.locator[k.alternation])) ; m--); if (void 0 != h) { f = parseInt(f); for (var p in i().validPositions) if (p = parseInt(p), k = i().validPositions[p], p >= f && void 0 != k.alternation) { var q = i().validPositions[f].locator[h].toString().split(","), s = k.locator[h] || q[0]; s.length > 0 && (s = s.split(",")[0]); for (var t = 0; t < q.length; t++) if (s < q[t]) { for (var u, v, w = p; w >= 0; w--) if (u = i().validPositions[w], void 0 != u) { v = u.locator[h], u.locator[h] = parseInt(q[t]); break } if (s != u.locator[h]) { for (var x = [], y = 0, z = p + 1; z < o() + 1; z++) { var B = i().validPositions[z]; B && (null != B.match.fn ? x.push(B.input) : b > z && y++), delete i().validPositions[z], delete i().tests[z] } for (n(!0), g.keepStatic = !g.keepStatic, j = !0; x.length > 0;) { var C = x.shift(); if (C != g.skipOptionalPartCharacter && !(j = A(o() + 1, C, !1, !0))) break } if (u.alternation = h, u.locator[h] = v, j) { for (var D = o(b) + 1, E = 0, z = p + 1; z < o() + 1; z++) { var B = i().validPositions[z]; B && null == B.match.fn && b > z && E++ } b += E - y, j = A(b > D ? D : b, c, d, e) } if (g.keepStatic = !g.keepStatic, j) return j; n(), i().validPositions = a.extend(!0, {}, l) } } break } } return !1 } function j(b, c) { for (var d = i().validPositions[c], e = d.locator, f = e.length, g = b; c > g; g++) if (!B(g)) { var h = u(g), j = h[0], k = -1; a.each(h, function (a, b) { for (var c = 0; f > c; c++) b.locator[c] && z(b.locator[c].toString().split(","), e[c].toString().split(",")) && c > k && (k = c, j = b) }), p(g, a.extend({}, j, { input: j.match.def }), !0) } } d = d === !0; for (var k = w(), l = b - 1; l > -1 && !i().validPositions[l]; l--); for (l++; b > l; l++) void 0 == i().validPositions[l] && ((!B(l) || k[l] != H(l)) && u(l).length > 1 || k[l] == g.radixPoint || "0" == k[l] && a.inArray(g.radixPoint, k) < l) && f(l, k[l], !0); var m = b, s = !1, t = a.extend(!0, {}, i().validPositions); if (m < C() && (s = f(m, c, d, e), (!d || e) && s === !1)) { var v = i().validPositions[m]; if (!v || null != v.match.fn || v.match.def != c && c != g.skipOptionalPartCharacter) { if ((g.insertMode || void 0 == i().validPositions[D(m)]) && !B(m)) for (var E = m + 1, G = D(m) ; G >= E; E++) if (s = f(E, c, d, e), s !== !1) { j(m, E), m = E; break } } else s = { caret: D(m) } } if (s === !1 && g.keepStatic && N(k) && (s = h(b, c, d, e)), s === !0 && (s = { pos: m }), a.isFunction(g.postValidation) && 0 != s && !d) { n(!0); var I = g.postValidation(w(), g); if (!I) return n(!0), i().validPositions = a.extend(!0, {}, t), !1 } return s } function B(a) { var b = s(a); if (null != b.fn) return b.fn; if (!g.keepStatic && void 0 == i().validPositions[a]) { for (var c = u(a), d = !0, e = 0; e < c.length; e++) if ("" != c[e].match.def && (void 0 == c[e].alternation || c[e].locator[c[e].alternation].length > 1)) { d = !1; break } return d } return !1 } function C() { var a; da = ca.prop("maxLength"), -1 == da && (da = void 0); var b, c = o(), d = i().validPositions[c], e = void 0 != d ? d.locator.slice() : void 0; for (b = c + 1; void 0 == d || null != d.match.fn || null == d.match.fn && "" != d.match.def; b++) d = r(b, e, b - 1), e = d.locator.slice(); var f = s(b - 1); return a = "" != f.def ? b : b - 1, void 0 == da || da > a ? a : da } function D(a) { var b = C(); if (a >= b) return b; for (var c = a; ++c < b && !B(c) && (g.nojumps !== !0 || g.nojumpsThreshold > c) ;); return c } function E(a) { var b = a; if (0 >= b) return 0; for (; --b > 0 && !B(b) ;); return b } function F(a) { return void 0 == i().validPositions[a] ? H(a) : i().validPositions[a].input } function G(b, c, d, e, f) { if (e && a.isFunction(g.onBeforeWrite)) { var h = g.onBeforeWrite.call(b, e, c, d, g); if (h) { if (h.refreshFromBuffer) { var i = h.refreshFromBuffer; x(i === !0 ? i : i.start, i.end, h.buffer), n(!0), c = w() } d = h.caret || d } } b._valueSet(c.join("")), void 0 != d && K(b, d), f === !0 && (ga = !0, a(b).trigger("input")) } function H(a, b) { if (b = b || s(a), void 0 != b.placeholder) return b.placeholder; if (null == b.fn) { if (!g.keepStatic && void 0 == i().validPositions[a]) { for (var c, d = u(a), e = !1, f = 0; f < d.length; f++) { if (c && "" != d[f].match.def && d[f].match.def != c.match.def && (void 0 == d[f].alternation || d[f].alternation == c.alternation)) { e = !0; break } 1 != d[f].match.optionality && 1 != d[f].match.optionalQuantifier && (c = d[f]) } if (e) return g.placeholder.charAt(a % g.placeholder.length) } return b.def } return g.placeholder.charAt(a % g.placeholder.length) } function I(c, d, e, f) { function h() { var a = !1, b = v().slice(l, D(l)).join("").indexOf(k); if (-1 != b && !B(l)) { a = !0; for (var c = v().slice(l, l + b), d = 0; d < c.length; d++) if (" " != c[d]) { a = !1; break } } return a } var j = void 0 != f ? f.slice() : c._valueGet().split(""), k = "", l = 0; if (n(), i().p = D(-1), d && c._valueSet(""), !e) if (1 != g.autoUnmask) { var m = v().slice(0, D(-1)).join(""), p = j.join("").match(new RegExp("^" + b.escapeRegex(m), "g")); p && p.length > 0 && (j.splice(0, p.length * m.length), l = D(l)) } else l = D(l); a.each(j, function (b, d) { var f = a.Event("keypress"); f.which = d.charCodeAt(0), k += d; var j = o(void 0, !0), m = i().validPositions[j], n = r(j + 1, m ? m.locator.slice() : void 0, j); if (!h() || e || g.autoUnmask) { var p = e ? b : null == n.match.fn && n.match.optionality && j + 1 < i().p ? j + 1 : i().p; T.call(c, f, !0, !1, e, p), l = p + 1, k = "" } else T.call(c, f, !0, !1, !0, j + 1) }), d && G(c, w(), a(c).is(":focus") ? D(o(0)) : void 0, a.Event("checkval")) } function J(b) { if (b[0].inputmask && !b.hasClass("hasDatepicker")) { var c = [], d = i().validPositions; for (var e in d) d[e].match && null != d[e].match.fn && c.push(d[e].input); var f = (ea ? c.reverse() : c).join(""), h = (ea ? w().slice().reverse() : w()).join(""); return a.isFunction(g.onUnMask) && (f = g.onUnMask.call(b, h, f, g) || f), f } return b[0]._valueGet() } function K(b, c, d) { function e(a) { if (ea && "number" == typeof a && (!g.greedy || "" != g.placeholder)) { var b = w().length; a = b - a } return a } var f, h = b.jquery && b.length > 0 ? b[0] : b; if ("number" != typeof c) return h.setSelectionRange ? (c = h.selectionStart, d = h.selectionEnd) : window.getSelection ? (f = window.getSelection().getRangeAt(0), (f.commonAncestorContainer.parentNode == h || f.commonAncestorContainer == h) && (c = f.startOffset, d = f.endOffset)) : document.selection && document.selection.createRange && (f = document.selection.createRange(), c = 0 - f.duplicate().moveStart("character", -1e5), d = c + f.text.length), { begin: e(c), end: e(d) }; if (c = e(c), d = e(d), d = "number" == typeof d ? d : c, a(h).is(":visible")) { var i = a(h).css("font-size").replace("px", "") * d; if (h.scrollLeft = i > h.scrollWidth ? i : 0, k || 0 != g.insertMode || c != d || d++, h.setSelectionRange) h.selectionStart = c, h.selectionEnd = d; else if (window.getSelection) { if (f = document.createRange(), void 0 == h.firstChild) { var j = document.createTextNode(""); h.appendChild(j) } f.setStart(h.firstChild, c < h._valueGet().length ? c : h._valueGet().length), f.setEnd(h.firstChild, d < h._valueGet().length ? d : h._valueGet().length), f.collapse(!0); var l = window.getSelection(); l.removeAllRanges(), l.addRange(f) } else h.createTextRange && (f = h.createTextRange(), f.collapse(!0), f.moveEnd("character", d), f.moveStart("character", c), f.select()) } } function L(b) { var c, d, e = w(), f = e.length, g = o(), h = {}, j = i().validPositions[g], k = void 0 != j ? j.locator.slice() : void 0; for (c = g + 1; c < e.length; c++) d = r(c, k, c - 1), k = d.locator.slice(), h[c] = a.extend(!0, {}, d); var l = j && void 0 != j.alternation ? j.locator[j.alternation] : void 0; for (c = f - 1; c > g && (d = h[c], (d.match.optionality || d.match.optionalQuantifier || l && (l != h[c].locator[j.alternation] && null != d.match.fn || null == d.match.fn && d.locator[j.alternation] && z(d.locator[j.alternation].toString().split(","), l.split(",")) && "" != u(c)[0].def)) && e[c] == H(c, d.match)) ; c--) f--; return b ? { l: f, def: h[f] ? h[f].match : void 0 } : f } function M(a) { for (var b = L(), c = a.length - 1; c > b && !B(c) ; c--); return a.splice(b, c + 1 - b), a } function N(b) { if (a.isFunction(g.isComplete)) return g.isComplete.call(ca, b, g); if ("*" == g.repeat) return void 0; var c = !1, d = L(!0), e = E(d.l); o(); if (void 0 == d.def || d.def.newBlockMarker || d.def.optionality || d.def.optionalQuantifier) { c = !0; for (var f = 0; e >= f; f++) { var h = r(f).match; if (null != h.fn && void 0 == i().validPositions[f] && h.optionality !== !0 && h.optionalQuantifier !== !0 || null == h.fn && b[f] != H(f, h)) { c = !1; break } } } return c } function O(a, b) { return ea ? a - b > 1 || a - b == 1 && g.insertMode : b - a > 1 || b - a == 1 && g.insertMode } function P(c) { var d = a._data(c).events, e = !1; a.each(d, function (c, d) { a.each(d, function (a, c) { if ("inputmask" == c.namespace && "setvalue" != c.type) { var d = c.handler; c.handler = function (a) { if (!(this.disabled || this.readOnly && !("keydown" == a.type && a.ctrlKey && 67 == a.keyCode || a.keyCode == b.keyCode.TAB))) { switch (a.type) { case "input": if (ga === !0 || e === !0) return ga = !1, a.preventDefault(); break; case "keydown": fa = !1, e = !1; break; case "keypress": if (fa === !0) return a.preventDefault(); fa = !0; break; case "compositionstart": e = !0; break; case "compositionupdate": ga = !0; break; case "compositionend": e = !1 } return d.apply(this, arguments) } a.preventDefault() } } }) }) } function Q(b) {
            function c(b) { if (void 0 == a.valHooks[b] || 1 != a.valHooks[b].inputmaskpatch) { var c = a.valHooks[b] && a.valHooks[b].get ? a.valHooks[b].get : function (a) { return a.value }, d = a.valHooks[b] && a.valHooks[b].set ? a.valHooks[b].set : function (a, b) { return a.value = b, a }; a.valHooks[b] = { get: function (b) { a(b); if (b.inputmask) { if (b.inputmask.opts.autoUnmask) return b.inputmask.unmaskedvalue(); var d = c(b), e = b.inputmask.maskset, f = e._buffer; return f = f ? f.join("") : "", d != f ? d : "" } return c(b) }, set: function (b, c) { var e, f = a(b); return e = d(b, c), b.inputmask && f.triggerHandler("setvalue.inputmask"), e }, inputmaskpatch: !0 } } } function d() { a(this); return this.inputmask ? this.inputmask.opts.autoUnmask ? this.inputmask.unmaskedvalue() : g.call(this) != v().join("") ? g.call(this) : "" : g.call(this) } function e(b) { h.call(this, b), this.inputmask && a(this).triggerHandler("setvalue.inputmask") } function f(b) {
                a(b).bind("mouseenter.inputmask", function (b) { var c = a(this), d = this, e = d._valueGet(); "" != e && e != w().join("") && c.triggerHandler("setvalue.inputmask") });
                //!! the bound handlers are executed in the order they where bound
                var c = a._data(b).events, d = c.mouseover; if (d) { for (var e = d[d.length - 1], f = d.length - 1; f > 0; f--) d[f] = d[f - 1]; d[0] = e }
            } var g, h; if (!b._valueGet) { var i; Object.getOwnPropertyDescriptor && void 0 == b.value ? (g = function () { return this.textContent }, h = function (a) { this.textContent = a }, Object.defineProperty(b, "value", { get: d, set: e })) : ((i = Object.getOwnPropertyDescriptor && Object.getOwnPropertyDescriptor(b, "value")) && i.configurable, document.__lookupGetter__ && b.__lookupGetter__("value") ? (g = b.__lookupGetter__("value"), h = b.__lookupSetter__("value"), b.__defineGetter__("value", d), b.__defineSetter__("value", e)) : (g = function () { return b.value }, h = function (a) { b.value = a }, c(b.type), f(b))), b._valueGet = function (a) { return ea && a !== !0 ? g.call(this).split("").reverse().join("") : g.call(this) }, b._valueSet = function (a) { h.call(this, ea ? a.split("").reverse().join("") : a) } }
        } function R(c, d, e, f) { function h() { if (g.keepStatic) { n(!0); var b, d = [], e = a.extend(!0, {}, i().validPositions); for (b = o() ; b >= 0; b--) { var f = i().validPositions[b]; if (f && (null != f.match.fn && d.push(f.input), delete i().validPositions[b], void 0 != f.alternation && f.locator[f.alternation] == r(b).locator[f.alternation])) break } if (b > -1) for (; d.length > 0;) { i().p = D(o()); var h = a.Event("keypress"); h.which = d.pop().charCodeAt(0), T.call(c, h, !0, !1, !1, i().p) } else i().validPositions = a.extend(!0, {}, e) } } if ((g.numericInput || ea) && (d == b.keyCode.BACKSPACE ? d = b.keyCode.DELETE : d == b.keyCode.DELETE && (d = b.keyCode.BACKSPACE), ea)) { var j = e.end; e.end = e.begin, e.begin = j } if (d == b.keyCode.BACKSPACE && (e.end - e.begin < 1 || 0 == g.insertMode) ? (e.begin = E(e.begin), void 0 == i().validPositions[e.begin] || i().validPositions[e.begin].input != g.groupSeparator && i().validPositions[e.begin].input != g.radixPoint || e.begin--) : d == b.keyCode.DELETE && e.begin == e.end && (e.end = B(e.end) ? e.end + 1 : D(e.end) + 1, void 0 == i().validPositions[e.begin] || i().validPositions[e.begin].input != g.groupSeparator && i().validPositions[e.begin].input != g.radixPoint || e.end++), q(e.begin, e.end, !1, f), f !== !0) { h(); var k = o(e.begin); k < e.begin ? (-1 == k && n(), i().p = D(k)) : i().p = e.begin } } function S(d) { var e = this, f = a(e), h = d.keyCode, k = K(e); h == b.keyCode.BACKSPACE || h == b.keyCode.DELETE || j && 127 == h || d.ctrlKey && 88 == h && !c("cut") ? (d.preventDefault(), 88 == h && ($ = w().join("")), R(e, h, k), G(e, w(), i().p, d, $ != w().join("")), e._valueGet() == v().join("") ? f.trigger("cleared") : N(w()) === !0 && f.trigger("complete"), g.showTooltip && f.prop("title", i().mask)) : h == b.keyCode.END || h == b.keyCode.PAGE_DOWN ? setTimeout(function () { var a = D(o()); g.insertMode || a != C() || d.shiftKey || a--, K(e, d.shiftKey ? k.begin : a, a) }, 0) : h == b.keyCode.HOME && !d.shiftKey || h == b.keyCode.PAGE_UP ? K(e, 0, d.shiftKey ? k.begin : 0) : (g.undoOnEscape && h == b.keyCode.ESCAPE || 90 == h && d.ctrlKey) && d.altKey !== !0 ? (I(e, !0, !1, $.split("")), f.click()) : h != b.keyCode.INSERT || d.shiftKey || d.ctrlKey ? 0 != g.insertMode || d.shiftKey || (h == b.keyCode.RIGHT ? setTimeout(function () { var a = K(e); K(e, a.begin) }, 0) : h == b.keyCode.LEFT && setTimeout(function () { var a = K(e); K(e, ea ? a.begin + 1 : a.begin - 1) }, 0)) : (g.insertMode = !g.insertMode, K(e, g.insertMode || k.begin != C() ? k.begin : k.begin - 1)), g.onKeyDown.call(this, d, w(), K(e).begin, g), ha = -1 != a.inArray(h, g.ignorables) } function T(c, d, e, f, h) { var j = this, k = a(j), l = c.which || c.charCode || c.keyCode; if (!(d === !0 || c.ctrlKey && c.altKey) && (c.ctrlKey || c.metaKey || ha)) return !0; if (l) { 46 == l && 0 == c.shiftKey && "," == g.radixPoint && (l = 44); var m, o = d ? { begin: h, end: h } : K(j), q = String.fromCharCode(l), r = O(o.begin, o.end); r && (i().undoPositions = a.extend(!0, {}, i().validPositions), R(j, b.keyCode.DELETE, o, !0), o.begin = i().p, g.insertMode || (g.insertMode = !g.insertMode, p(o.begin, f), g.insertMode = !g.insertMode), r = !g.multi), i().writeOutBuffer = !0; var s = ea && !r ? o.end : o.begin, t = A(s, q, f); if (t !== !1) { if (t !== !0 && (s = void 0 != t.pos ? t.pos : s, q = void 0 != t.c ? t.c : q), n(!0), void 0 != t.caret) m = t.caret; else { var v = i().validPositions; m = !g.keepStatic && (void 0 != v[s + 1] && u(s + 1, v[s].locator.slice(), s).length > 1 || void 0 != v[s].alternation) ? s + 1 : D(s) } i().p = m } if (e !== !1) { var y = this; if (setTimeout(function () { g.onKeyValidation.call(y, t, g) }, 0), i().writeOutBuffer && t !== !1) { var z = w(); G(j, z, d ? void 0 : g.numericInput ? E(m) : m, c, d !== !0), d !== !0 && setTimeout(function () { N(z) === !0 && k.trigger("complete") }, 0) } else r && (i().buffer = void 0, i().validPositions = i().undoPositions) } else r && (i().buffer = void 0, i().validPositions = i().undoPositions); if (g.showTooltip && k.prop("title", i().mask), d && a.isFunction(g.onBeforeWrite)) { var B = g.onBeforeWrite.call(this, c, w(), m, g); if (B && B.refreshFromBuffer) { var C = B.refreshFromBuffer; x(C === !0 ? C : C.start, C.end, B.buffer), n(!0), B.caret && (i().p = B.caret) } } c.preventDefault() } } function U(b) { var c = this, d = a(c), e = c._valueGet(!0), f = K(c); if ("propertychange" == b.type && c._valueGet().length <= C()) return !0; if ("paste" == b.type) { var h = e.substr(0, f.begin), i = e.substr(f.end, e.length); h == v().slice(0, f.begin).join("") && (h = ""), i == v().slice(f.end).join("") && (i = ""), window.clipboardData && window.clipboardData.getData ? e = h + window.clipboardData.getData("Text") + i : b.originalEvent && b.originalEvent.clipboardData && b.originalEvent.clipboardData.getData && (e = h + b.originalEvent.clipboardData.getData("text/plain") + i) } var j = e; if (a.isFunction(g.onBeforePaste)) { if (j = g.onBeforePaste.call(c, e, g), j === !1) return b.preventDefault(), !1; j || (j = e) } return I(c, !1, !1, ea ? j.split("").reverse() : j.split("")), G(c, w(), void 0, b, !0), d.click(), N(w()) === !0 && d.trigger("complete"), !1 } function V(b) { var c = this; I(c, !0, !1), N(w()) === !0 && a(c).trigger("complete"), b.preventDefault() } function W(a) { var b = this; $ = w().join(""), ("" == aa || 0 != a.originalEvent.data.indexOf(aa)) && (_ = K(b)) } function X(b) { var c = this, d = K(c); 0 == b.originalEvent.data.indexOf(aa) && (n(), d = _); var e = b.originalEvent.data; K(c, d.begin, d.end); for (var f = 0; f < e.length; f++) { var h = a.Event("keypress"); h.which = e.charCodeAt(f), fa = !1, ha = !1, T.call(c, h) } setTimeout(function () { var a = i().p; G(c, w(), g.numericInput ? E(a) : a) }, 0), aa = b.originalEvent.data } function Y(a) { } function Z(c) { ca = a(c), g.showTooltip && ca.prop("title", i().mask), ("rtl" == c.dir || g.rightAlign) && ca.css("text-align", "right"), ("rtl" == c.dir || g.numericInput) && (c.dir = "ltr", ca.removeAttr("dir"), c.inputmask.isRTL = !0, ea = !0), ca.unbind(".inputmask"), (ca.is(":input") && d(ca.attr("type")) || c.isContentEditable) && (ca.closest("form").bind("submit", function (a) { $ != w().join("") && ca.change(), g.clearMaskOnLostFocus && ca[0]._valueGet && ca[0]._valueGet() == v().join("") && ca[0]._valueSet(""), g.removeMaskOnSubmit && ca.inputmask("remove") }).bind("reset", function () { setTimeout(function () { ca.triggerHandler("setvalue.inputmask") }, 0) }), ca.bind("mouseenter.inputmask", function () { var b = a(this), c = this; ja = !0, !b.is(":focus") && g.showMaskOnHover && c._valueGet() != w().join("") && G(c, w()) }).bind("blur.inputmask", function (b) { var c = a(this), d = this; if (d.inputmask) { var e = d._valueGet(), f = w().slice(); ia = !0, $ != f.join("") && setTimeout(function () { c.change(), $ = f.join("") }, 0), "" != e && (g.clearMaskOnLostFocus && (e == v().join("") ? f = [] : M(f)), N(f) === !1 && (setTimeout(function () { c.trigger("incomplete") }, 0), g.clearIncomplete && (n(), f = g.clearMaskOnLostFocus ? [] : v().slice())), G(d, f, void 0, b)) } }).bind("focus.inputmask", function (b) { var c = (a(this), this), d = c._valueGet(); g.showMaskOnFocus && (!g.showMaskOnHover || g.showMaskOnHover && "" == d) ? c._valueGet() != w().join("") && G(c, w(), D(o())) : ja === !1 && K(c, D(o())), $ = w().join("") }).bind("mouseleave.inputmask", function () { var b = a(this), c = this; if (ja = !1, g.clearMaskOnLostFocus) { var d = w().slice(), e = c._valueGet(); b.is(":focus") || e == b.attr("placeholder") || "" == e || (e == v().join("") ? d = [] : M(d), G(c, d)) } }).bind("click.inputmask", function () { var b = a(this), c = this; if (b.is(":focus")) { var d = K(c); if (d.begin == d.end) if (g.radixFocus && "" != g.radixPoint && -1 != a.inArray(g.radixPoint, w()) && (ia || w().join("") == v().join(""))) K(c, a.inArray(g.radixPoint, w())), ia = !1; else { var e = d.begin, f = D(o(e)); f > e ? K(c, B(e) ? e : D(e)) : K(c, f) } } }).bind("dblclick.inputmask", function () { var a = this; setTimeout(function () { K(a, 0, D(o())) }, 0) }).bind(m + ".inputmask dragdrop.inputmask drop.inputmask", U).bind("cut.inputmask", function (c) { ga = !0; var d = this, e = a(d), f = K(d); if (ea) { var h = window.clipboardData || c.originalEvent.clipboardData, j = h.getData("text").split("").reverse().join(""); h.setData("text", j) } R(d, b.keyCode.DELETE, f), G(d, w(), i().p, c, $ != w().join("")), d._valueGet() == v().join("") && e.trigger("cleared"), g.showTooltip && e.prop("title", i().mask) }).bind("complete.inputmask", g.oncomplete).bind("incomplete.inputmask", g.onincomplete).bind("cleared.inputmask", g.oncleared), ca.bind("keydown.inputmask", S).bind("keypress.inputmask", T), l || ca.bind("compositionstart.inputmask", W).bind("compositionupdate.inputmask", X).bind("compositionend.inputmask", Y), "paste" === m && ca.bind("input.inputmask", V)), ca.bind("setvalue.inputmask", function () { var b = this, c = b._valueGet(); b._valueSet(a.isFunction(g.onBeforeMask) ? g.onBeforeMask.call(b, c, g) || c : c), I(b, !0, !1), $ = w().join(""), (g.clearMaskOnLostFocus || g.clearIncomplete) && b._valueGet() == v().join("") && b._valueSet("") }), Q(c); var e = a.isFunction(g.onBeforeMask) ? g.onBeforeMask.call(c, c._valueGet(), g) || c._valueGet() : c._valueGet(); I(c, !0, !1, e.split("")); var f = w().slice(); $ = f.join(""); var h; try { h = document.activeElement } catch (j) { } N(f) === !1 && g.clearIncomplete && n(), g.clearMaskOnLostFocus && (f.join("") == v().join("") ? f = [] : M(f)), G(c, f), h === c && K(c, D(o())), P(c) } var $, _, aa, ba, ca, da, ea = !1, fa = !1, ga = !1, ha = !1, ia = !0, ja = !0; if (void 0 != e) switch (e.action) { case "isComplete": return ba = e.el, ca = a(ba), f = ba.inputmask.maskset, g = ba.inputmask.opts, N(e.buffer); case "unmaskedvalue": return ba = e.el, ca = a(ba), f = ba.inputmask.maskset, g = ba.inputmask.opts, ea = ba.inputmask.isRTL, J(ca); case "mask": $ = w().join(""), Z(e.el); break; case "format": ca = a({}), ca[0].inputmask = new b, ca[0].inputmask.opts = g, ca[0].inputmask.el = ca[0], ca[0].inputmask.maskset = f, ca[0].inputmask.isRTL = g.numericInput, g.numericInput && (ea = !0); var ka = (a.isFunction(g.onBeforeMask) ? g.onBeforeMask.call(ca, e.value, g) || e.value : e.value).split(""); return I(ca, !1, !1, ea ? ka.reverse() : ka), a.isFunction(g.onBeforeWrite) && g.onBeforeWrite.call(this, void 0, w(), 0, g), e.metadata ? { value: ea ? w().slice().reverse().join("") : w().join(""), metadata: ca.inputmask("getmetadata") } : ea ? w().slice().reverse().join("") : w().join(""); case "isValid": ca = a({}), ca[0].inputmask = new b, ca[0].inputmask.opts = g, ca[0].inputmask.el = ca[0], ca[0].inputmask.maskset = f, ca[0].inputmask.isRTL = g.numericInput, g.numericInput && (ea = !0); var ka = e.value.split(""); I(ca, !1, !0, ea ? ka.reverse() : ka); for (var la = w(), ma = L(), na = la.length - 1; na > ma && !B(na) ; na--); return la.splice(ma, na + 1 - ma), N(la) && e.value == la.join(""); case "getemptymask": return ba = e.el, ca = a(ba), f = ba.inputmask.maskset, g = ba.inputmask.opts, v(); case "remove": ba = e.el, ca = a(ba), f = ba.inputmask.maskset, g = ba.inputmask.opts, ba._valueSet(J(ca)), ca.unbind(".inputmask"), ba.inputmask = void 0; var oa; Object.getOwnPropertyDescriptor && (oa = Object.getOwnPropertyDescriptor(ba, "value")), oa && oa.get ? ba._valueGet && Object.defineProperty(ba, "value", { get: ba._valueGet, set: ba._valueSet }) : document.__lookupGetter__ && ba.__lookupGetter__("value") && ba._valueGet && (ba.__defineGetter__("value", ba._valueGet), ba.__defineSetter__("value", ba._valueSet)); try { delete ba._valueGet, delete ba._valueSet } catch (pa) { ba._valueGet = void 0, ba._valueSet = void 0 } break; case "getmetadata": if (ba = e.el, ca = a(ba), f = ba.inputmask.maskset, g = ba.inputmask.opts, a.isArray(f.metadata)) { for (var qa, ra = o(), sa = ra; sa >= 0; sa--) if (i().validPositions[sa] && void 0 != i().validPositions[sa].alternation) { qa = i().validPositions[sa].alternation; break } return void 0 != qa ? f.metadata[i().validPositions[ra].locator[qa]] : f.metadata[0] } return f.metadata }
    } b.prototype = { defaults: { placeholder: "_", optionalmarker: { start: "[", end: "]" }, quantifiermarker: { start: "{", end: "}" }, groupmarker: { start: "(", end: ")" }, alternatormarker: "|", escapeChar: "\\", mask: null, oncomplete: a.noop, onincomplete: a.noop, oncleared: a.noop, repeat: 0, greedy: !0, autoUnmask: !1, removeMaskOnSubmit: !1, clearMaskOnLostFocus: !0, insertMode: !0, clearIncomplete: !1, aliases: {}, alias: null, onKeyDown: a.noop, onBeforeMask: void 0, onBeforePaste: void 0, onBeforeWrite: void 0, onUnMask: void 0, showMaskOnFocus: !0, showMaskOnHover: !0, onKeyValidation: a.noop, skipOptionalPartCharacter: " ", showTooltip: !1, numericInput: !1, rightAlign: !1, undoOnEscape: !0, radixPoint: "", groupSeparator: "", radixFocus: !1, nojumps: !1, nojumpsThreshold: 0, keepStatic: void 0, definitions: { 9: { validator: "[0-9]", cardinality: 1, definitionSymbol: "*" }, a: { validator: "[A-Za-z\u0410-\u044f\u0401\u0451\xc0-\xff\xb5]", cardinality: 1, definitionSymbol: "*" }, "*": { validator: "[0-9A-Za-z\u0410-\u044f\u0401\u0451\xc0-\xff\xb5]", cardinality: 1 } }, ignorables: [8, 9, 13, 19, 27, 33, 34, 35, 36, 37, 38, 39, 40, 45, 46, 93, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123], isComplete: void 0, canClearPosition: a.noop, postValidation: void 0 }, keyCode: { ALT: 18, BACKSPACE: 8, CAPS_LOCK: 20, COMMA: 188, COMMAND: 91, COMMAND_LEFT: 91, COMMAND_RIGHT: 93, CONTROL: 17, DELETE: 46, DOWN: 40, END: 35, ENTER: 13, ESCAPE: 27, HOME: 36, INSERT: 45, LEFT: 37, MENU: 93, NUMPAD_ADD: 107, NUMPAD_DECIMAL: 110, NUMPAD_DIVIDE: 111, NUMPAD_ENTER: 108, NUMPAD_MULTIPLY: 106, NUMPAD_SUBTRACT: 109, PAGE_DOWN: 34, PAGE_UP: 33, PERIOD: 190, RIGHT: 39, SHIFT: 16, SPACE: 32, TAB: 9, UP: 38, WINDOWS: 91 }, masksCache: {}, mask: function (c) { var d = c.jquery && c.length > 0 ? c[0] : c, e = a.extend(!0, {}, this.opts); f(c, e, a.extend(!0, {}, this.userOptions)); var i = g(e, this.noMasksCache); return void 0 != i && (d.inputmask = new b, d.inputmask.opts = e, d.inputmask.noMasksCache = this.noMasksCache, d.inputmask.el = d, d.inputmask.maskset = i, d.inputmask.isRTL = !1, h({ action: "mask", el: d }, i, d.inputmask.opts)), c }, unmaskedvalue: function () { return this.el ? h({ action: "unmaskedvalue", el: this.el }) : void 0 }, remove: function () { return this.el ? (h({ action: "remove", el: this.el }), this.el.inputmask = void 0, this.el) : void 0 }, getemptymask: function () { return this.el ? h({ action: "getemptymask", el: this.el }) : void 0 }, hasMaskedValue: function () { return !this.opts.autoUnmask }, isComplete: function () { return this.el ? h({ action: "isComplete", buffer: this.el._valueGet().split(""), el: this.el }) : void 0 }, getmetadata: function () { return this.el ? h({ action: "getmetadata", el: this.el }) : void 0 } }, b.extendDefaults = function (c) { a.extend(b.prototype.defaults, c) }, b.extendDefinitions = function (c) { a.extend(b.prototype.defaults.definitions, c) }, b.extendAliases = function (c) { a.extend(b.prototype.defaults.aliases, c) }, b.format = function (c, d, f) { var i = a.extend(!0, {}, b.prototype.defaults, d); return e(i.alias, d, i), h({ action: "format", value: c, metadata: f }, g(i, d && void 0 !== d.definitions), i) }, b.isValid = function (c, d) { var f = a.extend(!0, {}, b.prototype.defaults, d); return e(f.alias, d, f), h({ action: "isValid", value: c }, g(f, d && void 0 !== d.definitions), f) }, b.escapeRegex = function (a) { var b = ["/", ".", "*", "+", "?", "|", "(", ")", "[", "]", "{", "}", "\\", "$", "^"]; return a.replace(new RegExp("(\\" + b.join("|\\") + ")", "gim"), "\\$1") }, b.keyCode = { ALT: 18, BACKSPACE: 8, CAPS_LOCK: 20, COMMA: 188, COMMAND: 91, COMMAND_LEFT: 91, COMMAND_RIGHT: 93, CONTROL: 17, DELETE: 46, DOWN: 40, END: 35, ENTER: 13, ESCAPE: 27, HOME: 36, INSERT: 45, LEFT: 37, MENU: 93, NUMPAD_ADD: 107, NUMPAD_DECIMAL: 110, NUMPAD_DIVIDE: 111, NUMPAD_ENTER: 108, NUMPAD_MULTIPLY: 106, NUMPAD_SUBTRACT: 109, PAGE_DOWN: 34, PAGE_UP: 33, PERIOD: 190, RIGHT: 39, SHIFT: 16, SPACE: 32, TAB: 9, UP: 38, WINDOWS: 91 }; var i = navigator.userAgent, j = null !== i.match(new RegExp("iphone", "i")), k = (null !== i.match(new RegExp("android.*safari.*", "i")), null !== i.match(new RegExp("android.*chrome.*", "i"))), l = null !== i.match(new RegExp("android.*firefox.*", "i")), m = (/Kindle/i.test(i) || /Silk/i.test(i) || /KFTT/i.test(i) || /KFOT/i.test(i) || /KFJWA/i.test(i) || /KFJWI/i.test(i) || /KFSOWI/i.test(i) || /KFTHWA/i.test(i) || /KFTHWI/i.test(i) || /KFAPWA/i.test(i) || /KFAPWI/i.test(i), c("paste") ? "paste" : c("input") ? "input" : "propertychange"); return window.inputmask = b, b
});;
/*!
* jquery.inputmask.bundle
* http://github.com/RobinHerbots/jquery.inputmask
* Copyright (c) 2010 - 2015 Robin Herbots
* Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
* Version: 3.1.64-86
*/
!function(a){function b(b){this.el=void 0,this.opts=a.extend(!0,{},this.defaults,b),this.noMasksCache=b&&void 0!==b.definitions,this.userOptions=b||{},e(this.opts.alias,b,this.opts)}function c(a){var b=document.createElement("input"),c="on"+a,d=c in b;return d||(b.setAttribute(c,"return;"),d="function"==typeof b[c]),b=null,d}function d(a){var b="text"==a||"tel"==a||"password"==a;if(!b){var c=document.createElement("input");c.setAttribute("type",a),b="text"===c.type,c=null}return b}function e(b,c,d){var f=d.aliases[b];return f?(f.alias&&e(f.alias,void 0,d),a.extend(!0,d,f),a.extend(!0,d,c),!0):(void 0==d.mask&&(d.mask=b),!1)}function f(b,c,d){var f=a(b),g=f.data("inputmask");if(g&&""!=g)try{g=g.replace(new RegExp("'","g"),'"');var h=a.parseJSON("{"+g+"}");a.extend(!0,d,h)}catch(i){}for(var j in c){var k=f.data("inputmask-"+j.toLowerCase());void 0!=k&&(k="boolean"==typeof k?k:k.toString(),"mask"==j&&0==k.indexOf("[")?(d[j]=k.replace(/[\s[\]]/g,"").split("','"),d[j][0]=d[j][0].replace("'",""),d[j][d[j].length-1]=d[j][d[j].length-1].replace("'","")):d[j]=k)}return d.alias?e(d.alias,d,c):a.extend(!0,c,d),c}function g(c,d){function e(b){function d(a,b,c,d){this.matches=[],this.isGroup=a||!1,this.isOptional=b||!1,this.isQuantifier=c||!1,this.isAlternator=d||!1,this.quantifier={min:1,max:1}}function e(b,d,e){var f=c.definitions[d],g=0==b.matches.length;if(e=void 0!=e?e:b.matches.length,f&&!o){f.placeholder=a.isFunction(f.placeholder)?f.placeholder.call(this,c):f.placeholder;for(var h=f.prevalidator,i=h?h.length:0,j=1;j<f.cardinality;j++){var k=i>=j?h[j-1]:[],l=k.validator,m=k.cardinality;b.matches.splice(e++,0,{fn:l?"string"==typeof l?new RegExp(l):new function(){this.test=l}:new RegExp("."),cardinality:m?m:1,optionality:b.isOptional,newBlockMarker:g,casing:f.casing,def:f.definitionSymbol||d,placeholder:f.placeholder,mask:d})}b.matches.splice(e++,0,{fn:f.validator?"string"==typeof f.validator?new RegExp(f.validator):new function(){this.test=f.validator}:new RegExp("."),cardinality:f.cardinality,optionality:b.isOptional,newBlockMarker:g,casing:f.casing,def:f.definitionSymbol||d,placeholder:f.placeholder,mask:d})}else b.matches.splice(e++,0,{fn:null,cardinality:0,optionality:b.isOptional,newBlockMarker:g,casing:null,def:d,placeholder:void 0,mask:d}),o=!1}function f(a){a.isGroup&&(a.isGroup=!1,e(a,c.groupmarker.start,0),e(a,c.groupmarker.end))}function g(a,b,c,d){b.matches.length>0&&(void 0==d||d)&&(c=b.matches[b.matches.length-1],f(c)),e(b,a)}for(var h,i,j,k,l,m,n=/(?:[?*+]|\{[0-9\+\*]+(?:,[0-9\+\*]*)?\})\??|[^.?*+^${[]()|\\]+|./g,o=!1,p=new d,q=[],r=[];h=n.exec(b);)if(i=h[0],o)g(i,p,m);else switch(i.charAt(0)){case c.escapeChar:o=!0;break;case c.optionalmarker.end:case c.groupmarker.end:if(j=q.pop(),q.length>0){if(k=q[q.length-1],k.matches.push(j),k.isAlternator){l=q.pop();for(var s=0;s<l.matches.length;s++)l.matches[s].isGroup=!1;q.length>0?(k=q[q.length-1],k.matches.push(l)):p.matches.push(l)}}else p.matches.push(j);break;case c.optionalmarker.start:q.push(new d(!1,!0));break;case c.groupmarker.start:q.push(new d(!0));break;case c.quantifiermarker.start:var t=new d(!1,!1,!0);i=i.replace(/[{}]/g,"");var u=i.split(","),v=isNaN(u[0])?u[0]:parseInt(u[0]),w=1==u.length?v:isNaN(u[1])?u[1]:parseInt(u[1]);if(("*"==w||"+"==w)&&(v="*"==w?0:1),t.quantifier={min:v,max:w},q.length>0){var x=q[q.length-1].matches;if(h=x.pop(),!h.isGroup){var y=new d(!0);y.matches.push(h),h=y}x.push(h),x.push(t)}else{if(h=p.matches.pop(),!h.isGroup){var y=new d(!0);y.matches.push(h),h=y}p.matches.push(h),p.matches.push(t)}break;case c.alternatormarker:q.length>0?(k=q[q.length-1],m=k.matches.pop()):m=p.matches.pop(),m.isAlternator?q.push(m):(l=new d(!1,!1,!1,!0),l.matches.push(m),q.push(l));break;default:if(q.length>0){if(k=q[q.length-1],g(i,k,m,!k.isAlternator),k.isAlternator){l=q.pop();for(var s=0;s<l.matches.length;s++)l.matches[s].isGroup=!1;q.length>0?(k=q[q.length-1],k.matches.push(l)):p.matches.push(l)}}else g(i,p,m)}return p.matches.length>0&&(m=p.matches[p.matches.length-1],f(m),r.push(p)),r}function f(f,g){if(void 0==f||""==f)return void 0;if(1==f.length&&0==c.greedy&&0!=c.repeat&&(c.placeholder=""),c.repeat>0||"*"==c.repeat||"+"==c.repeat){var h="*"==c.repeat?0:"+"==c.repeat?1:c.repeat;f=c.groupmarker.start+f+c.groupmarker.end+c.quantifiermarker.start+h+","+c.repeat+c.quantifiermarker.end}var i;return void 0==b.prototype.masksCache[f]||d===!0?(i={mask:f,maskToken:e(f),validPositions:{},_buffer:void 0,buffer:void 0,tests:{},metadata:g},d!==!0&&(b.prototype.masksCache[f]=i)):i=a.extend(!0,{},b.prototype.masksCache[f]),i}function g(a){if(a=a.toString(),c.numericInput){a=a.split("").reverse();for(var b=0;b<a.length;b++)a[b]==c.optionalmarker.start?a[b]=c.optionalmarker.end:a[b]==c.optionalmarker.end?a[b]=c.optionalmarker.start:a[b]==c.groupmarker.start?a[b]=c.groupmarker.end:a[b]==c.groupmarker.end&&(a[b]=c.groupmarker.start);a=a.join("")}return a}var h=void 0;if(a.isFunction(c.mask)&&(c.mask=c.mask.call(this,c)),a.isArray(c.mask)){if(c.mask.length>1){c.keepStatic=void 0==c.keepStatic?!0:c.keepStatic;var i="(";return a.each(c.mask,function(b,c){i.length>1&&(i+=")|("),i+=g(void 0==c.mask||a.isFunction(c.mask)?c:c.mask)}),i+=")",f(i,c.mask)}c.mask=c.mask.pop()}return c.mask&&(h=void 0==c.mask.mask||a.isFunction(c.mask.mask)?f(g(c.mask),c.mask):f(g(c.mask.mask),c.mask)),h}function h(e,f,g){function h(a,b,c){b=b||0;var d,e,f,g=[],h=0;do{if(a===!0&&i().validPositions[h]){var j=i().validPositions[h];e=j.match,d=j.locator.slice(),g.push(c===!0?j.input:H(h,e))}else f=r(h,d,h-1),e=f.match,d=f.locator.slice(),g.push(H(h,e));h++}while((void 0==da||da>h-1)&&null!=e.fn||null==e.fn&&""!=e.def||b>=h);return g.pop(),g}function i(){return f}function n(a){var b=i();b.buffer=void 0,b.tests={},a!==!0&&(b._buffer=void 0,b.validPositions={},b.p=0)}function o(a,b){var c=i(),d=-1,e=c.validPositions;void 0==a&&(a=-1);var f=d,g=d;for(var h in e){var j=parseInt(h);e[j]&&(b||null!=e[j].match.fn)&&(a>=j&&(f=j),j>=a&&(g=j))}return d=-1!=f&&a-f>1||a>g?f:g}function p(b,c,d){if(g.insertMode&&void 0!=i().validPositions[b]&&void 0==d){var e,f=a.extend(!0,{},i().validPositions),h=o();for(e=b;h>=e;e++)delete i().validPositions[e];i().validPositions[b]=c;var j,k=!0,l=i().validPositions;for(e=j=b;h>=e;e++){var m=f[e];if(void 0!=m)for(var n=j,p=-1;n<C()&&(null==m.match.fn&&l[e]&&(l[e].match.optionalQuantifier===!0||l[e].match.optionality===!0)||null!=m.match.fn);){if(null==m.match.fn||!g.keepStatic&&l[e]&&(void 0!=l[e+1]&&u(e+1,l[e].locator.slice(),e).length>1||void 0!=l[e].alternation)?n++:n=D(j),t(n,m.match.def)){k=A(n,m.input,!0,!0)!==!1,j=n;break}if(k=null==m.match.fn,p==n)break;p=n}if(!k)break}if(!k)return i().validPositions=a.extend(!0,{},f),!1}else i().validPositions[b]=c;return!0}function q(a,b,c,d){var e,f=a;i().p=a;for(e=f;b>e;e++)void 0!=i().validPositions[e]&&(c===!0||0!=g.canClearPosition(i(),e,o(),d,g))&&delete i().validPositions[e];for(n(!0),e=f+1;e<=o();){for(;void 0!=i().validPositions[f];)f++;var h=i().validPositions[f];f>e&&(e=f+1);var j=i().validPositions[e];void 0!=j&&void 0==h?(t(f,j.match.def)&&A(f,j.input,!0)!==!1&&(delete i().validPositions[e],e++),f++):e++}var k=o(),l=C();for(c!==!0&&void 0!=i().validPositions[k]&&i().validPositions[k].input==g.radixPoint&&delete i().validPositions[k],e=k+1;l>=e;e++)i().validPositions[e]&&delete i().validPositions[e];n(!0)}function r(a,b,c){var d=i().validPositions[a];if(void 0==d)for(var e=u(a,b,c),f=o(),h=i().validPositions[f]||u(0)[0],j=void 0!=h.alternation?h.locator[h.alternation].toString().split(","):[],k=0;k<e.length&&(d=e[k],!(d.match&&(g.greedy&&d.match.optionalQuantifier!==!0||(d.match.optionality===!1||d.match.newBlockMarker===!1)&&d.match.optionalQuantifier!==!0)&&(void 0==h.alternation||h.alternation!=d.alternation||void 0!=d.locator[h.alternation]&&z(d.locator[h.alternation].toString().split(","),j))));k++);return d}function s(a){return i().validPositions[a]?i().validPositions[a].match:u(a)[0].match}function t(a,b){for(var c=!1,d=u(a),e=0;e<d.length;e++)if(d[e].match&&d[e].match.def==b){c=!0;break}return c}function u(b,c,d,e){function f(c,d,e,g){function j(e,g,n){if(h>1e4)return alert("jquery.inputmask: There is probably an error in your mask definition or in the code. Create an issue on github with an example of the mask you are using. "+i().mask),!0;if(h==b&&void 0==e.matches)return k.push({match:e,locator:g.reverse()}),!0;if(void 0!=e.matches){if(e.isGroup&&n!==!0){if(e=j(c.matches[m+1],g))return!0}else if(e.isOptional){var o=e;if(e=f(e,d,g,n)){var p=k[k.length-1].match,q=0==a.inArray(p,o.matches);if(!q)return!0;l=!0,h=b}}else if(e.isAlternator){var r,s=e,t=[],u=k.slice(),v=g.length,w=d.length>0?d.shift():-1;if(-1==w||"string"==typeof w){var x=h,y=d.slice(),z=[];"string"==typeof w&&(z=w.split(","));for(var A=0;A<s.matches.length;A++){if(k=[],e=j(s.matches[A],[A].concat(g),n)||e,e!==!0&&void 0!=e&&z[z.length-1]<s.matches.length){var B=c.matches.indexOf(e)+1;c.matches.length>B&&(e=j(c.matches[B],[B].concat(g.slice(1,g.length)),n),e&&(z.push(B.toString()),a.each(k,function(a,b){b.alternation=g.length-1})))}r=k.slice(),h=x,k=[];for(var C=0;C<y.length;C++)d[C]=y[C];for(var D=0;D<r.length;D++){var E=r[D];E.alternation=E.alternation||v;for(var F=0;F<t.length;F++){var G=t[F];if(E.match.mask==G.match.mask&&("string"!=typeof w||-1!=a.inArray(E.locator[E.alternation].toString(),z))){r.splice(D,1),D--,G.locator[E.alternation]=G.locator[E.alternation]+","+E.locator[E.alternation],G.alternation=E.alternation;break}}}t=t.concat(r)}"string"==typeof w&&(t=a.map(t,function(b,c){if(isFinite(c)){var d,e=b.alternation,f=b.locator[e].toString().split(",");b.locator[e]=void 0,b.alternation=void 0;for(var g=0;g<f.length;g++)d=-1!=a.inArray(f[g],z),d&&(void 0!=b.locator[e]?(b.locator[e]+=",",b.locator[e]+=f[g]):b.locator[e]=parseInt(f[g]),b.alternation=e);if(void 0!=b.locator[e])return b}})),k=u.concat(t),h=b,l=k.length>0}else e=s.matches[w]?j(s.matches[w],[w].concat(g),n):!1;if(e)return!0}else if(e.isQuantifier&&n!==!0)for(var H=e,I=d.length>0&&n!==!0?d.shift():0;I<(isNaN(H.quantifier.max)?I+1:H.quantifier.max)&&b>=h;I++){var J=c.matches[a.inArray(H,c.matches)-1];if(e=j(J,[I].concat(g),!0)){var p=k[k.length-1].match;p.optionalQuantifier=I>H.quantifier.min-1;var q=0==a.inArray(p,J.matches);if(q){if(I>H.quantifier.min-1){l=!0,h=b;break}return!0}return!0}}else if(e=f(e,d,g,n))return!0}else h++}for(var m=d.length>0?d.shift():0;m<c.matches.length;m++)if(c.matches[m].isQuantifier!==!0){var n=j(c.matches[m],[m].concat(e),g);if(n&&h==b)return n;if(h>b)break}}var g=i().maskToken,h=c?d:0,j=c||[0],k=[],l=!1;if(e===!0&&i().tests[b])return i().tests[b];if(void 0==c){for(var m,n=b-1;void 0==(m=i().validPositions[n])&&n>-1&&(!i().tests[n]||void 0==(m=i().tests[n][0]));)n--;void 0!=m&&n>-1&&(h=n,j=m.locator.slice())}for(var o=j.shift();o<g.length;o++){var p=f(g[o],j,[o]);if(p&&h==b||h>b)break}return(0==k.length||l)&&k.push({match:{fn:null,cardinality:0,optionality:!0,casing:null,def:""},locator:[]}),i().tests[b]=a.extend(!0,[],k),i().tests[b]}function v(){return void 0==i()._buffer&&(i()._buffer=h(!1,1)),i()._buffer}function w(){return void 0==i().buffer&&(i().buffer=h(!0,o(),!0)),i().buffer}function x(a,b,c){if(c=c||w().slice(),a===!0)n(),a=0,b=c.length;else for(var d=a;b>d;d++)delete i().validPositions[d],delete i().tests[d];for(var d=a;b>d;d++)c[d]!=g.skipOptionalPartCharacter&&A(d,c[d],!0,!0)}function y(a,b){switch(b.casing){case"upper":a=a.toUpperCase();break;case"lower":a=a.toLowerCase()}return a}function z(b,c){for(var d=g.greedy?c:c.slice(0,1),e=!1,f=0;f<b.length;f++)if(-1!=a.inArray(b[f],d)){e=!0;break}return e}function A(b,c,d,e){function f(b,c,d,e){var f=!1;return a.each(u(b),function(h,j){for(var k=j.match,l=c?1:0,m="",r=(w(),k.cardinality);r>l;r--)m+=F(b-(r-1));if(c&&(m+=c),f=null!=k.fn?k.fn.test(m,i(),b,d,g):c!=k.def&&c!=g.skipOptionalPartCharacter||""==k.def?!1:{c:k.def,pos:b},f!==!1){var s=void 0!=f.c?f.c:c;s=s==g.skipOptionalPartCharacter&&null===k.fn?k.def:s;var t=b,u=w();if(void 0!=f.remove&&(a.isArray(f.remove)||(f.remove=[f.remove]),a.each(f.remove.sort(function(a,b){return b-a}),function(a,b){q(b,b+1,!0)})),void 0!=f.insert&&(a.isArray(f.insert)||(f.insert=[f.insert]),a.each(f.insert.sort(function(a,b){return a-b}),function(a,b){A(b.pos,b.c,!0)})),f.refreshFromBuffer){var v=f.refreshFromBuffer;if(d=!0,x(v===!0?v:v.start,v.end,u),void 0==f.pos&&void 0==f.c)return f.pos=o(),!1;if(t=void 0!=f.pos?f.pos:b,t!=b)return f=a.extend(f,A(t,s,!0)),!1}else if(f!==!0&&void 0!=f.pos&&f.pos!=b&&(t=f.pos,x(b,t),t!=b))return f=a.extend(f,A(t,s,!0)),!1;return 1!=f&&void 0==f.pos&&void 0==f.c?!1:(h>0&&n(!0),p(t,a.extend({},j,{input:y(s,k)}),e)||(f=!1),!1)}}),f}function h(b,c,d,e){for(var f,h,j,k,l=a.extend(!0,{},i().validPositions),m=o();m>=0&&(k=i().validPositions[m],!k||void 0==k.alternation||(f=m,h=i().validPositions[f].alternation,r(f).locator[k.alternation]==k.locator[k.alternation]));m--);if(void 0!=h){f=parseInt(f);for(var p in i().validPositions)if(p=parseInt(p),k=i().validPositions[p],p>=f&&void 0!=k.alternation){var q=i().validPositions[f].locator[h].toString().split(","),s=k.locator[h]||q[0];s.length>0&&(s=s.split(",")[0]);for(var t=0;t<q.length;t++)if(s<q[t]){for(var u,v,w=p;w>=0;w--)if(u=i().validPositions[w],void 0!=u){v=u.locator[h],u.locator[h]=parseInt(q[t]);break}if(s!=u.locator[h]){for(var x=[],y=0,z=p+1;z<o()+1;z++){var B=i().validPositions[z];B&&(null!=B.match.fn?x.push(B.input):b>z&&y++),delete i().validPositions[z],delete i().tests[z]}for(n(!0),g.keepStatic=!g.keepStatic,j=!0;x.length>0;){var C=x.shift();if(C!=g.skipOptionalPartCharacter&&!(j=A(o()+1,C,!1,!0)))break}if(u.alternation=h,u.locator[h]=v,j){for(var D=o(b)+1,E=0,z=p+1;z<o()+1;z++){var B=i().validPositions[z];B&&null==B.match.fn&&b>z&&E++}b+=E-y,j=A(b>D?D:b,c,d,e)}if(g.keepStatic=!g.keepStatic,j)return j;n(),i().validPositions=a.extend(!0,{},l)}}break}}return!1}function j(b,c){for(var d=i().validPositions[c],e=d.locator,f=e.length,g=b;c>g;g++)if(!B(g)){var h=u(g),j=h[0],k=-1;a.each(h,function(a,b){for(var c=0;f>c;c++)b.locator[c]&&z(b.locator[c].toString().split(","),e[c].toString().split(","))&&c>k&&(k=c,j=b)}),p(g,a.extend({},j,{input:j.match.def}),!0)}}d=d===!0;for(var k=w(),l=b-1;l>-1&&!i().validPositions[l];l--);for(l++;b>l;l++)void 0==i().validPositions[l]&&((!B(l)||k[l]!=H(l))&&u(l).length>1||k[l]==g.radixPoint||"0"==k[l]&&a.inArray(g.radixPoint,k)<l)&&f(l,k[l],!0);var m=b,s=!1,t=a.extend(!0,{},i().validPositions);if(m<C()&&(s=f(m,c,d,e),(!d||e)&&s===!1)){var v=i().validPositions[m];if(!v||null!=v.match.fn||v.match.def!=c&&c!=g.skipOptionalPartCharacter){if((g.insertMode||void 0==i().validPositions[D(m)])&&!B(m))for(var E=m+1,G=D(m);G>=E;E++)if(s=f(E,c,d,e),s!==!1){j(m,E),m=E;break}}else s={caret:D(m)}}if(s===!1&&g.keepStatic&&N(k)&&(s=h(b,c,d,e)),s===!0&&(s={pos:m}),a.isFunction(g.postValidation)&&0!=s&&!d){n(!0);var I=g.postValidation(w(),g);if(!I)return n(!0),i().validPositions=a.extend(!0,{},t),!1}return s}function B(a){var b=s(a);if(null!=b.fn)return b.fn;if(!g.keepStatic&&void 0==i().validPositions[a]){for(var c=u(a),d=!0,e=0;e<c.length;e++)if(""!=c[e].match.def&&(void 0==c[e].alternation||c[e].locator[c[e].alternation].length>1)){d=!1;break}return d}return!1}function C(){var a;da=ca.prop("maxLength"),-1==da&&(da=void 0);var b,c=o(),d=i().validPositions[c],e=void 0!=d?d.locator.slice():void 0;for(b=c+1;void 0==d||null!=d.match.fn||null==d.match.fn&&""!=d.match.def;b++)d=r(b,e,b-1),e=d.locator.slice();var f=s(b-1);return a=""!=f.def?b:b-1,void 0==da||da>a?a:da}function D(a){var b=C();if(a>=b)return b;for(var c=a;++c<b&&!B(c)&&(g.nojumps!==!0||g.nojumpsThreshold>c););return c}function E(a){var b=a;if(0>=b)return 0;for(;--b>0&&!B(b););return b}function F(a){return void 0==i().validPositions[a]?H(a):i().validPositions[a].input}function G(b,c,d,e,f){if(e&&a.isFunction(g.onBeforeWrite)){var h=g.onBeforeWrite.call(b,e,c,d,g);if(h){if(h.refreshFromBuffer){var i=h.refreshFromBuffer;x(i===!0?i:i.start,i.end,h.buffer),n(!0),c=w()}d=h.caret||d}}b._valueSet(c.join("")),void 0!=d&&K(b,d),f===!0&&(ga=!0,a(b).trigger("input"))}function H(a,b){if(b=b||s(a),void 0!=b.placeholder)return b.placeholder;if(null==b.fn){if(!g.keepStatic&&void 0==i().validPositions[a]){for(var c,d=u(a),e=!1,f=0;f<d.length;f++){if(c&&""!=d[f].match.def&&d[f].match.def!=c.match.def&&(void 0==d[f].alternation||d[f].alternation==c.alternation)){e=!0;break}1!=d[f].match.optionality&&1!=d[f].match.optionalQuantifier&&(c=d[f])}if(e)return g.placeholder.charAt(a%g.placeholder.length)}return b.def}return g.placeholder.charAt(a%g.placeholder.length)}function I(c,d,e,f){function h(){var a=!1,b=v().slice(l,D(l)).join("").indexOf(k);if(-1!=b&&!B(l)){a=!0;for(var c=v().slice(l,l+b),d=0;d<c.length;d++)if(" "!=c[d]){a=!1;break}}return a}var j=void 0!=f?f.slice():c._valueGet().split(""),k="",l=0;if(n(),i().p=D(-1),d&&c._valueSet(""),!e)if(1!=g.autoUnmask){var m=v().slice(0,D(-1)).join(""),p=j.join("").match(new RegExp("^"+b.escapeRegex(m),"g"));p&&p.length>0&&(j.splice(0,p.length*m.length),l=D(l))}else l=D(l);a.each(j,function(b,d){var f=a.Event("keypress");f.which=d.charCodeAt(0),k+=d;var j=o(void 0,!0),m=i().validPositions[j],n=r(j+1,m?m.locator.slice():void 0,j);if(!h()||e||g.autoUnmask){var p=e?b:null==n.match.fn&&n.match.optionality&&j+1<i().p?j+1:i().p;T.call(c,f,!0,!1,e,p),l=p+1,k=""}else T.call(c,f,!0,!1,!0,j+1)}),d&&G(c,w(),a(c).is(":focus")?D(o(0)):void 0,a.Event("checkval"))}function J(b){if(b[0].inputmask&&!b.hasClass("hasDatepicker")){var c=[],d=i().validPositions;for(var e in d)d[e].match&&null!=d[e].match.fn&&c.push(d[e].input);var f=(ea?c.reverse():c).join(""),h=(ea?w().slice().reverse():w()).join("");return a.isFunction(g.onUnMask)&&(f=g.onUnMask.call(b,h,f,g)||f),f}return b[0]._valueGet()}function K(b,c,d){function e(a){if(ea&&"number"==typeof a&&(!g.greedy||""!=g.placeholder)){var b=w().length;a=b-a}return a}var f,h=b.jquery&&b.length>0?b[0]:b;if("number"!=typeof c)return h.setSelectionRange?(c=h.selectionStart,d=h.selectionEnd):window.getSelection?(f=window.getSelection().getRangeAt(0),(f.commonAncestorContainer.parentNode==h||f.commonAncestorContainer==h)&&(c=f.startOffset,d=f.endOffset)):document.selection&&document.selection.createRange&&(f=document.selection.createRange(),c=0-f.duplicate().moveStart("character",-1e5),d=c+f.text.length),{begin:e(c),end:e(d)};if(c=e(c),d=e(d),d="number"==typeof d?d:c,a(h).is(":visible")){var i=a(h).css("font-size").replace("px","")*d;if(h.scrollLeft=i>h.scrollWidth?i:0,k||0!=g.insertMode||c!=d||d++,h.setSelectionRange)h.selectionStart=c,h.selectionEnd=d;else if(window.getSelection){if(f=document.createRange(),void 0==h.firstChild){var j=document.createTextNode("");h.appendChild(j)}f.setStart(h.firstChild,c<h._valueGet().length?c:h._valueGet().length),f.setEnd(h.firstChild,d<h._valueGet().length?d:h._valueGet().length),f.collapse(!0);var l=window.getSelection();l.removeAllRanges(),l.addRange(f)}else h.createTextRange&&(f=h.createTextRange(),f.collapse(!0),f.moveEnd("character",d),f.moveStart("character",c),f.select())}}function L(b){var c,d,e=w(),f=e.length,g=o(),h={},j=i().validPositions[g],k=void 0!=j?j.locator.slice():void 0;for(c=g+1;c<e.length;c++)d=r(c,k,c-1),k=d.locator.slice(),h[c]=a.extend(!0,{},d);var l=j&&void 0!=j.alternation?j.locator[j.alternation]:void 0;for(c=f-1;c>g&&(d=h[c],(d.match.optionality||d.match.optionalQuantifier||l&&(l!=h[c].locator[j.alternation]&&null!=d.match.fn||null==d.match.fn&&d.locator[j.alternation]&&z(d.locator[j.alternation].toString().split(","),l.split(","))&&""!=u(c)[0].def))&&e[c]==H(c,d.match));c--)f--;return b?{l:f,def:h[f]?h[f].match:void 0}:f}function M(a){for(var b=L(),c=a.length-1;c>b&&!B(c);c--);return a.splice(b,c+1-b),a}function N(b){if(a.isFunction(g.isComplete))return g.isComplete.call(ca,b,g);if("*"==g.repeat)return void 0;var c=!1,d=L(!0),e=E(d.l);o();if(void 0==d.def||d.def.newBlockMarker||d.def.optionality||d.def.optionalQuantifier){c=!0;for(var f=0;e>=f;f++){var h=r(f).match;if(null!=h.fn&&void 0==i().validPositions[f]&&h.optionality!==!0&&h.optionalQuantifier!==!0||null==h.fn&&b[f]!=H(f,h)){c=!1;break}}}return c}function O(a,b){return ea?a-b>1||a-b==1&&g.insertMode:b-a>1||b-a==1&&g.insertMode}function P(c){var d=a._data(c).events,e=!1;a.each(d,function(c,d){a.each(d,function(a,c){if("inputmask"==c.namespace&&"setvalue"!=c.type){var d=c.handler;c.handler=function(a){if(!(this.disabled||this.readOnly&&!("keydown"==a.type&&a.ctrlKey&&67==a.keyCode||a.keyCode==b.keyCode.TAB))){switch(a.type){case"input":if(ga===!0||e===!0)return ga=!1,a.preventDefault();break;case"keydown":fa=!1,e=!1;break;case"keypress":if(fa===!0)return a.preventDefault();fa=!0;break;case"compositionstart":e=!0;break;case"compositionupdate":ga=!0;break;case"compositionend":e=!1}return d.apply(this,arguments)}a.preventDefault()}}})})}function Q(b){function c(b){if(void 0==a.valHooks[b]||1!=a.valHooks[b].inputmaskpatch){var c=a.valHooks[b]&&a.valHooks[b].get?a.valHooks[b].get:function(a){return a.value},d=a.valHooks[b]&&a.valHooks[b].set?a.valHooks[b].set:function(a,b){return a.value=b,a};a.valHooks[b]={get:function(b){a(b);if(b.inputmask){if(b.inputmask.opts.autoUnmask)return b.inputmask.unmaskedvalue();var d=c(b),e=b.inputmask.maskset,f=e._buffer;return f=f?f.join(""):"",d!=f?d:""}return c(b)},set:function(b,c){var e,f=a(b);return e=d(b,c),b.inputmask&&f.triggerHandler("setvalue.inputmask"),e},inputmaskpatch:!0}}}function d(){a(this);return this.inputmask?this.inputmask.opts.autoUnmask?this.inputmask.unmaskedvalue():g.call(this)!=v().join("")?g.call(this):"":g.call(this)}function e(b){h.call(this,b),this.inputmask&&a(this).triggerHandler("setvalue.inputmask")}function f(b){a(b).bind("mouseenter.inputmask",function(b){var c=a(this),d=this,e=d._valueGet();""!=e&&e!=w().join("")&&c.triggerHandler("setvalue.inputmask")});
//!! the bound handlers are executed in the order they where bound
var c=a._data(b).events,d=c.mouseover;if(d){for(var e=d[d.length-1],f=d.length-1;f>0;f--)d[f]=d[f-1];d[0]=e}}var g,h;if(!b._valueGet){var i;Object.getOwnPropertyDescriptor&&void 0==b.value?(g=function(){return this.textContent},h=function(a){this.textContent=a},Object.defineProperty(b,"value",{get:d,set:e})):((i=Object.getOwnPropertyDescriptor&&Object.getOwnPropertyDescriptor(b,"value"))&&i.configurable,document.__lookupGetter__&&b.__lookupGetter__("value")?(g=b.__lookupGetter__("value"),h=b.__lookupSetter__("value"),b.__defineGetter__("value",d),b.__defineSetter__("value",e)):(g=function(){return b.value},h=function(a){b.value=a},c(b.type),f(b))),b._valueGet=function(a){return ea&&a!==!0?g.call(this).split("").reverse().join(""):g.call(this)},b._valueSet=function(a){h.call(this,ea?a.split("").reverse().join(""):a)}}}function R(c,d,e,f){function h(){if(g.keepStatic){n(!0);var b,d=[],e=a.extend(!0,{},i().validPositions);for(b=o();b>=0;b--){var f=i().validPositions[b];if(f&&(null!=f.match.fn&&d.push(f.input),delete i().validPositions[b],void 0!=f.alternation&&f.locator[f.alternation]==r(b).locator[f.alternation]))break}if(b>-1)for(;d.length>0;){i().p=D(o());var h=a.Event("keypress");h.which=d.pop().charCodeAt(0),T.call(c,h,!0,!1,!1,i().p)}else i().validPositions=a.extend(!0,{},e)}}if((g.numericInput||ea)&&(d==b.keyCode.BACKSPACE?d=b.keyCode.DELETE:d==b.keyCode.DELETE&&(d=b.keyCode.BACKSPACE),ea)){var j=e.end;e.end=e.begin,e.begin=j}if(d==b.keyCode.BACKSPACE&&(e.end-e.begin<1||0==g.insertMode)?(e.begin=E(e.begin),void 0==i().validPositions[e.begin]||i().validPositions[e.begin].input!=g.groupSeparator&&i().validPositions[e.begin].input!=g.radixPoint||e.begin--):d==b.keyCode.DELETE&&e.begin==e.end&&(e.end=B(e.end)?e.end+1:D(e.end)+1,void 0==i().validPositions[e.begin]||i().validPositions[e.begin].input!=g.groupSeparator&&i().validPositions[e.begin].input!=g.radixPoint||e.end++),q(e.begin,e.end,!1,f),f!==!0){h();var k=o(e.begin);k<e.begin?(-1==k&&n(),i().p=D(k)):i().p=e.begin}}function S(d){var e=this,f=a(e),h=d.keyCode,k=K(e);h==b.keyCode.BACKSPACE||h==b.keyCode.DELETE||j&&127==h||d.ctrlKey&&88==h&&!c("cut")?(d.preventDefault(),88==h&&($=w().join("")),R(e,h,k),G(e,w(),i().p,d,$!=w().join("")),e._valueGet()==v().join("")?f.trigger("cleared"):N(w())===!0&&f.trigger("complete"),g.showTooltip&&f.prop("title",i().mask)):h==b.keyCode.END||h==b.keyCode.PAGE_DOWN?setTimeout(function(){var a=D(o());g.insertMode||a!=C()||d.shiftKey||a--,K(e,d.shiftKey?k.begin:a,a)},0):h==b.keyCode.HOME&&!d.shiftKey||h==b.keyCode.PAGE_UP?K(e,0,d.shiftKey?k.begin:0):(g.undoOnEscape&&h==b.keyCode.ESCAPE||90==h&&d.ctrlKey)&&d.altKey!==!0?(I(e,!0,!1,$.split("")),f.click()):h!=b.keyCode.INSERT||d.shiftKey||d.ctrlKey?0!=g.insertMode||d.shiftKey||(h==b.keyCode.RIGHT?setTimeout(function(){var a=K(e);K(e,a.begin)},0):h==b.keyCode.LEFT&&setTimeout(function(){var a=K(e);K(e,ea?a.begin+1:a.begin-1)},0)):(g.insertMode=!g.insertMode,K(e,g.insertMode||k.begin!=C()?k.begin:k.begin-1)),g.onKeyDown.call(this,d,w(),K(e).begin,g),ha=-1!=a.inArray(h,g.ignorables)}function T(c,d,e,f,h){var j=this,k=a(j),l=c.which||c.charCode||c.keyCode;if(!(d===!0||c.ctrlKey&&c.altKey)&&(c.ctrlKey||c.metaKey||ha))return!0;if(l){46==l&&0==c.shiftKey&&","==g.radixPoint&&(l=44);var m,o=d?{begin:h,end:h}:K(j),q=String.fromCharCode(l),r=O(o.begin,o.end);r&&(i().undoPositions=a.extend(!0,{},i().validPositions),R(j,b.keyCode.DELETE,o,!0),o.begin=i().p,g.insertMode||(g.insertMode=!g.insertMode,p(o.begin,f),g.insertMode=!g.insertMode),r=!g.multi),i().writeOutBuffer=!0;var s=ea&&!r?o.end:o.begin,t=A(s,q,f);if(t!==!1){if(t!==!0&&(s=void 0!=t.pos?t.pos:s,q=void 0!=t.c?t.c:q),n(!0),void 0!=t.caret)m=t.caret;else{var v=i().validPositions;m=!g.keepStatic&&(void 0!=v[s+1]&&u(s+1,v[s].locator.slice(),s).length>1||void 0!=v[s].alternation)?s+1:D(s)}i().p=m}if(e!==!1){var y=this;if(setTimeout(function(){g.onKeyValidation.call(y,t,g)},0),i().writeOutBuffer&&t!==!1){var z=w();G(j,z,d?void 0:g.numericInput?E(m):m,c,d!==!0),d!==!0&&setTimeout(function(){N(z)===!0&&k.trigger("complete")},0)}else r&&(i().buffer=void 0,i().validPositions=i().undoPositions)}else r&&(i().buffer=void 0,i().validPositions=i().undoPositions);if(g.showTooltip&&k.prop("title",i().mask),d&&a.isFunction(g.onBeforeWrite)){var B=g.onBeforeWrite.call(this,c,w(),m,g);if(B&&B.refreshFromBuffer){var C=B.refreshFromBuffer;x(C===!0?C:C.start,C.end,B.buffer),n(!0),B.caret&&(i().p=B.caret)}}c.preventDefault()}}function U(b){var c=this,d=a(c),e=c._valueGet(!0),f=K(c);if("propertychange"==b.type&&c._valueGet().length<=C())return!0;if("paste"==b.type){var h=e.substr(0,f.begin),i=e.substr(f.end,e.length);h==v().slice(0,f.begin).join("")&&(h=""),i==v().slice(f.end).join("")&&(i=""),window.clipboardData&&window.clipboardData.getData?e=h+window.clipboardData.getData("Text")+i:b.originalEvent&&b.originalEvent.clipboardData&&b.originalEvent.clipboardData.getData&&(e=h+b.originalEvent.clipboardData.getData("text/plain")+i)}var j=e;if(a.isFunction(g.onBeforePaste)){if(j=g.onBeforePaste.call(c,e,g),j===!1)return b.preventDefault(),!1;j||(j=e)}return I(c,!1,!1,ea?j.split("").reverse():j.split("")),G(c,w(),void 0,b,!0),d.click(),N(w())===!0&&d.trigger("complete"),!1}function V(b){var c=this;I(c,!0,!1),N(w())===!0&&a(c).trigger("complete"),b.preventDefault()}function W(a){var b=this;$=w().join(""),(""==aa||0!=a.originalEvent.data.indexOf(aa))&&(_=K(b))}function X(b){var c=this,d=K(c);0==b.originalEvent.data.indexOf(aa)&&(n(),d=_);var e=b.originalEvent.data;K(c,d.begin,d.end);for(var f=0;f<e.length;f++){var h=a.Event("keypress");h.which=e.charCodeAt(f),fa=!1,ha=!1,T.call(c,h)}setTimeout(function(){var a=i().p;G(c,w(),g.numericInput?E(a):a)},0),aa=b.originalEvent.data}function Y(a){}function Z(c){ca=a(c),g.showTooltip&&ca.prop("title",i().mask),("rtl"==c.dir||g.rightAlign)&&ca.css("text-align","right"),("rtl"==c.dir||g.numericInput)&&(c.dir="ltr",ca.removeAttr("dir"),c.inputmask.isRTL=!0,ea=!0),ca.unbind(".inputmask"),(ca.is(":input")&&d(ca.attr("type"))||c.isContentEditable)&&(ca.closest("form").bind("submit",function(a){$!=w().join("")&&ca.change(),g.clearMaskOnLostFocus&&ca[0]._valueGet&&ca[0]._valueGet()==v().join("")&&ca[0]._valueSet(""),g.removeMaskOnSubmit&&ca.inputmask("remove")}).bind("reset",function(){setTimeout(function(){ca.triggerHandler("setvalue.inputmask")},0)}),ca.bind("mouseenter.inputmask",function(){var b=a(this),c=this;ja=!0,!b.is(":focus")&&g.showMaskOnHover&&c._valueGet()!=w().join("")&&G(c,w())}).bind("blur.inputmask",function(b){var c=a(this),d=this;if(d.inputmask){var e=d._valueGet(),f=w().slice();ia=!0,$!=f.join("")&&setTimeout(function(){c.change(),$=f.join("")},0),""!=e&&(g.clearMaskOnLostFocus&&(e==v().join("")?f=[]:M(f)),N(f)===!1&&(setTimeout(function(){c.trigger("incomplete")},0),g.clearIncomplete&&(n(),f=g.clearMaskOnLostFocus?[]:v().slice())),G(d,f,void 0,b))}}).bind("focus.inputmask",function(b){var c=(a(this),this),d=c._valueGet();g.showMaskOnFocus&&(!g.showMaskOnHover||g.showMaskOnHover&&""==d)?c._valueGet()!=w().join("")&&G(c,w(),D(o())):ja===!1&&K(c,D(o())),$=w().join("")}).bind("mouseleave.inputmask",function(){var b=a(this),c=this;if(ja=!1,g.clearMaskOnLostFocus){var d=w().slice(),e=c._valueGet();b.is(":focus")||e==b.attr("placeholder")||""==e||(e==v().join("")?d=[]:M(d),G(c,d))}}).bind("click.inputmask",function(){var b=a(this),c=this;if(b.is(":focus")){var d=K(c);if(d.begin==d.end)if(g.radixFocus&&""!=g.radixPoint&&-1!=a.inArray(g.radixPoint,w())&&(ia||w().join("")==v().join("")))K(c,a.inArray(g.radixPoint,w())),ia=!1;else{var e=d.begin,f=D(o(e));f>e?K(c,B(e)?e:D(e)):K(c,f)}}}).bind("dblclick.inputmask",function(){var a=this;setTimeout(function(){K(a,0,D(o()))},0)}).bind(m+".inputmask dragdrop.inputmask drop.inputmask",U).bind("cut.inputmask",function(c){ga=!0;var d=this,e=a(d),f=K(d);if(ea){var h=window.clipboardData||c.originalEvent.clipboardData,j=h.getData("text").split("").reverse().join("");h.setData("text",j)}R(d,b.keyCode.DELETE,f),G(d,w(),i().p,c,$!=w().join("")),d._valueGet()==v().join("")&&e.trigger("cleared"),g.showTooltip&&e.prop("title",i().mask)}).bind("complete.inputmask",g.oncomplete).bind("incomplete.inputmask",g.onincomplete).bind("cleared.inputmask",g.oncleared),ca.bind("keydown.inputmask",S).bind("keypress.inputmask",T),l||ca.bind("compositionstart.inputmask",W).bind("compositionupdate.inputmask",X).bind("compositionend.inputmask",Y),"paste"===m&&ca.bind("input.inputmask",V)),ca.bind("setvalue.inputmask",function(){var b=this,c=b._valueGet();b._valueSet(a.isFunction(g.onBeforeMask)?g.onBeforeMask.call(b,c,g)||c:c),I(b,!0,!1),$=w().join(""),(g.clearMaskOnLostFocus||g.clearIncomplete)&&b._valueGet()==v().join("")&&b._valueSet("")}),Q(c);var e=a.isFunction(g.onBeforeMask)?g.onBeforeMask.call(c,c._valueGet(),g)||c._valueGet():c._valueGet();I(c,!0,!1,e.split(""));var f=w().slice();$=f.join("");var h;try{h=document.activeElement}catch(j){}N(f)===!1&&g.clearIncomplete&&n(),g.clearMaskOnLostFocus&&(f.join("")==v().join("")?f=[]:M(f)),G(c,f),h===c&&K(c,D(o())),P(c)}var $,_,aa,ba,ca,da,ea=!1,fa=!1,ga=!1,ha=!1,ia=!0,ja=!0;if(void 0!=e)switch(e.action){case"isComplete":return ba=e.el,ca=a(ba),f=ba.inputmask.maskset,g=ba.inputmask.opts,N(e.buffer);case"unmaskedvalue":return ba=e.el,ca=a(ba),f=ba.inputmask.maskset,g=ba.inputmask.opts,ea=ba.inputmask.isRTL,J(ca);case"mask":$=w().join(""),Z(e.el);break;case"format":ca=a({}),ca[0].inputmask=new b,ca[0].inputmask.opts=g,ca[0].inputmask.el=ca[0],ca[0].inputmask.maskset=f,ca[0].inputmask.isRTL=g.numericInput,g.numericInput&&(ea=!0);var ka=(a.isFunction(g.onBeforeMask)?g.onBeforeMask.call(ca,e.value,g)||e.value:e.value).split("");return I(ca,!1,!1,ea?ka.reverse():ka),a.isFunction(g.onBeforeWrite)&&g.onBeforeWrite.call(this,void 0,w(),0,g),e.metadata?{value:ea?w().slice().reverse().join(""):w().join(""),metadata:ca.inputmask("getmetadata")}:ea?w().slice().reverse().join(""):w().join("");case"isValid":ca=a({}),ca[0].inputmask=new b,ca[0].inputmask.opts=g,ca[0].inputmask.el=ca[0],ca[0].inputmask.maskset=f,ca[0].inputmask.isRTL=g.numericInput,g.numericInput&&(ea=!0);var ka=e.value.split("");I(ca,!1,!0,ea?ka.reverse():ka);for(var la=w(),ma=L(),na=la.length-1;na>ma&&!B(na);na--);return la.splice(ma,na+1-ma),N(la)&&e.value==la.join("");case"getemptymask":return ba=e.el,ca=a(ba),f=ba.inputmask.maskset,g=ba.inputmask.opts,v();case"remove":ba=e.el,ca=a(ba),f=ba.inputmask.maskset,g=ba.inputmask.opts,ba._valueSet(J(ca)),ca.unbind(".inputmask"),ba.inputmask=void 0;var oa;Object.getOwnPropertyDescriptor&&(oa=Object.getOwnPropertyDescriptor(ba,"value")),oa&&oa.get?ba._valueGet&&Object.defineProperty(ba,"value",{get:ba._valueGet,set:ba._valueSet}):document.__lookupGetter__&&ba.__lookupGetter__("value")&&ba._valueGet&&(ba.__defineGetter__("value",ba._valueGet),ba.__defineSetter__("value",ba._valueSet));try{delete ba._valueGet,delete ba._valueSet}catch(pa){ba._valueGet=void 0,ba._valueSet=void 0}break;case"getmetadata":if(ba=e.el,ca=a(ba),f=ba.inputmask.maskset,g=ba.inputmask.opts,a.isArray(f.metadata)){for(var qa,ra=o(),sa=ra;sa>=0;sa--)if(i().validPositions[sa]&&void 0!=i().validPositions[sa].alternation){qa=i().validPositions[sa].alternation;break}return void 0!=qa?f.metadata[i().validPositions[ra].locator[qa]]:f.metadata[0]}return f.metadata}}b.prototype={defaults:{placeholder:"_",optionalmarker:{start:"[",end:"]"},quantifiermarker:{start:"{",end:"}"},groupmarker:{start:"(",end:")"},alternatormarker:"|",escapeChar:"\\",mask:null,oncomplete:a.noop,onincomplete:a.noop,oncleared:a.noop,repeat:0,greedy:!0,autoUnmask:!1,removeMaskOnSubmit:!1,clearMaskOnLostFocus:!0,insertMode:!0,clearIncomplete:!1,aliases:{},alias:null,onKeyDown:a.noop,onBeforeMask:void 0,onBeforePaste:void 0,onBeforeWrite:void 0,onUnMask:void 0,showMaskOnFocus:!0,showMaskOnHover:!0,onKeyValidation:a.noop,skipOptionalPartCharacter:" ",showTooltip:!1,numericInput:!1,rightAlign:!1,undoOnEscape:!0,radixPoint:"",groupSeparator:"",radixFocus:!1,nojumps:!1,nojumpsThreshold:0,keepStatic:void 0,definitions:{9:{validator:"[0-9]",cardinality:1,definitionSymbol:"*"},a:{validator:"[A-Za-z\u0410-\u044f\u0401\u0451\xc0-\xff\xb5]",cardinality:1,definitionSymbol:"*"},"*":{validator:"[0-9A-Za-z\u0410-\u044f\u0401\u0451\xc0-\xff\xb5]",cardinality:1}},ignorables:[8,9,13,19,27,33,34,35,36,37,38,39,40,45,46,93,112,113,114,115,116,117,118,119,120,121,122,123],isComplete:void 0,canClearPosition:a.noop,postValidation:void 0},keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91},masksCache:{},mask:function(c){var d=c.jquery&&c.length>0?c[0]:c,e=a.extend(!0,{},this.opts);f(c,e,a.extend(!0,{},this.userOptions));var i=g(e,this.noMasksCache);return void 0!=i&&(d.inputmask=new b,d.inputmask.opts=e,d.inputmask.noMasksCache=this.noMasksCache,d.inputmask.el=d,d.inputmask.maskset=i,d.inputmask.isRTL=!1,h({action:"mask",el:d},i,d.inputmask.opts)),c},unmaskedvalue:function(){return this.el?h({action:"unmaskedvalue",el:this.el}):void 0},remove:function(){return this.el?(h({action:"remove",el:this.el}),this.el.inputmask=void 0,this.el):void 0},getemptymask:function(){return this.el?h({action:"getemptymask",el:this.el}):void 0},hasMaskedValue:function(){return!this.opts.autoUnmask},isComplete:function(){return this.el?h({action:"isComplete",buffer:this.el._valueGet().split(""),el:this.el}):void 0},getmetadata:function(){return this.el?h({action:"getmetadata",el:this.el}):void 0}},b.extendDefaults=function(c){a.extend(b.prototype.defaults,c)},b.extendDefinitions=function(c){a.extend(b.prototype.defaults.definitions,c)},b.extendAliases=function(c){a.extend(b.prototype.defaults.aliases,c)},b.format=function(c,d,f){var i=a.extend(!0,{},b.prototype.defaults,d);return e(i.alias,d,i),h({action:"format",value:c,metadata:f},g(i,d&&void 0!==d.definitions),i)},b.isValid=function(c,d){var f=a.extend(!0,{},b.prototype.defaults,d);return e(f.alias,d,f),h({action:"isValid",value:c},g(f,d&&void 0!==d.definitions),f)},b.escapeRegex=function(a){var b=["/",".","*","+","?","|","(",")","[","]","{","}","\\","$","^"];return a.replace(new RegExp("(\\"+b.join("|\\")+")","gim"),"\\$1")},b.keyCode={ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91};var i=navigator.userAgent,j=null!==i.match(new RegExp("iphone","i")),k=(null!==i.match(new RegExp("android.*safari.*","i")),null!==i.match(new RegExp("android.*chrome.*","i"))),l=null!==i.match(new RegExp("android.*firefox.*","i")),m=(/Kindle/i.test(i)||/Silk/i.test(i)||/KFTT/i.test(i)||/KFOT/i.test(i)||/KFJWA/i.test(i)||/KFJWI/i.test(i)||/KFSOWI/i.test(i)||/KFTHWA/i.test(i)||/KFTHWI/i.test(i)||/KFAPWA/i.test(i)||/KFAPWI/i.test(i),c("paste")?"paste":c("input")?"input":"propertychange");return window.inputmask=b,b}(jQuery),function(a){return void 0===a.fn.inputmask&&(a.fn.inputmask=function(b,c){var d;if(c=c||{},"string"==typeof b)switch(b){case"mask":return d=new inputmask(c),this.each(function(){d.mask(this)});case"unmaskedvalue":var e=this.jquery&&this.length>0?this[0]:this;return e.inputmask?e.inputmask.unmaskedvalue():a(e).val();case"remove":return this.each(function(){this.inputmask&&this.inputmask.remove()});case"getemptymask":var e=this.jquery&&this.length>0?this[0]:this;return e.inputmask?e.inputmask.getemptymask():"";case"hasMaskedValue":var e=this.jquery&&this.length>0?this[0]:this;return e.inputmask?e.inputmask.hasMaskedValue():!1;case"isComplete":var e=this.jquery&&this.length>0?this[0]:this;return e.inputmask?e.inputmask.isComplete():!0;case"getmetadata":var e=this.jquery&&this.length>0?this[0]:this;return e.inputmask?e.inputmask.getmetadata():void 0;default:return c.alias=b,d=new inputmask(c),this.each(function(){d.mask(this)})}else{if("object"==typeof b)return d=new inputmask(b),this.each(function(){d.mask(this)});if(void 0==b)return this.each(function(){d=new inputmask(c),d.mask(this)})}}),a.fn.inputmask}(jQuery),function(a){return inputmask.extendDefinitions({h:{validator:"[01][0-9]|2[0-3]",cardinality:2,prevalidator:[{validator:"[0-2]",cardinality:1}]},s:{validator:"[0-5][0-9]",cardinality:2,prevalidator:[{validator:"[0-5]",cardinality:1}]},d:{validator:"0[1-9]|[12][0-9]|3[01]",cardinality:2,prevalidator:[{validator:"[0-3]",cardinality:1}]},m:{validator:"0[1-9]|1[012]",cardinality:2,prevalidator:[{validator:"[01]",cardinality:1}]},y:{validator:"(19|20)\\d{2}",cardinality:4,prevalidator:[{validator:"[12]",cardinality:1},{validator:"(19|20)",cardinality:2},{validator:"(19|20)\\d",cardinality:3}]}}),inputmask.extendAliases({"dd/mm/yyyy":{mask:"1/2/y",placeholder:"dd/mm/yyyy",regex:{val1pre:new RegExp("[0-3]"),val1:new RegExp("0[1-9]|[12][0-9]|3[01]"),val2pre:function(a){var b=inputmask.escapeRegex.call(this,a);return new RegExp("((0[1-9]|[12][0-9]|3[01])"+b+"[01])")},val2:function(a){var b=inputmask.escapeRegex.call(this,a);return new RegExp("((0[1-9]|[12][0-9])"+b+"(0[1-9]|1[012]))|(30"+b+"(0[13-9]|1[012]))|(31"+b+"(0[13578]|1[02]))")}},leapday:"29/02/",separator:"/",yearrange:{minyear:1900,maxyear:2099},isInYearRange:function(a,b,c){if(isNaN(a))return!1;var d=parseInt(a.concat(b.toString().slice(a.length))),e=parseInt(a.concat(c.toString().slice(a.length)));return(isNaN(d)?!1:d>=b&&c>=d)||(isNaN(e)?!1:e>=b&&c>=e)},determinebaseyear:function(a,b,c){var d=(new Date).getFullYear();if(a>d)return a;if(d>b){for(var e=b.toString().slice(0,2),f=b.toString().slice(2,4);e+c>b;)e--;var g=e+f;return a>g?a:g}return d},onKeyDown:function(b,c,d,e){var f=a(this);if(b.ctrlKey&&b.keyCode==inputmask.keyCode.RIGHT){var g=new Date;f.val(g.getDate().toString()+(g.getMonth()+1).toString()+g.getFullYear().toString()),f.triggerHandler("setvalue.inputmask")}},getFrontValue:function(a,b,c){for(var d=0,e=0,f=0;f<a.length&&"2"!=a.charAt(f);f++){var g=c.definitions[a.charAt(f)];g?(d+=e,e=g.cardinality):e++}return b.join("").substr(d,e)},definitions:{1:{validator:function(a,b,c,d,e){var f=e.regex.val1.test(a);return d||f||a.charAt(1)!=e.separator&&-1=="-./".indexOf(a.charAt(1))||!(f=e.regex.val1.test("0"+a.charAt(0)))?f:(b.buffer[c-1]="0",{refreshFromBuffer:{start:c-1,end:c},pos:c,c:a.charAt(0)})},cardinality:2,prevalidator:[{validator:function(a,b,c,d,e){var f=a;isNaN(b.buffer[c+1])||(f+=b.buffer[c+1]);var g=1==f.length?e.regex.val1pre.test(f):e.regex.val1.test(f);if(!d&&!g){if(g=e.regex.val1.test(a+"0"))return b.buffer[c]=a,b.buffer[++c]="0",{pos:c,c:"0"};if(g=e.regex.val1.test("0"+a))return b.buffer[c]="0",c++,{pos:c}}return g},cardinality:1}]},2:{validator:function(a,b,c,d,e){var f=e.getFrontValue(b.mask,b.buffer,e);-1!=f.indexOf(e.placeholder[0])&&(f="01"+e.separator);var g=e.regex.val2(e.separator).test(f+a);if(!d&&!g&&(a.charAt(1)==e.separator||-1!="-./".indexOf(a.charAt(1)))&&(g=e.regex.val2(e.separator).test(f+"0"+a.charAt(0))))return b.buffer[c-1]="0",{refreshFromBuffer:{start:c-1,end:c},pos:c,c:a.charAt(0)};if(e.mask.indexOf("2")==e.mask.length-1&&g){var h=b.buffer.join("").substr(4,4)+a;if(h!=e.leapday)return!0;var i=parseInt(b.buffer.join("").substr(0,4),10);return i%4===0?i%100===0?i%400===0?!0:!1:!0:!1}return g},cardinality:2,prevalidator:[{validator:function(a,b,c,d,e){isNaN(b.buffer[c+1])||(a+=b.buffer[c+1]);var f=e.getFrontValue(b.mask,b.buffer,e);-1!=f.indexOf(e.placeholder[0])&&(f="01"+e.separator);var g=1==a.length?e.regex.val2pre(e.separator).test(f+a):e.regex.val2(e.separator).test(f+a);return d||g||!(g=e.regex.val2(e.separator).test(f+"0"+a))?g:(b.buffer[c]="0",c++,{pos:c})},cardinality:1}]},y:{validator:function(a,b,c,d,e){if(e.isInYearRange(a,e.yearrange.minyear,e.yearrange.maxyear)){var f=b.buffer.join("").substr(0,6);if(f!=e.leapday)return!0;var g=parseInt(a,10);return g%4===0?g%100===0?g%400===0?!0:!1:!0:!1}return!1},cardinality:4,prevalidator:[{validator:function(a,b,c,d,e){var f=e.isInYearRange(a,e.yearrange.minyear,e.yearrange.maxyear);if(!d&&!f){var g=e.determinebaseyear(e.yearrange.minyear,e.yearrange.maxyear,a+"0").toString().slice(0,1);if(f=e.isInYearRange(g+a,e.yearrange.minyear,e.yearrange.maxyear))return b.buffer[c++]=g.charAt(0),{pos:c};if(g=e.determinebaseyear(e.yearrange.minyear,e.yearrange.maxyear,a+"0").toString().slice(0,2),f=e.isInYearRange(g+a,e.yearrange.minyear,e.yearrange.maxyear))return b.buffer[c++]=g.charAt(0),b.buffer[c++]=g.charAt(1),{pos:c}}return f},cardinality:1},{validator:function(a,b,c,d,e){var f=e.isInYearRange(a,e.yearrange.minyear,e.yearrange.maxyear);if(!d&&!f){var g=e.determinebaseyear(e.yearrange.minyear,e.yearrange.maxyear,a).toString().slice(0,2);if(f=e.isInYearRange(a[0]+g[1]+a[1],e.yearrange.minyear,e.yearrange.maxyear))return b.buffer[c++]=g.charAt(1),{pos:c};if(g=e.determinebaseyear(e.yearrange.minyear,e.yearrange.maxyear,a).toString().slice(0,2),e.isInYearRange(g+a,e.yearrange.minyear,e.yearrange.maxyear)){var h=b.buffer.join("").substr(0,6);if(h!=e.leapday)f=!0;else{var i=parseInt(a,10);f=i%4===0?i%100===0?i%400===0?!0:!1:!0:!1}}else f=!1;if(f)return b.buffer[c-1]=g.charAt(0),b.buffer[c++]=g.charAt(1),b.buffer[c++]=a.charAt(0),{refreshFromBuffer:{start:c-3,end:c},pos:c}}return f},cardinality:2},{validator:function(a,b,c,d,e){return e.isInYearRange(a,e.yearrange.minyear,e.yearrange.maxyear)},cardinality:3}]}},insertMode:!1,autoUnmask:!1},"mm/dd/yyyy":{placeholder:"mm/dd/yyyy",alias:"dd/mm/yyyy",regex:{val2pre:function(a){var b=inputmask.escapeRegex.call(this,a);return new RegExp("((0[13-9]|1[012])"+b+"[0-3])|(02"+b+"[0-2])")},val2:function(a){var b=inputmask.escapeRegex.call(this,a);return new RegExp("((0[1-9]|1[012])"+b+"(0[1-9]|[12][0-9]))|((0[13-9]|1[012])"+b+"30)|((0[13578]|1[02])"+b+"31)")},val1pre:new RegExp("[01]"),val1:new RegExp("0[1-9]|1[012]")},leapday:"02/29/",onKeyDown:function(b,c,d,e){var f=a(this);if(b.ctrlKey&&b.keyCode==inputmask.keyCode.RIGHT){var g=new Date;f.val((g.getMonth()+1).toString()+g.getDate().toString()+g.getFullYear().toString()),f.triggerHandler("setvalue.inputmask")}}},"yyyy/mm/dd":{mask:"y/1/2",placeholder:"yyyy/mm/dd",alias:"mm/dd/yyyy",leapday:"/02/29",onKeyDown:function(b,c,d,e){var f=a(this);if(b.ctrlKey&&b.keyCode==inputmask.keyCode.RIGHT){var g=new Date;f.val(g.getFullYear().toString()+(g.getMonth()+1).toString()+g.getDate().toString()),f.triggerHandler("setvalue.inputmask")}}},"dd.mm.yyyy":{mask:"1.2.y",placeholder:"dd.mm.yyyy",leapday:"29.02.",separator:".",alias:"dd/mm/yyyy"},"dd-mm-yyyy":{mask:"1-2-y",placeholder:"dd-mm-yyyy",leapday:"29-02-",separator:"-",alias:"dd/mm/yyyy"},"mm.dd.yyyy":{mask:"1.2.y",placeholder:"mm.dd.yyyy",leapday:"02.29.",separator:".",alias:"mm/dd/yyyy"},"mm-dd-yyyy":{mask:"1-2-y",placeholder:"mm-dd-yyyy",leapday:"02-29-",separator:"-",alias:"mm/dd/yyyy"},"yyyy.mm.dd":{mask:"y.1.2",placeholder:"yyyy.mm.dd",leapday:".02.29",separator:".",alias:"yyyy/mm/dd"},"yyyy-mm-dd":{mask:"y-1-2",placeholder:"yyyy-mm-dd",leapday:"-02-29",separator:"-",alias:"yyyy/mm/dd"},datetime:{mask:"1/2/y h:s",placeholder:"dd/mm/yyyy hh:mm",alias:"dd/mm/yyyy",regex:{hrspre:new RegExp("[012]"),hrs24:new RegExp("2[0-4]|1[3-9]"),hrs:new RegExp("[01][0-9]|2[0-4]"),ampm:new RegExp("^[a|p|A|P][m|M]"),mspre:new RegExp("[0-5]"),ms:new RegExp("[0-5][0-9]")},timeseparator:":",hourFormat:"24",definitions:{h:{validator:function(a,b,c,d,e){if("24"==e.hourFormat&&24==parseInt(a,10))return b.buffer[c-1]="0",b.buffer[c]="0",{refreshFromBuffer:{start:c-1,end:c},c:"0"};var f=e.regex.hrs.test(a);if(!d&&!f&&(a.charAt(1)==e.timeseparator||-1!="-.:".indexOf(a.charAt(1)))&&(f=e.regex.hrs.test("0"+a.charAt(0))))return b.buffer[c-1]="0",b.buffer[c]=a.charAt(0),c++,{refreshFromBuffer:{start:c-2,end:c},pos:c,c:e.timeseparator};if(f&&"24"!==e.hourFormat&&e.regex.hrs24.test(a)){var g=parseInt(a,10);return 24==g?(b.buffer[c+5]="a",b.buffer[c+6]="m"):(b.buffer[c+5]="p",b.buffer[c+6]="m"),g-=12,10>g?(b.buffer[c]=g.toString(),b.buffer[c-1]="0"):(b.buffer[c]=g.toString().charAt(1),b.buffer[c-1]=g.toString().charAt(0)),{refreshFromBuffer:{start:c-1,end:c+6},c:b.buffer[c]}}return f},cardinality:2,prevalidator:[{validator:function(a,b,c,d,e){var f=e.regex.hrspre.test(a);return d||f||!(f=e.regex.hrs.test("0"+a))?f:(b.buffer[c]="0",c++,{pos:c})},cardinality:1}]},s:{validator:"[0-5][0-9]",cardinality:2,prevalidator:[{validator:function(a,b,c,d,e){var f=e.regex.mspre.test(a);return d||f||!(f=e.regex.ms.test("0"+a))?f:(b.buffer[c]="0",c++,{pos:c})},cardinality:1}]},t:{validator:function(a,b,c,d,e){return e.regex.ampm.test(a+"m")},casing:"lower",cardinality:1}},insertMode:!1,autoUnmask:!1},datetime12:{mask:"1/2/y h:s t\\m",placeholder:"dd/mm/yyyy hh:mm xm",alias:"datetime",hourFormat:"12"},"hh:mm t":{mask:"h:s t\\m",placeholder:"hh:mm xm",alias:"datetime",hourFormat:"12"},"h:s t":{mask:"h:s t\\m",placeholder:"hh:mm xm",alias:"datetime",hourFormat:"12"},"hh:mm:ss":{mask:"h:s:s",placeholder:"hh:mm:ss",alias:"datetime",autoUnmask:!1},"hh:mm":{mask:"h:s",placeholder:"hh:mm",alias:"datetime",autoUnmask:!1},date:{alias:"dd/mm/yyyy"},"mm/yyyy":{mask:"1/y",placeholder:"mm/yyyy",leapday:"donotuse",separator:"/",alias:"mm/dd/yyyy"},shamsi:{regex:{val2pre:function(a){var b=inputmask.escapeRegex.call(this,a);return new RegExp("((0[1-9]|1[012])"+b+"[0-3])")},val2:function(a){var b=inputmask.escapeRegex.call(this,a);return new RegExp("((0[1-9]|1[012])"+b+"(0[1-9]|[12][0-9]))|((0[1-9]|1[012])"+b+"30)|((0[1-6])"+b+"31)")},val1pre:new RegExp("[01]"),val1:new RegExp("0[1-9]|1[012]")},yearrange:{minyear:1300,maxyear:1499},mask:"y/1/2",leapday:"/12/30",placeholder:"yyyy/mm/dd",alias:"mm/dd/yyyy",clearIncomplete:!0}}),inputmask}(jQuery),function(a){return inputmask.extendDefinitions({A:{validator:"[A-Za-z\u0410-\u044f\u0401\u0451\xc0-\xff\xb5]",cardinality:1,casing:"upper"},"#":{validator:"[0-9A-Za-z\u0410-\u044f\u0401\u0451\xc0-\xff\xb5]",cardinality:1,casing:"upper"}}),inputmask.extendAliases({url:{mask:"ir",placeholder:"",separator:"",defaultPrefix:"http://",regex:{urlpre1:new RegExp("[fh]"),urlpre2:new RegExp("(ft|ht)"),urlpre3:new RegExp("(ftp|htt)"),urlpre4:new RegExp("(ftp:|http|ftps)"),urlpre5:new RegExp("(ftp:/|ftps:|http:|https)"),urlpre6:new RegExp("(ftp://|ftps:/|http:/|https:)"),urlpre7:new RegExp("(ftp://|ftps://|http://|https:/)"),urlpre8:new RegExp("(ftp://|ftps://|http://|https://)")},definitions:{i:{validator:function(a,b,c,d,e){return!0},cardinality:8,prevalidator:function(){for(var a=[],b=8,c=0;b>c;c++)a[c]=function(){var a=c;return{validator:function(b,c,d,e,f){if(f.regex["urlpre"+(a+1)]){var g,h=b;a+1-b.length>0&&(h=c.buffer.join("").substring(0,a+1-b.length)+""+h);var i=f.regex["urlpre"+(a+1)].test(h);if(!e&&!i){for(d-=a,g=0;g<f.defaultPrefix.length;g++)c.buffer[d]=f.defaultPrefix[g],d++;for(g=0;g<h.length-1;g++)c.buffer[d]=h[g],d++;return{pos:d}}return i}return!1},cardinality:a}}();return a}()},r:{validator:".",cardinality:50}},insertMode:!1,autoUnmask:!1},ip:{mask:"i[i[i]].i[i[i]].i[i[i]].i[i[i]]",definitions:{i:{validator:function(a,b,c,d,e){return c-1>-1&&"."!=b.buffer[c-1]?(a=b.buffer[c-1]+a,a=c-2>-1&&"."!=b.buffer[c-2]?b.buffer[c-2]+a:"0"+a):a="00"+a,new RegExp("25[0-5]|2[0-4][0-9]|[01][0-9][0-9]").test(a)},cardinality:1}}},email:{mask:"*{1,64}[.*{1,64}][.*{1,64}][.*{1,64}]@*{1,64}[.*{2,64}][.*{2,6}][.*{1,2}]",greedy:!1,onBeforePaste:function(a,b){return a=a.toLowerCase(),a.replace("mailto:","")},definitions:{"*":{validator:"[0-9A-Za-z!#$%&'*+/=?^_`{|}~-]",cardinality:1,casing:"lower"}}}}),inputmask}(jQuery),function(a){return inputmask.extendAliases({numeric:{mask:function(a){function b(b){for(var c="",d=0;d<b.length;d++)c+=a.definitions[b[d]]?"\\"+b[d]:b[d];return c}if(0!==a.repeat&&isNaN(a.integerDigits)&&(a.integerDigits=a.repeat),a.repeat=0,a.groupSeparator==a.radixPoint&&("."==a.radixPoint?a.groupSeparator=",":","==a.radixPoint?a.groupSeparator=".":a.groupSeparator="")," "===a.groupSeparator&&(a.skipOptionalPartCharacter=void 0),a.autoGroup=a.autoGroup&&""!=a.groupSeparator,a.autoGroup&&("string"==typeof a.groupSize&&isFinite(a.groupSize)&&(a.groupSize=parseInt(a.groupSize)),isFinite(a.integerDigits))){var c=Math.floor(a.integerDigits/a.groupSize),d=a.integerDigits%a.groupSize;a.integerDigits=parseInt(a.integerDigits)+(0==d?c-1:c)}a.placeholder.length>1&&(a.placeholder=a.placeholder.charAt(0)),a.radixFocus=a.radixFocus&&"0"==a.placeholder,a.definitions[";"]=a.definitions["~"],a.definitions[";"].definitionSymbol="~";var e=b(a.prefix);return e+="[+]",e+="~{1,"+a.integerDigits+"}",void 0!=a.digits&&(isNaN(a.digits)||parseInt(a.digits)>0)&&(e+=a.digitsOptional?"["+(a.decimalProtect?":":a.radixPoint)+";{"+a.digits+"}]":(a.decimalProtect?":":a.radixPoint)+";{"+a.digits+"}"),""!=a.negationSymbol.back&&(e+="[-]"),e+=b(a.suffix),a.greedy=!1,e},placeholder:"",greedy:!1,digits:"*",digitsOptional:!0,radixPoint:".",radixFocus:!0,groupSize:3,autoGroup:!1,allowPlus:!0,allowMinus:!0,negationSymbol:{front:"-",back:""},integerDigits:"+",prefix:"",suffix:"",rightAlign:!0,decimalProtect:!0,min:void 0,max:void 0,step:1,insertMode:!0,autoUnmask:!1,unmaskAsNumber:!1,postFormat:function(b,c,d,e){var f=!1;b.length>=e.suffix.length&&b.join("").indexOf(e.suffix)==b.length-e.suffix.length&&(b.length=b.length-e.suffix.length,f=!0),c=c>=b.length?b.length-1:c<e.prefix.length?e.prefix.length:c;var g=!1,h=b[c];if(""==e.groupSeparator||-1!=a.inArray(e.radixPoint,b)&&c>a.inArray(e.radixPoint,b)||new RegExp("["+inputmask.escapeRegex(e.negationSymbol.front)+"+]").test(h)){if(f)for(var i=0,j=e.suffix.length;j>i;i++)b.push(e.suffix.charAt(i));return{pos:c}}var k=b.slice();h==e.groupSeparator&&(k.splice(c--,1),h=k[c]),d?h!=e.radixPoint&&(k[c]="?"):k.splice(c,0,"?");var l=k.join(""),m=l;if(l.length>0&&e.autoGroup||d&&-1!=l.indexOf(e.groupSeparator)){var n=inputmask.escapeRegex(e.groupSeparator);g=0==l.indexOf(e.groupSeparator),l=l.replace(new RegExp(n,"g"),"");var o=l.split(e.radixPoint);if(l=""==e.radixPoint?l:o[0],l!=e.prefix+"?0"&&l.length>=e.groupSize+e.prefix.length)for(var p=new RegExp("([-+]?[\\d?]+)([\\d?]{"+e.groupSize+"})");p.test(l);)l=l.replace(p,"$1"+e.groupSeparator+"$2"),l=l.replace(e.groupSeparator+e.groupSeparator,e.groupSeparator);""!=e.radixPoint&&o.length>1&&(l+=e.radixPoint+o[1])}g=m!=l,b.length=l.length;for(var i=0,j=l.length;j>i;i++)b[i]=l.charAt(i);var q=a.inArray("?",b);if(-1==q&&h==e.radixPoint&&(q=a.inArray(e.radixPoint,b)),d?b[q]=h:b.splice(q,1),!g&&f)for(var i=0,j=e.suffix.length;j>i;i++)b.push(e.suffix.charAt(i));return{pos:q,refreshFromBuffer:g,buffer:b}},onBeforeWrite:function(b,c,d,e){if(b&&"blur"==b.type){var f=c.join(""),g=f.replace(e.prefix,"");if(g=g.replace(e.suffix,""),g=g.replace(new RegExp(inputmask.escapeRegex(e.groupSeparator),"g"),""),","===e.radixPoint&&(g=g.replace(inputmask.escapeRegex(e.radixPoint),".")),isFinite(g)&&isFinite(e.min)&&parseFloat(g)<parseFloat(e.min))return a.extend(!0,{refreshFromBuffer:!0,buffer:(e.prefix+e.min).split("")},e.postFormat((e.prefix+e.min).split(""),0,!0,e));var h=""!=e.radixPoint?c.join("").split(e.radixPoint):[c.join("")],i=h[0].match(e.regex.integerPart(e)),j=2==h.length?h[1].match(e.regex.integerNPart(e)):void 0;!i||i[0]!=e.negationSymbol.front+"0"&&i[0]!=e.negationSymbol.front&&"+"!=i[0]||void 0!=j&&!j[0].match(/^0+$/)||c.splice(i.index,1);var k=a.inArray(e.radixPoint,c);if(-1!=k&&isFinite(e.digits)&&!e.digitsOptional){for(var l=1;l<=e.digits;l++)(void 0==c[k+l]||c[k+l]==e.placeholder.charAt(0))&&(c[k+l]="0");return{refreshFromBuffer:!0,buffer:c}}}if(e.autoGroup){var m=e.postFormat(c,d-1,!0,e);return m.caret=d<=e.prefix.length?m.pos:m.pos+1,m}},regex:{integerPart:function(a){return new RegExp("["+inputmask.escapeRegex(a.negationSymbol.front)+"+]?\\d+")},integerNPart:function(a){
return new RegExp("[\\d"+inputmask.escapeRegex(a.groupSeparator)+"]+")}},signHandler:function(a,b,c,d,e){if(!d&&e.allowMinus&&"-"===a||e.allowPlus&&"+"===a){var f=b.buffer.join("").match(e.regex.integerPart(e));if(f&&f[0].length>0)return b.buffer[f.index]==("-"===a?"+":e.negationSymbol.front)?"-"==a?""!=e.negationSymbol.back?{pos:f.index,c:e.negationSymbol.front,remove:f.index,caret:c,insert:{pos:b.buffer.length-e.suffix.length-1,c:e.negationSymbol.back}}:{pos:f.index,c:e.negationSymbol.front,remove:f.index,caret:c}:""!=e.negationSymbol.back?{pos:f.index,c:"+",remove:[f.index,b.buffer.length-e.suffix.length-1],caret:c}:{pos:f.index,c:"+",remove:f.index,caret:c}:b.buffer[f.index]==("-"===a?e.negationSymbol.front:"+")?"-"==a&&""!=e.negationSymbol.back?{remove:[f.index,b.buffer.length-e.suffix.length-1],caret:c-1}:{remove:f.index,caret:c-1}:"-"==a?""!=e.negationSymbol.back?{pos:f.index,c:e.negationSymbol.front,caret:c+1,insert:{pos:b.buffer.length-e.suffix.length,c:e.negationSymbol.back}}:{pos:f.index,c:e.negationSymbol.front,caret:c+1}:{pos:f.index,c:a,caret:c+1}}return!1},radixHandler:function(b,c,d,e,f){if(!e&&b===f.radixPoint&&f.digits>0){var g=a.inArray(f.radixPoint,c.buffer),h=c.buffer.join("").match(f.regex.integerPart(f));if(-1!=g&&c.validPositions[g])return c.validPositions[g-1]?{caret:g+1}:{pos:h.index,c:h[0],caret:g+1};if(!h||"0"==h[0]&&h.index+1!=d)return c.buffer[h?h.index:d]="0",{pos:(h?h.index:d)+1}}return!1},leadingZeroHandler:function(b,c,d,e,f){var g=c.buffer.join("").match(f.regex.integerNPart(f)),h=a.inArray(f.radixPoint,c.buffer);if(g&&!e&&(-1==h||h>=d))if(0==g[0].indexOf("0")){d<f.prefix.length&&(d=g.index);var i=a.inArray(f.radixPoint,c._buffer),j=c._buffer&&c.buffer.slice(h).join("")==c._buffer.slice(i).join("")||0==parseInt(c.buffer.slice(h+1).join("")),k=c._buffer&&c.buffer.slice(g.index,h).join("")==c._buffer.slice(f.prefix.length,i).join("")||"0"==c.buffer.slice(g.index,h).join("");if(-1==h||j&&k)return c.buffer.splice(g.index,1),d=d>g.index?d-1:g.index,{pos:d,remove:g.index};if(g.index+1==d||"0"==b)return c.buffer.splice(g.index,1),d=g.index,{pos:d,remove:g.index}}else if("0"===b&&d<=g.index&&g[0]!=f.groupSeparator)return!1;return!0},postValidation:function(a,b){var c=!0,d=a.join(""),e=d.replace(b.prefix,"");return e=e.replace(b.suffix,""),e=e.replace(new RegExp(inputmask.escapeRegex(b.groupSeparator),"g"),""),","===b.radixPoint&&(e=e.replace(inputmask.escapeRegex(b.radixPoint),".")),e=e.replace(new RegExp("^"+inputmask.escapeRegex(b.negationSymbol.front)),"-"),e=e.replace(new RegExp(inputmask.escapeRegex(b.negationSymbol.back)+"$"),""),isFinite(e)&&isFinite(b.max)&&(c=parseFloat(e)<=parseFloat(b.max)),c},definitions:{"~":{validator:function(b,c,d,e,f){var g=f.signHandler(b,c,d,e,f);if(!g&&(g=f.radixHandler(b,c,d,e,f),!g&&(g=e?new RegExp("[0-9"+inputmask.escapeRegex(f.groupSeparator)+"]").test(b):new RegExp("[0-9]").test(b),g===!0&&(g=f.leadingZeroHandler(b,c,d,e,f),g===!0)))){var h=a.inArray(f.radixPoint,c.buffer);g=-1!=h&&f.digitsOptional===!1&&d>h&&!e?{pos:d,remove:d}:{pos:d}}return g},cardinality:1,prevalidator:null},"+":{validator:function(a,b,c,d,e){var f=e.signHandler(a,b,c,d,e);return!f&&(d&&e.allowMinus&&a===e.negationSymbol.front||e.allowMinus&&"-"==a||e.allowPlus&&"+"==a)&&(f="-"==a?""!=e.negationSymbol.back?{pos:c,c:"-"===a?e.negationSymbol.front:"+",caret:c+1,insert:{pos:b.buffer.length,c:e.negationSymbol.back}}:{pos:c,c:"-"===a?e.negationSymbol.front:"+",caret:c+1}:!0),f},cardinality:1,prevalidator:null,placeholder:""},"-":{validator:function(a,b,c,d,e){var f=e.signHandler(a,b,c,d,e);return!f&&d&&e.allowMinus&&a===e.negationSymbol.back&&(f=!0),f},cardinality:1,prevalidator:null,placeholder:""},":":{validator:function(a,b,c,d,e){var f=e.signHandler(a,b,c,d,e);if(!f){var g="["+inputmask.escapeRegex(e.radixPoint)+"]";f=new RegExp(g).test(a),f&&b.validPositions[c]&&b.validPositions[c].match.placeholder==e.radixPoint&&(f={caret:c+1})}return f},cardinality:1,prevalidator:null,placeholder:function(a){return a.radixPoint}}},onUnMask:function(a,b,c){var d=a.replace(c.prefix,"");return d=d.replace(c.suffix,""),d=d.replace(new RegExp(inputmask.escapeRegex(c.groupSeparator),"g"),""),c.unmaskAsNumber?(d=d.replace(inputmask.escapeRegex.call(this,c.radixPoint),"."),Number(d)):d},isComplete:function(a,b){var c=a.join(""),d=a.slice();if(b.postFormat(d,0,!0,b),d.join("")!=c)return!1;var e=c.replace(b.prefix,"");return e=e.replace(b.suffix,""),e=e.replace(new RegExp(inputmask.escapeRegex(b.groupSeparator),"g"),""),","===b.radixPoint&&(e=e.replace(inputmask.escapeRegex(b.radixPoint),".")),isFinite(e)},onBeforeMask:function(a,b){if(""!=b.radixPoint&&isFinite(a))a=a.toString().replace(".",b.radixPoint);else{var c=a.match(/,/g),d=a.match(/\./g);d&&c?d.length>c.length?(a=a.replace(/\./g,""),a=a.replace(",",b.radixPoint)):c.length>d.length?(a=a.replace(/,/g,""),a=a.replace(".",b.radixPoint)):a=a.indexOf(".")<a.indexOf(",")?a.replace(/\./g,""):a=a.replace(/,/g,""):a=a.replace(new RegExp(inputmask.escapeRegex(b.groupSeparator),"g"),"")}if(0==b.digits&&(-1!=a.indexOf(".")?a=a.substring(0,a.indexOf(".")):-1!=a.indexOf(",")&&(a=a.substring(0,a.indexOf(",")))),""!=b.radixPoint&&isFinite(b.digits)&&-1!=a.indexOf(b.radixPoint)){var e=a.split(b.radixPoint),f=e[1].match(new RegExp("\\d*"))[0];if(parseInt(b.digits)<f.toString().length){var g=Math.pow(10,parseInt(b.digits));a=a.replace(inputmask.escapeRegex(b.radixPoint),"."),a=Math.round(parseFloat(a)*g)/g,a=a.toString().replace(".",b.radixPoint)}}return a.toString()},canClearPosition:function(b,c,d,e,f){var g=b.validPositions[c].input,h=g!=f.radixPoint&&isFinite(g)||c==d||g==f.groupSeparator||g==f.negationSymbol.front||g==f.negationSymbol.back;if(h&&isFinite(g)){var i;if(!e&&b.buffer){i=b.buffer.join("").substr(0,c).match(f.regex.integerNPart(f));var j=c+1,k=null==i||0==parseInt(i[0].replace(new RegExp(inputmask.escapeRegex(f.groupSeparator),"g"),""));if(k)for(;b.validPositions[j]&&(b.validPositions[j].input==f.groupSeparator||"0"==b.validPositions[j].input);)delete b.validPositions[j],j++}var l=[];for(var m in b.validPositions)l.push(b.validPositions[m].input);i=l.join("").match(f.regex.integerNPart(f));var n=a.inArray(f.radixPoint,b.buffer);if(i&&(-1==n||n>=c))if(0==i[0].indexOf("0"))h=i.index!=c||-1==n;else{var o=parseInt(i[0].replace(new RegExp(inputmask.escapeRegex(f.groupSeparator),"g"),""));-1!=n&&10>o&&(b.validPositions[c].input="0",b.p=f.prefix.length+1,h=!1)}}return h},onKeyDown:function(b,c,d,e){var f=a(this);if(b.ctrlKey)switch(b.keyCode){case inputmask.keyCode.UP:f.val(parseFloat(this.inputmask.unmaskedvalue())+parseInt(e.step)),f.triggerHandler("setvalue.inputmask");break;case inputmask.keyCode.DOWN:f.val(parseFloat(this.inputmask.unmaskedvalue())-parseInt(e.step)),f.triggerHandler("setvalue.inputmask")}}},currency:{prefix:"$ ",groupSeparator:",",alias:"numeric",placeholder:"0",autoGroup:!0,digits:2,digitsOptional:!1,clearMaskOnLostFocus:!1},decimal:{alias:"numeric"},integer:{alias:"numeric",digits:0,radixPoint:""},percentage:{alias:"numeric",digits:2,radixPoint:".",placeholder:"0",autoGroup:!1,min:0,max:100,suffix:" %",allowPlus:!1,allowMinus:!1},numeric2:{alias:"numeric"}}),inputmask}(jQuery),function(a){return inputmask.extendAliases({phone:{url:"phone-codes/phone-codes.js",countrycode:"",mask:function(b){b.definitions["#"]=b.definitions[9];var c=[];return a.ajax({url:b.url,async:!1,dataType:"json",success:function(a){c=a},error:function(a,c,d){alert(d+" - "+b.url)}}),c=c.sort(function(a,b){return(a.mask||a)<(b.mask||b)?-1:1})},keepStatic:!1,nojumps:!0,nojumpsThreshold:1,onBeforeMask:function(a,b){var c=a.replace(/^0/g,"");return(c.indexOf(b.countrycode)>1||-1==c.indexOf(b.countrycode))&&(c="+"+b.countrycode+c),c}},phonebe:{alias:"phone",url:"phone-codes/phone-be.js",countrycode:"32",nojumpsThreshold:4}}),inputmask}(jQuery),function(a){return inputmask.extendAliases({Regex:{mask:"r",greedy:!1,repeat:"*",regex:null,regexTokens:null,tokenizer:/\[\^?]?(?:[^\\\]]+|\\[\S\s]?)*]?|\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9][0-9]*|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|c[A-Za-z]|[\S\s]?)|\((?:\?[:=!]?)?|(?:[?*+]|\{[0-9]+(?:,[0-9]*)?\})\??|[^.?*+^${[()|\\]+|./g,quantifierFilter:/[0-9]+[^,]/,isComplete:function(a,b){return new RegExp(b.regex).test(a.join(""))},definitions:{r:{validator:function(b,c,d,e,f){function g(a,b){this.matches=[],this.isGroup=a||!1,this.isQuantifier=b||!1,this.quantifier={min:1,max:1},this.repeaterPart=void 0}function h(){var a,b,c=new g,d=[];for(f.regexTokens=[];a=f.tokenizer.exec(f.regex);)switch(b=a[0],b.charAt(0)){case"(":d.push(new g(!0));break;case")":var e=d.pop();d.length>0?d[d.length-1].matches.push(e):c.matches.push(e);break;case"{":case"+":case"*":var h=new g(!1,!0);b=b.replace(/[{}]/g,"");var i=b.split(","),j=isNaN(i[0])?i[0]:parseInt(i[0]),k=1==i.length?j:isNaN(i[1])?i[1]:parseInt(i[1]);if(h.quantifier={min:j,max:k},d.length>0){var l=d[d.length-1].matches;if(a=l.pop(),!a.isGroup){var e=new g(!0);e.matches.push(a),a=e}l.push(a),l.push(h)}else{if(a=c.matches.pop(),!a.isGroup){var e=new g(!0);e.matches.push(a),a=e}c.matches.push(a),c.matches.push(h)}break;default:d.length>0?d[d.length-1].matches.push(b):c.matches.push(b)}c.matches.length>0&&f.regexTokens.push(c)}function i(b,c){var d=!1;c&&(k+="(",m++);for(var e=0;e<b.matches.length;e++){var f=b.matches[e];if(1==f.isGroup)d=i(f,!0);else if(1==f.isQuantifier){var g=a.inArray(f,b.matches),h=b.matches[g-1],j=k;if(isNaN(f.quantifier.max)){for(;f.repeaterPart&&f.repeaterPart!=k&&f.repeaterPart.length>k.length&&!(d=i(h,!0)););d=d||i(h,!0),d&&(f.repeaterPart=k),k=j+f.quantifier.max}else{for(var l=0,o=f.quantifier.max-1;o>l&&!(d=i(h,!0));l++);k=j+"{"+f.quantifier.min+","+f.quantifier.max+"}"}}else if(void 0!=f.matches)for(var p=0;p<f.length&&!(d=i(f[p],c));p++);else{var q;if("["==f.charAt(0)){q=k,q+=f;for(var r=0;m>r;r++)q+=")";var s=new RegExp("^("+q+")$");d=s.test(n)}else for(var t=0,u=f.length;u>t;t++)if("\\"!=f.charAt(t)){q=k,q+=f.substr(0,t+1),q=q.replace(/\|$/,"");for(var r=0;m>r;r++)q+=")";var s=new RegExp("^("+q+")$");if(d=s.test(n))break}k+=f}if(d)break}return c&&(k+=")",m--),d}null==f.regexTokens&&h();var j=c.buffer.slice(),k="",l=!1,m=0;j.splice(d,0,b);for(var n=j.join(""),o=0;o<f.regexTokens.length;o++){var g=f.regexTokens[o];if(l=i(g,g.isGroup))break}return l},cardinality:1}}}}),inputmask}(jQuery);;
/*! Sortable 1.4.2 - MIT | git://github.com/rubaxa/Sortable.git */
!function (a) { "use strict"; "function" == typeof define && define.amd ? define(a) : "undefined" != typeof module && "undefined" != typeof module.exports ? module.exports = a() : "undefined" != typeof Package ? Sortable = a() : window.Sortable = a() }(function () { "use strict"; function a(a, b) { if (!a || !a.nodeType || 1 !== a.nodeType) throw "Sortable: `el` must be HTMLElement, and not " + {}.toString.call(a); this.el = a, this.options = b = r({}, b), a[L] = this; var c = { group: Math.random(), sort: !0, disabled: !1, store: null, handle: null, scroll: !0, scrollSensitivity: 30, scrollSpeed: 10, draggable: /[uo]l/i.test(a.nodeName) ? "li" : ">*", ghostClass: "sortable-ghost", chosenClass: "sortable-chosen", ignore: "a, img", filter: null, animation: 0, setData: function (a, b) { a.setData("Text", b.textContent) }, dropBubble: !1, dragoverBubble: !1, dataIdAttr: "data-id", delay: 0, forceFallback: !1, fallbackClass: "sortable-fallback", fallbackOnBody: !1 }; for (var d in c) !(d in b) && (b[d] = c[d]); V(b); for (var f in this) "_" === f.charAt(0) && (this[f] = this[f].bind(this)); this.nativeDraggable = b.forceFallback ? !1 : P, e(a, "mousedown", this._onTapStart), e(a, "touchstart", this._onTapStart), this.nativeDraggable && (e(a, "dragover", this), e(a, "dragenter", this)), T.push(this._onDragOver), b.store && this.sort(b.store.get(this)) } function b(a) { v && v.state !== a && (h(v, "display", a ? "none" : ""), !a && v.state && w.insertBefore(v, s), v.state = a) } function c(a, b, c) { if (a) { c = c || N, b = b.split("."); var d = b.shift().toUpperCase(), e = new RegExp("\\s(" + b.join("|") + ")(?=\\s)", "g"); do if (">*" === d && a.parentNode === c || ("" === d || a.nodeName.toUpperCase() == d) && (!b.length || ((" " + a.className + " ").match(e) || []).length == b.length)) return a; while (a !== c && (a = a.parentNode)) } return null } function d(a) { a.dataTransfer && (a.dataTransfer.dropEffect = "move"), a.preventDefault() } function e(a, b, c) { a.addEventListener(b, c, !1) } function f(a, b, c) { a.removeEventListener(b, c, !1) } function g(a, b, c) { if (a) if (a.classList) a.classList[c ? "add" : "remove"](b); else { var d = (" " + a.className + " ").replace(K, " ").replace(" " + b + " ", " "); a.className = (d + (c ? " " + b : "")).replace(K, " ") } } function h(a, b, c) { var d = a && a.style; if (d) { if (void 0 === c) return N.defaultView && N.defaultView.getComputedStyle ? c = N.defaultView.getComputedStyle(a, "") : a.currentStyle && (c = a.currentStyle), void 0 === b ? c : c[b]; b in d || (b = "-webkit-" + b), d[b] = c + ("string" == typeof c ? "" : "px") } } function i(a, b, c) { if (a) { var d = a.getElementsByTagName(b), e = 0, f = d.length; if (c) for (; f > e; e++) c(d[e], e); return d } return [] } function j(a, b, c, d, e, f, g) { var h = N.createEvent("Event"), i = (a || b[L]).options, j = "on" + c.charAt(0).toUpperCase() + c.substr(1); h.initEvent(c, !0, !0), h.to = b, h.from = e || b, h.item = d || b, h.clone = v, h.oldIndex = f, h.newIndex = g, b.dispatchEvent(h), i[j] && i[j].call(a, h) } function k(a, b, c, d, e, f) { var g, h, i = a[L], j = i.options.onMove; return g = N.createEvent("Event"), g.initEvent("move", !0, !0), g.to = b, g.from = a, g.dragged = c, g.draggedRect = d, g.related = e || b, g.relatedRect = f || b.getBoundingClientRect(), a.dispatchEvent(g), j && (h = j.call(i, g)), h } function l(a) { a.draggable = !1 } function m() { R = !1 } function n(a, b) { var c = a.lastElementChild, d = c.getBoundingClientRect(); return (b.clientY - (d.top + d.height) > 5 || b.clientX - (d.right + d.width) > 5) && c } function o(a) { for (var b = a.tagName + a.className + a.src + a.href + a.textContent, c = b.length, d = 0; c--;) d += b.charCodeAt(c); return d.toString(36) } function p(a) { var b = 0; if (!a || !a.parentNode) return -1; for (; a && (a = a.previousElementSibling) ;) "TEMPLATE" !== a.nodeName.toUpperCase() && b++; return b } function q(a, b) { var c, d; return function () { void 0 === c && (c = arguments, d = this, setTimeout(function () { 1 === c.length ? a.call(d, c[0]) : a.apply(d, c), c = void 0 }, b)) } } function r(a, b) { if (a && b) for (var c in b) b.hasOwnProperty(c) && (a[c] = b[c]); return a } var s, t, u, v, w, x, y, z, A, B, C, D, E, F, G, H, I, J = {}, K = /\s+/g, L = "Sortable" + (new Date).getTime(), M = window, N = M.document, O = M.parseInt, P = !!("draggable" in N.createElement("div")), Q = function (a) { return a = N.createElement("x"), a.style.cssText = "pointer-events:auto", "auto" === a.style.pointerEvents }(), R = !1, S = Math.abs, T = ([].slice, []), U = q(function (a, b, c) { if (c && b.scroll) { var d, e, f, g, h = b.scrollSensitivity, i = b.scrollSpeed, j = a.clientX, k = a.clientY, l = window.innerWidth, m = window.innerHeight; if (z !== c && (y = b.scroll, z = c, y === !0)) { y = c; do if (y.offsetWidth < y.scrollWidth || y.offsetHeight < y.scrollHeight) break; while (y = y.parentNode) } y && (d = y, e = y.getBoundingClientRect(), f = (S(e.right - j) <= h) - (S(e.left - j) <= h), g = (S(e.bottom - k) <= h) - (S(e.top - k) <= h)), f || g || (f = (h >= l - j) - (h >= j), g = (h >= m - k) - (h >= k), (f || g) && (d = M)), (J.vx !== f || J.vy !== g || J.el !== d) && (J.el = d, J.vx = f, J.vy = g, clearInterval(J.pid), d && (J.pid = setInterval(function () { d === M ? M.scrollTo(M.pageXOffset + f * i, M.pageYOffset + g * i) : (g && (d.scrollTop += g * i), f && (d.scrollLeft += f * i)) }, 24))) } }, 30), V = function (a) { var b = a.group; b && "object" == typeof b || (b = a.group = { name: b }), ["pull", "put"].forEach(function (a) { a in b || (b[a] = !0) }), a.groups = " " + b.name + (b.put.join ? " " + b.put.join(" ") : "") + " " }; return a.prototype = { constructor: a, _onTapStart: function (a) { var b = this, d = this.el, e = this.options, f = a.type, g = a.touches && a.touches[0], h = (g || a).target, i = h, k = e.filter; if (!("mousedown" === f && 0 !== a.button || e.disabled) && (h = c(h, e.draggable, d))) { if (D = p(h), "function" == typeof k) { if (k.call(this, a, h, this)) return j(b, i, "filter", h, d, D), void a.preventDefault() } else if (k && (k = k.split(",").some(function (a) { return a = c(i, a.trim(), d), a ? (j(b, a, "filter", h, d, D), !0) : void 0 }))) return void a.preventDefault(); (!e.handle || c(i, e.handle, d)) && this._prepareDragStart(a, g, h) } }, _prepareDragStart: function (a, b, c) { var d, f = this, h = f.el, j = f.options, k = h.ownerDocument; c && !s && c.parentNode === h && (G = a, w = h, s = c, t = s.parentNode, x = s.nextSibling, F = j.group, d = function () { f._disableDelayedDrag(), s.draggable = !0, g(s, f.options.chosenClass, !0), f._triggerDragStart(b) }, j.ignore.split(",").forEach(function (a) { i(s, a.trim(), l) }), e(k, "mouseup", f._onDrop), e(k, "touchend", f._onDrop), e(k, "touchcancel", f._onDrop), j.delay ? (e(k, "mouseup", f._disableDelayedDrag), e(k, "touchend", f._disableDelayedDrag), e(k, "touchcancel", f._disableDelayedDrag), e(k, "mousemove", f._disableDelayedDrag), e(k, "touchmove", f._disableDelayedDrag), f._dragStartTimer = setTimeout(d, j.delay)) : d()) }, _disableDelayedDrag: function () { var a = this.el.ownerDocument; clearTimeout(this._dragStartTimer), f(a, "mouseup", this._disableDelayedDrag), f(a, "touchend", this._disableDelayedDrag), f(a, "touchcancel", this._disableDelayedDrag), f(a, "mousemove", this._disableDelayedDrag), f(a, "touchmove", this._disableDelayedDrag) }, _triggerDragStart: function (a) { a ? (G = { target: s, clientX: a.clientX, clientY: a.clientY }, this._onDragStart(G, "touch")) : this.nativeDraggable ? (e(s, "dragend", this), e(w, "dragstart", this._onDragStart)) : this._onDragStart(G, !0); try { N.selection ? N.selection.empty() : window.getSelection().removeAllRanges() } catch (b) { } }, _dragStarted: function () { w && s && (g(s, this.options.ghostClass, !0), a.active = this, j(this, w, "start", s, w, D)) }, _emulateDragOver: function () { if (H) { if (this._lastX === H.clientX && this._lastY === H.clientY) return; this._lastX = H.clientX, this._lastY = H.clientY, Q || h(u, "display", "none"); var a = N.elementFromPoint(H.clientX, H.clientY), b = a, c = " " + this.options.group.name, d = T.length; if (b) do { if (b[L] && b[L].options.groups.indexOf(c) > -1) { for (; d--;) T[d]({ clientX: H.clientX, clientY: H.clientY, target: a, rootEl: b }); break } a = b } while (b = b.parentNode); Q || h(u, "display", "") } }, _onTouchMove: function (b) { if (G) { a.active || this._dragStarted(), this._appendGhost(); var c = b.touches ? b.touches[0] : b, d = c.clientX - G.clientX, e = c.clientY - G.clientY, f = b.touches ? "translate3d(" + d + "px," + e + "px,0)" : "translate(" + d + "px," + e + "px)"; I = !0, H = c, h(u, "webkitTransform", f), h(u, "mozTransform", f), h(u, "msTransform", f), h(u, "transform", f), b.preventDefault() } }, _appendGhost: function () { if (!u) { var a, b = s.getBoundingClientRect(), c = h(s), d = this.options; u = s.cloneNode(!0), g(u, d.ghostClass, !1), g(u, d.fallbackClass, !0), h(u, "top", b.top - O(c.marginTop, 10)), h(u, "left", b.left - O(c.marginLeft, 10)), h(u, "width", b.width), h(u, "height", b.height), h(u, "opacity", "0.8"), h(u, "position", "fixed"), h(u, "zIndex", "100000"), h(u, "pointerEvents", "none"), d.fallbackOnBody && N.body.appendChild(u) || w.appendChild(u), a = u.getBoundingClientRect(), h(u, "width", 2 * b.width - a.width), h(u, "height", 2 * b.height - a.height) } }, _onDragStart: function (a, b) { var c = a.dataTransfer, d = this.options; this._offUpEvents(), "clone" == F.pull && (v = s.cloneNode(!0), h(v, "display", "none"), w.insertBefore(v, s)), b ? ("touch" === b ? (e(N, "touchmove", this._onTouchMove), e(N, "touchend", this._onDrop), e(N, "touchcancel", this._onDrop)) : (e(N, "mousemove", this._onTouchMove), e(N, "mouseup", this._onDrop)), this._loopId = setInterval(this._emulateDragOver, 50)) : (c && (c.effectAllowed = "move", d.setData && d.setData.call(this, c, s)), e(N, "drop", this), setTimeout(this._dragStarted, 0)) }, _onDragOver: function (a) { var d, e, f, g = this.el, i = this.options, j = i.group, l = j.put, o = F === j, p = i.sort; if (void 0 !== a.preventDefault && (a.preventDefault(), !i.dragoverBubble && a.stopPropagation()), I = !0, F && !i.disabled && (o ? p || (f = !w.contains(s)) : F.pull && l && (F.name === j.name || l.indexOf && ~l.indexOf(F.name))) && (void 0 === a.rootEl || a.rootEl === this.el)) { if (U(a, i, this.el), R) return; if (d = c(a.target, i.draggable, g), e = s.getBoundingClientRect(), f) return b(!0), void (v || x ? w.insertBefore(s, v || x) : p || w.appendChild(s)); if (0 === g.children.length || g.children[0] === u || g === a.target && (d = n(g, a))) { if (d) { if (d.animated) return; r = d.getBoundingClientRect() } b(o), k(w, g, s, e, d, r) !== !1 && (s.contains(g) || (g.appendChild(s), t = g), this._animate(e, s), d && this._animate(r, d)) } else if (d && !d.animated && d !== s && void 0 !== d.parentNode[L]) { A !== d && (A = d, B = h(d), C = h(d.parentNode)); var q, r = d.getBoundingClientRect(), y = r.right - r.left, z = r.bottom - r.top, D = /left|right|inline/.test(B.cssFloat + B.display) || "flex" == C.display && 0 === C["flex-direction"].indexOf("row"), E = d.offsetWidth > s.offsetWidth, G = d.offsetHeight > s.offsetHeight, H = (D ? (a.clientX - r.left) / y : (a.clientY - r.top) / z) > .5, J = d.nextElementSibling, K = k(w, g, s, e, d, r); if (K !== !1) { if (R = !0, setTimeout(m, 30), b(o), 1 === K || -1 === K) q = 1 === K; else if (D) { var M = s.offsetTop, N = d.offsetTop; q = M === N ? d.previousElementSibling === s && !E || H && E : N > M } else q = J !== s && !G || H && G; s.contains(g) || (q && !J ? g.appendChild(s) : d.parentNode.insertBefore(s, q ? J : d)), t = s.parentNode, this._animate(e, s), this._animate(r, d) } } } }, _animate: function (a, b) { var c = this.options.animation; if (c) { var d = b.getBoundingClientRect(); h(b, "transition", "none"), h(b, "transform", "translate3d(" + (a.left - d.left) + "px," + (a.top - d.top) + "px,0)"), b.offsetWidth, h(b, "transition", "all " + c + "ms"), h(b, "transform", "translate3d(0,0,0)"), clearTimeout(b.animated), b.animated = setTimeout(function () { h(b, "transition", ""), h(b, "transform", ""), b.animated = !1 }, c) } }, _offUpEvents: function () { var a = this.el.ownerDocument; f(N, "touchmove", this._onTouchMove), f(a, "mouseup", this._onDrop), f(a, "touchend", this._onDrop), f(a, "touchcancel", this._onDrop) }, _onDrop: function (b) { var c = this.el, d = this.options; clearInterval(this._loopId), clearInterval(J.pid), clearTimeout(this._dragStartTimer), f(N, "mousemove", this._onTouchMove), this.nativeDraggable && (f(N, "drop", this), f(c, "dragstart", this._onDragStart)), this._offUpEvents(), b && (I && (b.preventDefault(), !d.dropBubble && b.stopPropagation()), u && u.parentNode.removeChild(u), s && (this.nativeDraggable && f(s, "dragend", this), l(s), g(s, this.options.ghostClass, !1), g(s, this.options.chosenClass, !1), w !== t ? (E = p(s), E >= 0 && (j(null, t, "sort", s, w, D, E), j(this, w, "sort", s, w, D, E), j(null, t, "add", s, w, D, E), j(this, w, "remove", s, w, D, E))) : (v && v.parentNode.removeChild(v), s.nextSibling !== x && (E = p(s), E >= 0 && (j(this, w, "update", s, w, D, E), j(this, w, "sort", s, w, D, E)))), a.active && ((null === E || -1 === E) && (E = D), j(this, w, "end", s, w, D, E), this.save())), w = s = t = u = x = v = y = z = G = H = I = E = A = B = F = a.active = null) }, handleEvent: function (a) { var b = a.type; "dragover" === b || "dragenter" === b ? s && (this._onDragOver(a), d(a)) : ("drop" === b || "dragend" === b) && this._onDrop(a) }, toArray: function () { for (var a, b = [], d = this.el.children, e = 0, f = d.length, g = this.options; f > e; e++) a = d[e], c(a, g.draggable, this.el) && b.push(a.getAttribute(g.dataIdAttr) || o(a)); return b }, sort: function (a) { var b = {}, d = this.el; this.toArray().forEach(function (a, e) { var f = d.children[e]; c(f, this.options.draggable, d) && (b[a] = f) }, this), a.forEach(function (a) { b[a] && (d.removeChild(b[a]), d.appendChild(b[a])) }) }, save: function () { var a = this.options.store; a && a.set(this) }, closest: function (a, b) { return c(a, b || this.options.draggable, this.el) }, option: function (a, b) { var c = this.options; return void 0 === b ? c[a] : (c[a] = b, void ("group" === a && V(c))) }, destroy: function () { var a = this.el; a[L] = null, f(a, "mousedown", this._onTapStart), f(a, "touchstart", this._onTapStart), this.nativeDraggable && (f(a, "dragover", this), f(a, "dragenter", this)), Array.prototype.forEach.call(a.querySelectorAll("[draggable]"), function (a) { a.removeAttribute("draggable") }), T.splice(T.indexOf(this._onDragOver), 1), this._onDrop(), this.el = a = null } }, a.utils = { on: e, off: f, css: h, find: i, is: function (a, b) { return !!c(a, b, a) }, extend: r, throttle: q, closest: c, toggleClass: g, index: p }, a.create = function (b, c) { return new a(b, c) }, a.version = "1.4.2", a });
/**
 * Bootstrap based calendar full view.
 *
 * https://github.com/Serhioromano/bootstrap-calendar
 *
 * User: Sergey Romanov <serg4172@mail.ru>
 */
"use strict";

Date.prototype.getWeek = function () {
    var onejan = new Date(this.getFullYear(), 0, 1);
    return Math.ceil((((this.getTime() - onejan.getTime()) / 86400000) + onejan.getDay() + 1) / 7);
};
Date.prototype.getMonthFormatted = function () {
    var month = this.getMonth() + 1;
    return month < 10 ? '0' + month : month;
};
Date.prototype.getDateFormatted = function () {
    var date = this.getDate();
    return date < 10 ? '0' + date : date;
};

if (!String.prototype.format) {
    String.prototype.format = function () {
        var args = arguments;
        return this.replace(/{(\d+)}/g, function (match, number) {
            return typeof args[number] != 'undefined' ? args[number] : match;
        });
    };
}
if (!String.prototype.formatNum) {
    String.prototype.formatNum = function (decimal) {
        var r = "" + this;
        while (r.length < decimal)
            r = "0" + r;
        return r;
    };
}

(function ($) {

    var defaults = {
        // Width of the calendar
        width: '100%',
        // Initial view (can be 'month', 'week', 'day')
        view: 'month',
        // Initial date. No matter month, week or day this will be a starting point. Can be 'now' or a date in format 'yyyy-mm-dd'
        day: 'now',
        // Day Start time and end time with time intervals. Time split 10, 15 or 30.
        time_start: '06:00',
        time_end: '22:00',
        time_split: '30',
        // Source of events data. It can be one of the following:
        // - URL to return JSON list of events in special format.
        //   {success:1, result: [....]} or for error {success:0, error:'Something terrible happened'}
        //   events: [...] as described in events property description
        //   The start and end variables will be sent to this url
        // - A function that received the start and end date, and that
        //   returns an array of events (as described in events property description)
        // - An array containing the events
        events_source: '',
        // Set format12 to true if you want to use 12 Hour format instead of 24 Hour
        format12: false,
        am_suffix: "AM",
        pm_suffix: "PM",
        // Path to templates should end with slash /. It can be as relative
        // /component/bootstrap-calendar/tmpls/
        // or absolute
        // http://localhost/component/bootstrap-calendar/tmpls/
        tmpl_path: 'tmpls/',
        tmpl_cache: true,
        classes: {
            months: {
                inmonth: 'cal-day-inmonth',
                outmonth: 'cal-day-outmonth',
                saturday: 'cal-day-weekend',
                sunday: 'cal-day-weekend',
                holidays: 'cal-day-holiday',
                today: 'cal-day-today'
            },
            week: {
                workday: 'cal-day-workday',
                saturday: 'cal-day-weekend',
                sunday: 'cal-day-weekend',
                holidays: 'cal-day-holiday',
                today: 'cal-day-today'
            }
        },
        // ID of the element of modal window. If set, events URLs will be opened in modal windows.
        modal: null,
        //	modal handling setting, one of "iframe", "ajax" or "template"
        modal_type: "iframe",
        //	function to set modal title, will be passed the event as a parameter
        modal_title: null,
        views: {
            year: {
                slide_events: 1,
                enable: 1
            },
            month: {
                slide_events: 1,
                enable: 1
            },
            week: {
                enable: 1
            },
            day: {
                enable: 1
            }
        },
        merge_holidays: false,
        display_week_numbers: true,
        weekbox: true,
        // ------------------------------------------------------------
        // CALLBACKS. Events triggered by calendar class. You can use
        // those to affect you UI
        // ------------------------------------------------------------
        onAfterEventsLoad: function (events) {
            // Inside this function 'this' is the calendar instance
        },
        onBeforeEventsLoad: function (next) {
            // Inside this function 'this' is the calendar instance
            next();
        },
        onAfterViewLoad: function (view) {
            // Inside this function 'this' is the calendar instance
        },
        onAfterModalShown: function (events) {
            // Inside this function 'this' is the calendar instance
        },
        onAfterModalHidden: function (events) {
            // Inside this function 'this' is the calendar instance
        },
        // -------------------------------------------------------------
        // INTERNAL USE ONLY. DO NOT ASSIGN IT WILL BE OVERRIDDEN ANYWAY
        // -------------------------------------------------------------
        events: [],
        templates: {
            year: '',
            month: '',
            week: '',
            day: ''
        },
        stop_cycling: false
    };

    var defaults_extended = {
        first_day: 2,
        holidays: {
            // January 1
            '01-01': "New Year's Day",
            // Third (+3*) Monday (1) in January (01)
            '01+3*1': "Birthday of Dr. Martin Luther King, Jr.",
            // Third (+3*) Monday (1) in February (02)
            '02+3*1': "Washington's Birthday",
            // Last (-1*) Monday (1) in May (05)
            '05-1*1': "Memorial Day",
            // July 4
            '04-07': "Independence Day",
            // First (+1*) Monday (1) in September (09)
            '09+1*1': "Labor Day",
            // Second (+2*) Monday (1) in October (10)
            '10+2*1': "Columbus Day",
            // November 11
            '11-11': "Veterans Day",
            // Fourth (+4*) Thursday (4) in November (11)
            '11+4*4': "Thanksgiving Day",
            // December 25
            '25-12': "Christmas"
        }
    };

    var strings = {
        error_noview: 'Calendar: View {0} not found',
        error_dateformat: 'Calendar: Wrong date format {0}. Should be either "now" or "yyyy-mm-dd"',
        error_loadurl: 'Calendar: Event URL is not set',
        error_where: 'Calendar: Wrong navigation direction {0}. Can be only "next" or "prev" or "today"',
        error_timedevide: 'Calendar: Time split parameter should divide 60 without decimals. Something like 10, 15, 30',

        no_events_in_day: 'No events in this day.',

        title_year: '{0}',
        title_month: '{0} {1}',
        title_week: 'week {0} of {1}',
        title_day: '{0} {1} {2}, {3}',

        week: 'Week {0}',
        all_day: 'All day',
        time: 'Time',
        events: 'Events',
        before_time: 'Ends before timeline',
        after_time: 'Starts after timeline',

        m0: 'January',
        m1: 'February',
        m2: 'March',
        m3: 'April',
        m4: 'May',
        m5: 'June',
        m6: 'July',
        m7: 'August',
        m8: 'September',
        m9: 'October',
        m10: 'November',
        m11: 'December',

        ms0: 'Jan',
        ms1: 'Feb',
        ms2: 'Mar',
        ms3: 'Apr',
        ms4: 'May',
        ms5: 'Jun',
        ms6: 'Jul',
        ms7: 'Aug',
        ms8: 'Sep',
        ms9: 'Oct',
        ms10: 'Nov',
        ms11: 'Dec',

        d0: 'Sunday',
        d1: 'Monday',
        d2: 'Tuesday',
        d3: 'Wednesday',
        d4: 'Thursday',
        d5: 'Friday',
        d6: 'Saturday'
    };

    var browser_timezone = '';
    try {
        if ($.type(window.jstz) == 'object' && $.type(jstz.determine) == 'function') {
            browser_timezone = jstz.determine().name();
            if ($.type(browser_timezone) !== 'string') {
                browser_timezone = '';
            }
        }
    }
    catch (e) {
    }

    function buildEventsUrl(events_url, data) {
        var separator, key, url;
        url = events_url;
        separator = (events_url.indexOf('?') < 0) ? '?' : '&';
        for (key in data) {
            url += separator + key + '=' + encodeURIComponent(data[key]);
            separator = '&';
        }
        return url;
    }

    function getExtentedOption(cal, option_name) {
        var fromOptions = (cal.options[option_name] != null) ? cal.options[option_name] : null;
        var fromLanguage = (cal.locale[option_name] != null) ? cal.locale[option_name] : null;
        if ((option_name == 'holidays') && cal.options.merge_holidays) {
            var holidays = {};
            $.extend(true, holidays, fromLanguage ? fromLanguage : defaults_extended.holidays);
            if (fromOptions) {
                $.extend(true, holidays, fromOptions);
            }
            return holidays;
        }
        else {
            if (fromOptions != null) {
                return fromOptions;
            }
            if (fromLanguage != null) {
                return fromLanguage;
            }
            return defaults_extended[option_name];
        }
    }

    function getHolidays(cal, year) {
        var hash = [];
        var holidays_def = getExtentedOption(cal, 'holidays');
        for (var k in holidays_def) {
            hash.push(k + ':' + holidays_def[k]);
        }
        hash.push(year);
        hash = hash.join('|');
        if (hash in getHolidays.cache) {
            return getHolidays.cache[hash];
        }
        var holidays = [];
        $.each(holidays_def, function (key, name) {
            var firstDay = null, lastDay = null, failed = false;
            $.each(key.split('>'), function (i, chunk) {
                var m, date = null;
                if (m = /^(\d\d)-(\d\d)$/.exec(chunk)) {
                    date = new Date(year, parseInt(m[2], 10) - 1, parseInt(m[1], 10));
                }
                else if (m = /^(\d\d)-(\d\d)-(\d\d\d\d)$/.exec(chunk)) {
                    if (parseInt(m[3], 10) == year) {
                        date = new Date(year, parseInt(m[2], 10) - 1, parseInt(m[1], 10));
                    }
                }
                else if (m = /^easter(([+\-])(\d+))?$/.exec(chunk)) {
                    date = getEasterDate(year, m[1] ? parseInt(m[1], 10) : 0);
                }
                else if (m = /^(\d\d)([+\-])([1-5])\*([0-6])$/.exec(chunk)) {
                    var month = parseInt(m[1], 10) - 1;
                    var direction = m[2];
                    var offset = parseInt(m[3]);
                    var weekday = parseInt(m[4]);
                    switch (direction) {
                        case '+':
                            var d = new Date(year, month, 1 - 7);
                            while (d.getDay() != weekday) {
                                d = new Date(d.getFullYear(), d.getMonth(), d.getDate() + 1);
                            }
                            date = new Date(d.getFullYear(), d.getMonth(), d.getDate() + 7 * offset);
                            break;
                        case '-':
                            var d = new Date(year, month + 1, 0 + 7);
                            while (d.getDay() != weekday) {
                                d = new Date(d.getFullYear(), d.getMonth(), d.getDate() - 1);
                            }
                            date = new Date(d.getFullYear(), d.getMonth(), d.getDate() - 7 * offset);
                            break;
                    }
                }
                if (!date) {
                    warn('Unknown holiday: ' + key);
                    failed = true;
                    return false;
                }
                switch (i) {
                    case 0:
                        firstDay = date;
                        break;
                    case 1:
                        if (date.getTime() <= firstDay.getTime()) {
                            warn('Unknown holiday: ' + key);
                            failed = true;
                            return false;
                        }
                        lastDay = date;
                        break;
                    default:
                        warn('Unknown holiday: ' + key);
                        failed = true;
                        return false;
                }
            });
            if (!failed) {
                var days = [];
                if (lastDay) {
                    for (var date = new Date(firstDay.getTime()) ; date.getTime() <= lastDay.getTime() ; date.setDate(date.getDate() + 1)) {
                        days.push(new Date(date.getTime()));
                    }
                }
                else {
                    days.push(firstDay);
                }
                holidays.push({ name: name, days: days });
            }
        });
        getHolidays.cache[hash] = holidays;
        return getHolidays.cache[hash];
    }

    getHolidays.cache = {};

    function warn(message) {
        if ($.type(window.console) == 'object' && $.type(window.console.warn) == 'function') {
            window.console.warn('[Bootstrap-Calendar] ' + message);
        }
    }

    function Calendar(params, context) {
        this.options = $.extend(true, { position: { start: new Date(), end: new Date() } }, defaults, params);
        this.setLanguage(this.options.language);
        this.context = context;

        context.css('width', this.options.width).addClass('cal-context');

        this.view();
        return this;
    }

    Calendar.prototype.setOptions = function (object) {
        $.extend(this.options, object);
        if ('language' in object) {
            this.setLanguage(object.language);
        }
        if ('modal' in object) {
            this._update_modal();
        }
    }

    Calendar.prototype.setLanguage = function (lang) {
        if (window.calendar_languages && (lang in window.calendar_languages)) {
            this.locale = $.extend(true, {}, strings, calendar_languages[lang]);
            this.options.language = lang;
        } else {
            this.locale = strings;
            delete this.options.language;
        }
    }

    Calendar.prototype._render = function () {
        this.context.html('');
        this._loadTemplate(this.options.view);
        this.stop_cycling = false;

        var data = {};
        data.cal = this;
        data.day = 1;

        // Getting list of days in a week in correct order. Works for month and week views
        if (getExtentedOption(this, 'first_day') == 1) {
            data.days_name = [this.locale.d1, this.locale.d2, this.locale.d3, this.locale.d4, this.locale.d5, this.locale.d6, this.locale.d0]
        } else {
            data.days_name = [this.locale.d0, this.locale.d1, this.locale.d2, this.locale.d3, this.locale.d4, this.locale.d5, this.locale.d6]
        }

        // Get all events between start and end
        var start = parseInt(this.options.position.start.getTime());
        var end = parseInt(this.options.position.end.getTime());

        data.events = this.getEventsBetween(start, end);

        switch (this.options.view) {
            case 'month':
                break;
            case 'week':
                this._calculate_hour_minutes(data);
                break;
            case 'day':
                this._calculate_hour_minutes(data);
                break;
        }

        data.start = new Date(this.options.position.start.getTime());
        data.lang = this.locale;

        this.context.append(this.options.templates[this.options.view](data));
        this._update();
    };

    Calendar.prototype._format_hour = function (str_hour) {
        var hour_split = str_hour.split(":");
        var hour = parseInt(hour_split[0]);
        var minutes = parseInt(hour_split[1]);

        var suffix = '';

        if (this.options.format12) {
            if (hour < 12) {
                suffix = this.options.am_suffix;
            }
            else {
                suffix = this.options.pm_suffix;
            }

            hour = hour % 12;
            if (hour == 0) {
                hour = 12;
            }
        }

        return hour.toString().formatNum(2) + ':' + minutes.toString().formatNum(2) + suffix;
    };

    Calendar.prototype._format_time = function (datetime) {
        return this._format_hour(datetime.getHours() + ':' + datetime.getMinutes());
    };

    Calendar.prototype._calculate_hour_minutes = function (data) {
        var $self = this;
        var time_split = parseInt(this.options.time_split);
        var time_split_count = 60 / time_split;
        var time_split_hour = Math.min(time_split_count, 1);

        if (((time_split_count >= 1) && (time_split_count % 1 != 0)) || ((time_split_count < 1) && (1440 / time_split % 1 != 0))) {
            $.error(this.locale.error_timedevide);
        }

        var time_start = this.options.time_start.split(":");
        var time_end = this.options.time_end.split(":");

        data.hours = (parseInt(time_end[0]) - parseInt(time_start[0])) * time_split_hour;
        var lines = data.hours * time_split_count - parseInt(time_start[1]) / time_split;
        var ms_per_line = (60000 * time_split);

        var start = new Date(this.options.position.start.getTime());
        start.setHours(time_start[0]);
        start.setMinutes(time_start[1]);
        var end = new Date(this.options.position.end.getTime());
        end.setHours(time_end[0]);
        end.setMinutes(time_end[1]);

        data.all_day = [];
        data.by_hour = [];
        data.after_time = [];
        data.before_time = [];
        $.each(data.events, function (k, e) {
            var s = new Date(parseInt(e.start));
            var f = new Date(parseInt(e.end));

            e.start_hour = $self._format_time(s);
            e.end_hour = $self._format_time(f);

            if (e.start < start.getTime()) {
                warn(1);
                e.start_hour = s.getDate() + ' ' + $self.locale['ms' + s.getMonth()] + ' ' + e.start_hour;
            }

            if (e.end > end.getTime()) {
                warn(1);
                e.end_hour = f.getDate() + ' ' + $self.locale['ms' + f.getMonth()] + ' ' + e.end_hour;
            }

            if (e.start < start.getTime() && e.end > end.getTime()) {
                data.all_day.push(e);
                return;
            }

            if (e.end < start.getTime()) {
                data.before_time.push(e);
                return;
            }

            if (e.start > end.getTime()) {
                data.after_time.push(e);
                return;
            }

            var event_start = start.getTime() - e.start;

            if (event_start >= 0) {
                e.top = 0;
            } else {
                e.top = Math.abs(event_start) / ms_per_line;
            }

            var lines_left = Math.abs(lines - e.top);
            var lines_in_event = (e.end - e.start) / ms_per_line;
            if (event_start >= 0) {
                lines_in_event = (e.end - start.getTime()) / ms_per_line;
            }

            e.lines = lines_in_event;
            if (lines_in_event > lines_left) {
                e.lines = lines_left;
            }

            data.by_hour.push(e);
        });

        //var d = new Date('2013-03-14 13:20:00');
        //warn(d.getTime());
    };

    Calendar.prototype._hour_min = function (hour) {
        var time_start = this.options.time_start.split(":");
        var time_split = parseInt(this.options.time_split);
        var in_hour = 60 / time_split;
        return (hour == 0) ? (in_hour - (parseInt(time_start[1]) / time_split)) : in_hour;
    };

    Calendar.prototype._hour = function (hour, part) {
        var time_start = this.options.time_start.split(":");
        var time_split = parseInt(this.options.time_split);
        var h = "" + (parseInt(time_start[0]) + hour * Math.max(time_split / 60, 1));
        var m = "" + time_split * part;

        return this._format_hour(h.formatNum(2) + ":" + m.formatNum(2));
    };

    Calendar.prototype._week = function (event) {
        this._loadTemplate('week-days');

        var t = {};
        var start = parseInt(this.options.position.start.getTime());
        var end = parseInt(this.options.position.end.getTime());
        var events = [];
        var self = this;
        var first_day = getExtentedOption(this, 'first_day');

        $.each(this.getEventsBetween(start, end), function (k, event) {
            event.start_day = new Date(parseInt(event.start)).getDay();
            if (first_day == 1) {
                event.start_day = (event.start_day + 6) % 7;
            }
            if ((event.end - event.start) <= 86400000) {
                event.days = 1;
            } else {
                event.days = ((event.end - event.start) / 86400000);
            }

            if (event.start < start) {

                event.days = event.days - ((start - event.start) / 86400000);
                event.start_day = 0;
            }

            event.days = Math.ceil(event.days);

            if (event.start_day + event.days > 7) {
                event.days = 7 - (event.start_day);
            }

            events.push(event);
        });
        t.events = events;
        t.cal = this;
        return self.options.templates['week-days'](t);
    }

    Calendar.prototype._month = function (month) {
        this._loadTemplate('year-month');

        var t = { cal: this };
        var newmonth = month + 1;
        t.data_day = this.options.position.start.getFullYear() + '-' + (newmonth < 10 ? '0' + newmonth : newmonth) + '-' + '01';
        t.month_name = this.locale['m' + month];

        var curdate = new Date(this.options.position.start.getFullYear(), month, 1, 0, 0, 0);
        t.start = parseInt(curdate.getTime());
        t.end = parseInt(new Date(this.options.position.start.getFullYear(), month + 1, 1, 0, 0, 0).getTime());
        t.events = this.getEventsBetween(t.start, t.end);
        return this.options.templates['year-month'](t);
    }

    Calendar.prototype._day = function (week, day) {
        this._loadTemplate('month-day');

        var t = { tooltip: '', cal: this };
        var cls = this.options.classes.months.outmonth;

        var firstday = this.options.position.start.getDay();
        if (getExtentedOption(this, 'first_day') == 2) {
            firstday++;
        } else {
            firstday = (firstday == 0 ? 7 : firstday);
        }

        day = (day - firstday) + 1;
        var curdate = new Date(this.options.position.start.getFullYear(), this.options.position.start.getMonth(), day, 0, 0, 0);

        // if day of the current month
        if (day > 0) {
            cls = this.options.classes.months.inmonth;
        }
        // stop cycling table rows;
        var daysinmonth = (new Date(this.options.position.end.getTime() - 1)).getDate();
        if ((day + 1) > daysinmonth) {
            this.stop_cycling = true;
        }
        // if day of the next month
        if (day > daysinmonth) {
            day = day - daysinmonth;
            cls = this.options.classes.months.outmonth;
        }

        cls = $.trim(cls + " " + this._getDayClass("months", curdate));

        if (day <= 0) {
            var daysinprevmonth = (new Date(this.options.position.start.getFullYear(), this.options.position.start.getMonth(), 0)).getDate();
            day = daysinprevmonth - Math.abs(day);
            cls += ' cal-month-first-row';
        }

        var holiday = this._getHoliday(curdate);
        if (holiday !== false) {
            t.tooltip = holiday;
        }

        t.data_day = curdate.getFullYear() + '-' + curdate.getMonthFormatted() + '-' + (day < 10 ? '0' + day : day);
        t.cls = cls;
        t.day = day;

        t.start = parseInt(curdate.getTime());
        t.end = parseInt(t.start + 86400000);
        t.events = this.getEventsBetween(t.start, t.end);
        return this.options.templates['month-day'](t);
    }

    Calendar.prototype._getHoliday = function (date) {
        var result = false;
        $.each(getHolidays(this, date.getFullYear()), function () {
            var found = false;
            $.each(this.days, function () {
                if (this.toDateString() == date.toDateString()) {
                    found = true;
                    return false;
                }
            });
            if (found) {
                result = this.name;
                return false;
            }
        });
        return result;
    };

    Calendar.prototype._getHolidayName = function (date) {
        var holiday = this._getHoliday(date);
        return (holiday === false) ? "" : holiday;
    };

    Calendar.prototype._getDayClass = function (class_group, date) {
        var self = this;
        var addClass = function (which, to) {
            var cls;
            cls = (self.options.classes && (class_group in self.options.classes) && (which in self.options.classes[class_group])) ? self.options.classes[class_group][which] : "";
            if ((typeof (cls) == "string") && cls.length) {
                to.push(cls);
            }
        };
        var classes = [];
        if (date.toDateString() == (new Date()).toDateString()) {
            addClass("today", classes);
        }
        var holiday = this._getHoliday(date);
        if (holiday !== false) {
            addClass("holidays", classes);
        }
        switch (date.getDay()) {
            case 0:
                addClass("sunday", classes);
                break;
            case 6:
                addClass("saturday", classes);
                break;
        }

        addClass(date.toDateString(), classes);

        return classes.join(" ");
    };

    Calendar.prototype.view = function (view) {
        if (view) {
            if (!this.options.views[view].enable) {
                return;
            }
            this.options.view = view;
        }

        this._init_position();
        this._loadEvents();
        this._render();

        this.options.onAfterViewLoad.call(this, this.options.view);
    };

    Calendar.prototype.navigate = function (where, next) {
        var to = $.extend({}, this.options.position);
        if (where == 'next') {
            switch (this.options.view) {
                case 'year':
                    to.start.setFullYear(this.options.position.start.getFullYear() + 1);
                    break;
                case 'month':
                    to.start.setMonth(this.options.position.start.getMonth() + 1);
                    break;
                case 'week':
                    to.start.setDate(this.options.position.start.getDate() + 7);
                    break;
                case 'day':
                    to.start.setDate(this.options.position.start.getDate() + 1);
                    break;
            }
        } else if (where == 'prev') {
            switch (this.options.view) {
                case 'year':
                    to.start.setFullYear(this.options.position.start.getFullYear() - 1);
                    break;
                case 'month':
                    to.start.setMonth(this.options.position.start.getMonth() - 1);
                    break;
                case 'week':
                    to.start.setDate(this.options.position.start.getDate() - 7);
                    break;
                case 'day':
                    to.start.setDate(this.options.position.start.getDate() - 1);
                    break;
            }
        } else if (where == 'today') {
            to.start.setTime(new Date().getTime());
        }
        else {
            $.error(this.locale.error_where.format(where))
        }
        this.options.day = to.start.getFullYear() + '-' + to.start.getMonthFormatted() + '-' + to.start.getDateFormatted();
        this.view();
        if (_.isFunction(next)) {
            next();
        }
    };

    Calendar.prototype._init_position = function () {
        var year, month, day;

        if (this.options.day == 'now') {
            var date = new Date();
            year = date.getFullYear();
            month = date.getMonth();
            day = date.getDate();
        } else if (this.options.day.match(/^\d{4}-\d{2}-\d{2}$/g)) {
            var list = this.options.day.split('-');
            year = parseInt(list[0], 10);
            month = parseInt(list[1], 10) - 1;
            day = parseInt(list[2], 10);
        }
        else {
            $.error(this.locale.error_dateformat.format(this.options.day));
        }

        switch (this.options.view) {
            case 'year':
                this.options.position.start.setTime(new Date(year, 0, 1).getTime());
                this.options.position.end.setTime(new Date(year + 1, 0, 1).getTime());
                break;
            case 'month':
                this.options.position.start.setTime(new Date(year, month, 1).getTime());
                this.options.position.end.setTime(new Date(year, month + 1, 1).getTime());
                break;
            case 'day':
                this.options.position.start.setTime(new Date(year, month, day).getTime());
                this.options.position.end.setTime(new Date(year, month, day + 1).getTime());
                break;
            case 'week':
                var curr = new Date(year, month, day);
                var first;
                if (getExtentedOption(this, 'first_day') == 1) {
                    first = curr.getDate() - ((curr.getDay() + 6) % 7);
                }
                else {
                    first = curr.getDate() - curr.getDay();
                }
                this.options.position.start.setTime(new Date(year, month, first).getTime());
                this.options.position.end.setTime(new Date(year, month, first + 7).getTime());
                break;
            default:
                $.error(this.locale.error_noview.format(this.options.view))
        }
        return this;
    };

    Calendar.prototype.getTitle = function () {
        var p = this.options.position.start;
        switch (this.options.view) {
            case 'year':
                return this.locale.title_year.format(p.getFullYear());
                break;
            case 'month':
                return this.locale.title_month.format(this.locale['m' + p.getMonth()], p.getFullYear());
                break;
            case 'week':
                return this.locale.title_week.format(p.getWeek(), p.getFullYear());
                break;
            case 'day':
                return this.locale.title_day.format(this.locale['d' + p.getDay()], p.getDate(), this.locale['m' + p.getMonth()], p.getFullYear());
                break;
        }
        return;
    };

    Calendar.prototype.isToday = function () {
        var now = new Date().getTime();

        return ((now > this.options.position.start) && (now < this.options.position.end));
    }

    Calendar.prototype.getStartDate = function () {
        return this.options.position.start;
    }

    Calendar.prototype.getEndDate = function () {
        return this.options.position.end;
    }

    Calendar.prototype._loadEvents = function () {
        var self = this;
        var source = null;
        if ('events_source' in this.options && this.options.events_source !== '') {
            source = this.options.events_source;
        }
        else if ('events_url' in this.options) {
            source = this.options.events_url;
            warn('The events_url option is DEPRECATED and it will be REMOVED in near future. Please use events_source instead.');
        }
        var loader;
        switch ($.type(source)) {
            case 'function':
                loader = function () {
                    return source(self.options.position.start, self.options.position.end, browser_timezone);
                };
                break;
            case 'array':
                loader = function () {
                    return [].concat(source);
                };
                break;
            case 'string':
                if (source.length) {
                    loader = function () {
                        var events = [];
                        var d = new Date();
                        var utc_offset = d.getTimezoneOffset();
                        var params = { from: self.options.position.start.getTime(), to: self.options.position.end.getTime(), utc_offset: utc_offset };

                        if (browser_timezone.length) {
                            params.browser_timezone = browser_timezone;
                        }
                        $.ajax({
                            url: buildEventsUrl(source, params),
                            dataType: 'json',
                            type: 'GET',
                            async: false
                        }).done(function (json) {
                            if (!json.success) {
                                $.error(json.error);
                            }
                            if (json.result) {
                                events = json.result;
                            }
                        });
                        return events;
                    };
                }
                break;
        }
        if (!loader) {
            $.error(this.locale.error_loadurl);
        }
        this.options.onBeforeEventsLoad.call(this, function () {
            self.options.events = loader();
            self.options.events.sort(function (a, b) {
                var delta;
                delta = a.start - b.start;
                if (delta == 0) {
                    delta = a.end - b.end;
                }
                return delta;
            });
            self.options.onAfterEventsLoad.call(self, self.options.events);
        });
    };

    Calendar.prototype._templatePath = function (name) {
        if (typeof this.options.tmpl_path == 'function') {
            return this.options.tmpl_path(name)
        }
        else {
            return this.options.tmpl_path + name + '.html';
        }
    };

    Calendar.prototype._loadTemplate = function (name) {
        if (this.options.templates[name]) {
            return;
        }
        var self = this;
        $.ajax({
            url: self._templatePath(name),
            dataType: 'html',
            type: 'GET',
            async: false,
            cache: this.options.tmpl_cache
        }).done(function (html) {
            self.options.templates[name] = _.template(html);
        });
    };

    Calendar.prototype._update = function () {
        var self = this;

        $('*[data-toggle="tooltip"]').tooltip({ container: 'body' });

        $('*[data-cal-date]').click(function () {
            var view = $(this).data('cal-view');
            self.options.day = $(this).data('cal-date');
            self.view(view);
        });
        $('.cal-cell').dblclick(function () {
            var view = $('[data-cal-date]', this).data('cal-view');
            self.options.day = $('[data-cal-date]', this).data('cal-date');
            self.view(view);
        });

        this['_update_' + this.options.view]();

        this._update_modal();

    };

    Calendar.prototype._update_modal = function () {
        var self = this;

        $('a[data-event-id]', this.context).unbind('click');

        if (!self.options.modal) {
            return;
        }

        var modal = $(self.options.modal);

        if (!modal.length) {
            return;
        }

        var ifrm = null;
        if (self.options.modal_type == "iframe") {
            ifrm = $(document.createElement("iframe"))
				.attr({
				    width: "100%",
				    frameborder: "0"
				});
        }

        $('a[data-event-id]', this.context).on('click', function (event) {
            event.preventDefault();
            event.stopPropagation();

            var url = $(this).attr('href');
            var id = $(this).data("event-id");
            var event = _.find(self.options.events, function (event) {
                return event.id == id
            });

            if (self.options.modal_type == "iframe") {
                ifrm.attr('src', url);
                $('.modal-body', modal).html(ifrm);
            }

            if (!modal.data('handled.bootstrap-calendar') || (modal.data('handled.bootstrap-calendar') && modal.data('handled.event-id') != event.id)) {
                modal.off('show.bs.modal')
					.off('shown.bs.modal')
					.off('hidden.bs.modal')
					.on('show.bs.modal', function () {
					    var modal_body = $(this).find('.modal-body');
					    switch (self.options.modal_type) {
					        case "iframe":
					            var height = modal_body.height() - parseInt(modal_body.css('padding-top'), 10) - parseInt(modal_body.css('padding-bottom'), 10);
					            $(this).find('iframe').height(Math.max(height, 50));
					            break;

					        case "ajax":
					            $.ajax({
					                url: url, dataType: "html", async: false, success: function (data) {
					                    modal_body.html(data);
					                }
					            });
					            break;

					        case "template":
					            self._loadTemplate("modal");
					            //	also serve calendar instance to underscore template to be able to access current language strings
					            modal_body.html(self.options.templates["modal"]({ "event": event, "calendar": self }))
					            break;
					    }

					    //	set the title of the bootstrap modal
					    if (_.isFunction(self.options.modal_title)) {
					        modal.find(".modal-title").html(self.options.modal_title(event));
					    }
					})
					.on('shown.bs.modal', function () {
					    self.options.onAfterModalShown.call(self, self.options.events);
					})
					.on('hidden.bs.modal', function () {
					    self.options.onAfterModalHidden.call(self, self.options.events);
					})
					.data('handled.bootstrap-calendar', true).data('handled.event-id', event.id);
            }
            modal.modal('show');
        });
    };

    Calendar.prototype._update_day = function () {
        $('#cal-day-panel').height($('#cal-day-panel-hour').height());
    };

    Calendar.prototype._update_week = function () {
    };

    Calendar.prototype._update_year = function () {
        this._update_month_year();
    };

    Calendar.prototype._update_month = function () {
        this._update_month_year();

        var self = this;

        if (this.options.weekbox == true) {
            var week = $(document.createElement('div')).attr('id', 'cal-week-box');
            var start = this.options.position.start.getFullYear() + '-' + this.options.position.start.getMonthFormatted() + '-';
            self.context.find('.cal-month-box .cal-row-fluid')
				.on('mouseenter', function () {
				    var p = new Date(self.options.position.start);
				    var child = $('.cal-cell1:first-child .cal-month-day', this);
				    var day = (child.hasClass('cal-month-first-row') ? 1 : $('[data-cal-date]', child).text());
				    p.setDate(parseInt(day));
				    day = (day < 10 ? '0' + day : day);
				    week.html(self.locale.week.format(self.options.display_week_numbers == true ? p.getWeek() : ''));
				    week.attr('data-cal-week', start + day).show().appendTo(child);
				})
				.on('mouseleave', function () {
				    week.hide();
				});

            week.click(function () {
                self.options.day = $(this).data('cal-week');
                self.view('week');
            });
        }


        self.context.find('a.event').mouseenter(function () {
            $('a[data-event-id="' + $(this).data('event-id') + '"]').closest('.cal-cell1').addClass('day-highlight dh-' + $(this).data('event-class'));
        });
        self.context.find('a.event').mouseleave(function () {
            $('div.cal-cell1').removeClass('day-highlight dh-' + $(this).data('event-class'));
        });
    };

    Calendar.prototype._update_month_year = function () {
        if (!this.options.views[this.options.view].slide_events) {
            return;
        }
        var self = this;
        var activecell = 0;
        var downbox = $(document.createElement('div')).attr('id', 'cal-day-tick').html('<i class="icon-chevron-down glyphicon glyphicon-chevron-down"></i>');

        self.context.find('.cal-month-day, .cal-year-box .span3')
			.on('mouseenter', function () {
			    if ($('.events-list', this).length == 0) {
			        return;
			    }
			    if ($(this).children('[data-cal-date]').text() == self.activecell) {
			        return;
			    }
			    downbox.show().appendTo(this);
			})
			.on('mouseleave', function () {
			    downbox.hide();
			})
			.on('click', function (event) {
			    if ($('.events-list', this).length == 0) {
			        return;
			    }
			    if ($(this).children('[data-cal-date]').text() == self.activecell) {
			        return;
			    }
			    showEventsList(event, downbox, slider, self);
			})
        ;

        var slider = $(document.createElement('div')).attr('id', 'cal-slide-box');
        slider.hide().click(function (event) {
            event.stopPropagation();
        });

        this._loadTemplate('events-list');

        downbox.click(function (event) {
            showEventsList(event, $(this), slider, self);
        });
    };

    Calendar.prototype.getEventsBetween = function (start, end) {
        var events = [];
        $.each(this.options.events, function () {
            if (this.start == null) {
                return true;
            }
            var event_end = this.end || this.start;
            if ((parseInt(this.start) < end) && (parseInt(event_end) >= start)) {
                events.push(this);
            }
        });
        return events;
    };

    function showEventsList(event, that, slider, self) {

        event.stopPropagation();

        var that = $(that);
        var cell = that.closest('.cal-cell');
        var row = cell.closest('.cal-before-eventlist');
        var tick_position = cell.data('cal-row');

        that.fadeOut('fast');

        slider.slideUp('fast', function () {
            var event_list = $('.events-list', cell);
            slider.html(self.options.templates['events-list']({
                cal: self,
                events: self.getEventsBetween(parseInt(event_list.data('cal-start')), parseInt(event_list.data('cal-end')))
            }));
            row.after(slider);
            self.activecell = $('[data-cal-date]', cell).text();
            $('#cal-slide-tick').addClass('tick' + tick_position).show();
            slider.slideDown('fast', function () {
                $('body').one('click', function () {
                    slider.slideUp('fast');
                    self.activecell = 0;
                });
            });
        });

        // Wait 400ms before updating the modal & attach the mouseenter&mouseleave(400ms is the time for the slider to fade out and slide up)
        setTimeout(function () {
            $('a.event-item').mouseenter(function () {
                $('a[data-event-id="' + $(this).data('event-id') + '"]').closest('.cal-cell1').addClass('day-highlight dh-' + $(this).data('event-class'));
            });
            $('a.event-item').mouseleave(function () {
                $('div.cal-cell1').removeClass('day-highlight dh-' + $(this).data('event-class'));
            });
            self._update_modal();
        }, 400);
    }

    function getEasterDate(year, offsetDays) {
        var a = year % 19;
        var b = Math.floor(year / 100);
        var c = year % 100;
        var d = Math.floor(b / 4);
        var e = b % 4;
        var f = Math.floor((b + 8) / 25);
        var g = Math.floor((b - f + 1) / 3);
        var h = (19 * a + b - d - g + 15) % 30;
        var i = Math.floor(c / 4);
        var k = c % 4;
        var l = (32 + 2 * e + 2 * i - h - k) % 7;
        var m = Math.floor((a + 11 * h + 22 * l) / 451);
        var n0 = (h + l + 7 * m + 114)
        var n = Math.floor(n0 / 31) - 1;
        var p = n0 % 31 + 1;
        return new Date(year, n, p + (offsetDays ? offsetDays : 0), 0, 0, 0);
    }

    $.fn.calendar = function (params) {
        return new Calendar(params, this);
    }
}(jQuery));;
/*!
 * jQuery blockUI plugin
 * Version 2.70.0-2014.11.23
 * Requires jQuery v1.7 or later
 *
 * Examples at: http://malsup.com/jquery/block/
 * Copyright (c) 2007-2013 M. Alsup
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 * Thanks to Amir-Hossein Sobhi for some excellent contributions!
 */

; (function () {
    /*jshint eqeqeq:false curly:false latedef:false */
    "use strict";

    function setup($) {
        $.fn._fadeIn = $.fn.fadeIn;

        var noOp = $.noop || function () { };

        // this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle
        // confusing userAgent strings on Vista)
        var msie = /MSIE/.test(navigator.userAgent);
        var ie6 = /MSIE 6.0/.test(navigator.userAgent) && ! /MSIE 8.0/.test(navigator.userAgent);
        var mode = document.documentMode || 0;
        var setExpr = $.isFunction(document.createElement('div').style.setExpression);

        // global $ methods for blocking/unblocking the entire page
        $.blockUI = function (opts) { install(window, opts); };
        $.unblockUI = function (opts) { remove(window, opts); };

        // convenience method for quick growl-like notifications  (http://www.google.com/search?q=growl)
        $.growlUI = function (title, message, timeout, onClose) {
            var $m = $('<div class="growlUI"></div>');
            if (title) $m.append('<h1>' + title + '</h1>');
            if (message) $m.append('<h2>' + message + '</h2>');
            if (timeout === undefined) timeout = 3000;

            // Added by konapun: Set timeout to 30 seconds if this growl is moused over, like normal toast notifications
            var callBlock = function (opts) {
                opts = opts || {};

                $.blockUI({
                    message: $m,
                    fadeIn: typeof opts.fadeIn !== 'undefined' ? opts.fadeIn : 700,
                    fadeOut: typeof opts.fadeOut !== 'undefined' ? opts.fadeOut : 1000,
                    timeout: typeof opts.timeout !== 'undefined' ? opts.timeout : timeout,
                    centerY: false,
                    showOverlay: false,
                    onUnblock: onClose,
                    css: $.blockUI.defaults.growlCSS
                });
            };

            callBlock();
            var nonmousedOpacity = $m.css('opacity');
            $m.mouseover(function () {
                callBlock({
                    fadeIn: 0,
                    timeout: 30000
                });

                var displayBlock = $('.blockMsg');
                displayBlock.stop(); // cancel fadeout if it has started
                displayBlock.fadeTo(300, 1); // make it easier to read the message by removing transparency
            }).mouseout(function () {
                $('.blockMsg').fadeOut(1000);
            });
            // End konapun additions
        };

        // plugin method for blocking element content
        $.fn.block = function (opts) {
            if (this[0] === window) {
                $.blockUI(opts);
                return this;
            }
            var fullOpts = $.extend({}, $.blockUI.defaults, opts || {});
            this.each(function () {
                var $el = $(this);
                if (fullOpts.ignoreIfBlocked && $el.data('blockUI.isBlocked'))
                    return;
                $el.unblock({ fadeOut: 0 });
            });

            return this.each(function () {
                if ($.css(this, 'position') == 'static') {
                    this.style.position = 'relative';
                    $(this).data('blockUI.static', true);
                }
                this.style.zoom = 1; // force 'hasLayout' in ie
                install(this, opts);
            });
        };

        // plugin method for unblocking element content
        $.fn.unblock = function (opts) {
            if (this[0] === window) {
                $.unblockUI(opts);
                return this;
            }
            return this.each(function () {
                remove(this, opts);
            });
        };

        $.blockUI.version = 2.70; // 2nd generation blocking at no extra cost!

        // override these in your code to change the default behavior and style
        $.blockUI.defaults = {
            // message displayed when blocking (use null for no message)
            message: '<h1>Please wait...</h1>',

            title: null,		// title string; only used when theme == true
            draggable: true,	// only used when theme == true (requires jquery-ui.js to be loaded)

            theme: false, // set to true to use with jQuery UI themes

            // styles for the message when blocking; if you wish to disable
            // these and use an external stylesheet then do this in your code:
            // $.blockUI.defaults.css = {};
            css: {
                padding: 0,
                margin: 0,
                width: '30%',
                top: '40%',
                left: '35%',
                textAlign: 'center',
                color: '#000',
                border: '3px solid #aaa',
                backgroundColor: '#fff',
                cursor: 'wait'
            },

            // minimal style set used when themes are used
            themedCSS: {
                width: '30%',
                top: '40%',
                left: '35%'
            },

            // styles for the overlay
            overlayCSS: {
                backgroundColor: '#000',
                opacity: 0.6,
                cursor: 'wait'
            },

            // style to replace wait cursor before unblocking to correct issue
            // of lingering wait cursor
            cursorReset: 'default',

            // styles applied when using $.growlUI
            growlCSS: {
                width: '350px',
                top: '10px',
                left: '',
                right: '10px',
                border: 'none',
                padding: '5px',
                opacity: 0.6,
                cursor: 'default',
                color: '#fff',
                backgroundColor: '#000',
                '-webkit-border-radius': '10px',
                '-moz-border-radius': '10px',
                'border-radius': '10px'
            },

            // IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w
            // (hat tip to Jorge H. N. de Vasconcelos)
            /*jshint scripturl:true */
            iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank',

            // force usage of iframe in non-IE browsers (handy for blocking applets)
            forceIframe: false,

            // z-index for the blocking overlay
            baseZ: 1000,

            // set these to true to have the message automatically centered
            centerX: true, // <-- only effects element blocking (page block controlled via css above)
            centerY: true,

            // allow body element to be stetched in ie6; this makes blocking look better
            // on "short" pages.  disable if you wish to prevent changes to the body height
            allowBodyStretch: true,

            // enable if you want key and mouse events to be disabled for content that is blocked
            bindEvents: true,

            // be default blockUI will supress tab navigation from leaving blocking content
            // (if bindEvents is true)
            constrainTabKey: true,

            // fadeIn time in millis; set to 0 to disable fadeIn on block
            fadeIn: 200,

            // fadeOut time in millis; set to 0 to disable fadeOut on unblock
            fadeOut: 400,

            // time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock
            timeout: 0,

            // disable if you don't want to show the overlay
            showOverlay: true,

            // if true, focus will be placed in the first available input field when
            // page blocking
            focusInput: true,

            // elements that can receive focus
            focusableElements: ':input:enabled:visible',

            // suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity)
            // no longer needed in 2012
            // applyPlatformOpacityRules: true,

            // callback method invoked when fadeIn has completed and blocking message is visible
            onBlock: null,

            // callback method invoked when unblocking has completed; the callback is
            // passed the element that has been unblocked (which is the window object for page
            // blocks) and the options that were passed to the unblock call:
            //	onUnblock(element, options)
            onUnblock: null,

            // callback method invoked when the overlay area is clicked.
            // setting this will turn the cursor to a pointer, otherwise cursor defined in overlayCss will be used.
            onOverlayClick: null,

            // don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493
            quirksmodeOffsetHack: 4,

            // class name of the message block
            blockMsgClass: 'blockMsg',

            // if it is already blocked, then ignore it (don't unblock and reblock)
            ignoreIfBlocked: false
        };

        // private data and functions follow...

        var pageBlock = null;
        var pageBlockEls = [];

        function install(el, opts) {
            var css, themedCSS;
            var full = (el == window);
            var msg = (opts && opts.message !== undefined ? opts.message : undefined);
            opts = $.extend({}, $.blockUI.defaults, opts || {});

            if (opts.ignoreIfBlocked && $(el).data('blockUI.isBlocked'))
                return;

            opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {});
            css = $.extend({}, $.blockUI.defaults.css, opts.css || {});
            if (opts.onOverlayClick)
                opts.overlayCSS.cursor = 'pointer';

            themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {});
            msg = msg === undefined ? opts.message : msg;

            // remove the current block (if there is one)
            if (full && pageBlock)
                remove(window, { fadeOut: 0 });

            // if an existing element is being used as the blocking content then we capture
            // its current place in the DOM (and current display style) so we can restore
            // it when we unblock
            if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) {
                var node = msg.jquery ? msg[0] : msg;
                var data = {};
                $(el).data('blockUI.history', data);
                data.el = node;
                data.parent = node.parentNode;
                data.display = node.style.display;
                data.position = node.style.position;
                if (data.parent)
                    data.parent.removeChild(node);
            }

            $(el).data('blockUI.onUnblock', opts.onUnblock);
            var z = opts.baseZ;

            // blockUI uses 3 layers for blocking, for simplicity they are all used on every platform;
            // layer1 is the iframe layer which is used to supress bleed through of underlying content
            // layer2 is the overlay layer which has opacity and a wait cursor (by default)
            // layer3 is the message content that is displayed while blocking
            var lyr1, lyr2, lyr3, s;
            if (msie || opts.forceIframe)
                lyr1 = $('<iframe class="blockUI" style="z-index:' + (z++) + ';display:none;border:none;margin:0;padding:0;position:absolute;width:100%;height:100%;top:0;left:0" src="' + opts.iframeSrc + '"></iframe>');
            else
                lyr1 = $('<div class="blockUI" style="display:none"></div>');

            if (opts.theme)
                lyr2 = $('<div class="blockUI blockOverlay ui-widget-overlay" style="z-index:' + (z++) + ';display:none"></div>');
            else
                lyr2 = $('<div class="blockUI blockOverlay" style="z-index:' + (z++) + ';display:none;border:none;margin:0;padding:0;width:100%;height:100%;top:0;left:0"></div>');

            if (opts.theme && full) {
                s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage ui-dialog ui-widget ui-corner-all" style="z-index:' + (z + 10) + ';display:none;position:fixed">';
                if (opts.title) {
                    s += '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">' + (opts.title || '&nbsp;') + '</div>';
                }
                s += '<div class="ui-widget-content ui-dialog-content"></div>';
                s += '</div>';
            }
            else if (opts.theme) {
                s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement ui-dialog ui-widget ui-corner-all" style="z-index:' + (z + 10) + ';display:none;position:absolute">';
                if (opts.title) {
                    s += '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">' + (opts.title || '&nbsp;') + '</div>';
                }
                s += '<div class="ui-widget-content ui-dialog-content"></div>';
                s += '</div>';
            }
            else if (full) {
                s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage" style="z-index:' + (z + 10) + ';display:none;position:fixed"></div>';
            }
            else {
                s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement" style="z-index:' + (z + 10) + ';display:none;position:absolute"></div>';
            }
            lyr3 = $(s);

            // if we have a message, style it
            if (msg) {
                if (opts.theme) {
                    lyr3.css(themedCSS);
                    lyr3.addClass('ui-widget-content');
                }
                else
                    lyr3.css(css);
            }

            // style the overlay
            if (!opts.theme /*&& (!opts.applyPlatformOpacityRules)*/)
                lyr2.css(opts.overlayCSS);
            lyr2.css('position', full ? 'fixed' : 'absolute');

            // make iframe layer transparent in IE
            if (msie || opts.forceIframe)
                lyr1.css('opacity', 0.0);

            //$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el);
            var layers = [lyr1, lyr2, lyr3], $par = full ? $('body') : $(el);
            $.each(layers, function () {
                this.appendTo($par);
            });

            if (opts.theme && opts.draggable && $.fn.draggable) {
                lyr3.draggable({
                    handle: '.ui-dialog-titlebar',
                    cancel: 'li'
                });
            }

            // ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
            var expr = setExpr && (!$.support.boxModel || $('object,embed', full ? null : el).length > 0);
            if (ie6 || expr) {
                // give body 100% height
                if (full && opts.allowBodyStretch && $.support.boxModel)
                    $('html,body').css('height', '100%');

                // fix ie6 issue when blocked element has a border width
                if ((ie6 || !$.support.boxModel) && !full) {
                    var t = sz(el, 'borderTopWidth'), l = sz(el, 'borderLeftWidth');
                    var fixT = t ? '(0 - ' + t + ')' : 0;
                    var fixL = l ? '(0 - ' + l + ')' : 0;
                }

                // simulate fixed position
                $.each(layers, function (i, o) {
                    var s = o[0].style;
                    s.position = 'absolute';
                    if (i < 2) {
                        if (full)
                            s.setExpression('height', 'Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.support.boxModel?0:' + opts.quirksmodeOffsetHack + ') + "px"');
                        else
                            s.setExpression('height', 'this.parentNode.offsetHeight + "px"');
                        if (full)
                            s.setExpression('width', 'jQuery.support.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"');
                        else
                            s.setExpression('width', 'this.parentNode.offsetWidth + "px"');
                        if (fixL) s.setExpression('left', fixL);
                        if (fixT) s.setExpression('top', fixT);
                    }
                    else if (opts.centerY) {
                        if (full) s.setExpression('top', '(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
                        s.marginTop = 0;
                    }
                    else if (!opts.centerY && full) {
                        var top = (opts.css && opts.css.top) ? parseInt(opts.css.top, 10) : 0;
                        var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + ' + top + ') + "px"';
                        s.setExpression('top', expression);
                    }
                });
            }

            // show the message
            if (msg) {
                if (opts.theme)
                    lyr3.find('.ui-widget-content').append(msg);
                else
                    lyr3.append(msg);
                if (msg.jquery || msg.nodeType)
                    $(msg).show();
            }

            if ((msie || opts.forceIframe) && opts.showOverlay)
                lyr1.show(); // opacity is zero
            if (opts.fadeIn) {
                var cb = opts.onBlock ? opts.onBlock : noOp;
                var cb1 = (opts.showOverlay && !msg) ? cb : noOp;
                var cb2 = msg ? cb : noOp;
                if (opts.showOverlay)
                    lyr2._fadeIn(opts.fadeIn, cb1);
                if (msg)
                    lyr3._fadeIn(opts.fadeIn, cb2);
            }
            else {
                if (opts.showOverlay)
                    lyr2.show();
                if (msg)
                    lyr3.show();
                if (opts.onBlock)
                    opts.onBlock.bind(lyr3)();
            }

            // bind key and mouse events
            bind(1, el, opts);

            if (full) {
                pageBlock = lyr3[0];
                pageBlockEls = $(opts.focusableElements, pageBlock);
                if (opts.focusInput)
                    setTimeout(focus, 20);
            }
            else
                center(lyr3[0], opts.centerX, opts.centerY);

            if (opts.timeout) {
                // auto-unblock
                var to = setTimeout(function () {
                    if (full)
                        $.unblockUI(opts);
                    else
                        $(el).unblock(opts);
                }, opts.timeout);
                $(el).data('blockUI.timeout', to);
            }
        }

        // remove the block
        function remove(el, opts) {
            var count;
            var full = (el == window);
            var $el = $(el);
            var data = $el.data('blockUI.history');
            var to = $el.data('blockUI.timeout');
            if (to) {
                clearTimeout(to);
                $el.removeData('blockUI.timeout');
            }
            opts = $.extend({}, $.blockUI.defaults, opts || {});
            bind(0, el, opts); // unbind events

            if (opts.onUnblock === null) {
                opts.onUnblock = $el.data('blockUI.onUnblock');
                $el.removeData('blockUI.onUnblock');
            }

            var els;
            if (full) // crazy selector to handle odd field errors in ie6/7
                els = $('body').children().filter('.blockUI').add('body > .blockUI');
            else
                els = $el.find('>.blockUI');

            // fix cursor issue
            if (opts.cursorReset) {
                if (els.length > 1)
                    els[1].style.cursor = opts.cursorReset;
                if (els.length > 2)
                    els[2].style.cursor = opts.cursorReset;
            }

            if (full)
                pageBlock = pageBlockEls = null;

            if (opts.fadeOut) {
                count = els.length;
                els.stop().fadeOut(opts.fadeOut, function () {
                    if (--count === 0)
                        reset(els, data, opts, el);
                });
            }
            else
                reset(els, data, opts, el);
        }

        // move blocking element back into the DOM where it started
        function reset(els, data, opts, el) {
            var $el = $(el);
            if ($el.data('blockUI.isBlocked'))
                return;

            els.each(function (i, o) {
                // remove via DOM calls so we don't lose event handlers
                if (this.parentNode)
                    this.parentNode.removeChild(this);
            });

            if (data && data.el) {
                data.el.style.display = data.display;
                data.el.style.position = data.position;
                data.el.style.cursor = 'default'; // #59
                if (data.parent)
                    data.parent.appendChild(data.el);
                $el.removeData('blockUI.history');
            }

            if ($el.data('blockUI.static')) {
                $el.css('position', 'static'); // #22
            }

            if (typeof opts.onUnblock == 'function')
                opts.onUnblock(el, opts);

            // fix issue in Safari 6 where block artifacts remain until reflow
            var body = $(document.body), w = body.width(), cssW = body[0].style.width;
            body.width(w - 1).width(w);
            body[0].style.width = cssW;
        }

        // bind/unbind the handler
        function bind(b, el, opts) {
            var full = el == window, $el = $(el);

            // don't bother unbinding if there is nothing to unbind
            if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked')))
                return;

            $el.data('blockUI.isBlocked', b);

            // don't bind events when overlay is not in use or if bindEvents is false
            if (!full || !opts.bindEvents || (b && !opts.showOverlay))
                return;

            // bind anchors and inputs for mouse and key events
            var events = 'mousedown mouseup keydown keypress keyup touchstart touchend touchmove';
            if (b)
                $(document).bind(events, opts, handler);
            else
                $(document).unbind(events, handler);

            // former impl...
            //		var $e = $('a,:input');
            //		b ? $e.bind(events, opts, handler) : $e.unbind(events, handler);
        }

        // event handler to suppress keyboard/mouse events when blocking
        function handler(e) {
            // allow tab navigation (conditionally)
            if (e.type === 'keydown' && e.keyCode && e.keyCode == 9) {
                if (pageBlock && e.data.constrainTabKey) {
                    var els = pageBlockEls;
                    var fwd = !e.shiftKey && e.target === els[els.length - 1];
                    var back = e.shiftKey && e.target === els[0];
                    if (fwd || back) {
                        setTimeout(function () { focus(back); }, 10);
                        return false;
                    }
                }
            }
            var opts = e.data;
            var target = $(e.target);
            if (target.hasClass('blockOverlay') && opts.onOverlayClick)
                opts.onOverlayClick(e);

            // allow events within the message content
            if (target.parents('div.' + opts.blockMsgClass).length > 0)
                return true;

            // allow events for content that is not being blocked
            return target.parents().children().filter('div.blockUI').length === 0;
        }

        function focus(back) {
            if (!pageBlockEls)
                return;
            var e = pageBlockEls[back === true ? pageBlockEls.length - 1 : 0];
            if (e)
                e.focus();
        }

        function center(el, x, y) {
            var p = el.parentNode, s = el.style;
            var l = ((p.offsetWidth - el.offsetWidth) / 2) - sz(p, 'borderLeftWidth');
            var t = ((p.offsetHeight - el.offsetHeight) / 2) - sz(p, 'borderTopWidth');
            if (x) s.left = l > 0 ? (l + 'px') : '0';
            if (y) s.top = t > 0 ? (t + 'px') : '0';
        }

        function sz(el, p) {
            return parseInt($.css(el, p), 10) || 0;
        }

    }


    /*global define:true */
    if (typeof define === 'function' && define.amd && define.amd.jQuery) {
        define(['jquery'], setup);
    } else {
        setup(jQuery);
    }

})();;
/**
 * CryptoJS core components.
 */
var CryptoJS = CryptoJS || (function (Math, undefined) {
    /*
     * Local polyfil of Object.create
     */
    var create = Object.create || (function () {
        function F() { };

        return function (obj) {
            var subtype;

            F.prototype = obj;

            subtype = new F();

            F.prototype = null;

            return subtype;
        };
    }())

    /**
     * CryptoJS namespace.
     */
    var C = {};

    /**
     * Library namespace.
     */
    var C_lib = C.lib = {};

    /**
     * Base object for prototypal inheritance.
     */
    var Base = C_lib.Base = (function () {


        return {
            /**
             * Creates a new object that inherits from this object.
             *
             * @param {Object} overrides Properties to copy into the new object.
             *
             * @return {Object} The new object.
             *
             * @static
             *
             * @example
             *
             *     var MyType = CryptoJS.lib.Base.extend({
             *         field: 'value',
             *
             *         method: function () {
             *         }
             *     });
             */
            extend: function (overrides) {
                // Spawn
                var subtype = create(this);

                // Augment
                if (overrides) {
                    subtype.mixIn(overrides);
                }

                // Create default initializer
                if (!subtype.hasOwnProperty('init') || this.init === subtype.init) {
                    subtype.init = function () {
                        subtype.$super.init.apply(this, arguments);
                    };
                }

                // Initializer's prototype is the subtype object
                subtype.init.prototype = subtype;

                // Reference supertype
                subtype.$super = this;

                return subtype;
            },

            /**
             * Extends this object and runs the init method.
             * Arguments to create() will be passed to init().
             *
             * @return {Object} The new object.
             *
             * @static
             *
             * @example
             *
             *     var instance = MyType.create();
             */
            create: function () {
                var instance = this.extend();
                instance.init.apply(instance, arguments);

                return instance;
            },

            /**
             * Initializes a newly created object.
             * Override this method to add some logic when your objects are created.
             *
             * @example
             *
             *     var MyType = CryptoJS.lib.Base.extend({
             *         init: function () {
             *             // ...
             *         }
             *     });
             */
            init: function () {
            },

            /**
             * Copies properties into this object.
             *
             * @param {Object} properties The properties to mix in.
             *
             * @example
             *
             *     MyType.mixIn({
             *         field: 'value'
             *     });
             */
            mixIn: function (properties) {
                for (var propertyName in properties) {
                    if (properties.hasOwnProperty(propertyName)) {
                        this[propertyName] = properties[propertyName];
                    }
                }

                // IE won't copy toString using the loop above
                if (properties.hasOwnProperty('toString')) {
                    this.toString = properties.toString;
                }
            },

            /**
             * Creates a copy of this object.
             *
             * @return {Object} The clone.
             *
             * @example
             *
             *     var clone = instance.clone();
             */
            clone: function () {
                return this.init.prototype.extend(this);
            }
        };
    }());

    /**
     * An array of 32-bit words.
     *
     * @property {Array} words The array of 32-bit words.
     * @property {number} sigBytes The number of significant bytes in this word array.
     */
    var WordArray = C_lib.WordArray = Base.extend({
        /**
         * Initializes a newly created word array.
         *
         * @param {Array} words (Optional) An array of 32-bit words.
         * @param {number} sigBytes (Optional) The number of significant bytes in the words.
         *
         * @example
         *
         *     var wordArray = CryptoJS.lib.WordArray.create();
         *     var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]);
         *     var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6);
         */
        init: function (words, sigBytes) {
            words = this.words = words || [];

            if (sigBytes != undefined) {
                this.sigBytes = sigBytes;
            } else {
                this.sigBytes = words.length * 4;
            }
        },

        /**
         * Converts this word array to a string.
         *
         * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex
         *
         * @return {string} The stringified word array.
         *
         * @example
         *
         *     var string = wordArray + '';
         *     var string = wordArray.toString();
         *     var string = wordArray.toString(CryptoJS.enc.Utf8);
         */
        toString: function (encoder) {
            return (encoder || Hex).stringify(this);
        },

        /**
         * Concatenates a word array to this word array.
         *
         * @param {WordArray} wordArray The word array to append.
         *
         * @return {WordArray} This word array.
         *
         * @example
         *
         *     wordArray1.concat(wordArray2);
         */
        concat: function (wordArray) {
            // Shortcuts
            var thisWords = this.words;
            var thatWords = wordArray.words;
            var thisSigBytes = this.sigBytes;
            var thatSigBytes = wordArray.sigBytes;

            // Clamp excess bits
            this.clamp();

            // Concat
            if (thisSigBytes % 4) {
                // Copy one byte at a time
                for (var i = 0; i < thatSigBytes; i++) {
                    var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
                    thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8);
                }
            } else {
                // Copy one word at a time
                for (var i = 0; i < thatSigBytes; i += 4) {
                    thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2];
                }
            }
            this.sigBytes += thatSigBytes;

            // Chainable
            return this;
        },

        /**
         * Removes insignificant bits.
         *
         * @example
         *
         *     wordArray.clamp();
         */
        clamp: function () {
            // Shortcuts
            var words = this.words;
            var sigBytes = this.sigBytes;

            // Clamp
            words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8);
            words.length = Math.ceil(sigBytes / 4);
        },

        /**
         * Creates a copy of this word array.
         *
         * @return {WordArray} The clone.
         *
         * @example
         *
         *     var clone = wordArray.clone();
         */
        clone: function () {
            var clone = Base.clone.call(this);
            clone.words = this.words.slice(0);

            return clone;
        },

        /**
         * Creates a word array filled with random bytes.
         *
         * @param {number} nBytes The number of random bytes to generate.
         *
         * @return {WordArray} The random word array.
         *
         * @static
         *
         * @example
         *
         *     var wordArray = CryptoJS.lib.WordArray.random(16);
         */
        random: function (nBytes) {
            var words = [];

            var r = (function (m_w) {
                var m_w = m_w;
                var m_z = 0x3ade68b1;
                var mask = 0xffffffff;

                return function () {
                    m_z = (0x9069 * (m_z & 0xFFFF) + (m_z >> 0x10)) & mask;
                    m_w = (0x4650 * (m_w & 0xFFFF) + (m_w >> 0x10)) & mask;
                    var result = ((m_z << 0x10) + m_w) & mask;
                    result /= 0x100000000;
                    result += 0.5;
                    return result * (Math.random() > .5 ? 1 : -1);
                }
            });

            for (var i = 0, rcache; i < nBytes; i += 4) {
                var _r = r((rcache || Math.random()) * 0x100000000);

                rcache = _r() * 0x3ade67b7;
                words.push((_r() * 0x100000000) | 0);
            }

            return new WordArray.init(words, nBytes);
        }
    });

    /**
     * Encoder namespace.
     */
    var C_enc = C.enc = {};

    /**
     * Hex encoding strategy.
     */
    var Hex = C_enc.Hex = {
        /**
         * Converts a word array to a hex string.
         *
         * @param {WordArray} wordArray The word array.
         *
         * @return {string} The hex string.
         *
         * @static
         *
         * @example
         *
         *     var hexString = CryptoJS.enc.Hex.stringify(wordArray);
         */
        stringify: function (wordArray) {
            // Shortcuts
            var words = wordArray.words;
            var sigBytes = wordArray.sigBytes;

            // Convert
            var hexChars = [];
            for (var i = 0; i < sigBytes; i++) {
                var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
                hexChars.push((bite >>> 4).toString(16));
                hexChars.push((bite & 0x0f).toString(16));
            }

            return hexChars.join('');
        },

        /**
         * Converts a hex string to a word array.
         *
         * @param {string} hexStr The hex string.
         *
         * @return {WordArray} The word array.
         *
         * @static
         *
         * @example
         *
         *     var wordArray = CryptoJS.enc.Hex.parse(hexString);
         */
        parse: function (hexStr) {
            // Shortcut
            var hexStrLength = hexStr.length;

            // Convert
            var words = [];
            for (var i = 0; i < hexStrLength; i += 2) {
                words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);
            }

            return new WordArray.init(words, hexStrLength / 2);
        }
    };

    /**
     * Latin1 encoding strategy.
     */
    var Latin1 = C_enc.Latin1 = {
        /**
         * Converts a word array to a Latin1 string.
         *
         * @param {WordArray} wordArray The word array.
         *
         * @return {string} The Latin1 string.
         *
         * @static
         *
         * @example
         *
         *     var latin1String = CryptoJS.enc.Latin1.stringify(wordArray);
         */
        stringify: function (wordArray) {
            // Shortcuts
            var words = wordArray.words;
            var sigBytes = wordArray.sigBytes;

            // Convert
            var latin1Chars = [];
            for (var i = 0; i < sigBytes; i++) {
                var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
                latin1Chars.push(String.fromCharCode(bite));
            }

            return latin1Chars.join('');
        },

        /**
         * Converts a Latin1 string to a word array.
         *
         * @param {string} latin1Str The Latin1 string.
         *
         * @return {WordArray} The word array.
         *
         * @static
         *
         * @example
         *
         *     var wordArray = CryptoJS.enc.Latin1.parse(latin1String);
         */
        parse: function (latin1Str) {
            // Shortcut
            var latin1StrLength = latin1Str.length;

            // Convert
            var words = [];
            for (var i = 0; i < latin1StrLength; i++) {
                words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8);
            }

            return new WordArray.init(words, latin1StrLength);
        }
    };

    /**
     * UTF-8 encoding strategy.
     */
    var Utf8 = C_enc.Utf8 = {
        /**
         * Converts a word array to a UTF-8 string.
         *
         * @param {WordArray} wordArray The word array.
         *
         * @return {string} The UTF-8 string.
         *
         * @static
         *
         * @example
         *
         *     var utf8String = CryptoJS.enc.Utf8.stringify(wordArray);
         */
        stringify: function (wordArray) {
            try {
                return decodeURIComponent(escape(Latin1.stringify(wordArray)));
            } catch (e) {
                throw new Error('Malformed UTF-8 data');
            }
        },

        /**
         * Converts a UTF-8 string to a word array.
         *
         * @param {string} utf8Str The UTF-8 string.
         *
         * @return {WordArray} The word array.
         *
         * @static
         *
         * @example
         *
         *     var wordArray = CryptoJS.enc.Utf8.parse(utf8String);
         */
        parse: function (utf8Str) {
            return Latin1.parse(unescape(encodeURIComponent(utf8Str)));
        }
    };

    /**
     * Abstract buffered block algorithm template.
     *
     * The property blockSize must be implemented in a concrete subtype.
     *
     * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0
     */
    var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({
        /**
         * Resets this block algorithm's data buffer to its initial state.
         *
         * @example
         *
         *     bufferedBlockAlgorithm.reset();
         */
        reset: function () {
            // Initial values
            this._data = new WordArray.init();
            this._nDataBytes = 0;
        },

        /**
         * Adds new data to this block algorithm's buffer.
         *
         * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8.
         *
         * @example
         *
         *     bufferedBlockAlgorithm._append('data');
         *     bufferedBlockAlgorithm._append(wordArray);
         */
        _append: function (data) {
            // Convert string to WordArray, else assume WordArray already
            if (typeof data == 'string') {
                data = Utf8.parse(data);
            }

            // Append
            this._data.concat(data);
            this._nDataBytes += data.sigBytes;
        },

        /**
         * Processes available data blocks.
         *
         * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype.
         *
         * @param {boolean} doFlush Whether all blocks and partial blocks should be processed.
         *
         * @return {WordArray} The processed data.
         *
         * @example
         *
         *     var processedData = bufferedBlockAlgorithm._process();
         *     var processedData = bufferedBlockAlgorithm._process(!!'flush');
         */
        _process: function (doFlush) {
            // Shortcuts
            var data = this._data;
            var dataWords = data.words;
            var dataSigBytes = data.sigBytes;
            var blockSize = this.blockSize;
            var blockSizeBytes = blockSize * 4;

            // Count blocks ready
            var nBlocksReady = dataSigBytes / blockSizeBytes;
            if (doFlush) {
                // Round up to include partial blocks
                nBlocksReady = Math.ceil(nBlocksReady);
            } else {
                // Round down to include only full blocks,
                // less the number of blocks that must remain in the buffer
                nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0);
            }

            // Count words ready
            var nWordsReady = nBlocksReady * blockSize;

            // Count bytes ready
            var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes);

            // Process blocks
            if (nWordsReady) {
                for (var offset = 0; offset < nWordsReady; offset += blockSize) {
                    // Perform concrete-algorithm logic
                    this._doProcessBlock(dataWords, offset);
                }

                // Remove processed words
                var processedWords = dataWords.splice(0, nWordsReady);
                data.sigBytes -= nBytesReady;
            }

            // Return processed words
            return new WordArray.init(processedWords, nBytesReady);
        },

        /**
         * Creates a copy of this object.
         *
         * @return {Object} The clone.
         *
         * @example
         *
         *     var clone = bufferedBlockAlgorithm.clone();
         */
        clone: function () {
            var clone = Base.clone.call(this);
            clone._data = this._data.clone();

            return clone;
        },

        _minBufferSize: 0
    });

    /**
     * Abstract hasher template.
     *
     * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits)
     */
    var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({
        /**
         * Configuration options.
         */
        cfg: Base.extend(),

        /**
         * Initializes a newly created hasher.
         *
         * @param {Object} cfg (Optional) The configuration options to use for this hash computation.
         *
         * @example
         *
         *     var hasher = CryptoJS.algo.SHA256.create();
         */
        init: function (cfg) {
            // Apply config defaults
            this.cfg = this.cfg.extend(cfg);

            // Set initial values
            this.reset();
        },

        /**
         * Resets this hasher to its initial state.
         *
         * @example
         *
         *     hasher.reset();
         */
        reset: function () {
            // Reset data buffer
            BufferedBlockAlgorithm.reset.call(this);

            // Perform concrete-hasher logic
            this._doReset();
        },

        /**
         * Updates this hasher with a message.
         *
         * @param {WordArray|string} messageUpdate The message to append.
         *
         * @return {Hasher} This hasher.
         *
         * @example
         *
         *     hasher.update('message');
         *     hasher.update(wordArray);
         */
        update: function (messageUpdate) {
            // Append
            this._append(messageUpdate);

            // Update the hash
            this._process();

            // Chainable
            return this;
        },

        /**
         * Finalizes the hash computation.
         * Note that the finalize operation is effectively a destructive, read-once operation.
         *
         * @param {WordArray|string} messageUpdate (Optional) A final message update.
         *
         * @return {WordArray} The hash.
         *
         * @example
         *
         *     var hash = hasher.finalize();
         *     var hash = hasher.finalize('message');
         *     var hash = hasher.finalize(wordArray);
         */
        finalize: function (messageUpdate) {
            // Final message update
            if (messageUpdate) {
                this._append(messageUpdate);
            }

            // Perform concrete-hasher logic
            var hash = this._doFinalize();

            return hash;
        },

        blockSize: 512 / 32,

        /**
         * Creates a shortcut function to a hasher's object interface.
         *
         * @param {Hasher} hasher The hasher to create a helper for.
         *
         * @return {Function} The shortcut function.
         *
         * @static
         *
         * @example
         *
         *     var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256);
         */
        _createHelper: function (hasher) {
            return function (message, cfg) {
                return new hasher.init(cfg).finalize(message);
            };
        },

        /**
         * Creates a shortcut function to the HMAC's object interface.
         *
         * @param {Hasher} hasher The hasher to use in this HMAC helper.
         *
         * @return {Function} The shortcut function.
         *
         * @static
         *
         * @example
         *
         *     var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256);
         */
        _createHmacHelper: function (hasher) {
            return function (message, key) {
                return new C_algo.HMAC.init(hasher, key).finalize(message);
            };
        }
    });

    /**
     * Algorithm namespace.
     */
    var C_algo = C.algo = {};

    return C;
}(Math));;
(function () {
    // Shortcuts
    var C = CryptoJS;
    var C_lib = C.lib;
    var Base = C_lib.Base;
    var C_enc = C.enc;
    var Utf8 = C_enc.Utf8;
    var C_algo = C.algo;

    /**
     * HMAC algorithm.
     */
    var HMAC = C_algo.HMAC = Base.extend({
        /**
         * Initializes a newly created HMAC.
         *
         * @param {Hasher} hasher The hash algorithm to use.
         * @param {WordArray|string} key The secret key.
         *
         * @example
         *
         *     var hmacHasher = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key);
         */
        init: function (hasher, key) {
            // Init hasher
            hasher = this._hasher = new hasher.init();

            // Convert string to WordArray, else assume WordArray already
            if (typeof key == 'string') {
                key = Utf8.parse(key);
            }

            // Shortcuts
            var hasherBlockSize = hasher.blockSize;
            var hasherBlockSizeBytes = hasherBlockSize * 4;

            // Allow arbitrary length keys
            if (key.sigBytes > hasherBlockSizeBytes) {
                key = hasher.finalize(key);
            }

            // Clamp excess bits
            key.clamp();

            // Clone key for inner and outer pads
            var oKey = this._oKey = key.clone();
            var iKey = this._iKey = key.clone();

            // Shortcuts
            var oKeyWords = oKey.words;
            var iKeyWords = iKey.words;

            // XOR keys with pad constants
            for (var i = 0; i < hasherBlockSize; i++) {
                oKeyWords[i] ^= 0x5c5c5c5c;
                iKeyWords[i] ^= 0x36363636;
            }
            oKey.sigBytes = iKey.sigBytes = hasherBlockSizeBytes;

            // Set initial values
            this.reset();
        },

        /**
         * Resets this HMAC to its initial state.
         *
         * @example
         *
         *     hmacHasher.reset();
         */
        reset: function () {
            // Shortcut
            var hasher = this._hasher;

            // Reset
            hasher.reset();
            hasher.update(this._iKey);
        },

        /**
         * Updates this HMAC with a message.
         *
         * @param {WordArray|string} messageUpdate The message to append.
         *
         * @return {HMAC} This HMAC instance.
         *
         * @example
         *
         *     hmacHasher.update('message');
         *     hmacHasher.update(wordArray);
         */
        update: function (messageUpdate) {
            this._hasher.update(messageUpdate);

            // Chainable
            return this;
        },

        /**
         * Finalizes the HMAC computation.
         * Note that the finalize operation is effectively a destructive, read-once operation.
         *
         * @param {WordArray|string} messageUpdate (Optional) A final message update.
         *
         * @return {WordArray} The HMAC.
         *
         * @example
         *
         *     var hmac = hmacHasher.finalize();
         *     var hmac = hmacHasher.finalize('message');
         *     var hmac = hmacHasher.finalize(wordArray);
         */
        finalize: function (messageUpdate) {
            // Shortcut
            var hasher = this._hasher;

            // Compute HMAC
            var innerHash = hasher.finalize(messageUpdate);
            hasher.reset();
            var hmac = hasher.finalize(this._oKey.clone().concat(innerHash));

            return hmac;
        }
    });
}());;
(function (Math) {
    // Shortcuts
    var C = CryptoJS;
    var C_lib = C.lib;
    var WordArray = C_lib.WordArray;
    var Hasher = C_lib.Hasher;
    var C_algo = C.algo;

    // Initialization and round constants tables
    var H = [];
    var K = [];

    // Compute constants
    (function () {
        function isPrime(n) {
            var sqrtN = Math.sqrt(n);
            for (var factor = 2; factor <= sqrtN; factor++) {
                if (!(n % factor)) {
                    return false;
                }
            }

            return true;
        }

        function getFractionalBits(n) {
            return ((n - (n | 0)) * 0x100000000) | 0;
        }

        var n = 2;
        var nPrime = 0;
        while (nPrime < 64) {
            if (isPrime(n)) {
                if (nPrime < 8) {
                    H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2));
                }
                K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3));

                nPrime++;
            }

            n++;
        }
    }());

    // Reusable object
    var W = [];

    /**
     * SHA-256 hash algorithm.
     */
    var SHA256 = C_algo.SHA256 = Hasher.extend({
        _doReset: function () {
            this._hash = new WordArray.init(H.slice(0));
        },

        _doProcessBlock: function (M, offset) {
            // Shortcut
            var H = this._hash.words;

            // Working variables
            var a = H[0];
            var b = H[1];
            var c = H[2];
            var d = H[3];
            var e = H[4];
            var f = H[5];
            var g = H[6];
            var h = H[7];

            // Computation
            for (var i = 0; i < 64; i++) {
                if (i < 16) {
                    W[i] = M[offset + i] | 0;
                } else {
                    var gamma0x = W[i - 15];
                    var gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^
                                  ((gamma0x << 14) | (gamma0x >>> 18)) ^
                                   (gamma0x >>> 3);

                    var gamma1x = W[i - 2];
                    var gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^
                                  ((gamma1x << 13) | (gamma1x >>> 19)) ^
                                   (gamma1x >>> 10);

                    W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16];
                }

                var ch = (e & f) ^ (~e & g);
                var maj = (a & b) ^ (a & c) ^ (b & c);

                var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22));
                var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25));

                var t1 = h + sigma1 + ch + K[i] + W[i];
                var t2 = sigma0 + maj;

                h = g;
                g = f;
                f = e;
                e = (d + t1) | 0;
                d = c;
                c = b;
                b = a;
                a = (t1 + t2) | 0;
            }

            // Intermediate hash value
            H[0] = (H[0] + a) | 0;
            H[1] = (H[1] + b) | 0;
            H[2] = (H[2] + c) | 0;
            H[3] = (H[3] + d) | 0;
            H[4] = (H[4] + e) | 0;
            H[5] = (H[5] + f) | 0;
            H[6] = (H[6] + g) | 0;
            H[7] = (H[7] + h) | 0;
        },

        _doFinalize: function () {
            // Shortcuts
            var data = this._data;
            var dataWords = data.words;

            var nBitsTotal = this._nDataBytes * 8;
            var nBitsLeft = data.sigBytes * 8;

            // Add padding
            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);
            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;
            data.sigBytes = dataWords.length * 4;

            // Hash final blocks
            this._process();

            // Return final computed hash
            return this._hash;
        },

        clone: function () {
            var clone = Hasher.clone.call(this);
            clone._hash = this._hash.clone();

            return clone;
        }
    });

    /**
     * Shortcut function to the hasher's object interface.
     *
     * @param {WordArray|string} message The message to hash.
     *
     * @return {WordArray} The hash.
     *
     * @static
     *
     * @example
     *
     *     var hash = CryptoJS.SHA256('message');
     *     var hash = CryptoJS.SHA256(wordArray);
     */
    C.SHA256 = Hasher._createHelper(SHA256);

    /**
     * Shortcut function to the HMAC's object interface.
     *
     * @param {WordArray|string} message The message to hash.
     * @param {WordArray|string} key The secret key.
     *
     * @return {WordArray} The HMAC.
     *
     * @static
     *
     * @example
     *
     *     var hmac = CryptoJS.HmacSHA256(message, key);
     */
    C.HmacSHA256 = Hasher._createHmacHelper(SHA256);
}(Math));;
