

/*********************
Including file: lang.js
*********************/
/**
 * lang.js - js functions for working with multilingual strings
 *
 * @package    core
 * @author     Jon Randy
 * @copyright  (c) 2009 OnAsia
 */
var lang = {
    
};

String.prototype.format = function string_format(d) {
  // there are two modes of operation... unnamed indices are read in order;
  // named indices using %(name)s. The two styles cannot be mixed.
  // Unnamed indices can be passed as either a single argument to this function,
  // multiple arguments to this function, or as a single array argument
   curindex = 0;

  if (arguments.length > 1)
    d = arguments;

  function r(s, key, type) {
    var v;
    if (key == "" || key == null || key == undefined) {
      if (curindex == -1)
        throw Error("Cannot mix named and positional indices in string formatting.");

      if (curindex == 0 && (!(d instanceof Object) || !(0 in d)))
        v = d;
      else if (!(curindex in d))
        throw Error("Insufficient number of items in format, requesting item %i".format(curindex));
      else
        v = d[curindex];

      ++curindex;
    }
    else {
      key = key.slice(1, -1);
      if (curindex > 0)
        throw Error("Cannot mix named and positional indices in string formatting.");
      curindex = -1;

      if (!(key in d))
        throw Error("Key '%s' not present during string substitution.".format(key));
      v = d[key];
    }
    switch (type) {
    case "s":
      return v.toString();
    case "r":
      return v.toSource();
    case "i":
      return parseInt(v);
    case "f":
      return Number(v);
    case "%":
      return "%";
    default:
      throw Error("Unexpected format character '%s'.".format(type));
    }
  }
  return this.replace(/%(\([^)]+\))?(.)/g, r);
};
String.prototype.$f = String.prototype.format;

/*********************
Including file: ajaxLogout.js
*********************/
/**
 * ajaxLogout.js - handle the situation where a users session timed out before an ajax request
 *
 * @package    core
 * @author     Jon Randy
 * @copyright  (c) 2010 OnAsia
 */

(function() {
    
ajaxLogout = {
    
    /**
     * setup
     * 
     * @return  void
     */
    _setup:function(){

        // if we get an unauthorised staus back on the ajax request, redirect if told to do so
        $(document).ajaxComplete(function(o,xhr){
            var loc;
            if (xhr!= undefined && xhr.status==401) {
                var obj=eval('('+xhr.responseText+')');
                if (loc=obj.authError) location.href = APP.baseURL+loc;
            }
        });         
    }
}
})();
$(ajaxLogout._setup);



/*********************
Including file: hoverdropdown.js
*********************/
/**
 * hoverdropdown.js - js functions relating to common hover dropdown
 *
 * @package    core
 * @author     Tik Nipaporn
 * @copyright  (c) 2010 OnAsia
 */
(function() {
    
hoverDropdown = {
    
    /**
     * setup for hover dropdowns
     *
     * @return  void
     */
    _setup:function() {
        hoverDropdown._bindHoverEvents();
        
        // handle a click on hover list item
        $('ul.hoverdd ul li:not([onclick])').click(hoverDropdown._handleLIClick);
        
        hoverDropdown.rebind();
                
        hoverDropdown._resizeToContent();
    },
    
    /**
     * bind hidden input events for all hover dropdowns
     *
     * @return  void
     */
    rebind:function() {
        var inputs = $('ul.hoverdd > li > input[type=hidden]');
        inputs.unbind('click', hoverDropdown._handleClick).unbind('change', hoverDropdown._handleChange).unbind('refresh', hoverDropdown._handleChange);
        inputs.bind('click', hoverDropdown._handleClick).bind('change', hoverDropdown._handleChange).bind('refresh', hoverDropdown._handleChange);
    },
     
    /**
     * handle 'click' on hover dropdown option
     *
     * @return  void
     */
    _handleLIClick:function(event) {
        var thisID = $(this).closest('ul.hoverdd').find('input')[0].id;
        var ul = $(this).closest('ul.hoverdd');
        ul.addClass('shut'); // make sure dropdown closes
        $('#'+thisID).trigger('click', this);
        hoverDropdown.setScrollPosition(ul);
    },
     
    /**
     * handle 'click' on contained hidden input
     *
     * @return  void
     */
     _handleClick:function(event, li) {
        var thisVal = $(li).attr('hval');
        if (this.value != thisVal) {
            $(this).val(thisVal);
            $(this).trigger('change');
        }
     },
    
    /**
     * handle 'change' event for dropdown
     *
     * @return  void
     */
     _handleChange:function() {
        
        $(this).next().children().removeClass('_sel');
        var li = $(this).parent().find('li[hval="'+this.value+'"]');
        $(this).prev().text(li.text());
        li.addClass('_sel');
     },
    
    
    /**
     * hook up events to make sure hover dropdowns re-open
     *
     * @return  void
     */
    _bindHoverEvents:function() {
        $('ul.hoverdd').mouseover(hoverDropdown._reopenFix).mouseout(hoverDropdown._reopenFix);
    },
     _reopenFix:function() { $(this).removeClass('shut'); },
     
    /**
     * resize dropdowns to their content (except when asked not to)
     *
     * @return  void
     */
    _resizeToContent:function() {
        $('ul.hoverdd:not([noresize])').each(function(idx, el) {
            $(el).css('width', $(el).outerWidth() + 5 + 'px')
        });
    },
    
    /**
     * make the selected option visible when the dropdown opens
     * 
     * @param    hover dropdown
     * @return    void
     */
    setScrollPosition:function(ul) {
        var scrollUL = ul.children().find('ul');
        var val = ul.children().find('input[type=hidden]').val();
        if(val == "") return;
        var pos = scrollUL.children('li').index($('li[hval='+val+']'));
        scrollUL.attr({ scrollTop: pos*10 });
    }
};


})();


$(hoverDropdown._setup);

/*********************
Including file: app.js
*********************/
/**
 * app.js - js functions tools for the application
 *
 * @package    core
 * @author     Laurent Hunaut
 * @copyright  (c) 2021 Lightrocket
 */

(function() {
    APP = $.extend({}, APP,{
        htmlTagsRegex : {
            searchRegExPP       : {
                rx : new RegExp('</p><p>', 'g'),
                rp : '<br>',
            },
            searchRegExP        : {
                rx : new RegExp('<p>', 'g'),
                rp : '',
            },
            searchRegExSP       : {
                rx : new RegExp('</p>', 'g'),
                rp : '',
            },
            searchRegExSpace    : {
                rx : new RegExp('&nbsp;', 'g'),
                rp : ' ',
            },
        },
        descriptionConvTextJS: function(desc) {
            let elements = $.parseHTML(desc);
            desc = APP.traverseDOM(elements);
            desc = desc.replace('  ', ' ');

            return desc;
        },
        traverseDOM: function(elements) {
            let text = '';
            $.each(elements, function(key, element) {
                if ($(element).attr('href')) {
                    text += ' ' + $(element).attr('href');
                } else if (element.childNodes.length) {
                    text += ' ' + APP.traverseDOM(element.childNodes);
                } else if ($(element).text().trim() != '') {
                    text += ' ' + $(element).text().trim();
                }
            });
            return text.trim();
        },
        getUrlParameter:function(param) {
            var pageUrl = window.location.search.substring(1),
            urlVariables = pageUrl.split('&');
            var parameterName,
            i;
            for (i = 0; i < urlVariables.length; i++) {
                parameterName = urlVariables[i].split('=');

                if (parameterName[0] === param) {
                    return parameterName[1] === undefined ? true : decodeURIComponent(parameterName[1]);
                }
            }
        },
        decodeEntities:function(encodedString) {
            var textArea = document.createElement('textarea');
            textArea.innerHTML = encodedString;
            return textArea.value;
        },
        copyToClipboard:function(value) {
            var appendToEl = (arguments.length>1) ? arguments[1] : "body";
            var $temp = $("<input>");
            $(appendToEl).append($temp);
            $temp.val(value).select();
            document.execCommand("copy");
            $temp.remove();
        },
        copyToClipboardHTML:function(value) {
            var appendToEl = (arguments.length>1) ? arguments[1] : "body";
            var $temp = $("<textarea>");
            $(appendToEl).append($temp);
            $temp.val(value).select();
            document.execCommand("copy");
            $temp.remove();
        },
        removeArrDup:function(arr){
            var newArray = arr.filter(function(elem, index, self) {
                return index === self.indexOf(elem);
            });
            return newArray;
        },
        getNumHandlers:function(selector){
            nums = {total:0};
            $.each($(selector), function(){

                events = getEventListeners($(this)[0]);
                $.each(Object.keys(events), function(){
                    if(nums[this] == undefined) nums[this] = 0;
                    nums.total += events[this].length;
                    nums[this] += events[this].length;
                });
            });
            return nums;
        },
        registerRTFeditor:function(editor, key){
            if(window.editors === undefined) window.editors = {};
            window.editors[key] = editor;
        },
        destroyRTFeditors:function(){
            if(window.editors !== undefined){
                $.each(Object.keys(window.editors), function(){
                    if(window.editors[this] !== undefined && typeof(window.editors[this].destroy) == "function"){
                        let toDestroy = window.editors[this];
                        delete window.editors[this];
                        toDestroy.destroy();

                    }
                });
            }
            
        },
    });
})();


