Source: winjscontrib.core.js

/* 
 * WinJS Contrib v2.1.0.6
 * licensed under MIT license (see http://opensource.org/licenses/MIT)
 * sources available at https://github.com/gleborgne/winjscontrib
 */

var WinJSContrib;
(function (WinJSContrib) {
    var Logs;
    (function (Logs) {
        var Appenders;
        (function (Appenders) {
            /**
             * @namespace
             */
            WinJSContrib.Logs.Appenders = WinJSContrib.Logs.Appenders;
            var ConsoleAppender = (function () {
                /**
                 * Appender writing to console
                 * @class WinJSContrib.Logs.Appenders.ConsoleAppender
                 */
                function ConsoleAppender(config) {
                    this.config = config || { level: Logs.Levels.inherit };
                }
                /**
                 * clone appender
                 * @function WinJSContrib.Logs.Appenders.ConsoleAppender.prototype.clone
                 */
                ConsoleAppender.prototype.clone = function () {
                    return new WinJSContrib.Logs.Appenders.ConsoleAppender(this.config);
                };
                /**
                 * log item
                 * @function WinJSContrib.Logs.Appenders.ConsoleAppender.prototype.log
                 * @param {string} message log message
                 * @param {WinJSContrib.Logs.Levels} log level
                 */
                ConsoleAppender.prototype.log = function (logger, message, level) {
                    var args = [];
                    for (var _i = 3; _i < arguments.length; _i++) {
                        args[_i - 3] = arguments[_i];
                    }
                    if (this.config.level == Logs.Levels.inherit || level >= this.config.level) {
                        var msg = [this.format(logger, message, level)];
                        if (args.length) {
                            args.forEach(function (a) {
                                msg.push(a);
                            });
                        }
                        switch (level) {
                            case Logs.Levels.verbose:
                                return console.log.apply(console, msg);
                            case Logs.Levels.debug:
                                return console.log.apply(console, msg);
                            case Logs.Levels.info:
                                return console.info.apply(console, msg);
                            case Logs.Levels.warn:
                                return console.warn.apply(console, msg);
                            case Logs.Levels.error:
                                return console.error.apply(console, msg);
                        }
                    }
                };
                /**
                 * create log group
                 * @function WinJSContrib.Logs.Appenders.ConsoleAppender.prototype.group
                 */
                ConsoleAppender.prototype.group = function (title) {
                    console.group(title);
                };
                /**
                 * create collapsed log group
                 * @function WinJSContrib.Logs.Appenders.ConsoleAppender.prototype.groupCollapsed
                 */
                ConsoleAppender.prototype.groupCollapsed = function (title) {
                    console.groupCollapsed(title);
                };
                /**
                 * close log group
                 * @function WinJSContrib.Logs.Appenders.ConsoleAppender.prototype.groupEnd
                 */
                ConsoleAppender.prototype.groupEnd = function () {
                    console.groupEnd();
                };
                ConsoleAppender.prototype.format = function (logger, message, level) {
                    var finalMessage = "";
                    if (logger.Config && logger.Config.prefix)
                        finalMessage += logger.Config.prefix + " # ";
                    if (this.config.showLoggerNameInMessage)
                        finalMessage += logger.name + " # ";
                    if (this.config.showLevelInMessage)
                        finalMessage += Logs.logginLevelToString(level) + " # ";
                    finalMessage += message;
                    return finalMessage;
                };
                return ConsoleAppender;
            })();
            Appenders.ConsoleAppender = ConsoleAppender;
            var BufferAppender = (function () {
                /**
                 * Appender writing to console
                 * @class WinJSContrib.Logs.Appenders.BufferAppender
                 */
                function BufferAppender(config) {
                    this.config = config || { level: Logs.Levels.inherit };
                    this.buffer = [];
                }
                /**
                 * clone appender
                 * @function WinJSContrib.Logs.Appenders.BufferAppender.prototype.clone
                 */
                BufferAppender.prototype.clone = function () {
                    return new WinJSContrib.Logs.Appenders.BufferAppender(this.config);
                };
                /**
                 * log item
                 * @function WinJSContrib.Logs.Appenders.BufferAppender.prototype.log
                 * @param {string} message log message
                 * @param {WinJSContrib.Logs.Levels} log level
                 */
                BufferAppender.prototype.log = function (logger, message, level) {
                    var args = [];
                    for (var _i = 3; _i < arguments.length; _i++) {
                        args[_i - 3] = arguments[_i];
                    }
                    if (this.config.level == Logs.Levels.inherit || level >= this.config.level) {
                        var msg = [new Date().getTime() + "", Logs.Levels[level].toUpperCase(), this.format(logger, message, level)];
                        if (args.length) {
                            args.forEach(function (a) {
                                if (typeof a == "object")
                                    a = JSON.stringify(a);
                                msg.push(a);
                            });
                        }
                        this.buffer.push(msg.join(" "));
                    }
                };
                /**
                 * create log group
                 * @function WinJSContrib.Logs.Appenders.BufferAppender.prototype.group
                 */
                BufferAppender.prototype.group = function (title) {
                };
                /**
                 * create collapsed log group
                 * @function WinJSContrib.Logs.Appenders.BufferAppender.prototype.groupCollapsed
                 */
                BufferAppender.prototype.groupCollapsed = function (title) {
                };
                /**
                 * close log group
                 * @function WinJSContrib.Logs.Appenders.BufferAppender.prototype.groupEnd
                 */
                BufferAppender.prototype.groupEnd = function () {
                };
                BufferAppender.prototype.format = function (logger, message, level) {
                    var finalMessage = "";
                    if (logger.Config && logger.Config.prefix)
                        finalMessage += logger.Config.prefix + " # ";
                    if (this.config.showLoggerNameInMessage)
                        finalMessage += logger.name + " # ";
                    if (this.config.showLevelInMessage)
                        finalMessage += Logs.logginLevelToString(level) + " # ";
                    finalMessage += message;
                    return finalMessage;
                };
                return BufferAppender;
            })();
            Appenders.BufferAppender = BufferAppender;
        })(Appenders = Logs.Appenders || (Logs.Appenders = {}));
    })(Logs = WinJSContrib.Logs || (WinJSContrib.Logs = {}));
})(WinJSContrib || (WinJSContrib = {}));
var WinJSContrib;
(function (WinJSContrib) {
    var Logs;
    (function (Logs) {
        /**
         * @namespace WinJSContrib.Logs
         */
        WinJSContrib.Logs = WinJSContrib.Logs;
        /**
        * enumeration for log levels
        * @enum {number} Levels
        * @memberof WinJSContrib.Logs
        */
        (function (Levels) {
            /**
             * disabled
             */
            Levels[Levels["inherit"] = 512] = "inherit";
            /**
             * disabled
             */
            Levels[Levels["off"] = 256] = "off";
            /**
             * log error
             */
            Levels[Levels["error"] = 32] = "error";
            /**
             * log warn and error
             */
            Levels[Levels["warn"] = 16] = "warn";
            /**
             * log info, warn, error
             */
            Levels[Levels["info"] = 8] = "info";
            /**
             * log debug, info, warn, error
             */
            Levels[Levels["debug"] = 4] = "debug";
            /**
            * verbose mode
            */
            Levels[Levels["verbose"] = 2] = "verbose";
        })(Logs.Levels || (Logs.Levels = {}));
        var Levels = Logs.Levels;
        ;
        // Default config
        Logs.defaultConfig = {
            "level": Levels.off,
            "showLevelInMessage": false,
            "showLoggerNameInMessage": false,
            "appenders": ["DefaultConsole"]
        };
        var Loggers = {};
        Logs.RuntimeAppenders = {
            "DefaultConsole": new Logs.Appenders.ConsoleAppender()
        };
        Logs.DefaultAppenders = [];
        /**
         * get a logger, logger is created if it does not exists
         * @function WinJSContrib.Logs.getLogger
         * @param {string} name name for the logger
         * @param {Object} config logger configuration
         * @param {...Object} appenders appenders to add to the logger
         * @returns {WinJSContrib.Logs.Logger}
         */
        function getLogger(name, config) {
            var existing = Loggers[name];
            if (!existing) {
                existing = new Logger(config || Logs.defaultConfig);
                existing.name = name;
                Loggers[name] = existing;
            }
            if (config || arguments.length > 2)
                configure.apply(null, arguments);
            return existing;
        }
        Logs.getLogger = getLogger;
        function configure(name, config) {
            var existing = Loggers[name];
            if (existing) {
                if (config)
                    existing.Config = config;
                if (arguments.length > 2) {
                    for (var i = 2; i < arguments.length; i++) {
                        existing.addAppender(arguments[i]);
                    }
                }
            }
        }
        Logs.configure = configure;
        function loggingLevelStringToEnum(level) {
            switch (level.toLowerCase()) {
                default:
                case "log":
                case "debug":
                    return Levels.debug;
                case "info":
                    return Levels.info;
                case "warn":
                    return Levels.warn;
                case "error":
                    return Levels.error;
            }
        }
        Logs.loggingLevelStringToEnum = loggingLevelStringToEnum;
        function logginLevelToString(level) {
            switch (level) {
                default:
                case Levels.verbose:
                    return "VERBOSE";
                case Levels.debug:
                    return "DEBUG";
                case Levels.info:
                    return "INFO";
                case Levels.warn:
                    return "WARN";
                case Levels.error:
                    return "ERROR";
            }
        }
        Logs.logginLevelToString = logginLevelToString;
        var Logger = (function () {
            /**
             * @class WinJSContrib.Logs.Logger
             * @param {Object} config logger configuration
             */
            function Logger(config) {
                this.appenders = [];
                /**
                 * Logger configuration
                 * @field Config
                 * @type {Object}
                 */
                this.Config = config || Logs.defaultConfig;
            }
            Object.defineProperty(Logger.prototype, "Config", {
                get: function () {
                    return this._config;
                },
                set: function (newValue) {
                    var _this = this;
                    this._config = newValue || { level: Logs.Levels.off, showLevelInMessage: false, showLoggerNameInMessage: false };
                    if (typeof newValue.level === "number")
                        this.Level = newValue.level;
                    if (typeof newValue.showLevelInMessage === "boolean")
                        this.Config.showLevelInMessage = newValue.showLevelInMessage;
                    if (typeof newValue.showLoggerNameInMessage === "boolean")
                        this.Config.showLoggerNameInMessage = newValue.showLoggerNameInMessage;
                    if (this._config.appenders) {
                        this._config.appenders.forEach(function (a) {
                            _this.addAppender(a);
                        });
                    }
                    else {
                        this._config.appenders = [];
                    }
                },
                enumerable: true,
                configurable: true
            });
            Object.defineProperty(Logger.prototype, "Level", {
                get: function () {
                    return this._level;
                },
                set: function (val) {
                    this._level = val;
                    if (this._level <= Logs.Levels.verbose) {
                        this.verbose = Logger.verbose;
                    }
                    else {
                        this.verbose = Logger.noop;
                    }
                    if (this._level <= Logs.Levels.debug) {
                        this.debug = Logger.debug;
                    }
                    else {
                        this.debug = Logger.noop;
                    }
                    if (this._level <= Logs.Levels.info) {
                        this.info = Logger.info;
                    }
                    else {
                        this.info = Logger.noop;
                    }
                    if (this._level <= Logs.Levels.warn) {
                        this.warn = Logger.warn;
                    }
                    else {
                        this.warn = Logger.noop;
                    }
                    if (this._level <= Logs.Levels.error) {
                        this.error = Logger.error;
                    }
                    else {
                        this.error = Logger.noop;
                    }
                },
                enumerable: true,
                configurable: true
            });
            /**
             * add appender to logger
             * @function WinJSContrib.Logs.Logger.prototype.addAppender
             * @param {Object} appender
             */
            Logger.prototype.addAppender = function (appender) {
                if (typeof appender == "string") {
                    appender = WinJSContrib.Logs.RuntimeAppenders[appender];
                }
                var currentappender = appender;
                if (!currentappender)
                    return;
                var exists = this.appenders.indexOf(currentappender) >= 0;
                if (exists)
                    return;
                //if (!currentappender.format)
                //    currentappender.format = this.format.bind(this);
                this.appenders.push(currentappender);
            };
            /**
             * Add log entry
             * @function WinJSContrib.Logs.Logger.prototype.log
             * @param {string} message log message
             * @param {WinJSContrib.Logs.Levels} log level
             */
            Logger.prototype.log = function (message, level) {
                var args = [];
                for (var _i = 2; _i < arguments.length; _i++) {
                    args[_i - 2] = arguments[_i];
                }
                // If general logging level is set to 'none', returns
                if (this._config.level === WinJSContrib.Logs.Levels.off || level < this._config.level)
                    return;
                if (!this.appenders || !this.appenders.length)
                    return;
                var fnargs = [this, message, level];
                if (args.length) {
                    for (var i = 0; i < args.length; i++) {
                        fnargs.push(args[i]);
                    }
                }
                Logs.DefaultAppenders.forEach(function (a) {
                    a.log.apply(a, fnargs);
                });
                this.appenders.forEach(function (a) {
                    a.log.apply(a, fnargs);
                });
            };
            ///**
            // * format log entry
            // * @function WinJSContrib.Logs.Logger.prototype.format
            // * @param {string} message log message
            // * @param {string} group group/category for the entry
            // * @param {WinJSContrib.Logs.Levels} log level
            // */
            //public format(message: string, level: Logs.Levels) {
            //    var finalMessage = "";
            //    if (!this.Config.hideLevelInMessage) finalMessage += logginLevelToString(level) + " - ";
            //    finalMessage += message;
            //    return finalMessage;
            //}
            /**
             * add debug log entry
             * @function WinJSContrib.Logs.Logger.prototype.debug
             * @param {string} message log message
             */
            Logger.prototype.verbose = function (message) {
                var args = [];
                for (var _i = 1; _i < arguments.length; _i++) {
                    args[_i - 1] = arguments[_i];
                }
            };
            /**
             * add debug log entry
             * @function WinJSContrib.Logs.Logger.prototype.debug
             * @param {string} message log message
             */
            Logger.prototype.debug = function (message) {
                var args = [];
                for (var _i = 1; _i < arguments.length; _i++) {
                    args[_i - 1] = arguments[_i];
                }
            };
            /**
             * add info log entry
             * @function WinJSContrib.Logs.Logger.prototype.info
             * @param {string} message log message
             * @param {string} [group] log group name
             */
            Logger.prototype.info = function (message) {
                var args = [];
                for (var _i = 1; _i < arguments.length; _i++) {
                    args[_i - 1] = arguments[_i];
                }
            };
            /**
             * add warn log entry
             * @function WinJSContrib.Logs.Logger.prototype.warn
             * @param {string} message log message
             */
            Logger.prototype.warn = function (message) {
                var args = [];
                for (var _i = 1; _i < arguments.length; _i++) {
                    args[_i - 1] = arguments[_i];
                }
            };
            /**
             * add error log entry
             * @function WinJSContrib.Logs.Logger.prototype.error
             * @param {string} message log message
             */
            Logger.prototype.error = function (message) {
                var args = [];
                for (var _i = 1; _i < arguments.length; _i++) {
                    args[_i - 1] = arguments[_i];
                }
            };
            /**
             * create a log group
             * @function WinJSContrib.Logs.Logger.prototype.group
             * @param {string} title group title
             */
            Logger.prototype.group = function (title) {
                this.appenders.forEach(function (a) {
                    if (a.group)
                        a.group(title);
                });
            };
            /**
             * create a collapsed log group
             * @function WinJSContrib.Logs.Logger.prototype.groupCollapsed
             * @param {string} title group title
             */
            Logger.prototype.groupCollapsed = function (title) {
                this.appenders.forEach(function (a) {
                    if (a.groupCollapsed)
                        a.groupCollapsed(title);
                });
            };
            /**
             * end current group
             * @function WinJSContrib.Logs.Logger.prototype.groupEnd
             */
            Logger.prototype.groupEnd = function () {
                this.appenders.forEach(function (a) {
                    if (a.groupEnd)
                        a.groupEnd();
                });
            };
            /**
             * Get a child logger
             * @function WinJSContrib.Logs.Logger.prototype.getChildLogger
             * @param {string} name child logger name
             * @param {WinJSContrib.Logs.Levels} level
             */
            Logger.prototype.getChildLogger = function (name, level) {
                var res = WinJSContrib.Logs.getLogger(this.name + '.' + name, JSON.parse(JSON.stringify(this.Config)));
                res.Config.appenders = [];
                this.appenders.forEach(function (a) {
                    if (a.clone)
                        res.addAppender(a.clone());
                });
                if (level)
                    res.Config.level = level;
                return res;
            };
            Logger.noop = function (message) {
                var args = [];
                for (var _i = 1; _i < arguments.length; _i++) {
                    args[_i - 1] = arguments[_i];
                }
            };
            Logger.getLogFn = function (level) {
                return function (message) {
                    var args = null;
                    if (arguments.length > 1) {
                        args = [];
                        for (var i = 1; i < arguments.length; i++) {
                            args.push(arguments[i]);
                        }
                        this.log(message, level, args);
                    }
                    else
                        this.log(message, level);
                };
            };
            Logger.verbose = Logger.getLogFn(Logs.Levels.verbose);
            Logger.debug = Logger.getLogFn(Logs.Levels.debug);
            Logger.info = Logger.getLogFn(Logs.Levels.info);
            Logger.warn = Logger.getLogFn(Logs.Levels.warn);
            Logger.error = Logger.getLogFn(Logs.Levels.error);
            return Logger;
        })();
        Logs.Logger = Logger;
    })(Logs = WinJSContrib.Logs || (WinJSContrib.Logs = {}));
})(WinJSContrib || (WinJSContrib = {}));