/*********************
Including file: notify.js
*********************/
/**
 * notify.js - fancy notifications
 *
 * @package    core
 * @author     Jon Randy
 * @copyright  (c) 2010 OnAsia
 */

(function() {
    
notify = {
    
    timeoutID:false,
    waiting:false,
    confirmResult:false,
    
    defaults: {
        background_color    : '#FFFFCC',
        color                    : '#000',
        time                    : 8000,
        onDisplayed            : false
    },
    
    show:function(message) {
        var opts = {};
        $.extend(opts, notify.defaults, (arguments.length>1) ? arguments[1] : {});
        
        // make sure message is a string
        message = ''+message;
        
        // remove existing if there
        if ($('.notifyBar').length) {
            notify.hide(function(){notify.show(message, opts);});
            return;
        }
        
        if (message==='') return;
        
        var msg = $('<div/>').html('<p>'+message.replace(/\n/i, '<br />')+'</p>').css({"color" : opts.color});
        var mouseoverMsg = '';
        if (typeof(lang.common)!='undefined')  mouseoverMsg = lang.common.lbl_dismissNotification;
        var wrapDiv = $('<div/>').addClass('notifyBar').css({"background-color" : opts.background_color}).attr('title', mouseoverMsg);
        wrapDiv.mousemove(notify.hide);
        wrapDiv.append(msg).hide().appendTo('body').slideDown('fast', opts.onDisplayed);
        
        notify.timeoutID = setTimeout(notify.hide, opts.time);

        
    },
    
    hide:function() {
        var callback = arguments.length ? arguments[0] : false;
        if ($('.notifyBar').length){
            clearTimeout(notify.timeoutID);
            $('.notifyBar').slideUp('fast',function(){
                $('.notifyBar').remove();
                if ($.isFunction(callback)) callback();
            });
        }
    },
    
    confirmAction:function(message, title, opts) {
        var o = {onOK:false, onCancel:false, opts:false};
        $.extend(o, opts);
        var okAction = opts.onOK ? opts.onOK : function(){};
        var cancelAction = opts.onCancel ? opts.onCancel : function(){};
        console.log("notify confirm");
        console.log(message);
        if (title) {
            var msgOpts = opts.opts ? opts.opts : {};
            var notifyOpts = {
                time:100000000,
                onDisplayed:function(){
                    var res = confirm(message);
                    notify.hide(function() {res ? okAction() : cancelAction();});
                }
            };
            $.extend(notifyOpts, msgOpts);
            notify.show(title, notifyOpts);
        } else {
            confirm(message) ? okAction() : cancelAction();
        }
    }
        

};




})();

window._alert = window.alert;
window.alert = function() { notify.show.apply(this, arguments); };

window.confirmAction = function() { return(notify.confirmAction.apply(this, arguments)); };



/*********************
Including file: labs_json.js
*********************/
/**
 * labs_json Script by Giraldo Rosales.
 * Version 1.0
 * Visit www.liquidgear.net for documentation and updates.
 *
 *
 * Copyright (c) 2009 Nitrogen Design, Inc. All rights reserved.
 * 
 * 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.
 **/
 
/**
 * HOW TO USE
 * ==========
 * Serialize:
 * var obj = {};
 * obj.name    = "Test JSON";
 * obj.type    = "test";
 * $.json.serialize(obj); //output: {"name":"Test JSON", "type":"test"}
 * 
 * Deserialize:
 * $.json.deserialize({"name":"Test JSON", "type":"test"}); //output: object
 * 
 */

jQuery.json = {
    serialize:function(value, replacer, space) {
        var i;
        gap = '';
        var indent = '';
        
        if (typeof space === 'number') {
            for (i = 0; i < space; i += 1) {
                indent += ' ';
            }
            
        } else if (typeof space === 'string') {
            indent = space;
        }
        
        rep = replacer;
        if (replacer && typeof replacer !== 'function' &&
                (typeof replacer !== 'object' ||
                 typeof replacer.length !== 'number')) {
            throw new Error('JSON.serialize');
        }
        
        return this.str('', {'': value});
    },
    
    deserialize:function(text, reviver) {
        var j;
        var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
        
        function walk(holder, key) {
            var k, v, value = holder[key];
            
            if (value && typeof value === 'object') {
                for (k in value) {
                    if (Object.hasOwnProperty.call(value, k)) {
                        v = walk(value, k);
                        if (v !== undefined) {
                            value[k] = v;
                        } else {
                            delete value[k];
                        }
                    }
                }
            }
            return reviver.call(holder, key, value);
        }
        
        cx.lastIndex = 0;
        
        if (cx.test(text)) {
            text = text.replace(cx, function (a) {
                return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
            });
        }
        
        if (/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
            j = eval('(' + text + ')');
            return typeof reviver === 'function' ? walk({'': j}, '') : j;
        }
        
        throw new SyntaxError('JSON.parse');
    },
    
    f:function(n) {
        return n < 10 ? '0' + n : n;
    },
    
    DateToJSON:function(key) {
        return this.getUTCFullYear() + '-' + this.f(this.getUTCMonth() + 1) + '-' + this.f(this.getUTCDate())      + 'T' + this.f(this.getUTCHours())     + ':' + this.f(this.getUTCMinutes())   + ':' + this.f(this.getUTCSeconds())   + 'Z';
    },
    
    StringToJSON:function(key) {
        return this.valueOf();
    },
    
    quote:function(string) {
        var meta = {'\b': '\\b','\t': '\\t','\n': '\\n','\f': '\\f','\r': '\\r','"' : '\\"','\\': '\\\\'};
        var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
        
        escapable.lastIndex = 0;
        return escapable.test(string) ?
            '"' + string.replace(escapable, function (a) {
                var c = meta[a];
                return typeof c === 'string' ? c :
                    '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
            }) + '"' :
            '"' + string + '"';
    },
    
    str:function(key, holder) {
        var indent='', gap = '', i, k, v, length, mind = gap, partial, value = holder[key];
        
        if (value && typeof value === 'object') {
            switch((typeof value)) {
                case 'date':
                    this.DateToJSON(key);
                    break;
                default:
                    this.StringToJSON(key);
                    break;
            }
        }
        
        if (typeof rep === 'function') {
            value = rep.call(holder, key, value);
        }
        switch (typeof value) {
            case 'string':
                return this.quote(value);
            case 'number':
                return isFinite(value) ? String(value) : 'null';
            case 'boolean':
            case 'null':
                return String(value);
            case 'object':
                if (!value) {
                    return 'null';
                }
                gap += indent;
                partial = [];
                
                if (Object.prototype.toString.apply(value) === '[object Array]') {
                    length = value.length;
                    
                    for (i = 0; i < length; i += 1) {
                        partial[i] = this.str(i, value) || 'null';
                    }
    
                    v = partial.length === 0 ? '[]' : gap ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : '[' + partial.join(',') + ']';
                    gap = mind;
                    return v;
                }
                    
                if (rep && typeof rep === 'object') {
                    length = rep.length;
                    for (i = 0; i < length; i += 1) {
                        k = rep[i];
                        if (typeof k === 'string') {
                            v = this.str(k, value);
                            if (v) {
                                partial.push(this.quote(k) + (gap ? ': ' : ':') + v);
                            }
                        }
                    }
                } else {
                    for (k in value) {
                        if (Object.hasOwnProperty.call(value, k)) {
                            v = this.str(k, value);
                            if (v) {
                                partial.push(this.quote(k) + (gap ? ': ' : ':') + v);
                            }
                        }
                    }
                }

                v = partial.length === 0 ? '{}' :
                    gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
                            mind + '}' : '{' + partial.join(',') + '}';
                gap = mind;
                return v;
        }
    }
};


/*********************
Including file: jqContext.js
*********************/
/**
 * jqContext.js - jquery extension to allow for easy creation of context specific callbacks
 *
 * @package    core
 * @author     Jon Randy
 * @copyright  (c) 2009 OnAsia
 */
 
 // $.context - example use: $.context(this).callback('myCallback') - would return a function that calls 'myCallback' in the context of this
jQuery.extend(
{
    context: function (context)
    {
        var co = 
        {
            callback: function (method)
            {
                if (typeof method == 'string') method = context[method];
                var cb = function () { method.apply(context, arguments); }
                return cb;
            }
        };
        return co;
    }
}); 


/*********************
Including file: jqModal.js
*********************/
/*
 * jqModal - Minimalist Modaling with jQuery
 *
 * Copyright (c) 2007-2015 Brice Burgess @IceburgBrice
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * $Version: 1.4.1 (2015.09.07 +r26)
 * Requires: jQuery 1.2.3+
 */

(function (factory) {
  if (typeof module === 'object' && typeof module.exports === 'object') {
    // Node/CommonJS
    module.exports = factory(require('jquery'));
  } else {
    // Browser globals
    factory(jQuery);
  }
}(function ($) {

    /**
     * Initialize elements as "modals". Modals typically are popup dialogs,
     * notices, modal windows, &c.
     *
     * @name jqm
     * @param options user defined options, augments defaults.
     * @type jQuery
     * @cat Plugins/jqModal
     */

    $.fn.jqm=function(options){
        return this.each(function(){
            var jqm = $(this).data('jqm') || $.extend({ID: I++}, $.jqm.params),
              o = $.extend(jqm,options);

            // add/extend options to modal and mark as initialized
            $(this).data('jqm',o).addClass('jqm-init')[0]._jqmID = o.ID;

            // ... Attach events to trigger showing of this modal
            $(this).jqmAddTrigger(o.trigger);
        });
    };

    /**
     * Matching modals will have their jqmShow() method fired by attaching a
     *   onClick event to elements matching `trigger`.
     *
     * @name jqmAddTrigger
     * @param trigger a a string selector, jQuery collection, or DOM element.
     */
    $.fn.jqmAddTrigger=function(trigger){
      if(trigger){
        return this.each(function(){
              if (!addTrigger($(this), 'jqmShow', trigger))
                err("jqmAddTrigger must be called on initialized modals");
          });
      }
    };

    /**
     * Matching modals will have their jqmHide() method fired by attaching an
     *   onClick event to elements matching `trigger`.
     *
     * @name jqmAddClose
     * @param trigger a string selector, jQuery collection, or DOM element.
     */
    $.fn.jqmAddClose=function(trigger){
      if(trigger){
        return this.each(function(){
              if(!addTrigger($(this), 'jqmHide', trigger))
                err ("jqmAddClose must be called on initialized modals");
          });
      }
    };

    /**
     * Open matching modals (if not shown)
     */
    $.fn.jqmShow=function(trigger){
        return this.each(function(){ if(!this._jqmShown) show($(this), trigger); });
    };

    /**
     * Close matching modals
     */
    $.fn.jqmHide=function(trigger){
        return this.each(function(){ if(this._jqmShown) hide($(this), trigger); });
    };

    // utility functions

    var
        err = function(msg){
            if(window.console && window.console.error) window.console.error(msg);

    }, show = function(m, t){

        /**
         * m = modal element (as jQuery object)
         * t = triggering element
         *
         * o = options
         * z = z-index of modal
         * v = overlay element (as jQuery object)
         * h = hash (for jqModal <= r15 compatibility)
         */

      t = t || window.event;

        var o = m.data('jqm'),
            z = (parseInt(m.css('z-index'))) || 3000,
            v = $('<div></div>').addClass(o.overlayClass).css({
              height:'100%',
              width:'100%',
              position:'fixed',
              left:0,
              top:0,
              'z-index':z-1,
              opacity:o.overlay/100
            }),

            // maintain legacy "hash" construct
            h = {w: m, c: o, o: v, t: t};

        m.css('z-index',z);

        if(o.ajax){
            var target = o.target || m,
                url = o.ajax;

            target = (typeof target === 'string') ? $(target,m) : $(target);
            if(url.substr(0,1) === '@') url = $(t).attr(url.substring(1));

            // load remote contents
            target.load(url,function(){
                if(o.onLoad) o.onLoad.call(this,h);
            });

            // show modal
            if(o.ajaxText) target.html(o.ajaxText);
      open(h);
        }
        else { open(h); }

    }, hide = function(m, t){
        /**
         * m = modal element (as jQuery object)
         * t = triggering element
         *
         * o = options
         * h = hash (for jqModal <= r15 compatibility)
         */

      t = t || window.event;
        var o = m.data('jqm'),
            // maintain legacy "hash" construct
            h = {w: m, c: o, o: m.data('jqmv'), t: t};

        close(h);

    }, onShow = function(hash){
        // onShow callback. Responsible for showing a modal and overlay.
        //  return false to stop opening modal.

        // hash object;
        //  w: (jQuery object) The modal element
        //  c: (object) The modal's options object
        //  o: (jQuery object) The overlay element
        //  t: (DOM object) The triggering element

        // if overlay not disabled, prepend to body
        if(hash.c.overlay > 0) hash.o.prependTo('body');

        // make modal visible
        hash.w.show();

        // call focusFunc (attempts to focus on first input in modal)
        $.jqm.focusFunc(hash.w,true);

        return true;

    }, onHide = function(hash){
        // onHide callback. Responsible for hiding a modal and overlay.
        //  return false to stop closing modal.

        // hash object;
        //  w: (jQuery object) The modal element
        //  c: (object) The modal's options object
        //  o: (jQuery object) The overlay element
        //  t: (DOM object) The triggering element

        // hide modal and if overlay, remove overlay.
        if(hash.w.hide() && hash.o) hash.o.remove();

        return true;

    },  addTrigger = function(m, key, trigger){
        // addTrigger: Adds a jqmShow/jqmHide (key) event click on modal (m)
        //  to all elements that match trigger string (trigger)

        var jqm = m.data('jqm');
        if(jqm) return $(trigger).each(function(){
            this[key] = this[key] || [];

            // register this modal with this trigger only once
            if($.inArray(jqm.ID,this[key]) < 0) {
                this[key].push(jqm.ID);

                // register trigger click event for this modal
                //  allows cancellation of show/hide event from
                $(this).click(function(e){
                    if(!e.isDefaultPrevented()) m[key](this);
                    return false;
                });
            }

        });

    }, open = function(h){
        // open: executes the onOpen callback + performs common tasks if successful

        // transform legacy hash into new var shortcuts
        var m = h.w,
            v = h.o,
            o = h.c;

        // execute onShow callback
        if(o.onShow(h) !== false){
            // mark modal as shown
            m[0]._jqmShown = true;

            // if modal:true  dialog
            //   Bind the Keep Focus Function [F] if no other Modals are active
            // else,
            //   trigger closing of dialog when overlay is clicked
            if(o.modal){
              if(!ActiveModals[0]){ F('bind'); }
              ActiveModals.push(m[0]);
            }
            else m.jqmAddClose(v);

            //  Attach events to elements inside the modal matching closingClass
            if(o.closeClass) m.jqmAddClose($('.' + o.closeClass,m));

            // if toTop is true and overlay exists;
            //  remember modal DOM position with <span> placeholder element, and move
            //  the modal to a direct child of the body tag (after overlyay)
            if(o.toTop && v)
              m.before('<span id="jqmP'+o.ID+'"></span>').insertAfter(v);

            // remember overlay (for closing function)
            m.data('jqmv',v);

            // close modal if the esc key is pressed and closeOnEsc is set to true
            m.unbind("keydown",$.jqm.closeOnEscFunc);
            if(o.closeOnEsc) {
                m.attr("tabindex", 0).bind("keydown",$.jqm.closeOnEscFunc).focus();
            }
        }

    }, close = function(h){
        // close: executes the onHide callback + performs common tasks if successful

        // transform legacy hash into new var shortcuts
         var m = h.w,
            v = h.o,
            o = h.c;

        // execute onHide callback
        if(o.onHide(h) !== false){
            // mark modal as !shown
            m[0]._jqmShown = false;

             // If modal, remove from modal stack.
             // If no modals in modal stack, unbind the Keep Focus Function
             if(o.modal){
               ActiveModals.pop();
               if(!ActiveModals[0]) F('unbind');
             }

             // IF toTop was passed and an overlay exists;
             //  Move modal back to its "remembered" position.
             if(o.toTop && v) $('#jqmP'+o.ID).after(m).remove();
        }

    },  F = function(t){
        // F: The Keep Focus Function (for modal: true dialos)
        // Binds or Unbinds (t) the Focus Examination Function (X)

        $(document)[t]("keypress keydown mousedown",X);

    }, X = function(e){
        // X: The Focus Examination Function (for modal: true dialogs)

        var targetModal = $(e.target).data('jqm') ||
                          $(e.target).parents('.jqm-init:first').data('jqm');
        var activeModal = ActiveModals[ActiveModals.length-1];

        // allow bubbling if event target is within active modal dialog
        return (targetModal && targetModal.ID === activeModal._jqmID) ?
                 true : $.jqm.focusFunc(activeModal,e);
    },

    I = 0,   // modal ID increment (for nested modals)
    ActiveModals = [];  // array of active modals

    // $.jqm, overridable defaults
    $.jqm = {
        /**
         *  default options
         *
         * (Integer)   overlay      - [0-100] Translucency percentage (opacity) of the body covering overlay. Set to 0 for NO overlay, and up to 100 for a 100% opaque overlay.
         * (String)    overlayClass - Applied to the body covering overlay. Useful for controlling overlay look (tint, background-image, &c) with CSS.
         * (String)    closeClass   - Children of the modal element matching `closeClass` will fire the onHide event (to close the modal).
         * (Mixed)     trigger      - Matching elements will fire the onShow event (to display the modal). Trigger can be a selector String, a jQuery collection of elements, a DOM element, or a False boolean.
         * (String)    ajax         - URL to load content from via an AJAX request. False to disable ajax. If ajax begins with a "@", the URL is extracted from the attribute of the triggering element (e.g. use '@data-url' for; <a href="#" class="jqModal" data-url="modal.html">...)
         * (Mixed)     target       - Children of the modal element to load the ajax response into. If false, modal content will be overwritten by ajax response. Useful for retaining modal design.
         *                            Target may be a selector string, jQuery collection of elements, or a DOM element -- and MUST exist as a child of the modal element.
         * (String)    ajaxText     - Text shown while waiting for ajax return. Replaces HTML content of `target` element.
         * (Boolean)   modal        - If true, user interactivity will be locked to the modal window until closed.
         * (Boolean)   toTop        - If true, modal will be posistioned as a first child of the BODY element when opened, and its DOM posistion restored when closed. Useful for overcoming z-Index container issues.
         * (Function)  onShow       - User defined callback function fired when modal opened.
         * (Function)  onHide       - User defined callback function fired when modal closed.
         * (Function)  onLoad       - User defined callback function fired when ajax content loads.
         */
        params: {
            overlay: 50,
            overlayClass: 'jqmOverlay',
            closeClass: 'jqmClose',
            closeOnEsc: false,
            trigger: '.jqModal',
            ajax: false,
            target: false,
            ajaxText: '',
            modal: false,
            toTop: false,
            onShow: onShow,
            onHide: onHide,
            onLoad: false
        },

        // focusFunc is fired:
        //   a) when a modal:true dialog is shown,
        //   b) when an event occurs outside an active modal:true dialog
        // It is passed the active modal:true dialog as well as event
        focusFunc: function(activeModal, e) {

          // if the event occurs outside the activeModal, focus on first element
          if(e) $(':input:visible:first',activeModal).focus();

          // lock interactions to the activeModal
          return false;
        },

        // closeOnEscFunc is attached to modals where closeOnEsc param true.
        closeOnEscFunc: function(e){
            if (e.keyCode === 27) {
                $(this).jqmHide();
                return false;
            }
        }
    };

    return $.jqm;

}));