(function (_global) {
    //polyfill setimmediate
    if (!this.setImmediate) {
        this.setImmediate = function (callback) {
            var args = [];
            for (var _i = 1; _i < arguments.length; _i++) {
                args[_i - 1] = arguments[_i];
            }
            setTimeout(callback, 0);
            return 0;
        };
    }
    //Windows 10 doesn't have it anymore, polyfill for backward compat
    if (!this.toStaticHTML) {
        this.toStaticHTML = function (text) {
            return text;
        };
    }
    var msapp = _global.MSApp;
    if (msapp && !msapp.execUnsafeLocalFunction) {
        msapp.execUnsafeLocalFunction = function (c) { c(); };
    }
})(this);
if (!Object.map) {
    Object.map = function (obj, mapping) {
        var mapped = {};
        if (typeof obj !== 'object') {
            return mapped;
        }
        if (typeof mapping !== 'function') {
            // We could just return obj but that wouldn't be
            // consistent with the rest of the interface which always returns
            // a new object.
            mapping = function (key, val) {
                return [key, val];
            };
        }
        Object.keys(obj).forEach(function (key) {
            var transmuted = mapping.apply(obj, [key, obj[key]]);
            if (transmuted && transmuted.length) {
                mapped[transmuted[0] || key] = transmuted[1];
            }
        });
        return mapped;
    };
}
if (!String.prototype.format) {
    String.prototype.format = function () {
        var args = arguments;
        return this.replace(/{(\d+)}/g, function (match, number) {
            return typeof args[number] !== 'undefined' ? args[number] : match;
        });
    };
}
if (!String.prototype.padLeft) {
    String.prototype.padLeft = function padLeft(length, leadingChar) {
        if (leadingChar === undefined) {
            leadingChar = "0";
        }
        return this.length < length ? (leadingChar + this).padLeft(length, leadingChar) : this;
    };
}
var WinJSContrib;
(function (WinJSContrib) {
    var Promise;
    (function (Promise) {
        /**
         * apply callback for each item in the array in waterfall
         * @function WinJSContrib.Promise.waterfall
         * @param {Array} dataArray items to process with async tasks
         * @param {function} promiseCallback function applyed to each item (could return a promise for item callback completion)
         * @returns {WinJS.Promise}
         */
        function waterfall(dataArray, promiseCallback) {
            var resultPromise = WinJS.Promise.wrap();
            var results = [];
            if (!dataArray) {
                return WinJS.Promise.wrap([]);
            }
            var dataPromise = WinJS.Promise.as(dataArray);
            return dataPromise.then(function (items) {
                var queueP = function (p, item) {
                    var prComplete, prError;
                    var result = new WinJS.Promise(function (c, e) {
                        prComplete = c;
                        prError = e;
                    });
                    p.then(function (previous) {
                        WinJS.Promise.as(promiseCallback(item, previous)).then(function (r) {
                            results.push(r);
                            return r;
                        }).then(prComplete, prError);
                    });
                    return result;
                };
                for (var i = 0, l = items.length; i < l; i++) {
                    var item = items[i];
                    if (!item && items.getItem) {
                        item = items.getItem(i);
                    }
                    resultPromise = queueP(resultPromise, item);
                }
                return resultPromise.then(function (r) {
                    return results;
                });
            });
        }
        Promise.waterfall = waterfall;
        function promises(dataArray, promiseCallback) {
            if (!dataArray) {
                return WinJS.Promise.wrap([]);
            }
            var dataPromise = WinJS.Promise.as(dataArray);
            return dataPromise.then(function (items) {
                var promises = [];
                for (var i = 0, l = items.length; i < l; i++) {
                    var item = items[i];
                    if (!item && items.getItem) {
                        item = items.getItem(i);
                    }
                    promises.push(WinJS.Promise.as(promiseCallback(item)));
                }
                return promises;
            });
        }
        /**
         * apply callback for each item in the array in parallel (equivalent to WinJS.Promise.join)
         * @function WinJSContrib.Promise.parallel
         * @param {Array} dataArray items to process with async tasks
         * @param {function} promiseCallback function applyed to each item (could return a promise for item callback completion)
         * @returns {WinJS.Promise}
         */
        function parallel(dataArray, promiseCallback) {
            if (!dataArray) {
                return WinJS.Promise.wrap([]);
            }
            var dataPromise = WinJS.Promise.as(dataArray);
            return dataPromise.then(function (items) {
                var promises = [];
                for (var i = 0, l = items.length; i < l; i++) {
                    var item = items[i];
                    if (!item && items.getItem) {
                        item = items.getItem(i);
                    }
                    promises.push(WinJS.Promise.as(promiseCallback(item)));
                }
                return WinJS.Promise.join(promises);
            });
        }
        Promise.parallel = parallel;
        /**
         * apply callback for each item in the array in batch of X parallel items
         * @function WinJSContrib.Promise.batch
         * @param {Array} dataArray items to process with async tasks
         * @param {number} batchSize number of items to batch
         * @param {function} promiseCallback function applyed to each item (could return a promise for item callback completion)
         * @returns {WinJS.Promise}
         */
        function batch(dataArray, batchSize, promiseCallback, batchWrapCallback) {
            if (!dataArray) {
                return WinJS.Promise.wrap([]);
            }
            var dataPromise = WinJS.Promise.as(dataArray);
            return dataPromise.then(function (items) {
                var resultPromise = WinJS.Promise.wrap();
                var batcheditems = [];
                var results = [];
                var hasErrors = false;
                var queueBatch = function (p, items) {
                    var prComplete, prError;
                    var result = new WinJS.Promise(function (c, e) {
                        prComplete = c;
                        prError = e;
                    });
                    p.then(function (r) {
                        WinJS.Promise.join(items.map(function (item, index) {
                            return WinJS.Promise.as(promiseCallback(item, index));
                        })).then(function (results) {
                            if (batchWrapCallback)
                                return batchWrapCallback(results);
                            return results;
                        }).then(function (results) {
                            results = results.concat(results);
                            return results;
                        }, function (errors) {
                            results = results.concat(errors);
                            hasErrors = true;
                            return results;
                        }).then(prComplete, prError);
                    });
                    return result;
                };
                for (var i = 0, l = items.length; i < l; i++) {
                    var item = items[i];
                    if (!item && items.getItem) {
                        item = items.getItem(i);
                    }
                    batcheditems.push(item);
                    if (i > 0 && i % batchSize === 0) {
                        resultPromise = queueBatch(resultPromise, batcheditems);
                        batcheditems = [];
                    }
                }
                if (batcheditems.length) {
                    resultPromise = queueBatch(resultPromise, batcheditems);
                }
                return resultPromise.then(function () {
                    if (hasErrors)
                        return WinJS.Promise.wrapError(results);
                    return results;
                });
            });
        }
        Promise.batch = batch;
    })(Promise = WinJSContrib.Promise || (WinJSContrib.Promise = {}));
})(WinJSContrib || (WinJSContrib = {}));
var WinJSContrib;
(function (WinJSContrib) {
    var Utils;
    (function (Utils) {
        var EventDispatcher = (function () {
            function EventDispatcher() {
            }
            EventDispatcher.prototype.dispatchEvent = function (type, data) { };
            EventDispatcher.prototype.addEventListener = function (type, callback) { };
            EventDispatcher.prototype.removeEventListener = function (type, callback) { };
            return EventDispatcher;
        })();
        Utils.EventDispatcher = EventDispatcher;
        Utils.EventDispatcher = WinJS.Class.mix(EventDispatcher, WinJS.Utilities.eventMixin);
        /**
         * extend an object with properties from subsequent objects
         * @function WinJSContrib.Utils.extend
         * @returns {Object} composite object
         */
        function extend() {
            for (var i = 1; i < arguments.length; i++)
                for (var key in arguments[i])
                    if (arguments[i].hasOwnProperty(key))
                        arguments[0][key] = arguments[i][key];
            return arguments[0];
        }
        Utils.extend = extend;
        /** indicate if string starts with featured characters
         * @function WinJSContrib.Utils.startsWith
         * @param {string} str string to search within
         * @param {string} strToMatch match string
         * @returns {boolean} true if string starts with strToMatch
         */
        function startsWith(str, strToMatch) {
            if (!strToMatch) {
                return false;
            }
            var match = (str.match("^" + strToMatch) == strToMatch);
            return match;
        }
        Utils.startsWith = startsWith;
        if (!String.prototype.startsWith) {
            String.prototype.startsWith = function (str) {
                return WinJSContrib.Utils.startsWith(this, str);
            };
        }
        function asyncForEach(array, callback, batchsize) {
            if (batchsize === void 0) { batchsize = 1; }
            var i = 0;
            while (i < array.length) {
                setImmediate(function () {
                    for (var j = 0; j < batchsize && i < array.length; j++) {
                        i++;
                        callback(array[i]);
                    }
                });
            }
        }
        Utils.asyncForEach = asyncForEach;
        /** indicate if string ends with featured characters
         * @function WinJSContrib.Utils.endsWith
         * @param {string} str string to search within
         * @param {string} strToMatch match string
         * @returns {boolean} true if string starts with strToMatch
         */
        function endsWith(str, strToMatch) {
            if (!strToMatch) {
                return false;
            }
            return (str.match(strToMatch + "$") == strToMatch);
        }
        Utils.endsWith = endsWith;
        if (!String.prototype.endsWith) {
            String.prototype.endsWith = function (str) {
                return WinJSContrib.Utils.endsWith(this, str);
            };
        }
        /**
         * generate a string formatted as a query string from object properties
         * @function WinJSContrib.Utils.queryStringFrom
         * @param {Object} obj object to format
         * @returns {string}
         */
        function queryStringFrom(obj) {
            var str = [];
            for (var p in obj)
                if (obj.hasOwnProperty(p)) {
                    var key = encodeURIComponent(p);
                    var rawValue = obj[p];
                    var value = WinJSContrib.Utils.hasValue(rawValue) ? encodeURIComponent(rawValue) : "";
                    str.push(key + "=" + value);
                }
            return str.join("&");
        }
        Utils.queryStringFrom = queryStringFrom;
        /**
         * trigger an event on a DOM node
         * @function WinJSContrib.Utils.triggerEvent
         * @param {HTMLElement} element receiving the event
         * @param {string} eventName name of the event
         * @param {boolean} bubbles indicate if event should bubble
         * @param {boolean} cancellable indicate if event can be cancelled
         */
        function triggerEvent(element, eventName, bubbles, cancellable) {
            var eventToTrigger = document.createEvent("Event");
            eventToTrigger.initEvent(eventName, bubbles, cancellable);
            element.dispatchEvent(eventToTrigger);
        }
        Utils.triggerEvent = triggerEvent;
        /**
         * @function WinJSContrib.Utils.triggerCustomEvent
         * @param {HTMLElement} element receiving the event
         * @param {string} eventName name of the event
         * @param {boolean} bubbles indicate if event should bubble
         * @param {boolean} cancellable indicate if event can be cancelled
         */
        function triggerCustomEvent(element, eventName, bubbles, cancellable, data) {
            var eventToTrigger = document.createEvent("CustomEvent");
            eventToTrigger.initCustomEvent(eventName, bubbles, cancellable, data);
            element.dispatchEvent(eventToTrigger);
        }
        Utils.triggerCustomEvent = triggerCustomEvent;
        /*
        Core object properties features
        */
        //return object value based on property name. Property name is a string containing the name of the property, 
        //or the name of the property with an indexer, ex: myproperty[2] (to get item in a array)
        function getobject(obj, prop) {
            if (!obj)
                return;
            if (prop === 'this')
                return obj;
            var baseValue = obj[prop];
            if (typeof baseValue !== "undefined")
                return baseValue;
            var idx = prop.indexOf('[');
            if (idx < 0)
                return;
            var end = prop.indexOf(']', idx);
            if (end < 0)
                return;
            var val = prop.substr(idx + 1, end - idx);
            val = parseInt(val);
            return obj[val];
        }
        //set object property value based on property name. Property name is a string containing the name of the property, 
        //or the name of the property with an indexer, ex: myproperty[2] (to get item in a array)
        function setobject(obj, prop, data) {
            if (!obj)
                return;
            if (WinJSContrib.Utils.hasValue(prop)) {
                if (obj.setProperty) {
                    obj.setProperty(prop, data);
                    return;
                }
                obj[prop] = data;
                return;
            }
            if (typeof prop === "string") {
                var idx = prop.indexOf('[');
                if (idx < 0)
                    return;
                var end = prop.indexOf(']', idx);
                if (end < 0)
                    return;
                var val = prop.substr(idx + 1, end - idx);
                var intval = parseInt(val);
                obj[intval] = data;
            }
        }
        /** Read property value on an object based on expression
        * @function WinJSContrib.Utils.readProperty
        * @param {Object} source the object containing data
        * @param {Object} properties property descriptor. could be a string in js notation ex: 'myProp.myChildProp,
        * or an array of strings ['myProp', 'myChildProp']. String notation can contain indexers
        * @returns {Object} property value
        */
        function readProperty(source, properties) {
            if (!source)
                return null;
            if (typeof properties == 'string' && source[properties])
                return source[properties];
            if (!properties || !properties.length)
                return source;
            var prop = WinJSContrib.Utils.getProperty(source, properties);
            if (prop) {
                return prop.propValue;
            }
        }
        Utils.readProperty = readProperty;
        var PropertyDescriptor = (function () {
            function PropertyDescriptor(parent, parentDescriptor, keyProp) {
                this.parent = parent;
                this.parentDescriptor = parentDescriptor;
                this.keyProp = keyProp;
            }
            PropertyDescriptor.prototype.ensureParent = function () {
                if (parent) {
                    return parent;
                }
                else {
                    if (this.parentDescriptor) {
                        this.parentDescriptor.ensureParent();
                        if (!this.parentDescriptor.parent[this.parentDescriptor.keyProp]) {
                            this.parentDescriptor.parent[this.parentDescriptor.keyProp] = {};
                            this.parent = this.parentDescriptor.parent[this.parentDescriptor.keyProp];
                        }
                    }
                }
            };
            Object.defineProperty(PropertyDescriptor.prototype, "propValue", {
                get: function () {
                    return getobject(this.parent, this.keyProp);
                },
                set: function (val) {
                    this.ensureParent();
                    setobject(this.parent, this.keyProp, val);
                },
                enumerable: true,
                configurable: true
            });
            return PropertyDescriptor;
        })();
        Utils.PropertyDescriptor = PropertyDescriptor;
        /**
         * return a propery descriptor for an object based on expression
         * @function WinJSContrib.Utils.getProperty
         * @param {Object} source the object containing data
         * @param {string[]} properties property descriptor. could be a string in js notation ex: 'myProp.myChildProp,
         * or an array of strings ['myProp', 'myChildProp']. String notation can contain indexers
         * @returns {Object} property descriptor
         */
        function getProperty(source, properties) {
            if (typeof properties == 'string') {
                properties = properties.split('.');
            }
            if (!properties || !properties.length) {
                properties = ['this'];
            }
            var parent = source;
            var previousDescriptor = null;
            for (var i = 0; i < properties.length; i++) {
                var descriptor = new PropertyDescriptor(parent, previousDescriptor, properties[i]);
                previousDescriptor = descriptor;
                if (i == properties.length - 1) {
                    return descriptor;
                }
                parent = getobject(parent, properties[i]);
            }
            return;
        }
        Utils.getProperty = getProperty;
        /**
         * Write property value on an object based on expression
         * @function WinJSContrib.Utils.writeProperty
         * @param {Object} source the object containing data
         * @param {string[]} properties property descriptor. could be a string in js notation ex: 'myProp.myChildProp,
         * or an array of strings ['myProp', 'myChildProp']. String notation can contain indexers
         * @param {Object} data data to feed to the property
         */
        function writeProperty(source, properties, data) {
            var prop = WinJSContrib.Utils.getProperty(source, properties);
            if (prop) {
                prop.propValue = data;
            }
        }
        Utils.writeProperty = writeProperty;
        /** generate a random value between two numbers
         * @function WinJSContrib.Utils.randomFromInterval
         * @param {number} from lower limit
         * @param {number} to upper limit
         * @returns {number}
         */
        function randomFromInterval(from, to) {
            return (Math.random() * (to - from + 1) + from) << 0;
        }
        Utils.randomFromInterval = randomFromInterval;
        /**
         * function to use as a callback for Array.sort when you want the array to be sorted alphabetically
         * @function WinJSContrib.Utils.alphabeticSort
         * @param {string} a
         * @param {string} b
         * @returns {number}
         */
        function alphabeticSort(a, b) {
            if (a > b)
                return 1;
            if (a < b)
                return -1;
            return 0;
        }
        Utils.alphabeticSort = alphabeticSort;
        /**
         * generate an array with only distinct elements
         * @function WinJSContrib.Utils.distinctArray
         * @param {Array} array
         * @param {string} path to array's item property used for checking items
         * @param {boolean} ignorecase indicate if comparison should ignore case when using string
         * @returns {Array}
         */
        function distinctArray(array, property, ignorecase) {
            if (array === null || array.length === 0)
                return array;
            if (typeof ignorecase == "undefined")
                ignorecase = false;
            var sMatchedItems = "";
            var foundCounter = 0;
            var newArray = [];
            var sFind;
            var i;
            if (ignorecase) {
                for (i = 0; i < array.length; i++) {
                    if (property) {
                        var data = WinJSContrib.Utils.readProperty(array[i], property.split('.'));
                        sFind = data;
                        if (!data)
                            sFind = data;
                        if (data && data.toLowerCase)
                            sFind = data.toLowerCase();
                    }
                    else {
                        sFind = array[i];
                    }
                    if (sMatchedItems.indexOf("|" + sFind + "|") < 0) {
                        sMatchedItems += "|" + sFind + "|";
                        newArray[foundCounter++] = array[i];
                    }
                }
            }
            else {
                for (i = 0; i < array.length; i++) {
                    if (property) {
                        sFind = WinJSContrib.Utils.readProperty(array[i], property.split('.'));
                    }
                    else {
                        sFind = array[i];
                    }
                    if (sMatchedItems.indexOf("|" + sFind + "|") < 0) {
                        sMatchedItems += "|" + sFind + "|";
                        newArray[foundCounter++] = array[i];
                    }
                }
            }
            return newArray;
        }
        Utils.distinctArray = distinctArray;
        /**
         * get distinct values from an array of items
         * @function WinJSContrib.Utils.getDistinctPropertyValues
         * @param {Array} array items array
         * @param {string} property property path for values
         * @param {boolean} ignorecase ignore case for comparisons
         */
        function getDistinctPropertyValues(array, property, ignorecase) {
            return Utils.distinctArray(array, property, ignorecase).map(function (item) {
                return WinJSContrib.Utils.readProperty(item, property.split('.'));
            });
        }
        Utils.getDistinctPropertyValues = getDistinctPropertyValues;
        /**
         * Remove all accented characters from a string and replace them with their non-accented counterpart for ex: replace "é" with "e"
         * @function WinJSContrib.Utils.removeAccents
         * @param {string} s
         * @returns {string}
         */
        function removeAccents(s) {
            var r = s.toLowerCase();
            r = r.replace(new RegExp("[àáâãäå]", 'g'), "a");
            r = r.replace(new RegExp("æ", 'g'), "ae");
            r = r.replace(new RegExp("ç", 'g'), "c");
            r = r.replace(new RegExp("[èéêë]", 'g'), "e");
            r = r.replace(new RegExp("[ìíîï]", 'g'), "i");
            r = r.replace(new RegExp("ñ", 'g'), "n");
            r = r.replace(new RegExp("[òóôõö]", 'g'), "o");
            r = r.replace(new RegExp("œ", 'g'), "oe");
            r = r.replace(new RegExp("[ùúûü]", 'g'), "u");
            r = r.replace(new RegExp("[ýÿ]", 'g'), "y");
            return r;
        }
        Utils.removeAccents = removeAccents;
        /**
         * remove a page from navigation history
         * @function WinJSContrib.Utils.removePageFromHistory
         * @param {string} pageLocation page url
         */
        function removePageFromHistory(pageLoc) {
            var history = [];
            if (WinJS.Navigation.history && WinJS.Navigation.history.backStack && WinJS.Navigation.history.backStack.length) {
                WinJS.Navigation.history.backStack.forEach(function (page) {
                    if (page.location !== pageLoc) {
                        history.push(page);
                    }
                });
            }
            WinJS.Navigation.history.backStack = history;
        }
        Utils.removePageFromHistory = removePageFromHistory;
        /**
         * format a number on 2 digits
         * @function WinJSContrib.Utils.pad2
         * @param {number} number
         */
        function pad2(number) {
            return (number < 10 ? '0' : '') + number;
        }
        Utils.pad2 = pad2;
        /**
         * truncate a string and add ellipse if text if greater than certain size
         * @function WinJSContrib.Utils.ellipsisizeString
         * @param {string} text text to truncate
         * @param {number} maxSize maximum size for text
         * @param {boolean} useWordBoundary indicate if truncate should happen on the closest word boundary (like space)
         */
        function ellipsisizeString(text, maxSize, useWordBoundary) {
            if (!text) {
                return '';
            }
            var toLong = text.length > maxSize, text_ = toLong ? text.substr(0, maxSize - 1) : text;
            text_ = useWordBoundary && toLong ? text_.substr(0, text_.lastIndexOf(' ')) : text_;
            return toLong ? text_ + '...' : text_;
        }
        Utils.ellipsisizeString = ellipsisizeString;
        /**
         * generate a new Guid
         * @function WinJSContrib.Utils.guid
         * @returns {string}
         */
        function guid() {
            var d = new Date().getTime();
            var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
                var r = (d + Math.random() * 16) % 16 | 0;
                d = Math.floor(d / 16);
                return (c == 'x' ? r : (r & 0x7 | 0x8)).toString(16);
            });
            return uuid;
        }
        Utils.guid = guid;
        /**
         * inherit property from parent WinJS controls
         * @function WinJSContrib.Utils.inherit
         * @param {HTMLElement} element
         * @param {string} property property name
         */
        function inherit(element, property) {
            if (element && element.parentElement) {
                var current = element.parentElement;
                while (current) {
                    if (current.winControl) {
                        if (current.winControl[property] !== undefined) {
                            return current.winControl[property];
                        }
                    }
                    current = current.parentElement;
                }
            }
        }
        Utils.inherit = inherit;
        /**
         * move DOM childrens form one node to the other
         * @function WinJSContrib.Utils.moveChilds
         * @param {HTMLElement} source source node containing elements to move
         * @param {HTMLElement} target target node for moved elements
         */
        function moveChilds(source, target) {
            if (!source || !target)
                return;
            var childs = [];
            for (var i = 0; i < source.childNodes.length; i++) {
                childs.push(source.childNodes[i]);
            }
            childs.forEach(function (elt) {
                target.appendChild(elt);
            });
        }
        Utils.moveChilds = moveChilds;
        /**
         * get parent control identifyed by a property attached on DOM element
         * @function WinJSContrib.Utils.getParent
         * @param {string} property property attached to control's DOM element, for ex: msParentSelectorScope
         * @param {HTMLElement} element DOM element to scan
         * @returns {Object} WinJS control
         */
        function getParent(property, element) {
            if (!element)
                return;
            var current = element.parentNode;
            while (current) {
                if (current[property] && current.winControl) {
                    return current.winControl;
                }
                current = current.parentNode;
            }
        }
        Utils.getParent = getParent;
        /**
         * get parent control identifyed by a css class
         * @function WinJSContrib.Utils.getParentControlByClass
         * @param {string} className css class name
         * @param {HTMLElement} element DOM element to scan
         * @returns {Object} WinJS control
         */
        function getParentControlByClass(className, element) {
            if (!element)
                return;
            var current = element.parentNode;
            while (current) {
                if (current.classList && current.classList.contains(className) && current.winControl) {
                    return current.winControl;
                }
                current = current.parentNode;
            }
        }
        Utils.getParentControlByClass = getParentControlByClass;
        /**
         * get parent page control (work only with WinJSContrib.UI.PageControlNavigator
         * @function WinJSContrib.Utils.getParentPage
         * @param {HTMLElement} element DOM element to scan
         * @returns {Object} WinJS control
         */
        function getParentPage(element) {
            return WinJSContrib.Utils.getParent('mcnPage', element);
        }
        Utils.getParentPage = getParentPage;
        /**
         * get parent scope control (based on msParentSelectorScope)
         * @function WinJSContrib.Utils.getScopeControl
         * @param {HTMLElement} element DOM element to scan
         * @returns {Object} WinJS control
         */
        function getScopeControl(element) {
            var current = element.parentNode;
            while (current) {
                if (current.msParentSelectorScope) {
                    var scope = current.parentNode;
                    if (scope) {
                        var scopeControl = scope.winControl;
                        if (scopeControl) {
                            return scopeControl;
                        }
                    }
                }
                current = current.parentNode;
            }
        }
        Utils.getScopeControl = getScopeControl;
        /**
         * get WinJS.Binding.Template like control from a path, a control, a function or a DOM element
         * @function WinJSContrib.Utils.getTemplate
         * @param {Object} template template input
         * @returns {Object} WinJS.Binding.Template or template-like object (object with a render function)
         */
        function getTemplate(template) {
            if (template) {
                var templatetype = typeof template;
                if (templatetype == 'string') {
                    return new WinJS.Binding.Template(null, { href: template });
                }
                if (templatetype == 'function') {
                    return {
                        render: function (data, elt) {
                            var res = template(data, elt);
                            return WinJS.Promise.as(res);
                        }
                    };
                }
                else if (template.winControl) {
                    return template.winControl;
                }
                else if (template.render) {
                    return template;
                }
            }
        }
        Utils.getTemplate = getTemplate;
        /**
         * get a function from an expression, for example 'page:myAction' will return the myAction function from the parent page.
         * The returned function will be bound to it's owner. This function relies on {link WinJSContrib.Utils.resolveValue}, see this for details about how data are crawled
         * @function WinJSContrib.Utils.resolveMethod
         * @param {HTMLElement} element DOM element to look
         * @param {string} text expression like 'page:something' or 'ctrl:something' or 'something'
         * @returns {function}
         */
        function resolveMethod(element, text) {
            var res = WinJSContrib.Utils.resolveValue(element, text);
            if (res && typeof res == 'function')
                return res;
            return undefined;
        }
        Utils.resolveMethod = resolveMethod;
        function readValue(element, text) {
            var res = WinJSContrib.Utils.resolveValue(element, text);
            if (res) {
                if (typeof res == 'function')
                    return res(element);
                else
                    return res;
            }
            return undefined;
        }
        Utils.readValue = readValue;
        /**
         * Utility functions used by WinJSContrib.Utils.resolveValue and WinJSContrib.Utils.applyValue
         * @namespace WinJSContrib.Utils.ValueParsers
         */
        Utils.ValueParsers = {
            /**
             * Get value from current page in parent navigator
             * @function WinJSContrib.Utils.ValueParsers.navpage
             */
            "navpage": function (element, text, context) {
                var control = (context && context.data) ? context.data.navpage : null;
                if (!control) {
                    if (WinJSContrib.Utils.getParentPage) {
                        control = WinJSContrib.Utils.getParentPage(element);
                        if (context && context.data)
                            context.data.navpage = control;
                    }
                    if (!control && WinJSContrib.UI.Application.navigator) {
                        control = WinJSContrib.UI.Application.navigator.pageControl;
                        if (context && context.data)
                            context.data.navpage = control;
                    }
                }
                if (!control)
                    return;
                if (context)
                    context.parentControl = control;
                var method = WinJSContrib.Utils.readProperty(control, text);
                if (method && typeof method === 'function')
                    return method.bind(control);
                else
                    return method;
            },
            /**
             * Get value from parent element with 'pagecontrol' class
             * @function WinJSContrib.Utils.ValueParsers.page
             */
            "page": function (element, text, context) {
                var control = (context && context.data) ? context.data.page : null;
                if (!control) {
                    control = WinJSContrib.Utils.getParentControlByClass('pagecontrol', element);
                    if (context && context.data)
                        context.data.page = control;
                }
                if (!control)
                    return;
                if (context)
                    context.parentControl = control;
                var method = WinJSContrib.Utils.readProperty(control, text);
                if (method && typeof method === 'function')
                    return method.bind(control);
                else
                    return method;
            },
            /**
             * Get value from parent scope
             * @function WinJSContrib.Utils.ValueParsers.ctrl
             */
            "ctrl": function (element, text, context) {
                var control = (context && context.data) ? context.data.scope : null;
                if (!control) {
                    control = WinJSContrib.Utils.getScopeControl(element);
                    if (context && context.data)
                        context.data.scope = control;
                }
                if (!control)
                    return;
                if (context)
                    context.parentControl = control;
                var method = WinJSContrib.Utils.readProperty(control, text);
                if (method && typeof method === 'function')
                    return method.bind(control);
                else
                    return method;
            },
            /**
             * select a node from DOM
             * @function WinJSContrib.Utils.ValueParsers.select
             */
            "select": function (element, text, context) {
                var control = (context && context.data) ? context.data.scope : null;
                if (!control) {
                    control = WinJSContrib.Utils.getScopeControl(element);
                    if (context && context.data)
                        context.data.scope = control;
                }
                var element = null;
                var items = text.split('|');
                var selector = items[0];
                if (control) {
                    element = control.element.querySelector(selector);
                }
                if (!element)
                    element = document.querySelector(selector);
                if (items.length == 1) {
                    return element;
                }
                else if (items.length > 1) {
                    var val = readProperty(element, text.substr(items[0].length + 1));
                    return val;
                }
            },
            /**
             * get an object formatted as JSON
             * @function WinJSContrib.Utils.ValueParsers.obj
             */
            "obj": function (element, text, context) {
                return WinJS.UI.optionsParser(text, window, {
                    select: WinJS.Utilities.markSupportedForProcessing(function (text) {
                        var parent = WinJSContrib.Utils.getScopeControl(element);
                        if (parent) {
                            return parent.element.querySelector(text);
                        }
                        else {
                            return document.querySelector(text);
                        }
                    })
                });
            },
            /**
             * mark a promise for resolution (if used in applyValue, the promise will get resolved and the promise's result will be affected)
             * @function WinJSContrib.Utils.ValueParsers.prom
             */
            "prom": function (element, text, context) {
                var res = resolveValue(element, text, context);
                if (res.then) {
                    res = res.then(null, null);
                    res.mcnMustResolve = true;
                }
                return res;
            },
            /**
             * wrap result in WinJS.Binding.List().dataSource
             * usefull for ListViews
             * @function WinJSContrib.Utils.ValueParsers.list
             */
            "list": function (element, text, context) {
                var res = resolveValue(element, text, context);
                if (res) {
                    if (res.then) {
                        var p = res.then(function (data) {
                            return new WinJS.Binding.List(data).dataSource;
                        });
                        p.mcnMustResolve = true;
                        return p;
                    }
                    return new WinJS.Binding.List(res).dataSource;
                }
            },
            /**
             * get value from global scope
             * @function WinJSContrib.Utils.ValueParsers.global
             */
            "global": function (element, text, context) {
                return WinJSContrib.Utils.readProperty(window, text);
            },
            /**
             * get a template from uri
             * @function WinJSContrib.Utils.ValueParsers.templ
             */
            "templ": function (element, text, context) {
                return WinJSContrib.Templates.get(text);
            },
            /**
             * return element property
             * @function WinJSContrib.Utils.ValueParsers.element
             */
            "element": function (element, text, context) {
                var res = resolveValue(element, text, context);
                if (res)
                    return res.element;
            },
            "event": function (element, text, context) {
                var res = resolveValue(element, text, context);
                var parentControl = null;
                if (!res || !context || !context.name) {
                    return;
                }
                if (context)
                    parentControl = context.parentControl;
                if (res && typeof res === 'function') {
                    if (parentControl && parentControl.eventTracker) {
                        parentControl.eventTracker.addEvent(context.control, context.name, res);
                    }
                    else {
                        context.control.addEventListener(context.name, res);
                    }
                }
            }
        };
        /**
         * resolve value from an expression. This helper will crawl the DOM up, and provide the property or function from parent page or control.
         * @function WinJSContrib.Utils.resolveValue
         * @param {HTMLElement} element DOM element to look
         * @param {string} text expression like 'page:something' or 'ctrl:something' or 'something'
         * @returns {Object}
         */
        function resolveValue(element, text, context) {
            var methodName, control, method;
            var items = text.split(':');
            if (items.length > 1) {
                var name = items[0];
                var val = text.substr(name.length + 1);
                var parser = Utils.ValueParsers[name];
                if (parser) {
                    return parser(element, val, context);
                }
            }
            return text; //WinJSContrib.Utils.readProperty(window, text);
        }
        Utils.resolveValue = resolveValue;
        /**
         * call resolve value and apply result to a target object
         * @function WinJSContrib.Utils.applyValue
         * @param {HTMLElement} element DOM element to look
         * @param {string} text expression like 'page:something' or 'ctrl:something' or 'something'
         * @param {string} target target object
         * @param {string} targetPath path to dest property
         */
        function applyValue(element, text, target, targetPath, context) {
            var tmp = WinJSContrib.Utils.resolveValue(element, text, context);
            if (tmp && tmp.then && tmp.mcnMustResolve) {
                tmp.then(function (data) {
                    WinJSContrib.Utils.writeProperty(target, targetPath, data);
                });
            }
            else {
                WinJSContrib.Utils.writeProperty(target, targetPath, tmp);
            }
        }
        Utils.applyValue = applyValue;
        /**
         * Checks in a safe way if an object has a value, which could be 'false', '0' or '""'
         * @function WinJSContrib.Utils.hasValue
         * @param {Object} item The object to check.
         * @returns {Boolean} Whether the object has a value or not.
         */
        function hasValue(item) {
            return typeof item !== "undefined" && item !== null;
        }
        Utils.hasValue = hasValue;
        /**
         * format error from an xhr call
         * @function WinJSContrib.Utils.formatXHRError
         */
        function formatXHRError(xhr) {
            return "{0} - {1}: {2}".format(xhr.status, xhr.statusText, xhr.responseText);
        }
        Utils.formatXHRError = formatXHRError;
        /**
         * Unwraps the real error from a WinJS.Promise.join operation, which by design returns an array with 'undefined' for all cells,
         * excepts the one corresponding to the promise that really faulted.
         * @function WinJSContrib.Utils.unwrapJoinError
         * @param {function} errorCallback The callback to use to handle the error.
         * @returns {Function} The result of the callback being fired with the real error.
         */
        function unwrapJoinError(errorCallback) {
            return function (errorArray) {
                var unwrappedError = null;
                for (var i = 0; i < errorArray.length; i++) {
                    var tentativeError = errorArray[i];
                    if (typeof tentativeError !== "undefined") {
                        unwrappedError = tentativeError;
                        break;
                    }
                }
                return errorCallback(unwrappedError);
            };
        }
        Utils.unwrapJoinError = unwrapJoinError;
        /**
         * inject properties from source object to target object
         * @function WinJSContrib.Utils.inject
         */
        function inject(target, source) {
            if (source) {
                for (var k in source) {
                    target[k] = source[k];
                }
            }
        }
        Utils.inject = inject;
    })(Utils = WinJSContrib.Utils || (WinJSContrib.Utils = {}));
})(WinJSContrib || (WinJSContrib = {}));
/**
 * @namespace WinJSContrib.Templates
 */