/*********************
Including file: login.js
*********************/
/**
 * Login js - js functions relating to logging in
 *
 * @package    application/js
 * @author     Jon Randy
 * @copyright  (c) 2009 OnAsia
 */
var login = {
    ssoLoginOnly: 0,

    /**
     * setup login object
     *
     * @return  void
     */
    _setup:function() {
        if (!$('body').hasClass('noLoginPop')) {
            if (login.ssoLoginOnly) {
                $('a.mainLinkLogin').attr('href', APP.baseURL + 'access/sso');
            } else {
                $('a.mainLinkLogin').attr('data-toggle', 'modal');
                $('a.mainLinkLogin').attr('data-target', '#LoginForm');
                $('a.mainLinkLogin').attr('href', '#');
                $('a.mainLinkLogin').click(function(e){e.preventDefault();});
            }
        }

        $('#password-login').off().on('click', function() {
            $('#FailForm').removeClass('hideMe');
        });
        
        //set auto focus when the page loads for login failed page
        if($('#FailForm').length) {
            if($('#username').val().length > 0) {
                $('#username').select();
            }
            else {
                $('#username').focus();
            }
        }
        if($('#forgotpassword').length) {
            if($('#email').val().length > 0) {
                $('#email').select();
            }
            else {
                $('#email').focus();
            }
        }
        if ($('#LoginFailForm').length){
            $('#LoginForm').remove();
        }
        if ($('.login-form-button').length) {
            $('.login-form-button').click(function() {
                $('.back-arrow').removeClass('hidden');
                $('.loginform').removeClass('hidden');
                $('.login_form_buttons').addClass('hidden');
                $('.social_auth_buttons').addClass('hidden');
            });
        }
        if ($('.back-arrow').length) {
            $('.back-arrow').click(function() {
                $(this).siblings('h2').html(lang.common.lbl_MainLinkLogIn);
                $(this).addClass('hidden');
                $('.loginform').addClass('hidden');
                $('.alert-danger').addClass('hidden');
                $('.login_form_buttons').removeClass('hidden');
                $('.social_auth_buttons').removeClass('hidden');
            });
        }
    },
};

// set up on DOM ready
$(login._setup);



/*********************
Including file: headerSearch.js
*********************/
/**
 * headerSearch js - js functions relating to Header Search
 *
 * @package    search
 * @author     Pachara Chutisawaeng
 * @copyright  (c) 2009 Lightrocket
 */
var headerSearch = {
        
    
    _setup:function() {
        
        $('#search #header_search').focus(function() {
            if(this.value == $('#search #header_search').attr('tag')) {
                this.value = '';
            } else {
                this.select();
            }
        });
        $('#block_search').find('br').remove();
        $('#main_search_btn').attr("value",lang.common.lbl_headerSearchBtn);
        
        var lang_html = '';
        $('#lang_list li').each(function(){
            var link = $(this).find('a');
            var lang = $(this).data('lang');
            lang_html += '<span class="'+$(this).attr('class')+'"><a href="'+$(link).attr('href')+'" title="'+$(link).attr('title')+'">'+lang+'</a></span>';
        });
        $('#lang_panel').html(lang_html);
        
    }
};

// set up on DOM ready
$(headerSearch._setup);

/*********************
Including file: linkRel.js
*********************/
/**
 * linkRel.js - js functions relating to link pages
 *
 * @author     Tik Nipaporn
 * @copyright  (c) 2009 OnAsia
 */

var linkRel = {
    openPopup:function() {
        var features = "height=700,width=1000,scrollTo,resizable=1,scrollbars=1,location=0";
        newwindow = window.open(this.href, 'Popup_'+this.id, features);
        if (window.focus) newwindow.focus();
        return false;
    },
    _setup:function() {
        $('a#poweredBy').attr('target', '_blank');
        $('a[rel=external]').attr('target', '_blank');
        $('a[rel=popup]').unbind('click', linkRel.openPopup);
        $('a[rel=popup]').click(linkRel.openPopup);
    }
};

// set up on dom ready
$(linkRel._setup);

// dumbass IE fix
if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function(obj, start) {
         for (var i = (start || 0), j = this.length; i < j; i++) {
             if (this[i] === obj) { return i; }
         }
         return -1;
    };
}



/*********************
Including file: jqueryCookie.js
*********************/
/**
 * Cookie plugin
 *
 * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 */

/**
 * Create a cookie with the given name and value and other optional parameters.
 *
 * @example $.cookie('the_cookie', 'the_value');
 * @desc Set the value of a cookie.
 * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
 * @desc Create a cookie with all available options.
 * @example $.cookie('the_cookie', 'the_value');
 * @desc Create a session cookie.
 * @example $.cookie('the_cookie', null);
 * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
 *       used when the cookie was set.
 *
 * @param String name The name of the cookie.
 * @param String value The value of the cookie.
 * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
 * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
 *                             If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
 *                             If set to null or omitted, the cookie will be a session cookie and will not be retained
 *                             when the the browser exits.
 * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
 * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
 * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
 *                        require a secure protocol (like HTTPS).
 * @type undefined
 *
 * @name $.cookie
 * @cat Plugins/Cookie
 * @author Klaus Hartl/klaus.hartl@stilbuero.de
 */

/**
 * Get the value of a cookie with the given name.
 *
 * @example $.cookie('the_cookie');
 * @desc Get the value of a cookie.
 *
 * @param String name The name of the cookie.
 * @return The value of the cookie.
 * @type String
 *
 * @name $.cookie
 * @cat Plugins/Cookie
 * @author Klaus Hartl/klaus.hartl@stilbuero.de
 */
jQuery.cookie = function(name, value, options) {
    if (typeof value != 'undefined') { // name and value given, set cookie
        options = options || {};
        if (value === null) {
            value = '';
            options.expires = -1;
        }
        var expires = '';
        if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
            var date;
            if (typeof options.expires == 'number') {
                date = new Date();
                date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
            } else {
                date = options.expires;
            }
            expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
        }
        // CAUTION: Needed to parenthesize options.path and options.domain
        // in the following expressions, otherwise they evaluate to undefined
        // in the packed version for some reason...
        var path = options.path ? '; path=' + (options.path) : '';
        var domain = options.domain ? '; domain=' + (options.domain) : '';
        var secure = options.secure ? '; secure' : '';
        document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
    } else { // only name given, get cookie
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
};

/*********************
Including file: jquery.blockUI.js
*********************/
/*!
 * 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);
    }

})();


/*********************
Including file: userPrefs.js
*********************/
/**
 * userPrefs js - js functions for getting and setting user preferences
 *
 * @package    user
 * @author     Jon Randy
 * @copyright  (c) 2009 OnAsia
 */
var userPrefs = {
    
    cookiePrefix:'userPrefs',
    
    /**
     * get a user pref
     *
     * @param  string        user pref name to retrieve
     * @return  mixed        value of user pref
     */
    get:function(name) {
        return $.cookie(userPrefs._cookieName(name));
    },
    
    /**
     * set a user pref
     *
     * @param  string        user pref name to retrieve
     * @param  mixed        value of user pref
     * @return  void
     */
    set:function(name, value) {
        $.cookie(userPrefs._cookieName(name), value, {path:'/'});
    },
    
    /**
     * get cookie name used to store pref
     *
     * @param  string        user pref name
     * @return  string        name of cookie
     */
    _cookieName:function(name) {
        return userPrefs.cookiePrefix + '[' + name + ']';    
    },
    
    /**
     * setup for userPrefs object
     *
     * @return  void
     */
    _setup:function() {
        if (APP.userPrefCookiePrefix) userPrefs.cookiePrefix = APP.userPrefCookiePrefix;
    }
    
};

// set up on DOM ready
$(userPrefs._setup);

/*********************
Including file: fullscreen.js
*********************/
/**
 * fullscreen.js - popup messages for fullscreen pages
 *
 * @package    core
 * @author     Jon Randy
 * @copyright  (c) 2010 OnAsia
 */

(function() {
    
fullscreen = {
    
    keyName:false, // will store 'name' of fullscreen key
    keyCode:false, // will store code of 'fullscreen key'
    ctrlKey:false, 
    altKey:false, 
    metaKey:false, 
    shiftKey:false, 
    _tempW:0,
    _tempH:0,
    notifications:false,
    isFull:false,
    leaveMessage:false,
    
    /**
     * setup
     * 
     * @return  void
     */
    _setup:function(){
        var isWin = (navigator.platform.indexOf('win') != -1) || (navigator.platform.indexOf('Win') != -1);
        var isMac = (navigator.platform.indexOf('mac') != -1) || (navigator.platform.indexOf('Mac') != -1);
        var isChrome = (navigator.userAgent.indexOf('chrome') != -1) || (navigator.userAgent.indexOf('Chrome') != -1);
        var isFirefox = (navigator.userAgent.indexOf('firefox') != -1) || (navigator.userAgent.indexOf('Firefox') != -1);
        var ffVer = isFirefox ? navigator.userAgent.match(/firefox\/([0-9\.]*)/i)[1] : '0';
        var isSafari = !isChrome && ((navigator.userAgent.indexOf('safari') != -1) || (navigator.userAgent.indexOf('Safari') != -1));
        var ver = $.browser.version;
        // set up keys
        if ((isWin && !isSafari)||(isWin && isChrome && (ver>'2'))) {
            fullscreen.keyName = 'F11';
            fullscreen.keyCode = 122;
            fullscreen.ctrlKey = false;
            fullscreen.altKey = false;
            fullscreen.shiftKey = false;
            fullscreen.metaKey = false;
            fullscreen.leaveMessage = !isChrome;
        } else if (isMac && isFirefox && (ffVer>='3.6')) {
            fullscreen.keyName = '⇧⌘F';
            fullscreen.keyCode = 70;
            fullscreen.ctrlKey = false;
            fullscreen.altKey = false;
            fullscreen.shiftKey = true;
            fullscreen.metaKey = true;
            fullscreen.leaveMessage = true;
        }
        $('html').keydown(fullscreen._checkKeys);
    },
    
    /**
     * check the keys pressed to see if it is our 'fullscreen' key
     * 
     * @param  object            -    event object
     * @return  void
     */
    _checkKeys:function(e){
        var e_ctrlKey = e.ctrlKey ? true : false;
        var e_altKey = e.altKey ? true : false;
        var e_shiftKey = e.shiftKey ? true : false;
        var e_metaKey = e.metaKey ? true : false;
        if ((e.which==fullscreen.keyCode) && (e_ctrlKey==fullscreen.ctrlKey) && (e_altKey==fullscreen.altKey) && (e_shiftKey==fullscreen.shiftKey) && (e_metaKey==fullscreen.metaKey)) {
            fullscreen._tempW = $(window).width();
            fullscreen._tempH = $(window).height();
            setTimeout(fullscreen._checkFull, 500);
        }
    },

    /**
     * check the page has gone in/out of full mode
     * 
     * @return  void
     */
    _checkFull:function(){
        var newW = $(window).width();
        var newH = $(window).height();
        if (fullscreen.isFull) {
            if ((newW<fullscreen._tempW)||(newH<fullscreen._tempH)) {
                fullscreen.isFull = false;
                alert('');
            }
        } else {
            if ((newW>fullscreen._tempW)||(newH>fullscreen._tempH)) {
                fullscreen.isFull = true;
                if (fullscreen.notifications) alert(fullscreen.leaveMessage ? lang.common.msg_leaveFullScreen.format(fullscreen.keyName) : '');
            }
        }
    },
    
    /**
     * turn on/off notifications
     * 
     * @param  [bool]        -    optional state on/off - default is true
     * @return  void
     */
    notify:function(){
        var state = arguments.length ? arguments[0] : true;
        if ((fullscreen.notifications = state) && fullscreen.keyCode) alert(lang.common.msg_goFullScreen.format(fullscreen.keyName));
    }
    
}

})();


$(fullscreen._setup);



/*********************
Including file: dialog.js
*********************/
/**
 * dialog.js - js functions allowing to display dialog boxes
 *
 * @package    core
 * @author     Romain Bouillard
 * @copyright  (c) 2016 OnAsia
 */