var WinJSContrib;
(function (WinJSContrib) {
    var Templates;
    (function (Templates) {
        var cache = {};
        /**
         * get a template from it's path
         * @function get
         * @memberof WinJSContrib.Templates
         * @param {string} uri path to template file
         * @returns {WinJS.Binding.Template} template object
         */
        function get(uri) {
            var template = cache[uri];
            if (cache[uri])
                return template;
            return new WinJS.Binding.Template(null, { href: uri });
        }
        Templates.get = get;
        /**
         * get a template and turn it to a rendering function that takes an item promise, and return a DOM element
         * @function WinJSContrib.Templates.interactive
         * @param {string} uri path to template file
         * @param {Object} args definition of interactive elements
         * @returns {function} rendering function that takes an item promise, and return a DOM element
         */
        function interactive(uri, args) {
            var template = WinJSContrib.Templates.get(uri);
            if (template) {
                return WinJSContrib.Templates.makeInteractive(template, args);
            }
            else {
                throw { message: 'template not found for ' + uri };
            }
        }
        Templates.interactive = interactive;
        /**
         * generate a rendering function that takes an item promise, and return a DOM element
         * @function WinJSContrib.Templates.get
         * @param {WinJS.Binding.Template} template template object
         * @param {Object} args definition of interactive elements
         * @returns {function} rendering function that takes an item promise, and return a DOM element
         */
        function makeInteractive(template, args) {
            return function (itemPromise) {
                return itemPromise.then(function (item) {
                    return template.render(item).then(function (rendered) {
                        if (args.tap) {
                            for (var n in args.tap) {
                                var elt = rendered.querySelector(n);
                                WinJSContrib.UI.tap(elt, function (arg) {
                                    args.tap[n](arg, item);
                                });
                            }
                        }
                        if (args.click) {
                            for (var n in args.click) {
                                var elt = rendered.querySelector(n);
                                elt.onclick = function (arg) {
                                    args.click[n](arg, item);
                                };
                            }
                        }
                        return rendered;
                    });
                });
            };
        }
        Templates.makeInteractive = makeInteractive;
    })(Templates = WinJSContrib.Templates || (WinJSContrib.Templates = {}));
})(WinJSContrib || (WinJSContrib = {}));