(function() {

dialog = {
    default_options:{
        boxId           : "dialog-box",
        sizeClass       : "modal-sm",
        tallModal       : false,
        title           : "",
        showHeader      : true,
        resizable       : false,
        height          : 140,
        modal           : true,
        buttonsClass    : "nice_btn grey",
        hideCallback    : false,
        shownCallback   : false,
        backdrop        : true,
        onHiddenCallback: false,
    },
    options:{},
    template: _.template(
        '<div id="<%-boxId%>" class="modal fade"  tabindex="-1" role="dialog" <%-backdrop?"":\'data-backdrop=false\'%>>' +
        '   <div class="modal-dialog <%-tallModal?"tall-modal":""%> <%-sizeClass%>" role="document">' +
        '       <div class="modal-content">' +
        '           <div class="<%-showHeader?"":"hideMe"%> modal-header">' +
        '               <button type="button" class="close" data-dismiss="modal" aria-label="Close"><img src="'+APP.baseURL+'/media/icon?src=close-757575.svg"></button>' +
        '               <h4 class="modal-title"><%-title%></h4>' +
        '           </div>' +
        '           <div class="modal-body">' +
        '               <%=content%>' +
        '           </div>' +
        '           <div class="modal-footer">' +
        '               <%=buttons%>' +
        '           </div>' +
        '       </div>' +
        '   </div>' +
        '</div>'),
    button_template : _.template('<button id="<%-buttonId%>" type="button" class="btn <%-classes%> btn-sm" <%=attributes%>><%-label%></button>'),
    message_template: _.template('<p><%=message%></p>'),
    prompt_template: _.template('<p><%=message%></p><input class="form-control input-sm" placeholder="<%=placeHolder%>" type="text"<%=(inputLength)?" maxlength="+inputLength:""%> value="<%-initInput%>">'),
    buttons_html:"",
    shown:false,
    hiding:false,
    setup:function(){},
    addBox:function(){
        this.remove();
        if(!this.hiding){
            $("body").append(this.template({
                boxId       : this.options.boxId,
                sizeClass   : this.options.sizeClass,
                tallModal   : this.options.tallModal,
                showHeader  : this.options.showHeader,
                title       : this.options.title,
                content     : this.options.content,
                buttons     : this.buttons_html,
                backdrop    : this.options.backdrop,
            }));
        }   
    },
    reset:function(){
        this.options = {};
        this.buttons_html = "";
    },
    show:function(){
        if(!this.hiding && this.shown) this.hide(this.show);
        if(!this.hiding){
            var that = this;
            $("#"+this.options.boxId).removeClass("hideMe");
            $("#"+this.options.boxId).modal({backdrop:that.options.backdrop});
            $("#"+that.options.boxId).off("hide.bs.modal").on("hide.bs.modal", function(){
                that.hiding = true;
                if(that.options.hideCallback){
                    that.options.hideCallback();
                    that.options.hideCallback = false;
                }
            });
            this.setHidingEvent();
            this.shown = true;
        }
        $("#"+that.options.boxId).off("shown.bs.modal").on('shown.bs.modal', function () {
            $("#"+that.options.boxId+" .modal-footer button:last-child").focus();
            that.callbackOnShown();
        });
    },
    hide:function(){
        if(!this.shown) return;
        if(this.options.hideCallback){
            this.options.hideCallback();
            this.options.hideCallback = false;
        }
        $("#"+this.options.boxId).modal("hide");
    },
    temporarilyHide:function(){
        let state = (arguments.length > 0)?arguments[0]: true;
        $("#"+this.options.boxId)[state?"addClass":"removeClass"]("hideMe");
    },
    setHidingEvent:function(){
        var that = this;
        $("#"+that.options.boxId).off('hidden.bs.modal').on('hidden.bs.modal', function (e) {
            that.hiding = false;
            that.shown = false;
            $(".modal").each(function(){
                if($(this).css("display") == "block") $("body").addClass("modal-open"); 
            });
            if(that.options.onHiddenCallback){
                that.options.onHiddenCallback();
            }
            that.remove();
        });
    },
    remove:function(){
        if($("#"+this.options.boxId).length !== 0){
            $("#"+this.options.boxId + "+.modal-backdrop").remove();
            $("#"+this.options.boxId).remove();
        }
    },
    /**
     * Display a simple dialog box with a single button to close it.
     * @param options object containing option for the dialog: message, title, buttons object etc.
     * @return void
     */
    alert:function(options){
        if(this.hiding){
            setTimeout(function(){this.alert(options)},500);
            return;
        }
        this.reset();
        $.extend(this.options,this.default_options,
            {
                buttons:{
                    ok:{
                        label:lang.common.lbl_OK,
                        events:{
                        },
                        attributes:{
                            "data-dismiss":"modal",
                        },
                    },
                }
            }, options
        );
        this.options.content = this.message_template({message:this.options.message});
        
        this.makeButtonsDismiss();
        this.setButtonsHtml();
        this.addBox();
        var that = this;
        this.show();
        this.setButtonsEvents();
    },
    
    confirm:function(options){
        if(this.hiding){
            var that = this
            setTimeout(function(){that.confirm(options)}, 500);
            return;
        }
        this.reset();
        $.extend(this.options,this.default_options,
            {
                buttons:{
                    yes:{
                        label:lang.common.lbl_Yes,
                        events:{
                            click:function(){}
                        },
                    },
                    no:{
                        label:lang.common.lbl_No,
                        events:{
                            click:function(){}
                        },
                    },
                },
            }, options
        );
        this.options.content = this.message_template({message:this.options.message});
        
        //set event attached to click on yes
        if(this.options.actionOnYes !== undefined)
            this.options.buttons.yes.events.click = this.options.actionOnYes;
        //if defined, set event attached to click on No (otherwise leaves default action: dismiss modal)
        if(this.options.actionOnNo !== undefined){
            this.options.actionOnCancel = this.options.actionOnNo;
            this.options.buttons.no.events.click = this.options.actionOnNo;
        }
        this.makeButtonsDismiss();
        this.setButtonsHtml();
        this.addBox();
        var that = this;
        this.show();
        this.setButtonsEvents();
        this.setButtonCancel();
    },
    prompt:function(options){
        if(this.hiding){
            setTimeout(function(){this.prompt(options)}, 500);
            return;
        }
        this.reset();
        $.extend(this.options,this.default_options, 
            {
                buttons:{
                    ok:{
                        label:lang.common.lbl_OK,
                        events:{
                            click:function(){}
                        },
                    },
                    cancel:{
                        label:lang.common.lbl_Cancel,
                    },
                },
            },options
        );
        this.options.content = this.prompt_template({
            message:this.options.message,
            placeHolder:this.options.placeHolder,
            initInput:this.options.initInput?this.options.initInput:"",
            inputLength:this.options.inputLength?this.options.inputLength:0,
        });
        //set event attached to click on yes
        if(this.options.actionOnOk !== undefined)
            this.options.buttons.ok.events.click = this.options.actionOnOk;
        //if defined, set event attached to click on No (otherwise leaves default action: dismiss modal)
        if(this.options.actionOnCancel !== undefined)
            this.options.buttons.cancel.events.click = this.options.actionOnCancel;
        this.makeButtonsDismiss();
        this.setButtonsHtml();
        this.addBox();
        this.show();
        var that = this;
        $("#"+that.options.boxId).off("shown.bs.modal").on('shown.bs.modal', function () {
            $("#"+that.options.boxId+" input").focus();
            $("#"+that.options.boxId+" input").caret({start:0,end:$("#"+that.options.boxId+" input").val().length});
            $("#"+that.options.boxId+" input").on("keypress", function(event){
                var keycode = (event.keyCode ? event.keyCode : event.which);
                if(keycode == '13'){
                    $("#"+that.options.boxId+"-btn-ok").trigger("click");
                }
            });
        });
        this.setButtonsEvents();
    },
    customModal:function(options){
        if(this.hiding){
            setTimeout(function(){this.customModal(options)},500);
            return;
        }
        this.reset();
        $.extend(this.options,this.default_options, options);
        if(this.options.message !== undefined && this.options.message) this.options.content = this.message_template({message:this.options.message});
        
        this.makeButtonsDismiss();
        this.setButtonsHtml();
        this.addBox();
        var that = this;
        $("#"+that.options.boxId).off("show.bs.modal").on('show.bs.modal', function () {
            that.callbackBeforeShow();
        });
        this.show();
        this.setButtonsEvents();
    },
    
    makeButtonsDismiss:function(){
        $.each(this.options.buttons, function(name, button){
            if(button.preventDismiss == undefined || !button.preventDismiss) button.attributes = (button.attributes == undefined)?{"data-dismiss":"modal"}:$.extend(button.attributes,{"data-dismiss":"modal"});
        });
    },
    setButtonsHtml:function(){
        btn_html = "";
        var that = this;
        $.each(this.options.buttons, function(name, button){
            attr_str = "";
            $.each(button.attributes, function(key, value){
                attr_str += " "+key+'="'+value+'"';
            });
            btn_html += that.button_template({
                label:button.label,
                attributes:attr_str,
                buttonId:that.options.boxId+"-btn-"+name,
                classes:button.classes?button.classes:"btn-default",
            });
        });
        this.buttons_html = btn_html;
    },
    setButtonCancel:function(){
        if(this.options.actionOnCancel !== undefined){
            $("#"+this.options.boxId+" .modal-header button.close").on("click", this.options.actionOnCancel);
        }
    },
    setButtonsEvents:function(){
        var that = this;
        $.each(that.options.buttons, function(name, button){
            $.each(button.events, function(event, callback){
                $("#"+that.options.boxId).on(event, "#"+that.options.boxId+"-btn-"+name, callback);
            });
        });
    },
    callbackOnShown:function(){
        if(this.options.shownCallback)this.options.shownCallback();
    },
    callbackBeforeShow : function(){
        if(this.options.beforeShowCallback)this.options.beforeShowCallback();
    }
}})(); 

//dialog.setup()


/*********************
Including file: jquery.caret.js
*********************/
/*
 *
 * Copyright (c) 2010 C. F., Wong (<a href="http://cloudgen.w0ng.hk">Cloudgen Examplet Store</a>)
 * Licensed under the MIT License:
 * http://www.opensource.org/licenses/mit-license.php
 *
 */
﻿(function($,len,createRange,duplicate){
    $.fn.caret=function(options,opt2){
        var start,end,t=this[0],browser=$.browser.msie;
        if(typeof options==="object" && typeof options.start==="number" && typeof options.end==="number") {
            start=options.start;
            end=options.end;
        } else if(typeof options==="number" && typeof opt2==="number"){
            start=options;
            end=opt2;
        } else if(typeof options==="string"){
            if((start=t.value.indexOf(options))>-1) end=start+options[len];
            else start=null;
        } else if(Object.prototype.toString.call(options)==="[object RegExp]"){
            var re=options.exec(t.value);
            if(re != null) {
                start=re.index;
                end=start+re[0][len];
            }
        }
        if(typeof start!="undefined"){
            if(browser){
                var selRange = this[0].createTextRange();
                selRange.collapse(true);
                selRange.moveStart('character', start);
                selRange.moveEnd('character', end-start);
                selRange.select();
            } else {
                this[0].selectionStart=start;
                this[0].selectionEnd=end;
            }
            this[0].focus();
            return this
        } else {
           if(browser){
                var selection=document.selection;
                if (this[0].tagName.toLowerCase() != "textarea") {
                    var val = this.val(),
                    range = selection[createRange]()[duplicate]();
                    range.moveEnd("character", val[len]);
                    var s = (range.text == "" ? val[len]:val.lastIndexOf(range.text));
                    range = selection[createRange]()[duplicate]();
                    range.moveStart("character", -val[len]);
                    var e = range.text[len];
                } else {
                    var range = selection[createRange](),
                    stored_range = range[duplicate]();
                    stored_range.moveToElementText(this[0]);
                    stored_range.setEndPoint('EndToEnd', range);
                    var s = stored_range.text[len] - range.text[len],
                    e = s + range.text[len]
                }
            } else {
                var s=t.selectionStart,
                    e=t.selectionEnd;
            }
            var te=t.value.substring(s,e);
            return {start:s,end:e,text:te,replace:function(st){
                return t.value.substring(0,s)+st+t.value.substring(e,t.value[len])
            }}
        }
    }
})(jQuery,"length","createRange","duplicate");

/*********************
Including file: messages.js
*********************/
/**
 * messages.js - js functions relating to messaging system
 *
 * @package    messages
 * @author     Tik Nipaporn
 * @copyright  (c) 2012 Lightrocket
 */

var messages = {

    _queue:[], // message queue to display
    _queueCallback:false, // store callback function
    _currentMsgID:false, // current message id

    
    /**
     * extract message and store in a queue
     *
     * @param  mixed UL element or UL id
     * @return void
     */
    processMessageList:function(ul){
        var li = (typeof(ul)=='string')?$('#'+ul+' li'):ul.children();
        messages._queue = []; messages._queueCallback = false;
        li.each(function(){ messages._queue.push({id:$(this).attr('mval'),type:$(this).attr('mtype'),content:$(this).html()}); });
        messages._processQueue(function(msg){ messages._dismissOnScreen(msg.id); messages._processQueue(); });
    },
    
    /**
     * manage and display messages in the queue
     */
    _processQueue:function(){
        if (!messages._queue.length) { messages.hide(); return; }
        if (arguments.length) { messages._queueCallback = arguments[0]; }
        var msg = messages._queue.shift();
        messages.show(msg, messages._queueCallback);
    },
    
    /**
     * display given message
     *
     * @param  object Message
     * @return void
     */
    show:function(msg){
        var callback = (arguments.length==2) ? arguments[1] : false;
        $('#system_message span').attr('class','').addClass('type'+msg.type);
        $('#system_message div').html(msg.content);
        (callback) ? $('#dismiss').unbind().click(function(){callback(msg);}) : $('#dismiss').unbind().click(messages.hide);
        $('#system_message').jqmShow();
        // store current id if we have one, also make sure msg is dissmissed if links clicked within message html
        if (typeof(msg.id)!='undefined') {
            messages._currentMsgID = msg.id;
            ////// ** Removed as we are now marking messages as dismissed on the server as soon as they are shown
            ////// $('#system_message div a[href]').unbind().click(function(e) {
            //////     e.preventDefault();
            //////     var nextURL = $(this).attr('href');
            //////     messages._dismissCurrent(function() {
            //////         messages.hide();
            //////         location.href = nextURL;
            //////     });
            ////// });
            messages._dismissOnServer(msg.id);
        }
    },
    
    /**
     * hide any message being displayed
     */
    hide:function(){
        $('#system_message').jqmHide();
        messages._currentMsgID = false;
    },
    
    
    /**
     * dismiss the message on the server
     */
    _dismissOnServer:function(msg_id){
        ////// var callback = (arguments.length>1) ? arguments[1] : false;
        var callback = false;
        $.post(APP.baseURL+'messages/dismiss', {msg_id:msg_id}, callback);
    },
    
    /**
     * dismiss the message on the screen
     */
    _dismissOnScreen:function(msg_id){
        var callback = (arguments.length>1) ? arguments[1] : false;
        ////// $.post(APP.baseURL+'messages/dismiss', {msg_id:msg_id}, callback);
        if (callback) callback();
    },
    
    /**
     * dismiss current message (if we have an id stored)
     */
    _dismissCurrent:function(){
        var callback = arguments.length ? arguments[0] : false;
        if (messages._currentMsgID) messages._dismiss(messages._currentMsgID, callback);
    },
    
    /**
     * setup for system messages
     *
     * @return  void
     */
    _setup:function(){
        $('#system_message').jqm({modal:true, trigger:false});
        if ($('#system_message ul#system_msg li').length) { messages.processMessageList($('#system_msg')); }
    }
};

$(messages._setup);

/*********************
Including file: initial.min.js
*********************/
!function(a){a.fn.initial=function(b){var c=["#1abc9c","#16a085","#f1c40f","#f39c12","#2ecc71","#27ae60","#e67e22","#d35400","#3498db","#2980b9","#e74c3c","#c0392b","#9b59b6","#8e44ad","#bdc3c7","#34495e","#2c3e50","#95a5a6","#7f8c8d","#ec87bf","#d870ad","#f69785","#9ba37e","#b49255","#b49255","#a94136"];return this.each(function(){var d=a(this),e=a.extend({name:"Name",seed:0,charCount:1,textColor:"#ffffff",height:100,width:100,fontSize:60,fontWeight:400,fontFamily:"HelveticaNeue-Light,Helvetica Neue Light,Helvetica Neue,Helvetica, Arial,Lucida Grande, sans-serif",radius:0},b);e=a.extend(e,d.data());var f=e.name.substr(0,e.charCount).toUpperCase(),g=a('<text text-anchor="middle"></text>').attr({y:"50%",x:"50%",dy:"0.35em","pointer-events":"auto",fill:e.textColor,"font-family":e.fontFamily}).html(f).css({"font-weight":e.fontWeight,"font-size":e.fontSize+"px"}),h=Math.floor((f.charCodeAt(0)+e.seed)%c.length),i=a("<svg></svg>").attr({xmlns:"http://www.w3.org/2000/svg","pointer-events":"none",width:e.width,height:e.height}).css({"background-color":c[h],width:e.width+"px",height:e.height+"px","border-radius":e.radius+"px","-moz-border-radius":e.radius+"px"});i.append(g);var j=window.btoa(unescape(encodeURIComponent(a("<div>").append(i.clone()).html())));d.attr("src","data:image/svg+xml;base64,"+j)})}}(jQuery);

/*********************
Including file: hashchange.js
*********************/
/*
 * jQuery hashchange event, v1.4, 2013-11-29
 * https://github.com/georgekosmidis/jquery-hashchange
 */