var WinJSContrib;
(function (WinJSContrib) {
    var UI;
    (function (UI) {
        UI.Application = {};
        /**
         * indicate if fragment should not look for resources when building control
         * @field WinJSContrib.UI.disableAutoResources
         * @type {boolean}
         */
        UI.disableAutoResources = false;
        /**
         * Calculate offset of element relative to parent element. If parent parameter is null, offset is relative to document
         * @function WinJSContrib.UI.offsetFrom
         * @param {HTMLElement} element element to evaluate
         * @param {HTMLElement} parent reference of offset
         */
        function offsetFrom(element, parent) {
            var xPosition = 0;
            var yPosition = 0;
            var w = element.clientWidth;
            var h = element.clientHeight;
            while (element && element != parent) {
                xPosition += (element.offsetLeft - element.scrollLeft + element.clientLeft);
                yPosition += (element.offsetTop - element.scrollTop + element.clientTop);
                element = element.offsetParent;
            }
            return { x: xPosition, y: yPosition, width: w, height: h };
        }
        UI.offsetFrom = offsetFrom;
        var EventTracker = (function () {
            /**
             * @class WinJSContrib.UI.EventTracker
             * @classdesc object to register and release events from addEventListener or bind
             */
            function EventTracker() {
                this.events = [];
            }
            /**
             * register an event from an object
             * @function WinJSContrib.UI.EventTracker.prototype.addEvent
             * @param {Object} e object containing addEventListener
             * @param {string} eventName name of the event
             * @param {function} handler
             * @param {boolean} capture
             * @returns {function} function to call for unregistering the event
             */
            EventTracker.prototype.addEvent = function (e, eventName, handler, capture) {
                var tracker = this;
                e.addEventListener(eventName, handler, capture);
                var unregister = function () {
                    try {
                        e.removeEventListener(eventName, handler);
                        var idx = tracker.events.indexOf(unregister);
                        if (idx >= 0) {
                            tracker.events.splice(idx, 1);
                        }
                    }
                    catch (exception) {
                        console.error('unexpected error while releasing callback ' + exception.message);
                    }
                };
                this.events.push(unregister);
                return unregister;
            };
            /**
             * register binding event
             * @function WinJSContrib.UI.EventTracker.prototype.addBinding
             * @param {Object} e object containing bind method
             * @param {string} eventName name of the binding event
             * @param {function} handler
             */
            EventTracker.prototype.addBinding = function (e, eventName, handler) {
                e.bind(eventName, handler);
                var unregister = function () {
                    e.unbind(eventName, handler);
                };
                this.events.push(unregister);
                return unregister;
            };
            /**
             * release all registered events
             * @function WinJSContrib.UI.EventTracker.prototype.dispose
             */
            EventTracker.prototype.dispose = function () {
                for (var i = 0; i < this.events.length; i++) {
                    this.events[i]();
                }
                this.events = [];
            };
            return EventTracker;
        })();
        UI.EventTracker = EventTracker;
        /**
         * open all appbars
         * @function WinJSContrib.UI.appbarsOpen
         */
        function appbarsOpen() {
            var res = document.querySelectorAll('div[data-win-control="WinJS.UI.AppBar"],div[data-win-control="WinJS.UI.NavBar"]');
            if (res && res.length) {
                for (var i = 0; i < res.length; i++) {
                    var e = res[i];
                    if (e.winControl) {
                        e.winControl.show();
                    }
                }
            }
        }
        UI.appbarsOpen = appbarsOpen;
        /**
         * close all appbars
         * @function WinJSContrib.UI.appbarsClose
         */
        function appbarsClose() {
            var res = document.querySelectorAll('div[data-win-control="WinJS.UI.AppBar"],div[data-win-control="WinJS.UI.NavBar"]');
            if (res && res.length) {
                for (var i = 0; i < res.length; i++) {
                    var e = res[i];
                    if (e.winControl) {
                        e.winControl.hide();
                    }
                }
            }
        }
        UI.appbarsClose = appbarsClose;
        /**
         * disable all appbars
         * @function WinJSContrib.UI.appbarsDisable
         */
        function appbarsDisable() {
            var res = document.querySelectorAll('div[data-win-control="WinJS.UI.AppBar"],div[data-win-control="WinJS.UI.NavBar"]');
            if (res && res.length) {
                for (var i = 0; i < res.length; i++) {
                    var e = res[i];
                    if (e.winControl) {
                        e.winControl.disabled = true;
                    }
                }
            }
        }
        UI.appbarsDisable = appbarsDisable;
        /**
         * enable all appbars
         * @function WinJSContrib.UI.appbarsEnable
         */
        function appbarsEnable() {
            var elements = document.querySelectorAll('div[data-win-control="WinJS.UI.AppBar"],div[data-win-control="WinJS.UI.NavBar"]');
            if (elements && elements.length) {
                for (var i = 0, l = elements.length; i < l; i++) {
                    var el = elements[i];
                    if (el.winControl) {
                        el.winControl.disabled = false;
                    }
                }
            }
        }
        UI.appbarsEnable = appbarsEnable;
        /**
         * build a promise around element "load" event (work for all element with src property like images, iframes, ...)
         * @function WinJSContrib.UI.elementLoaded
         * @param {HTMLElement} element
         * @param {string} url url used to feed "src" on element
         * @returns {WinJS.Promise}
         */
        function elementLoaded(elt, url) {
            return new WinJS.Promise(function (complete, error) {
                function onerror(e) {
                    elt.onload = undefined;
                    elt.onerror = undefined;
                    elt.onreadystatechange = undefined;
                    error('element not loaded');
                }
                function onload(e) {
                    elt.onload = undefined;
                    elt.onerror = undefined;
                    elt.onreadystatechange = undefined;
                    complete({
                        element: elt,
                        url: url
                    });
                }
                elt.onerror = onerror;
                elt.onload = onload;
                elt.onreadystatechange = onload;
                if (elt.naturalWidth > 0) {
                    onload(undefined);
                }
                elt.src = url;
            });
        }
        UI.elementLoaded = elementLoaded;
        /**
         * Create a promise for getting an image object from url
         * @function WinJSContrib.UI.loadImage
         * @param {string} imgUrl url for the picture
         * @returns {WinJS.Promise}
         */
        function loadImage(imgUrl) {
            return new WinJS.Promise(function (complete, error) {
                var image = new Image();
                function onerror(e) {
                    image.onload = undefined;
                    image.onerror = undefined;
                    error({ message: 'image not loaded : ' + imgUrl, path: imgUrl });
                }
                function onload(e) {
                    image.onload = undefined;
                    image.onerror = undefined;
                    complete({
                        element: image,
                        url: imgUrl
                    });
                }
                image.onerror = onerror;
                image.onload = onload;
                if (image.naturalWidth > 0) {
                    onload(undefined);
                }
                image.src = imgUrl;
            });
        }
        UI.loadImage = loadImage;
        /**
         * List all elements found after provided element
         * @function WinJSContrib.UI.listElementsAfterMe
         * @param {HTMLElement} elt target element
         * @returns {Array} list of sibling elements
         */
        function listElementsAfterMe(elt) {
            var res = [];
            var passed = false;
            if (elt.parentElement) {
                var parent = elt.parentElement;
                for (var i = 0; i < parent.children.length; i++) {
                    if (parent.children[i] === elt) {
                        passed = true;
                    }
                    else if (passed) {
                        res.push(parent.children[i]);
                    }
                }
            }
            return res;
        }
        UI.listElementsAfterMe = listElementsAfterMe;
        /**
         * create an animation for removing an element from a list
         * @function WinJSContrib.UI.removeElementAnimation
         * @param {HTMLElement} element that will be removed
         * @returns {WinJS.Promise}
         */
        function removeElementAnimation(elt) {
            return new WinJS.Promise(function (complete, error) {
                var remainings = WinJSContrib.UI.listElementsAfterMe(elt);
                var anim = WinJS.UI.Animation.createDeleteFromListAnimation([
                    elt
                ], remainings);
                elt.style.position = "fixed";
                elt.style.opacity = '0';
                anim.execute().done(function () {
                    complete(elt);
                });
            });
        }
        UI.removeElementAnimation = removeElementAnimation;
        function bindAction(el, element, control, item) {
            if (!el)
                return;
            el.classList.add('page-action');
            var actionName = el.dataset.pageAction || el.getAttribute('tap');
            var action = control[actionName];
            if (action && typeof action === 'function') {
                WinJSContrib.UI.tap(el, function (eltarg) {
                    var p = WinJS.Promise.wrap(actionArgs);
                    var actionArgs = eltarg.dataset.pageActionArgs || el.getAttribute('tap-args');
                    if (actionArgs && typeof actionArgs == 'string') {
                        var tmp = WinJSContrib.Utils.readValue(eltarg, actionArgs);
                        p = WinJS.Promise.as(tmp).then(function (val) {
                            if (typeof val === 'string') {
                                try {
                                    val = WinJS.UI.optionsParser(val, window);
                                }
                                catch (exception) {
                                    return;
                                }
                            }
                            return val;
                        });
                        if (tmp) {
                            actionArgs = tmp;
                        }
                    }
                    return p.then(function (arg) {
                        return control[actionName].bind(control)({ elt: eltarg, args: arg, item: item });
                    });
                });
            }
        }
        /**
         * setup declarative binding to parent control function. It looks for "data-page-action" attributes,
         * and try to find a matching method on the supplyed control.
         * You could add arguments with a "page-action-args" attribute. The argument can be an object or a function
         * @function WinJSContrib.UI.bindPageActions
         * @param {HTMLElement} element root node crawled for page actions
         * @param {Object} control control owning functions to call
         * @param {item} optionnal argument for adding an item to call
         */
        function bindPageActions(element, control, item) {
            var elements = element.querySelectorAll('*[data-page-action], *[tap]');
            if (elements && elements.length) {
                for (var i = 0, l = elements.length; i < l; i++) {
                    var el = elements[i];
                    bindAction(el, element, control, item);
                }
            }
        }
        UI.bindPageActions = bindPageActions;
        function bindLink(el, element, item) {
            if (!el)
                return;
            el.classList.add('page-link');
            var applink = el.getAttribute('applink');
            var target = el.dataset.pageLink || el.getAttribute('linkto');
            if (target && target.indexOf('/') < 0) {
                var tmp = WinJSContrib.Utils.readProperty(window, target);
                if (tmp) {
                    target = tmp;
                }
            }
            if (target) {
                var options = el.dataset.pageActionOptions || el.getAttribute('tap-options');
                if (options) {
                    try {
                        options = WinJS.UI.optionsParser(options, window);
                    }
                    catch (exception) {
                        return;
                    }
                }
                WinJSContrib.UI.tap(el, function (eltarg) {
                    var p = WinJS.Promise.wrap();
                    var actionArgs = eltarg.dataset.pageActionArgs || el.getAttribute('linkto-args');
                    if (actionArgs && typeof actionArgs == 'string') {
                        var tmp = WinJSContrib.Utils.readValue(eltarg, actionArgs);
                        p = WinJS.Promise.as(tmp).then(function (val) {
                            if (typeof val === 'string') {
                                try {
                                    val = WinJS.UI.optionsParser(val, window);
                                }
                                catch (exception) {
                                }
                            }
                            return val;
                        });
                    }
                    if (!actionArgs && item)
                        actionArgs = { item: item };
                    return p.then(function (actionArgs) {
                        if (!applink && WinJSContrib.UI.parentNavigator && WinJSContrib.UI.parentNavigator(eltarg)) {
                            var nav = WinJSContrib.UI.parentNavigator(eltarg);
                            return nav.navigate(target, actionArgs);
                        }
                        else {
                            return WinJS.Navigation.navigate(target, actionArgs);
                        }
                    });
                }, options);
            }
        }
        /**
         * setup declarative binding to page link. It looks for "data-page-link" attributes.
         * If any the content of the attribute point toward a page. clicking that element will navigate to that page.
         * You could add arguments with a "page-action-args" attribute. The argument can be an object or a function
         * @function WinJSContrib.UI.bindPageLinks
         * @param {HTMLElement} element root node crawled for page actions
         */
        function bindPageLinks(element, item) {
            var elements = element.querySelectorAll('*[data-page-link], *[linkto]');
            if (elements && elements.length) {
                for (var i = 0, l = elements.length; i < l; i++) {
                    var el = elements[i];
                    bindLink(el, element, item);
                }
            }
        }
        UI.bindPageLinks = bindPageLinks;
        function parentNavigator(element) {
            var current = element.parentNode;
            while (current) {
                if (current.mcnNavigator) {
                    return current.winControl;
                }
                current = current.parentNode;
            }
        }
        UI.parentNavigator = parentNavigator;
        function bindMember(el, element, control) {
            if (!el)
                return;
            el.classList.add('page-member');
            var memberName = el.dataset.pageMember || el.getAttribute('member');
            if (!memberName)
                memberName = el.id;
            if (memberName && !control[memberName]) {
                control[memberName] = el;
                if (el.winControl) {
                    control[memberName] = el.winControl;
                }
            }
        }
        /**
         * Add this element or control as member to the control. It looks for "data-page-member" attributes. If attribute is empty, it tooks the element id as member name.
         * @function WinJSContrib.UI.bindMembers
         * @param {HTMLElement} element root node crawled for page actions
         * @param {Object} control control owning functions to call
         */
        function bindMembers(element, control) {
            var elements = element.querySelectorAll('*[data-page-member], *[member]');
            if (elements && elements.length) {
                for (var i = 0, l = elements.length; i < l; i++) {
                    var el = elements[i];
                    bindMember(el, element, control);
                }
            }
        }
        UI.bindMembers = bindMembers;
        /**
         * setup declarative binding to parent control function and to navigation links. It internally invoke both {@link WinJSContrib.UI.bindPageActions} and {@link WinJSContrib.UI.bindPageLinks}
         * @function WinJSContrib.UI.bindActions
         * @param {HTMLElement} element root node crawled for page actions
         * @param {Object} control control owning functions to call
         */
        function bindActions(element, control, item) {
            WinJSContrib.UI.bindPageActions(element, control, item);
            WinJSContrib.UI.bindPageLinks(element, item);
        }
        UI.bindActions = bindActions;
        /**
         * Trigger events on media queries. This class is usefull as a component for other controls to change some properties based on media queries
         * @class WinJSContrib.UI.MediaTrigger
         * @param {Object} items object containing one property for each query
         * @param {Object} linkedControl control linked to media trigger
         */
        var MediaTrigger = (function () {
            function MediaTrigger(items, linkedControl) {
                var ctrl = this;
                ctrl.queries = [];
                ctrl.linkedControl = linkedControl;
                for (var name in items) {
                    var e = items[name];
                    if (e.query) {
                        ctrl.registerMediaEvent(name, e.query, e);
                    }
                }
            }
            /**
             * @function WinJSContrib.UI.MediaTrigger.prototype.dispose
             * release media trigger
             */
            MediaTrigger.prototype.dispose = function () {
                var ctrl = this;
                ctrl.linkedControl = null;
                this.queries.forEach(function (q) {
                    q.dispose();
                });
            };
            /**
             * register an event from a media query
             * @function WinJSContrib.UI.MediaTrigger.prototype.registerMediaEvent
             * @param {string} name event name
             * @param {string} query media query
             * @param {Object} data data associated with this query
             */
            MediaTrigger.prototype.registerMediaEvent = function (name, query, data) {
                var ctrl = this;
                var mq = window.matchMedia(query);
                var internalQuery = {
                    name: name,
                    query: query,
                    data: data,
                    mq: mq,
                    dispose: null
                };
                var f = function (arg) {
                    if (arg.matches) {
                        ctrl._mediaEvent(arg, internalQuery);
                    }
                };
                mq.addListener(f);
                internalQuery.dispose = function () {
                    mq.removeListener(f);
                };
                ctrl.queries.push(internalQuery);
            };
            MediaTrigger.prototype._mediaEvent = function (arg, query) {
                var ctrl = this;
                if (ctrl.linkedControl) {
                    WinJS.UI.setOptions(ctrl.linkedControl, query.data);
                }
                ctrl.dispatchEvent('media', query);
            };
            /**
             * @function WinJSContrib.UI.MediaTrigger.prototype.check
             * Check all registered queries
             */
            MediaTrigger.prototype.check = function () {
                var ctrl = this;
                ctrl.queries.forEach(function (q) {
                    var mq = window.matchMedia(q.query);
                    if (mq.matches) {
                        ctrl._mediaEvent({ matches: true }, q);
                    }
                });
            };
            /**
             * Adds an event listener to the control.
             * @function WinJSContrib.UI.MediaTrigger.prototype.addEventListener
             * @param type The type (name) of the event.
             * @param listener The listener to invoke when the event gets raised.
             * @param useCapture If true, initiates capture, otherwise false.
            **/
            MediaTrigger.prototype.addEventListener = function (type, listener, useCapture) {
            };
            /**
             * Raises an event of the specified type and with the specified additional properties.
             * @function WinJSContrib.UI.MediaTrigger.prototype.dispatchEvent
             * @param type The type (name) of the event.
             * @param eventProperties The set of additional properties to be attached to the event object when the event is raised.
             * @returns true if preventDefault was called on the event.
            **/
            MediaTrigger.prototype.dispatchEvent = function (type, eventProperties) {
                return false;
            };
            /**
             * Removes an event listener from the control.
             * @function WinJSContrib.UI.MediaTrigger.prototype.removeEventListener
             * @param type The type (name) of the event.
             * @param listener The listener to remove.
             * @param useCapture true if capture is to be initiated, otherwise false.
            **/
            MediaTrigger.prototype.removeEventListener = function (type, listener, useCapture) { };
            return MediaTrigger;
        })();
        UI.MediaTrigger = MediaTrigger;
        WinJS.Class.mix(WinJSContrib.UI.MediaTrigger, WinJS.Utilities.eventMixin);
        /**
         * register navigation related events like hardware backbuttons. This method keeps track of previously registered navigation handlers
         *  and disable them until the latests is closed, enablinh multi-level navigation.
         * @function WinJSContrib.UI.registerNavigationEvents
         * @param {Object} control control taking ownership of navigation handlers
         * @param {function} callback callback to invoke when "back" is requested
         * @returns {function} function to call for releasing navigation handlers
         */
        var registeredNavigationStack = [];
        function registerNavigationEvents(control, callback) {
            var locked = [];
            var registration = { control: control, callback: callback };
            registeredNavigationStack.push(registration);
            //control.navLocks = control.navLocks || [];
            //control.navLocks.isActive = true;
            var backhandler = function (arg) {
                var idx = registeredNavigationStack.indexOf(registration);
                if (idx === registeredNavigationStack.length - 1) {
                    registration.callback.bind(registration.control)(arg);
                    idx--;
                    while (idx >= 0 && !arg.handled) {
                        var tmp = registeredNavigationStack[idx];
                        tmp.callback.bind(tmp.control)(arg);
                        idx--;
                    }
                }
                //if (!control.navLocks || control.navLocks.length === 0) {
                //    callback.bind(control)(arg);
                //}
            };
            //var navcontrols = document.querySelectorAll('.mcn-navigation-ctrl');
            //for (var i = 0; i < navcontrols.length; i++) {
            //    var navigationCtrl = (<any>navcontrols[i]).winControl;
            //    if (navigationCtrl && navigationCtrl != control) {
            //        navigationCtrl.navLocks = navigationCtrl.navLocks || [];
            //        if (navigationCtrl.navLocks.isActive && (!navigationCtrl.navLocks.length || navigationCtrl.navLocks.indexOf(control) < 0)) {
            //            navigationCtrl.navLocks.push(control);
            //            locked.push(navigationCtrl);
            //        }
            //    }
            //}
            function cancelNavigation(args) {
                //this.eventTracker.addEvent(nav, 'beforenavigate', this._beforeNavigate.bind(this));
                var p = new WinJS.Promise(function (c) { });
                args.detail.setPromise(p);
                //setImmediate(function () {
                p.cancel();
                //});
            }
            WinJS.Navigation.addEventListener('beforenavigate', cancelNavigation);
            if (window.Windows && window.Windows.Phone)
                window.Windows.Phone.UI.Input.HardwareButtons.addEventListener("backpressed", backhandler);
            else {
                document.addEventListener("backbutton", backhandler);
                var systemNavigationManager = null;
                if (WinJSContrib.UI && WinJSContrib.UI.enableSystemBackButtonVisibility && window.Windows && window.Windows.UI && window.Windows.UI.Core && window.Windows.UI.Core.SystemNavigationManager) {
                    systemNavigationManager = window.Windows.UI.Core.SystemNavigationManager.getForCurrentView();
                    systemNavigationManager.addEventListener('backrequested', backhandler);
                }
            }
            var keypress = function (args) {
                if (args.key === "Esc" || args.key === "Backspace") {
                    backhandler(args);
                }
            };
            document.body.addEventListener('keypress', keypress);
            if (WinJSContrib.UI.Application && WinJSContrib.UI.Application.navigator)
                WinJSContrib.UI.Application.navigator.addLock();
            return function () {
                if (WinJSContrib.UI.Application && WinJSContrib.UI.Application.navigator)
                    WinJSContrib.UI.Application.navigator.removeLock();
                //control.navLocks.isActive = false;
                //locked.forEach(function (navigationCtrl) {
                //    var idx = navigationCtrl.navLocks.indexOf(control);
                //    if (idx >= 0)
                //        navigationCtrl.navLocks.splice(idx, 1);
                //});
                var idx = registeredNavigationStack.indexOf(registration);
                registeredNavigationStack.splice(idx, 1);
                document.body.removeEventListener('keypress', keypress);
                WinJS.Navigation.removeEventListener('beforenavigate', cancelNavigation);
                if (window.Windows && window.Windows.Phone)
                    window.Windows.Phone.UI.Input.HardwareButtons.removeEventListener("backpressed", backhandler);
                else {
                    document.removeEventListener("backbutton", backhandler);
                    var systemNavigationManager = null;
                    if (WinJSContrib.UI && WinJSContrib.UI.enableSystemBackButtonVisibility && window.Windows && window.Windows.UI && window.Windows.UI.Core && window.Windows.UI.Core.SystemNavigationManager) {
                        systemNavigationManager = window.Windows.UI.Core.SystemNavigationManager.getForCurrentView();
                        systemNavigationManager.removeEventListener('backrequested', backhandler);
                    }
                }
            };
        }
        UI.registerNavigationEvents = registerNavigationEvents;
        /**
         * remove tap behavior
         * @function WinJSContrib.UI.untap
         * @param {HtmlElement} element element to clean
         */
        function untap(element) {
            if (!element)
                return;
            if (element.mcnTapTracking) {
                element.mcnTapTracking.dispose();
                element.mcnTapTracking = null;
            }
        }
        UI.untap = untap;
        /**
         * remove tap behavior from all childs
         * @function WinJSContrib.UI.untapAll
         * @param {HtmlElement} element element to clean
         */
        function untapAll(element) {
            if (!element)
                return;
            var taps = element.querySelectorAll('.tap');
            for (var i = 0, l = taps.length; i < l; i++) {
                untap(taps[i]);
            }
        }
        UI.untapAll = untapAll;
        UI.defaultTapBehavior = {
            animDown: null,
            animUp: null,
            disableAnimation: false,
            disableAria: false,
            awaitAnim: false,
            errorDelay: 3000,
            mapClickEvents: 0
        };
        if (WinJS && WinJS.UI && WinJS.UI.Animation) {
            UI.defaultTapBehavior.animDown = WinJS.UI.Animation.pointerDown;
            UI.defaultTapBehavior.animUp = WinJS.UI.Animation.pointerUp;
        }
        /**
         * add tap behavior to an element, tap manages quirks like click delay, visual feedback, etc
         * @function WinJSContrib.UI.tap
         * @param {HtmlElement} element element to make "tappable"
         * @param {function} callback callback function invoked on tap
         * @param {Object} options tap options
         */
        function tap(element, callback, options) {
            if (!element)
                return;
            var ptDown = function (event) {
                var elt = event.currentTarget || event.target;
                var tracking = elt.mcnTapTracking;
                if (!elt.disabled && tracking && (event.button === undefined || event.button === 0 || (tracking.allowRickClickTap && event.button === 2))) {
                    if (tracking.lock) {
                        if (event.pointerId && event.currentTarget.setPointerCapture)
                            event.currentTarget.setPointerCapture(event.pointerId);
                        event.stopPropagation();
                        event.preventDefault();
                    }
                    WinJS.Utilities.addClass(elt, 'tapped');
                    WinJS.Utilities.removeClass(elt, 'tap-error');
                    clearTimeout(tracking.pendingErrorTimeout);
                    if (event.changedTouches) {
                        tracking.pointerdown = { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
                    }
                    else {
                        tracking.pointerdown = { x: event.clientX, y: event.clientY };
                    }
                    tracking.animDown(event.currentTarget);
                    if (tracking.tapOnDown) {
                        tracking.invoke(elt, event);
                    }
                }
            };
            var ptOut = function (event) {
                var elt = event.currentTarget || event.target;
                var tracking = elt.mcnTapTracking;
                if (tracking && tracking.pointerdown) {
                    WinJS.Utilities.removeClass(elt, 'tapped');
                    if (event.pointerId && elt.releasePointerCapture) {
                        try {
                            elt.releasePointerCapture(event.pointerId);
                        }
                        catch (exception) {
                            console.error(exception);
                        }
                    }
                    if (!tracking.disableAnimation)
                        tracking.animUp(event.currentTarget);
                }
            };
            var ptUp = function (event) {
                var elt = event.currentTarget || event.target;
                var tracking = elt.mcnTapTracking;
                if (tracking && (event.button === undefined || event.button === 0 || (tracking.allowRickClickTap && event.button === 2))) {
                    if (elt.releasePointerCapture) {
                        try {
                            elt.releasePointerCapture(event.pointerId);
                        }
                        catch (exception) {
                            console.error(exception);
                        }
                    }
                    if (tracking && !tracking.tapOnDown) {
                        event.stopPropagation();
                        var resolveTap = function () {
                            if (tracking && tracking.pointerdown) {
                                if (event.changedTouches) {
                                    var dX = Math.abs(tracking.pointerdown.x - event.changedTouches[0].clientX);
                                    var dY = Math.abs(tracking.pointerdown.y - event.changedTouches[0].clientY);
                                }
                                else {
                                    var dX = Math.abs(tracking.pointerdown.x - event.clientX);
                                    var dY = Math.abs(tracking.pointerdown.y - event.clientY);
                                }
                                if (tracking.callback && dX < 15 && dY < 15) {
                                    event.stopImmediatePropagation();
                                    event.stopPropagation();
                                    event.preventDefault();
                                    tracking.invoke();
                                }
                                if (tracking && tracking.pointerdown)
                                    tracking.pointerdown = undefined;
                            }
                        };
                        if (tracking.awaitAnim) {
                            tracking.animUp(elt).done(resolveTap);
                        }
                        else {
                            tracking.animUp(elt);
                            resolveTap();
                        }
                    }
                    WinJS.Utilities.removeClass(elt, 'tapped');
                }
            };
            if (!options) {
                var attroptions = element.getAttribute('tap-options');
                if (attroptions) {
                    try {
                        options = WinJS.UI.optionsParser(attroptions, window);
                    }
                    catch (exception) {
                        return;
                    }
                }
            }
            var opt = options || {};
            if (element.mcnTapTracking) {
                element.mcnTapTracking.dispose();
            }
            WinJS.Utilities.addClass(element, 'tap');
            element.mcnTapTracking = element.mcnTapTracking || {};
            element.mcnTapTracking.disableAria = opt.disableAria || UI.defaultTapBehavior.disableAria;
            if (!element.mcnTapTracking.disableAria) {
                if (!element.hasAttribute("tabindex"))
                    element.setAttribute("tabindex", "0");
                if (!element.hasAttribute("role"))
                    element.setAttribute("role", "button");
            }
            element.mcnTapTracking.eventTracker = new WinJSContrib.UI.EventTracker();
            element.mcnTapTracking.disableAnimation = opt.disableAnimation || UI.defaultTapBehavior.disableAnimation;
            if (element.mcnTapTracking.disableAnimation) {
                if (opt.disableAnimation)
                    WinJS.Utilities.addClass(element, 'tap-disableanimation');
                element.mcnTapTracking.animDown = function () { return WinJS.Promise.wrap(); };
                element.mcnTapTracking.animUp = function () { return WinJS.Promise.wrap(); };
            }
            else {
                element.mcnTapTracking.animDown = opt.animDown || UI.defaultTapBehavior.animDown;
                element.mcnTapTracking.animUp = opt.animUp || UI.defaultTapBehavior.animUp;
            }
            element.mcnTapTracking.element = element;
            element.mcnTapTracking.callback = callback;
            element.mcnTapTracking.lock = opt.lock;
            element.mcnTapTracking.awaitAnim = opt.awaitAnim || UI.defaultTapBehavior.awaitAnim;
            element.mcnTapTracking.errorDelay = opt.errorDelay || UI.defaultTapBehavior.errorDelay;
            element.mcnTapTracking.mapClickEvents = opt.mapClickEvents || UI.defaultTapBehavior.mapClickEvents;
            element.mcnTapTracking.tapOnDown = opt.tapOnDown;
            element.mcnTapTracking.pointerModel = 'none';
            element.mcnTapTracking.invoke = function (arg) {
                var elt = element;
                if (elt && elt.mcnTapTracking) {
                    var tracking = elt.mcnTapTracking;
                    if (tracking) {
                        var now = (new Date());
                        var dif = 9000;
                        if (tracking.lastinvoke) {
                            dif = now - tracking.lastinvoke;
                        }
                        if (dif < tracking.mapClickEvents) {
                            arg.preventDefault();
                            arg.stopPropagation();
                            return;
                        }
                        var res = tracking.callback(elt, arg);
                        tracking.lastinvoke = new Date();
                        if (res && WinJS.Promise.is(res)) {
                            elt.disabled = true;
                            WinJS.Utilities.addClass(elt, 'tap-working');
                            res.then(function () {
                                elt.disabled = false;
                                WinJS.Utilities.removeClass(elt, 'tap-working');
                            }, function (err) {
                                elt.disabled = false;
                                WinJS.Utilities.removeClass(elt, 'tap-working');
                                console.error(err);
                                WinJS.Application.queueEvent({ type: "mcn-taperror", error: err });
                                WinJS.Utilities.addClass(elt, 'tap-error');
                                if (tracking.errorDelay) {
                                    tracking.pendingErrorTimeout = setTimeout(function () {
                                        tracking.pendingErrorTimeout = null;
                                        WinJS.Utilities.removeClass(elt, 'tap-error');
                                    }, tracking.errorDelay);
                                }
                            });
                        }
                    }
                }
            };
            if (element.mcnTapTracking.mapClickEvents > 0) {
                element.onclick = function (arg) {
                    if (element && arg.target == element && element.mcnTapTracking) {
                        element.mcnTapTracking.invoke(arg);
                    }
                };
            }
            element.mcnTapTracking.dispose = function () {
                WinJS.Utilities.removeClass(element, 'tap');
                this.eventTracker.dispose();
                element.mcnTapTracking = null;
                element = null;
            };
            if (element.onpointerdown !== undefined) {
                element.mcnTapTracking.pointerModel = 'pointers';
                element.mcnTapTracking.eventTracker.addEvent(element, 'pointerdown', ptDown);
                element.mcnTapTracking.eventTracker.addEvent(element, 'pointerout', ptOut);
                element.mcnTapTracking.eventTracker.addEvent(element, 'pointerup', ptUp);
            }
            else if (window.Touch && !opt.noWebkitTouch) {
                element.mcnTapTracking.pointerModel = 'touch';
                element.mcnTapTracking.eventTracker.addEvent(element, 'touchstart', function (arg) {
                    element.mcnTapTracking.cancelMouse = true;
                    ptDown(arg);
                });
                element.mcnTapTracking.eventTracker.addEvent(element, 'touchcancel', function (arg) {
                    setTimeout(function () {
                        if (element && element.mcnTapTracking)
                            element.mcnTapTracking.cancelMouse = false;
                    }, 1000);
                    ptOut(arg);
                });
                element.mcnTapTracking.eventTracker.addEvent(element, 'touchend', function (arg) {
                    setTimeout(function () {
                        if (element && element.mcnTapTracking)
                            element.mcnTapTracking.cancelMouse = false;
                    }, 1000);
                    ptUp(arg);
                });
                element.mcnTapTracking.eventTracker.addEvent(element, 'mousedown', function (arg) {
                    if (!element.mcnTapTracking.cancelMouse)
                        ptDown(arg);
                });
                element.mcnTapTracking.eventTracker.addEvent(element, 'mouseleave', function (arg) {
                    ptOut(arg);
                });
                element.mcnTapTracking.eventTracker.addEvent(element, 'mouseup', function (arg) {
                    if (!element.mcnTapTracking.cancelMouse)
                        ptUp(arg);
                    else
                        ptOut(arg);
                });
            }
            else {
                element.mcnTapTracking.pointerModel = 'mouse';
                element.mcnTapTracking.eventTracker.addEvent(element, 'mousedown', ptDown);
                element.mcnTapTracking.eventTracker.addEvent(element, 'mouseleave', ptOut);
                element.mcnTapTracking.eventTracker.addEvent(element, 'mouseup', ptUp);
            }
        }
        UI.tap = tap;
        /**
         * return a promise completed after css transition on the element is ended
         * @function WinJSContrib.UI.afterTransition
         * @param {HtmlElement} element element to watch
         * @param {number} timeout timeout
         */
        function afterTransition(element, timeout) {
            var timeOutRef = null;
            return new WinJS.Promise(function (complete, error) {
                var onaftertransition = function (event) {
                    if (event.srcElement === element) {
                        close();
                    }
                };
                var close = function () {
                    clearTimeout(timeOutRef);
                    element.removeEventListener("transitionend", onaftertransition, false);
                    complete();
                };
                element.addEventListener("transitionend", onaftertransition, false);
                timeOutRef = setTimeout(close, timeout || 1000);
            });
        }
        UI.afterTransition = afterTransition;
        /**
         * Utility class for building DOM elements through code with a fluent API
         * @class WinJSContrib.UI.FluentDOM
         * @param {string} nodeType type of DOM node (ex: 'DIV')
         * @param className css classes
         * @param parentElt parent DOM element
         * @param {WinJSContrib.UI.FluentDOM} parent parent FluentDOM
         * @example
         * var elt = new WinJSContrib.UI.FluentDOM('DIV', 'item-content')
         *    .text(item.title)
         *    .display('none')
         *    .element;
         */
        var FluentDOM = (function () {
            function FluentDOM(nodeType, className, parentElt, parent) {
                this.element = document.createElement(nodeType);
                if (className)
                    this.element.className = className;
                if (parentElt)
                    parentElt.appendChild(this.element);
                this.parent = parent;
                this.childs = [];
                if (parent) {
                    parent.childs.push(this);
                }
            }
            FluentDOM.for = function (element) {
                var res = new FluentDOM(null);
                res.element = element;
                return res;
            };
            FluentDOM.fragment = function () {
                var res = new FluentDOM(null);
                res.element = document.createDocumentFragment();
                return res;
            };
            Object.defineProperty(FluentDOM.prototype, "control", {
                get: function () {
                    return this.element.winControl;
                },
                enumerable: true,
                configurable: true
            });
            /**
             * Add a css class
             * @function WinJSContrib.UI.FluentDOM.prototype.addClass
             * @param classname css class
             * @returns {WinJSContrib.UI.FluentDOM}
             */
            FluentDOM.prototype.addClass = function (classname) {
                if (this.element)
                    this.element.classList.add(classname);
                return this;
            };
            /**
             * set className
             * @function WinJSContrib.UI.FluentDOM.prototype.className
             * @param classname css classes
             * @returns {WinJSContrib.UI.FluentDOM}
             */
            FluentDOM.prototype.className = function (classname) {
                if (this.element)
                    this.element.className = classname;
                return this;
            };
            /**
             * set opacity
             * @function WinJSContrib.UI.FluentDOM.prototype.opacity
             * @param opacity opacity
             * @returns {WinJSContrib.UI.FluentDOM}
             */
            FluentDOM.prototype.opacity = function (opacity) {
                if (this.element)
                    this.element.style.opacity = opacity;
                return this;
            };
            /**
             * set display
             * @function WinJSContrib.UI.FluentDOM.prototype.display
             * @param display display
             * @returns {WinJSContrib.UI.FluentDOM}
             */
            FluentDOM.prototype.display = function (display) {
                if (this.element)
                    this.element.style.display = display;
                return this;
            };
            /**
             * set display 'none'
             * @function WinJSContrib.UI.FluentDOM.prototype.hide
             * @returns {WinJSContrib.UI.FluentDOM}
             */
            FluentDOM.prototype.hide = function () {
                if (this.element)
                    this.element.style.display = 'none';
                return this;
            };
            /**
             * set visibility
             * @function WinJSContrib.UI.FluentDOM.prototype.visibility
             * @param visibility visibility
             * @returns {WinJSContrib.UI.FluentDOM}
             */
            FluentDOM.prototype.visibility = function (visibility) {
                if (this.element)
                    this.element.style.visibility = visibility;
                return this;
            };
            /**
             * set textContent
             * @function WinJSContrib.UI.FluentDOM.prototype.text
             * @param text text
             * @returns {WinJSContrib.UI.FluentDOM}
             */
            FluentDOM.prototype.text = function (text) {
                if (this.element)
                    this.element.textContent = text;
                return this;
            };
            /**
             * set innerHTML
             * @function WinJSContrib.UI.FluentDOM.prototype.html
             * @param text text
             * @returns {WinJSContrib.UI.FluentDOM}
             */
            FluentDOM.prototype.html = function (text) {
                if (this.element)
                    this.element.innerHTML = text;
                return this;
            };
            /**
             * set attribute
             * @function WinJSContrib.UI.FluentDOM.prototype.attr
             * @param name attribute name
             * @param val attribute value
             * @returns {WinJSContrib.UI.FluentDOM}
             */
            FluentDOM.prototype.attr = function (name, val) {
                if (this.element)
                    this.element.setAttribute(name, val);
                return this;
            };
            /**
             * set style property
             * @function WinJSContrib.UI.FluentDOM.prototype.style
             * @param name attribute name
             * @param val attribute value
             * @returns {WinJSContrib.UI.FluentDOM}
             */
            FluentDOM.prototype.style = function (name, val) {
                if (this.element)
                    this.element.style[name] = val;
                return this;
            };
            /**
             * set style property
             * @function WinJSContrib.UI.FluentDOM.prototype.style
             * @param name attribute name
             * @param val attribute value
             * @returns {WinJSContrib.UI.FluentDOM}
             */
            FluentDOM.prototype.styles = function (obj) {
                var st = this.element.style;
                var keys = Object.keys(obj);
                keys.forEach(function (k) {
                    st[k] = obj[k];
                });
                return this;
            };
            /**
             * append element to another DOM element
             * @function WinJSContrib.UI.FluentDOM.prototype.appendTo
             * @param elt parent element
             * @returns {WinJSContrib.UI.FluentDOM}
             */
            FluentDOM.prototype.appendTo = function (elt) {
                if (this.element && elt)
                    elt.appendChild(this.element);
                return this;
            };
            /**
             * add tap behavior
             * @function WinJSContrib.UI.FluentDOM.prototype.tap
             * @param callback tap callback
             * @param options tap options
             * @returns {WinJSContrib.UI.FluentDOM}
             */
            FluentDOM.prototype.tap = function (callback, options) {
                if (this.element)
                    WinJSContrib.UI.tap(this.element, callback, options);
                return this;
            };
            /**
             * create a child FluentDOM and append it to current
             * @function WinJSContrib.UI.FluentDOM.prototype.append
             * @param nodeType child node type
             * @param className css classes
             * @param callback callback receiving the new FluentDOM as an argument
             * @returns {WinJSContrib.UI.FluentDOM} current instance (for method chaining)
             */
            FluentDOM.prototype.append = function (nodeType, className, callback) {
                var child = new FluentDOM(nodeType, className, this.element, this);
                if (callback) {
                    callback(child);
                }
                return this;
            };
            /**
             * create a child FluentDOM and append it to current
             * @function WinJSContrib.UI.FluentDOM.prototype.createChild
             * @param nodeType child node type
             * @param className css classes
             * @returns {WinJSContrib.UI.FluentDOM} child FluentDOM
             */
            FluentDOM.prototype.createChild = function (nodeType, className) {
                var child = new FluentDOM(nodeType, className, this.element, this);
                return child;
            };
            /**
             * create a WinJS control
             * @function WinJSContrib.UI.FluentDOM.prototype.ctrl
             * @param ctrl constructor or full name of the control
             * @param options control options
             * @returns {WinJSContrib.UI.FluentDOM}
             */
            FluentDOM.prototype.ctrl = function (ctrl, options) {
                var ctor = ctrl;
                if (typeof ctrl === 'string')
                    ctor = WinJSContrib.Utils.readProperty(window, ctrl);
                if (ctor) {
                    new ctor(this.element, options);
                }
                return this;
            };
            return FluentDOM;
        })();
        UI.FluentDOM = FluentDOM;
        function dismissableShow(targetElement, classPrefix, animationTarget) {
            animationTarget = animationTarget || targetElement;
            targetElement.classList.add(classPrefix + "-enter");
            targetElement.getBoundingClientRect();
            targetElement.classList.remove(classPrefix + "-leave");
            targetElement.classList.remove(classPrefix + "-leave-active");
            //setImmediate(() => {
            WinJSContrib.UI.afterTransition(animationTarget).then(function () {
                //if (targetElement.classList.contains(classPrefix + "-lea")) {
                //    targetElement.classList.remove(classPrefix + "-enter");
                //    targetElement.classList.remove(classPrefix + "-enter-active");
                //}
            });
            targetElement.classList.add(classPrefix + "-enter-active");
            //});
        }
        UI.dismissableShow = dismissableShow;
        function dismissableHide(targetElement, classPrefix, animationTarget) {
            animationTarget = animationTarget || targetElement;
            targetElement.classList.add(classPrefix + "-leave");
            targetElement.classList.remove(classPrefix + "-enter");
            targetElement.classList.remove(classPrefix + "-enter-active");
            setImmediate(function () {
                WinJSContrib.UI.afterTransition(animationTarget).then(function () {
                    targetElement.classList.remove(classPrefix + "-leave");
                    targetElement.classList.remove(classPrefix + "-leave-active");
                });
                targetElement.classList.add(classPrefix + "-leave-active");
            });
        }
        UI.dismissableHide = dismissableHide;
        function forwardFocus(container, focusTarget, allowed) {
            var isInContainer = function (elt) {
                while (elt.parentElement && elt.parentElement != container) {
                    elt = elt.parentElement;
                }
                if (elt.parentElement == container)
                    return true;
                return false;
            };
            var focusManager = function (arg) {
                if (!isInContainer(arg.target) && (!allowed || !(allowed.indexOf(arg.target) >= 0))) {
                    focusTarget.focus();
                }
            };
            document.addEventListener("focus", focusManager, true);
            return function () {
                document.removeEventListener("focus", focusManager);
            };
        }
        UI.forwardFocus = forwardFocus;
    })(UI = WinJSContrib.UI || (WinJSContrib.UI = {}));
})(WinJSContrib || (WinJSContrib = {}));

var __global = this;
var profiler = __global.msWriteProfilerMark || function () { };
var WinJSContrib;
(function (WinJSContrib) {
    var UI;
    (function (UI) {
        var Pages;
        (function (Pages) {
            function abs(uri) {
                var a = window.document.createElement("a");
                a.href = uri;
                return a.href;
            }
            var logger = WinJSContrib.Logs.getLogger("WinJSContrib.UI.Pages");
            Pages.verboseTraces = false;
            Pages.preloadDelay = 500;
            var loadedPages = {};
            function preload() {
                var pathes = [];
                for (var _i = 0; _i < arguments.length; _i++) {
                    pathes[_i - 0] = arguments[_i];
                }
                return WinJSContrib.Promise.waterfall(pathes, function (path) {
                    return preloadPath(path);
                });
            }
            Pages.preload = preload;
            function preloadPath(path) {
                var absuri = abs(path);
                if (!loadedPages[absuri]) {
                    logger.verbose("preload " + absuri);
                    loadedPages[absuri] = true;
                    return WinJS.Promise.timeout(Pages.preloadDelay).then(function () {
                        return WinJS.Utilities.Scheduler.schedule(function () {
                            var wrapper = document.createDocumentFragment();
                            var elt = document.createElement("DIV");
                            wrapper.appendChild(elt);
                            WinJS.UI.Fragments.render(absuri, elt);
                        }, WinJS.Utilities.Scheduler.Priority.idle, {}, "preload|" + absuri);
                    });
                }
                return WinJS.Promise.wrap();
            }
            Pages.preloadPath = preloadPath;
            /**
             * List of mixins to apply to each fragment managed by WinJS Contrib (through navigator or by calling explicitely {@link WinJSContrib.UI.Pages.fragmentMixin}).
             * @field WinJSContrib.UI.Pages.defaultFragmentMixins
             * @type {Array}
             */
            Pages.defaultFragmentMixins = [{
                    $: function (selector) {
                        return $(selector, this.element || this._element);
                    },
                    q: function (selector) {
                        if (!this.element)
                            return;
                        return this.element.querySelector(selector);
                    },
                    qAll: function (selector) {
                        if (!this.element)
                            return;
                        var res = this.element.querySelectorAll(selector);
                        if (res && !res.forEach) {
                            res = [].slice.call(res);
                        }
                        return res;
                    },
                },
                {
                    initPageMixin: function () {
                        this.promises = [];
                    },
                    disposePageMixin: function () {
                        if (this.promises) {
                            this.cancelPromises();
                            this.promises = null;
                        }
                    },
                    addPromise: function (prom) {
                        this.promises.push(prom);
                        return prom;
                    },
                    cancelPromises: function () {
                        var page = this;
                        if (page.promises) {
                            for (var i = 0; i < page.promises.length; i++) {
                                if (page.promises[i]) {
                                    page.promises[i].cancel();
                                }
                            }
                            page.promises = [];
                        }
                    }
                },
                {
                    initPageMixin: function () {
                        this.eventTracker = new WinJSContrib.UI.EventTracker();
                    },
                    disposePageMixin: function () {
                        if (this.eventTracker) {
                            this.eventTracker.dispose();
                            this.eventTracker = null;
                        }
                    },
                }];
            function broadcast(ctrl, element, eventName, args, before, after) {
                var promises = [];
                if (before)
                    promises.push(WinJS.Promise.as(before.apply(ctrl, args)));
                var query = element.querySelectorAll(".mcn-layout-ctrl");
                if (query && query.length) {
                    var index = 0;
                    var length = query.length;
                    while (index < length) {
                        var childctrl = query[index];
                        if (childctrl) {
                            var event = childctrl.winControl[eventName];
                            if (event) {
                                if (childctrl.winControl.pageLifeCycle) {
                                    promises.push(childctrl.winControl.pageLifeCycle.steps.layout.promise);
                                }
                                else {
                                    promises.push(WinJS.Promise.as(event.apply(childctrl.winControl, args)));
                                }
                            }
                        }
                        // Skip descendants
                        if (childctrl && childctrl.winControl && childctrl.winControl.pageLifeCycle) {
                            index += childctrl.querySelectorAll(".mcn-fragment, .mcn-layout-ctrl").length + 1;
                            childctrl.winControl.__checkLayout();
                        }
                        else {
                            index += 1;
                        }
                    }
                    //if (after)
                    //    promises.push(WinJS.Promise.as(after.apply(ctrl, args)));
                    return WinJS.Promise.join(promises).then(function () {
                        if (after)
                            return WinJS.Promise.as(after.apply(ctrl, args));
                    });
                }
                else {
                    if (after)
                        return WinJS.Promise.as(after.apply(ctrl, args));
                    return WinJS.Promise.wrap();
                }
            }
            /**
             * render a html fragment with winjs contrib pipeline and properties, and add WinJS Contrib page events.
             * @function WinJSContrib.UI.Pages.renderFragment
             * @param {HTMLElement} container element that will contain the fragment
             * @param {string} location url for the fragment
             * @param {Object} args arguments to the fragment
             * @param {Object} options rendering options
             */
            function renderFragment(container, location, args, options) {
                var fragmentCompleted;
                var fragmentError;
                options = options || {};
                var element = document.createElement("div");
                element.setAttribute("dir", __global.getComputedStyle(element, null).direction);
                element.style.opacity = '0';
                container.appendChild(element);
                var fragmentPromise = new WinJS.Promise(function (c, e) { fragmentCompleted = c; fragmentError = e; });
                var parented = options.parented ? WinJS.Promise.as(options.parented) : null;
                var layoutCtrls = [];
                var pageConstructor = WinJS.UI.Pages.get(location);
                function preparePageControl(elementCtrl) {
                    if (options.getFragmentElement) {
                        options.getFragmentElement(elementCtrl);
                    }
                    if (args && args.injectToPage) {
                        WinJSContrib.Utils.inject(elementCtrl, args.injectToPage);
                    }
                    elementCtrl.navigationState = { location: location, state: args };
                    if (options.oncreate) {
                        options.oncreate(elementCtrl.element, args);
                    }
                    if (options.oninit) {
                        elementCtrl.pageLifeCycle.steps.init.attach(function () {
                            return options.oninit(elementCtrl.element, args);
                        });
                    }
                    if (elementCtrl.enterPageAnimation || options.enterPage) {
                        if (elementCtrl.enterPageAnimation)
                            elementCtrl._enterAnimation = elementCtrl.enterPageAnimation;
                        else
                            elementCtrl._enterAnimation = options.enterPage;
                        elementCtrl.enterPageAnimation = function () {
                            var page = this;
                            var elts = null;
                            element.style.opacity = '';
                            if (page && page.getAnimationElements) {
                                elts = page.getAnimationElements(false);
                            }
                            else {
                                elts = page.element;
                            }
                            if (elts)
                                return page._enterAnimation(elts);
                        };
                    }
                    if (options.onrender) {
                        elementCtrl.pageLifeCycle.steps.process.attach(function () {
                            options.onrender(elementCtrl.element, args);
                        });
                    }
                    if (!WinJSContrib.UI.disableAutoResources) {
                        elementCtrl.pageLifeCycle.steps.process.attach(function () {
                            return WinJS.Resources.processAll(element);
                        });
                    }
                    if (options.closeOldPagePromise) {
                        elementCtrl.pageLifeCycle.steps.ready.attach(function () {
                            return options.closeOldPagePromise;
                        });
                    }
                    if (options.onready) {
                        elementCtrl.pageLifeCycle.steps.ready.attach(function () {
                            if (options.onready)
                                options.onready(elementCtrl.element, args);
                        });
                    }
                    elementCtrl.pageLifeCycle.steps.enter.attach(function () {
                        if (elementCtrl.enterPageAnimation) {
                            return WinJS.Promise.as(elementCtrl.enterPageAnimation(element, options));
                        }
                        else {
                            elementCtrl.element.style.opacity = '';
                        }
                    });
                    elementCtrl.pageLifeCycle.steps.ready.promise.then(fragmentCompleted, fragmentError);
                }
                var elementCtrl = new pageConstructor(element, args, preparePageControl, parented);
                return fragmentPromise;
            }
            Pages.renderFragment = renderFragment;
            var DefferedLoadings = (function () {
                function DefferedLoadings(page) {
                    var _this = this;
                    this.items = [];
                    this.page = page;
                    this.resolved = false;
                    page.promises.push(page.pageLifeCycle.steps.ready.promise.then(function () {
                        return _this.resolve();
                    }));
                }
                DefferedLoadings.prototype.push = function (delegate) {
                    var _this = this;
                    if (!this.resolved) {
                        this.items.push(delegate);
                    }
                    else {
                        setImmediate(function () {
                            _this.page.promises.push(WinJS.Promise.as(delegate()));
                        });
                    }
                };
                DefferedLoadings.prototype.resolve = function () {
                    this.resolved = true;
                    if (!this.items.length) {
                        return WinJS.Promise.wrap();
                    }
                    logger.verbose("resolve deffered loads");
                    return WinJSContrib.Promise.waterfall(this.items, function (job) {
                        return WinJS.Promise.as(job()).then(function () {
                            return WinJS.Promise.timeout();
                        });
                    });
                };
                return DefferedLoadings;
            })();
            Pages.DefferedLoadings = DefferedLoadings;
            var PageBase = (function () {
                function PageBase() {
                }
                return PageBase;
            })();
            Pages.PageBase = PageBase;
            var PageLifeCycleStep = (function () {
                function PageLifeCycleStep(page, stepName, parent) {
                    var _this = this;
                    this.page = page;
                    this.queue = [];
                    this.isDone = false;
                    this.stepName = stepName;
                    if (Pages.verboseTraces) {
                        this.created = new Date();
                    }
                    this.promise = new WinJS.Promise(function (c, e) {
                        _this._resolvePromise = c;
                        _this._rejectPromise = e;
                    });
                    page.promises.push(this.promise);
                    //if their is a parent page fragment, we attach step to synchronize page construction
                    if (parent && parent.pageLifeCycle) {
                        parent.pageLifeCycle.steps[stepName].attach(function () {
                            return _this.promise;
                        });
                    }
                }
                PageLifeCycleStep.prototype.attach = function (callback) {
                    if (this.queue && !this.isDone) {
                        this.queue.push(callback);
                        return this.promise;
                    }
                    else {
                        return WinJS.Promise.as(callback());
                    }
                };
                PageLifeCycleStep.prototype.resolve = function (arg) {
                    var step = this;
                    this.isDone = true;
                    function closeStep() {
                        step.resolved = new Date();
                        step._resolvePromise(arg);
                        if (Pages.verboseTraces) {
                            step.resolved = new Date();
                            logger.verbose((step.resolved - step.created) + 'ms ' + step.stepName.toUpperCase() + ' ' + step.page.pageLifeCycle.profilerMarkIdentifier);
                            profiler("WinJS.UI.Pages:" + step.stepName.toUpperCase() + step.page.pageLifeCycle.profilerMarkIdentifier + ",StartTM");
                        }
                        return step.promise;
                    }
                    if (this.queue && this.queue.length) {
                        var promises = [];
                        this.queue.forEach(function (q) {
                            promises.push(new WinJS.Promise(function (c, e) {
                                try {
                                    WinJS.Promise.as(q()).then(function (res) {
                                        c(res);
                                    }, e);
                                }
                                catch (exception) {
                                    e(exception);
                                }
                            }));
                        });
                        this.queue = null;
                        return WinJS.Promise.join(promises).then(function () {
                            return closeStep();
                        }, this.reject.bind(this));
                    }
                    else {
                        this.queue = null;
                        return closeStep();
                    }
                };
                PageLifeCycleStep.prototype.reject = function (arg) {
                    this.isDone = true;
                    this.queue = null;
                    this._rejectPromise(arg);
                    return WinJS.Promise.wrapError(this.promise);
                };
                return PageLifeCycleStep;
            })();
            Pages.PageLifeCycleStep = PageLifeCycleStep;
            (function (_Pages, _Global, _Base, _CorePages, _BaseUtils, _ElementUtilities, _WriteProfilerMark, Promise, Fragments, ControlProcessor) {
                'use strict';
                if (!_Global.document || !_CorePages)
                    return;
                var viewMap = _CorePages._viewMap || _CorePages.viewMap || {};
                //this property allows defining mixins applyed to all pages
                function abs(uri) {
                    var a = _Global.document.createElement("a");
                    a.href = uri;
                    return a.href;
                }
                function selfhost(uri) {
                    return _Global.document.location.href.toLowerCase() === uri.toLowerCase();
                }
                var _mixinBase = {
                    dispose: function () {
                        /// <signature helpKeyword="WinJS.UI.Pages.dispose">
                        /// <summary locid="WinJS.UI.Pages.dispose">
                        /// Disposes this Page.
                        /// </summary>
                        /// </signature>
                        if (this._disposed) {
                            return;
                        }
                        if (this.disposePageMixin) {
                            this.disposePageMixin();
                        }
                        this.pageLifeCycle.stop();
                        this.pageLifeCycle = null;
                        this._disposed = true;
                        this.readyComplete.cancel();
                        _ElementUtilities.disposeSubTree(this.element);
                        this.element = null;
                    },
                    init: function () {
                    },
                    load: function (uri) {
                        /// <signature helpKeyword="WinJS.UI.Pages._mixin.load">
                        /// <summary locid="WinJS.UI.Pages._mixin.load">
                        /// Creates a copy of the DOM elements from the specified URI.  In order for this override
                        /// to be used, the page that contains the load override needs to be defined by calling
                        /// WinJS.UI.Pages.define() before WinJS.UI.Pages.render() is called.
                        /// </summary>
                        /// <param name="uri" locid="WinJS.UI.Pages._mixin.load_p:uri">
                        /// The URI from which to copy the DOM elements.
                        /// </param>
                        /// <returns type="WinJS.Promise" locid="WinJS.UI.Pages._mixin.load_returnValue">
                        /// A promise whose fulfilled value is the set of unparented DOM elements, if asynchronous processing is necessary. If not, returns nothing.
                        /// </returns>
                        /// </signature>
                        if (!this.selfhost) {
                            return Fragments.renderCopy(abs(uri));
                        }
                    },
                    process: function (element, options) {
                        /// <signature helpKeyword="WinJS.UI.Pages._mixin.process">
                        /// <summary locid="WinJS.UI.Pages._mixin.process">
                        /// Processes the unparented DOM elements returned by load.
                        /// </summary>
                        /// <param name="element" locid="WinJS.UI.Pages._mixin.process_p:element">
                        /// The DOM element that will contain all the content for the page.
                        /// </param>
                        /// <param name="options" locid="WinJS.UI.Pages._mixin.process_p:options">
                        /// The options that are to be passed to the constructor of the page.
                        /// </param>
                        /// <returns type="WinJS.Promise" locid="WinJS.UI.Pages._mixin.process_returnValue">
                        /// A promise that is fulfilled when processing is complete.
                        /// </returns>
                        /// </signature>
                        return ControlProcessor.processAll(element);
                    },
                    processed: function (element, options) { },
                    render: function (element, options, loadResult) {
                        /// <signature helpKeyword="WinJS.UI.Pages._mixin.render">
                        /// <summary locid="WinJS.UI.Pages._mixin.render">
                        /// Renders the control, typically by adding the elements specified in the loadResult parameter to the specified element.
                        /// </summary>
                        /// <param name="element" locid="WinJS.UI.Pages._mixin.render_p:element">
                        /// The DOM element that will contain all the content for the page.
                        /// </param>
                        /// <param name="options" locid="WinJS.UI.Pages._mixin.render_p:options">
                        /// The options passed into the constructor of the page.
                        /// </param>
                        /// <param name="loadResult" locid="WinJS.UI.Pages._mixin.render_p:loadResult">
                        /// The elements returned from the load method.
                        /// </param>
                        /// <returns type="WinJS.Promise" locid="WinJS.UI.Pages._mixin.render_returnValue">
                        /// A promise that is fulfilled when rendering is complete, if asynchronous processing is necessary. If not, returns nothing.
                        /// </returns>
                        /// </signature>
                        if (!this.selfhost) {
                            element.appendChild(loadResult);
                        }
                        return element;
                    },
                    rendered: function (element, options) { },
                    ready: function () { }
                };
                function injectMixin(base, mixin) {
                    var d = base.prototype.dispose;
                    var dM = base.prototype.disposePageMixin;
                    var iM = base.prototype.initPageMixin;
                    base = _Base.Class.mix(base, mixin);
                    //we want to allow this mixins to provide their own addition to "dispose" and initialize custom properties
                    if (d && mixin.hasOwnProperty('dispose')) {
                        base.prototype.dispose = function () {
                            mixin.dispose.apply(this);
                            if (d)
                                d.apply(this);
                        };
                    }
                    if (d && mixin.hasOwnProperty('disposePageMixin')) {
                        base.prototype.disposePageMixin = function () {
                            mixin.disposePageMixin.apply(this);
                            if (dM)
                                dM.apply(this);
                        };
                    }
                    if (d && mixin.hasOwnProperty('initPageMixin')) {
                        base.prototype.initPageMixin = function () {
                            mixin.initPageMixin.apply(this);
                            if (iM)
                                iM.apply(this);
                        };
                    }
                    return base;
                }
                function mergeJavaScriptClass(baseCtor, classDef) {
                    var keys = Object.keys(baseCtor.prototype);
                    keys.forEach(function (k) {
                        if (classDef.prototype[k] === undefined) {
                            classDef.prototype[k] = baseCtor.prototype[k];
                        }
                    });
                    return baseCtor;
                }
                function addMembers(ctor, members) {
                    if (!members)
                        return ctor;
                    if (typeof members == 'function') {
                        ctor.prototype._attachedConstructor = members;
                        return mergeJavaScriptClass(ctor, members);
                    }
                    else if (typeof members == 'object') {
                        return injectMixin(ctor, members);
                    }
                    return ctor;
                }
                function pageLifeCycle(that, uri, element, options, complete, parentedPromise) {
                    if (element.style.display)
                        that.pageLifeCycle.initialDisplay = element.style.display;
                    element.style.display = 'none';
                    var profilerMarkIdentifier = " uri='" + uri + "'" + _BaseUtils._getProfilerMarkIdentifier(that.element);
                    that.pageLifeCycle.profilerMarkIdentifier = profilerMarkIdentifier;
                    _WriteProfilerMark("WinJS.UI.Pages:createPage" + profilerMarkIdentifier + ",StartTM");
                    if (WinJSContrib.UI.WebComponents) {
                        that.pageLifeCycle.observer = WinJSContrib.UI.WebComponents.watch(that.element);
                    }
                    var load = Promise.timeout().then(function Pages_load() {
                        that.pageLifeCycle.log(function () { return "URI loading " + that.pageLifeCycle.profilerMarkIdentifier; });
                        return that.load(uri);
                    }).then(function (loadResult) {
                        that.pageLifeCycle.log(function () { return "URI loaded " + that.pageLifeCycle.profilerMarkIdentifier; });
                        //if page is defined by Js classes, call class constructors 
                        if (that._attachedConstructor) {
                            var realControl = new that._attachedConstructor(element, options);
                            element.winControl = realControl;
                            var keys = Object.keys(that);
                            keys.forEach(function (k) {
                                realControl[k] = that[k];
                            });
                            realControl.pageLifeCycle.page = realControl;
                            that.pageControl = realControl;
                            that.dismissed = true;
                            that = realControl;
                        }
                        return loadResult;
                    });
                    var renderCalled = load.then(function Pages_init(loadResult) {
                        return Promise.join({
                            loadResult: loadResult,
                            initResult: that.init(element, options)
                        });
                    }).then(function Pages_render(result) {
                        return that.pageLifeCycle.steps.init.resolve().then(function () {
                            return result;
                        });
                    }).then(function Pages_render(result) {
                        return that.render(element, options, result.loadResult);
                    }).then(function Pages_render(result) {
                        return that.rendered(element, options);
                    }).then(function (result) {
                        return that.pageLifeCycle.steps.render.resolve();
                    }).then(function Pages_processed() {
                        if (WinJSContrib.UI.WebComponents) {
                            //add delay to enable webcomponent processing
                            return WinJS.Promise.timeout();
                        }
                    });
                    that.elementReady = renderCalled.then(function () {
                        return element;
                    });
                    that.renderComplete = renderCalled.then(function Pages_process() {
                        return that.process(element, options);
                    }).then(function (result) {
                        return that.pageLifeCycle.steps.process.resolve();
                    }).then(function Pages_processed() {
                        WinJSContrib.UI.bindMembers(element, that);
                        return that.processed(element, options);
                    }).then(function () {
                        return that;
                    });
                    var callComplete = function () {
                        complete && complete(that);
                        _WriteProfilerMark("WinJS.UI.Pages:createPage" + profilerMarkIdentifier + ",StopTM");
                    };
                    // promises guarantee order, so this will be called prior to ready path below
                    //
                    that.renderComplete.then(callComplete, callComplete);
                    that.layoutComplete = that.renderComplete.then(function () {
                        return parentedPromise;
                    }).then(function () {
                        element.style.display = that.pageLifeCycle.initialDisplay || '';
                        var r = element.getBoundingClientRect(); //force element layout
                        return broadcast(that, element, 'pageLayout', [element, options], null, that.pageLayout);
                    }).then(function () {
                        WinJSContrib.UI.bindActions(element, that);
                    }).then(function (result) {
                        return that.pageLifeCycle.steps.layout.resolve();
                    }).then(function () {
                        return that;
                    });
                    that.readyComplete = that.layoutComplete.then(function Pages_ready() {
                        that.ready(element, options);
                        that.pageLifeCycle.ended = new Date();
                        that.pageLifeCycle.delta = that.pageLifeCycle.ended - that.pageLifeCycle.created;
                        //broadcast(that, element, 'pageReady', [element, options]);
                    }).then(function (result) {
                        return that.pageLifeCycle.steps.ready.resolve();
                    }).then(function (result) {
                        return that.pageLifeCycle.steps.enter.resolve();
                    }).then(function () {
                        return that;
                    }).then(null, function Pages_error(err) {
                        if (that.error)
                            return that.error(err);
                        if (err && err._value && err._value.name === "Canceled")
                            return;
                        return WinJS.Promise.wrapError(err);
                    });
                    that.__checkLayout = function () {
                        var page = this;
                        var updateLayoutArgs = arguments;
                        var p = null;
                        if (page.updateLayout) {
                            p = WinJS.Promise.as(page.updateLayout.apply(page, updateLayoutArgs));
                        }
                        else {
                            p = WinJS.Promise.wrap();
                        }
                        return p.then(function () {
                            return broadcast(page, page.element, 'updateLayout', updateLayoutArgs);
                        });
                    };
                }
                function getPageConstructor(uri, members) {
                    /// <signature helpKeyword="WinJS.UI.Pages.define">
                    /// <summary locid="WinJS.UI.Pages.define">
                    /// Creates a new page control from the specified URI that contains the specified members.
                    /// Multiple calls to this method for the same URI are allowed, and all members will be
                    /// merged.
                    /// </summary>
                    /// <param name="uri" locid="WinJS.UI.Pages.define_p:uri">
                    /// The URI for the content that defines the page.
                    /// </param>
                    /// <param name="members" locid="WinJS.UI.Pages.define_p:members">
                    /// Additional members that the control will have.
                    /// </param>
                    /// <returns type="Function" locid="WinJS.UI.Pages.define_returnValue">
                    /// A constructor function that creates the page.
                    /// </returns>
                    /// </signature>
                    var refUri = abs(uri).toLowerCase();
                    var base = viewMap[refUri];
                    uri = abs(uri);
                    if (!base) {
                        base = _Base.Class.define(
                        // This needs to follow the WinJS.UI.processAll "async constructor"
                        // pattern to interop nicely in the "Views.Control" use case.
                        //
                        // This needs to follow the WinJS.UI.processAll "async constructor"
                        // pattern to interop nicely in the "Views.Control" use case.
                        //
                        function PageControl_ctor(element, options, complete, parentedPromise) {
                            var that = this;
                            if (that._attachedConstructor) {
                                var realControl = new this._attachedConstructor(element, options);
                                element.winControl = realControl;
                                var keys = Object.keys(that);
                                keys.forEach(function (k) {
                                    if (k !== "_attachedConstructor") {
                                        realControl[k] = that[k];
                                    }
                                });
                                that = realControl;
                            }
                            var parent = WinJSContrib.Utils.getScopeControl(element);
                            _ElementUtilities.addClass(element, "win-disposable");
                            _ElementUtilities.addClass(element, "pagecontrol");
                            _ElementUtilities.addClass(element, "mcn-layout-ctrl");
                            if (that.initPageMixin)
                                that.initPageMixin();
                            //that._eventTracker = new WinJSContrib.UI.EventTracker();
                            //that._promises = [];
                            that.pageLifeCycle = {
                                created: new Date(),
                                location: uri,
                                log: function (callback) {
                                    if (Pages.verboseTraces) {
                                        var delta = new Date() - this.created;
                                        logger.verbose(delta + "ms " + callback());
                                    }
                                },
                                stop: function () {
                                    that.readyComplete.cancel();
                                    that.cancelPromises();
                                    if (this.observer) {
                                        this.observer.disconnect();
                                        this.observer = null;
                                    }
                                },
                                steps: {
                                    init: new PageLifeCycleStep(that, 'init', null),
                                    render: new PageLifeCycleStep(that, 'render', null),
                                    process: new PageLifeCycleStep(that, 'process', parent),
                                    layout: new PageLifeCycleStep(that, 'layout', parent),
                                    ready: new PageLifeCycleStep(that, 'ready', parent),
                                    enter: new PageLifeCycleStep(that, 'enter', parent),
                                },
                                initialDisplay: null
                            };
                            that.defferedLoading = new DefferedLoadings(that);
                            that._disposed = false;
                            that.element = element = element || _Global.document.createElement("div");
                            element.msSourceLocation = uri;
                            that.uri = uri;
                            that.selfhost = selfhost(uri);
                            element.winControl = that;
                            that.parentedComplete = parentedPromise;
                            pageLifeCycle(that, uri, element, options, complete, parentedPromise);
                            return that;
                        }, _mixinBase);
                        base = _Base.Class.mix(base, WinJS.UI.DOMEventMixin);
                        //inject default behaviors to page constructor
                        WinJSContrib.UI.Pages.defaultFragmentMixins.forEach(function (mixin) {
                            injectMixin(base, mixin);
                        });
                        //WinJSContrib.UI.Pages.fragmentMixin(base);
                        viewMap[refUri] = base;
                    }
                    base = addMembers(base, members);
                    base.selfhost = selfhost(uri);
                    return base;
                }
                function Pages_define(uri, members) {
                    /// <signature helpKeyword="WinJS.UI.Pages.define">
                    /// <summary locid="WinJS.UI.Pages.define">
                    /// Creates a new page control from the specified URI that contains the specified members.
                    /// Multiple calls to this method for the same URI are allowed, and all members will be
                    /// merged.
                    /// </summary>
                    /// <param name="uri" locid="WinJS.UI.Pages.define_p:uri">
                    /// The URI for the content that defines the page.
                    /// </param>
                    /// <param name="members" locid="WinJS.UI.Pages.define_p:members">
                    /// Additional members that the control will have.
                    /// </param>
                    /// <returns type="Function" locid="WinJS.UI.Pages.define_returnValue">
                    /// A constructor function that creates the page.
                    /// </returns>
                    /// </signature>
                    var ctor = viewMap[uri];
                    if (!ctor) {
                        ctor = getPageConstructor(uri);
                    }
                    if (members) {
                        ctor = addMembers(ctor, members);
                    }
                    if (ctor.selfhost) {
                        WinJS.Utilities.ready(function () {
                            render(abs(uri), _Global.document.body);
                        }, true);
                    }
                    //in case we are on WinJS<4 we reference members on WinJS Core Pages
                    if (!_CorePages.viewMap && !_CorePages._viewMap && typeof members !== 'function')
                        _Pages._corePages.define(uri, members);
                    return ctor;
                }
                function render(uri, element, options, parentedPromise) {
                    var Ctor = _CorePages.get(uri);
                    loadedPages[abs(uri)] = true;
                    var control = new Ctor(element, options, null, parentedPromise);
                    return control.renderComplete.then(null, function (err) {
                        return Promise.wrapError({
                            error: err,
                            page: control
                        });
                    });
                }
                function get(uri) {
                    var ctor = viewMap[uri];
                    if (!ctor) {
                        ctor = Pages_define(uri);
                    }
                    return ctor;
                }
                function remove(uri) {
                    Fragments.clearCache(abs(uri));
                    delete viewMap[uri.toLowerCase()];
                }
                _Pages._corePages = {
                    get: _CorePages.get,
                    render: _CorePages.render,
                    define: _CorePages.define,
                    _remove: _CorePages._remove,
                    _viewMap: viewMap,
                };
                var pageOverride = {
                    define: Pages_define,
                    get: get,
                    render: render,
                    _remove: remove,
                    _viewMap: viewMap
                };
                var source = WinJS.UI.Pages;
                WinJS.Namespace._moduleDefine(_Pages, null, pageOverride);
                source.get = pageOverride.get;
                source.define = pageOverride.define;
                source.render = pageOverride.render;
                source._remove = pageOverride._remove;
                //replaces HtmlControl, otherwise it does not use proper Page constructor
                WinJS.UI.HtmlControl = WinJS.Class.define(function HtmlControl_ctor(element, options, complete) {
                    /// <signature helpKeyword="WinJS.UI.HtmlControl.HtmlControl">
                    /// <summary locid="WinJS.UI.HtmlControl.constructor">
                    /// Initializes a new instance of HtmlControl to define a new page control.
                    /// </summary>
                    /// <param name="element" locid="WinJS.UI.HtmlControl.constructor_p:element">
                    /// The element that hosts the HtmlControl.
                    /// </param>
                    /// <param name="options" locid="WinJS.UI.HtmlControl.constructor_p:options">
                    /// The options for configuring the page. The uri option is required in order to specify the source
                    /// document for the content of the page.
                    /// </param>
                    /// </signature>
                    WinJS.UI.Pages.render(options.uri, element, options).
                        then(complete, function () { complete(); });
                });
            })(WinJSContrib.UI.Pages, __global, WinJS, WinJS.UI.Pages, WinJS.Utilities, WinJS.Utilities, profiler, WinJS.Promise, WinJS.UI.Fragments, WinJS.UI);
        })(Pages = UI.Pages || (UI.Pages = {}));
    })(UI = WinJSContrib.UI || (WinJSContrib.UI = {}));
})(WinJSContrib || (WinJSContrib = {}));

//# sourceMappingURL=winjscontrib.core.js.map