(function(e,t,n){"$:nomunge";function f(e){e=e||location.href;return"#"+e.replace(/^[^#]*#?(.*)$/,"$1")}var r="hashchange",i=document,s,o=e.event.special,u=i.documentMode,a="on"+r in t&&(u===n||u>7);e.fn[r]=function(e){return e?this.bind(r,e):this.trigger(r)};e.fn[r].delay=50;o[r]=e.extend(o[r],{setup:function(){if(a){return false}e(s.start)},teardown:function(){if(a){return false}e(s.stop)}});s=function(){function p(){var n=f(),i=h(u);if(n!==u){c(u=n,i);e(t).trigger(r)}else if(i!==u){location.href=location.href.replace(/#.*/,"")+i}o=setTimeout(p,e.fn[r].delay)}var s={},o,u=f(),l=function(e){return e},c=l,h=l;s.start=function(){o||p()};s.stop=function(){o&&clearTimeout(o);o=n};var d=function(){var e,t=3,n=document.createElement("div"),r=n.getElementsByTagName("i");while(n.innerHTML="<!--[if gt IE "+ ++t+"]><i></i><![endif]-->",r[0]);return t>4?t:e}();d&&!a&&function(){var t,n;s.start=function(){if(!t){n=e.fn[r].src;n=n&&n+f();t=e('<iframe tabindex="-1" title="empty"/>').hide().one("load",function(){n||c(f());p()}).attr("src",n||"javascript:0").insertAfter("body")[0].contentWindow;i.onpropertychange=function(){try{if(event.propertyName==="title"){t.document.title=i.title}}catch(e){}}}};s.stop=l;h=function(){return f(t.location.href)};c=function(n,s){var o=t.document,u=e.fn[r].domain;if(n!==s){o.title=i.title;o.open();u&&o.write('<script>document.domain="'+u+'"</script>');o.close();t.location.hash=n}}}();return s}()})(jQuery,this);


/*********************
Including file: popupform.js
*********************/
/**
 * popupform.js - generic Backbone view for creating popup form functionality
 *
 * @package    core
 * @author     Jon Randy
 * @copyright  (c) 2013 OnAsia
 */

var _View = Backbone.View.extend({
    // proxifier for functions
    _p:function(fn, context) {
        var args = Array.prototype.slice.call(arguments, 2);
      var prxy = function () {
            return fn.apply(context, args.concat(Array.prototype.slice.call(arguments)));
        };
        return prxy;
   }
});



var PopupFormView = Backbone.View.extend({

    // width and height (px) of the popup
    width        :            250,
    height    :            150,

    // Close when ESC pressed?
    closeOnESC    :        true,

    // details used to retrieve the form
    formURL        :            '',
    formParams    :            {},
    _gotForm        :            false,

    // id for the div that will be created to contain the form
    containerDivID        :        'popup',
    _visible                :        false,

    // show the form
    show:function() {
        if (!this._gotForm) {
            this._loadForm();
            this._setupForm();
        }
        this._setFormCSS();
        this._dimBackground();
        if (this.closeOnESC) this._setESCHandler();
        this.$el.show();
        this._visible = true;
    },

    // hide the form
    hide:function() {
        if (this.closeOnESC) this._setESCHandler(false);
        this.$el.hide();
        $this._dimBackground(false);
        $this._visible = false;
    }


});


/*********************
Including file: nice_buttons.js
*********************/
/**
 * nice_buttons.js - js functions relating to customize html element
 *
 * @author     Tik Nipaporn
 * @copyright  (c) 2014 OnAsia
 */
 
var nice_buttons = {

    toggleCheckbox:false,

    /**
     * setup 
     *
     * @return  void
     */
    _setup:function() {
        // $(document).delegate('.custom-checkbox>input[type="checkbox"]', 'click', function(){
        //     var input = $(this), wrapper = input.parent();
        //     (input.attr('checked')) ? wrapper.addClass('checked') : wrapper.removeClass('checked');
        //     if (nice_buttons.toggleCheckbox!==false) nice_buttons.toggleCheckbox($(this));
        // });
        // $(document).delegate('.custom-checkbox.radio>input[type="radio"]', 'click', function(){
        //     var radioBtns = $('input[name="'+$(this).attr('name')+'"]');
        //     $.each(radioBtns, function(){
        //         (this.checked) ? $(this).parent('.radio').addClass('checked') : $(this).parent('.radio').removeClass('checked');
        //     });
        // });
        // $(document).delegate('.custom-switch.common', 'click', function(){
        //     if ($(this).hasClass('disabled')) return;
        //     $('input[name="'+this.id+'"][type="hidden"]').val($(this).hasClass('on')?0:1).trigger('change');
        //     nice_buttons.setCommonSwitch($(this));
        // });
    },
    
    setCommonSwitch:function() {
        var input;
        var fields = (arguments.length) ? arguments[0] : $('.custom-switch.common');
        $.each(fields, function(){
            input = $(this).find('input[name="'+this.id+'"][type="hidden"]');
            if (input.length) {
                input = input.val();
                $('.custom-switch.common span[id^="'+this.id+'_"]').hide();
                if (input=='1') {
                    $(this).removeClass('off').addClass('on');
                    $('#'+this.id+'_1').show();
                } else {
                    $(this).removeClass('on').addClass('off');
                    $('#'+this.id+'_0').show();
                }
            }
        });
    }
    
};

// set up on dom ready
$(nice_buttons._setup);

/*********************
Including file: mobile_menu.js
*********************/
$(document).ready(function(){
    $("ul#headerLinks>li>a.hasSubMenu").click(function(e){
        e.preventDefault();
        $(this).parent('li').children('ul').toggleClass('showSubMenu');
    });
    $("#header").on("click", ".hamburgerButton", toggleMobileMenu);
    $("#header").on("click", ".mobile-menu-overlay", toggleMobileMenu);
});
toggleMobileMenu = function(){
    $(this).toggleClass('active');
    $("#header").toggleClass('openHeader');
    $("body").toggleClass('mobile-menu-opened');
};

/*********************
Including file: highlightCurrentMenu.js
*********************/
/**
 * highlightCurrentMenu.js - js functions relating to Navigation Menu - Highlight the active menu
 *
 * @package    skin (_base)
 * @author     Laurent hunaut
 * @copyright  (c) 2016 Lightrocket
 */
var highlightCurrentMenu = {
    _setup:function() {
        if ($('body').attr("class") !== undefined) {
            var classes = $('body').attr("class").split(" ");
            $.each(classes, function(){
                bodyClass = this.toString();
                if($('#headerLinks li a[data-page-name="'+bodyClass+'"]').length > 0) $('#headerLinks li a[data-page-name="'+bodyClass+'"]').addClass('selected_menu');
            });
        }
    },

};


/*********************
Including file: who.js
*********************/

(function() {
    who = {
        isFlickityInitialized   : {},
        windowWidth             : 0,
        _setup:function() {
            if(window.makeLinkToGallery !== undefined && makeLinkToGallery !== 0){
                $('#mainCarousel').find('.carousel-inner').addClass("linkable");
                $('#mainCarousel').find('.carousel-inner').click(function(){
                    window.location.href = makeLinkToGallery;
                });
            }
            $('#mainCarousel .left.carousel-control span.fa').removeClass('fa-chevron-circle-left').addClass('fa-chevron-left');
            $('#mainCarousel .right.carousel-control span.fa').removeClass('fa-chevron-circle-right').addClass('fa-chevron-right');
            $(window).load(function() {
                who.windowWidth = $(window).width();
            });
            who.callFlickity('.largeCarousel');
            $(window).resize(function() {
                if(who.windowWidth != $(window).width()) {
                    who.callFlickity('.largeCarousel');
                    who.windowWidth = $(window).width();
                    delete who.windowWidth;
                }
            });      
        },

        callFlickity:function(carouselName) {
            var carouselSelector = carouselName + " .flickityCell";
            if ($(carouselSelector).length != 0 ){
                if ( ($(carouselSelector).size() * $(carouselSelector).width()) < $(carouselName).width() ) {
                    if(Object.keys(who.isFlickityInitialized).length && who.isFlickityInitialized[carouselName]) {
                        $(carouselName).flickity('destroy');
                        who.isFlickityInitialized[carouselName] = false;
                    }
                    if ($(window).width() < 768) {
                        $(carouselSelector).css('float', 'none');
                        $(carouselSelector).css('margin', 'auto');
                    } else {
                        $(carouselSelector).css('float', 'left');
                    }
                    return;
                }
                var alignStyle = ( $(window).width() <= 768 )?'center':'left';
                $(carouselName).flickity({
                    wrapAround      : true,
                    //cellAlign       : alignStyle,
                    cellAlign       : 'center',
                    percentPosition : true
                });
                who.isFlickityInitialized[carouselName] = true;
            }
        },
    };
})();

$(who._setup);