/* Minification failed. Returning unminified contents.
(605,21-22): run-time error JS1005: Expected '(': {
(606,47-48): run-time error JS1009: Expected '}': ;
(606,47-48): run-time error JS1006: Expected ')': ;
(606,47-48): run-time error JS1008: Expected '{': ;
 */
!function (r) { "use strict"; var n = {}; r.PubSub = n; var t = r.define; !function (c) { "use strict"; var a = {}, e = -1, u = "*"; function i(r) { var n; for (n in r) { if (r.hasOwnProperty(n)) { return true } } return false } function o(n) { return function r() { throw n } } function f(r, n, t) { try { r(n, t) } catch (r) { setTimeout(o(r), 0) } } function s(r, n, t) { r(n, t) } function p(r, n, t, e) { var i = a[n], o = e ? s : f, u; if (!a.hasOwnProperty(n)) { return } for (u in i) { if (i.hasOwnProperty(u)) { o(i[u], r, t) } } } function l(e, i, o) { return function r() { var n = String(e), t = n.lastIndexOf("."); p(e, e, i, o); while (t !== -1) { n = n.substr(0, t); t = n.lastIndexOf("."); p(e, n, i, o) } p(e, u, i, o) } } function b(r) { var n = String(r), t = Boolean(a.hasOwnProperty(n) && i(a[n])); return t } function y(r) { var n = String(r), t = b(n) || b(u), e = n.lastIndexOf("."); while (!t && e !== -1) { n = n.substr(0, e); e = n.lastIndexOf("."); t = b(n) } return t } function t(r, n, t, e) { r = typeof r === "symbol" ? r.toString() : r; var i = l(r, n, e), o = y(r); if (!o) { return false } if (t === true) { i() } else { setTimeout(i, 0) } return true } c.publish = function (r, n) { return t(r, n, false, c.immediateExceptions) }, c.publishSync = function (r, n) { return t(r, n, true, c.immediateExceptions) }, c.subscribe = function (r, n) { if (typeof n !== "function") { return false } r = typeof r === "symbol" ? r.toString() : r; if (!a.hasOwnProperty(r)) { a[r] = {} } var t = "uid_" + String(++e); a[r][t] = n; return t }, c.subscribeAll = function (r) { return c.subscribe(u, r) }, c.subscribeOnce = function (r, n) { var t = c.subscribe(r, function () { c.unsubscribe(t); n.apply(this, arguments) }); return c }, c.clearAllSubscriptions = function r() { a = {} }, c.clearSubscriptions = function r(n) { var t; for (t in a) { if (a.hasOwnProperty(t) && t.indexOf(n) === 0) { delete a[t] } } }, c.countSubscriptions = function r(n) { var t; var e = 0; for (t in a) { if (a.hasOwnProperty(t) && t.indexOf(n) === 0) { e++ } } return e }, c.getSubscriptions = function r(n) { var t; var e = []; for (t in a) { if (a.hasOwnProperty(t) && t.indexOf(n) === 0) { e.push(t) } } return e }, c.unsubscribe = function (r) { var n = function (r) { var n; for (n in a) { if (a.hasOwnProperty(n) && n.indexOf(r) === 0) { return true } } return false }, t = typeof r === "string" && (a.hasOwnProperty(r) || n(r)), e = !t && typeof r === "string", i = typeof r === "function", o = false, u, f, s; if (t) { c.clearSubscriptions(r); return } for (u in a) { if (a.hasOwnProperty(u)) { f = a[u]; if (e && f[r]) { delete f[r]; o = r; break } if (i) { for (s in f) { if (f.hasOwnProperty(s) && f[s] === r) { delete f[s]; o = true } } } } } return o } }(n), "function" == typeof t && t.amd ? t(function () { return n }) : "object" == typeof exports && (void 0 !== module && module.exports && (exports = module.exports = n), exports.PubSub = n, module.exports = exports = n) }("object" == typeof window && window || this);;
var SY = SY || {};
SY.Validation = SY.Validation || {};
SY.Constants = SY.Constants || {};
SY.ModalWindows = SY.ModalWindows || {};
SY.NET = SY.NET || { debug: false };
SY.PubSub = SY.PubSub || {};
SY.Tooltip = SY.Tooltip || {};

"use strict";

//--------------------------------------------
// extension of basic js classes
//--------------------------------------------

// please note that we don't check for the existing ones, because they _are_ different
// and we want these versions (otherwise functionality will break);

String.prototype.trimLeft = function () {
    var search = '\\s+';
    if (!!arguments && arguments.length > 0) {
        var args = $.makeArray(arguments);
        search = '[' + args.join('') + ']' + '+';
    }
    return this.replace(new RegExp("^" + search, "gim"), '');
};

String.prototype.trimRight = function () {
    var search = '\\s+';
    if (!!arguments && arguments.length > 0) {
        var args = $.makeArray(arguments);
        search = '[' + args.join('') + ']' + '+';
    }
    return this.replace(new RegExp(search + "$", "gim"), '');
};

String.prototype.trim = function () {
    return this.trimLeft().trimRight();
};

// usage:
// "{0}, {1}!".format("hello", "world");
// escaping curly brackets is supported with {{ and }}
String.prototype.format = function () {
    var args = arguments;
    return this.replace(/\{\{|\}\}|\{(\d+)\}/gim, function (curly, index) {
        return ((curly == "{{") ? "{" : ((curly == "}}") ? "}" : args[index]));
    });
};

String.prototype.startsWith = function (searchString, position) {
    position = position || 0;
    return this.indexOf(searchString, position) === position;
};

String.prototype.includes = function (search, start) {
    'use strict';
    if (typeof start !== 'number') {
        start = 0;
    }

    if (start + search.length > this.length) {
        return false;
    } else {
        return this.indexOf(search, start) !== -1;
    }
};

//--------------------------------------------
// Validation
//--------------------------------------------

SY.Validation.enableOrDisableSubmitButton = function (buttonSelector, errorSpanSelector, inputfields, additionalfunc) {
    var errors = $(buttonSelector).closest('form').find(errorSpanSelector).length;
    var empties = inputfields.filter(function () {
        return !$(this).val();
    }).length;
    if (typeof additionalfunc === 'function') {
        var additionalcond = additionalfunc();
        SY.Validation.enableSubmitButton(buttonSelector, errors === 0 && empties === 0 && additionalcond);
    } else {
        SY.Validation.enableSubmitButton(buttonSelector, errors === 0 && empties === 0);
    }
};

SY.Validation.enableSubmitButton = function (buttonSelector, flag) {
    if (typeof flag === 'undefined' || flag == null) {
        flag = true;
    }
    if (flag) {
        $(buttonSelector).removeAttr('disabled').removeClass("disabled").prop('disabled', false).css({ "cursor": "pointer" });
    } else {
        $(buttonSelector).attr('disabled', 'disabled').addClass("disabled").prop('disabled', true).css({ "cursor": "not-allowed" });
    }
};

SY.Validation.IsValidEmail = function (email) {
    // note: this regex is a javascript version of the one in CustomDataAnnotation.cs
    var accentedCharacters = "àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝâêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿÄËÏÖÜŸçÇßØøÅåÆæœ";
    var regex = "^[\\w" + accentedCharacters + "]+[\\w" + accentedCharacters + "\\.!#$%&'\\*\\+\\-/=\\?\\^_`{|}~]*@[a-zA-Z0-9]+(?:(?:[\\w\\-]*)(?:\\.(?!\\.)))*(?:[\\w\\-]*)(?:\\.(?!\\.))[a-zA-Z0-9]{2,20}$";
    var regexCompiled = new RegExp(regex, 'gi');
    var emailValid = regexCompiled.test(email);
    return emailValid;
};

SY.Validation.ValidateLoginFields = function (fieldType) {
    if (fieldType === 'email') {
        var regex = this.data('val-regex-pattern');
        if (typeof regex !== 'undefined' && regex != null) {
            var regexEmail = new RegExp(regex, 'gi');
            if (regexEmail.test(this.val())) {
                this.closest('.form-group').find('.error-message').addClass('d-none');
                this.closest('.form-group').find('.icon').removeClass('d-none');
            } else {
                this.closest('.form-group').find('.icon').addClass('d-none');
                this.closest('.form-group').find('.error-message').removeClass('d-none');
            }
        }
    } else if (fieldType === 'password') {
        if (this.val()) {
            this.closest('.form-group').find('.error-message').addClass('d-none');
            this.closest('.form-group').find('.icon').removeClass('d-none')
        } else {
            this.closest('.form-group').find('.icon').addClass('d-none')
            this.closest('.form-group').find('.error-message').removeClass('d-none');
        }
    }
};


//--------------------------------------------
// Constants
//--------------------------------------------

// keep these strings sorted alphabetically by key
SY.Constants.Messages = {
    abort: 'Abort',
    cancel: 'Cancel',
    clearAllDesigns: 'Are you sure you want to clear all designs on your page?',
    clearQ: 'Clear?',
    confirmation: 'Confirmation',
    couldNotSavePendingOrder: 'Could not save pending order details:',
    deleteObject: 'Are you sure you want to remove this object?',
    deletePageFromCart: 'Are you sure you want to delete this page?<br><br>Clicking on &quot;Yes&quot; will delete the page from your shopping cart.',
    deleteAccessoryFromCart: 'Are you sure you want to remove this accessory?<br><br>Click on &quot;Yes&quot; to remove now.<br>To add again, adjust the quantity needed.',
    error: 'Error',
    failedSetCurency: 'Could not set currency.',
    ignore: 'Ignore',
    ignoreErrorsMsg: 'We want you to love our products!<br>Ignoring errors may result in poor quality products when printed.<br><br>Ignore error anyway?',
    ignoreErrorsQ: 'Ignore Errors?',
    inactiveTooLong: 'You\'ve been inactive for too long.',
    no: 'No',
    none: 'None',
    noSlotsAvailable: 'All available spaces on the layout have been taken, please remove a sticker before trying to add a new one.',
    ok: 'OK',
    pageWillReload: 'Current page will be reloaded.',
    retry: 'Retry',
    serverError: 'Oops! The server returned an error:',
    sessionExpired: 'Session Expired',
    warning: 'Warning',
    yes: 'Yes',
    information: 'Information',
    reorderCustomSales: 'Please Contact Your Custom Sales Representative to re-order this product.',
    inactiveProductReorder: 'Please <a href="/support/post/get-in-touch-with-stickeryou#form">Contact Our Support Team</a> to re-order this product.',
    oops: 'Oops!',
    yesRemove: 'Yes, remove',
    leaveCheckout: 'Leave Checkout',
    leaveCheckoutMsg: '<p>You about to leave checkout. Your information might not be saved.</p><p>Want to proceed?</p>'
};
// alias for frequently used SY.Constants.Messages
SY.CM = SY.Constants.Messages;

SY.Constants.CanvasLayerType =
{
    unknown: 0,
    image: 1,
    multitext: 2,
    customizableimage: 3,
    vinyllettering: 4
};

SY.Constants.messageDialogResult = {
    NONE: { Value: -1, Text: SY.CM.none },
    OK: { Value: 0, Text: SY.CM.ok },
    CANCEL: { Value: 1, Text: SY.CM.cancel },
    ABORT: { Value: 2, Text: SY.CM.abort },
    RETRY: { Value: 3, Text: SY.CM.retry },
    IGNORE: { Value: 4, Text: SY.CM.ignore },
    YES: { Value: 5, Text: SY.CM.yes },
    NO: { Value: 6, Text: SY.CM.no },
    YESREMOVE: { Value: 7, Text: SY.CM.yesRemove },
    LEAVECHECKOUT: { Value: 8, Text: SY.CM.leaveCheckout },

    getMessageDialogResultByValue: function (num) {
        for (var key in this) {
            if (typeof this[key] !== 'function' && this.hasOwnProperty(key) && parseInt(this[key].Value, 10) == parseInt(num, 10))
                return this[key];
        }
        return null;
    }
};

SY.Constants.messageDialogType = {
    NONE: { Value: 0, HTML: '{message-goes-here}' },
    WARNING: { Value: 1, HTML: '<div class="icon-warning"><i class="fa fa-exclamation-triangle fa-4x" aria-hidden="true"></i></div><p class="centered-text">{message-goes-here}</p>' },
};

SY.Constants.InkAttributeValues = {
    KEEPWHITE: { Id: 0, Value: "KeepWhite" },
    NOWHITE: { Id: 1, Value: "NoWhite" },

    getValueById: function (num) {
        if (typeof num !== 'undefined' && num != null) {
            for (var key in this) {
                if (typeof this[key] !== 'function' && this.hasOwnProperty(key) && parseInt(this[key].Id, 10) == parseInt(num, 10))
                    return this[key].Value;
            }
        }
        return this.KEEPWHITE.Value;
    },
    getIdByValue: function (val) {
        if (typeof val === 'string' && val != null) {
            for (var key in this) {
                if (typeof this[key] !== 'function' && this.hasOwnProperty(key) && this[key].Value.toLowerCase() == val.toLowerCase())
                    return this[key].Id;
            }
        }
        return this.KEEPWHITE.Id;
    },
};

SY.Constants.AdhesiveAttributeValues = {
    BACK: { Id: 0, Value: "Back" },
    FRONT: { Id: 1, Value: "Front" },

    getValueById: function (num) {
        if (typeof num !== 'undefined' && num != null) {
            for (var key in this) {
                if (typeof this[key] !== 'function' && this.hasOwnProperty(key) && parseInt(this[key].Id, 10) == parseInt(num, 10)) {
                    return this[key].Value;
                }
            }
        }
        return this.BACK.Value;
    },
    getIdByValue: function (val) {
        if (typeof val === 'string' && val != null) {
            for (var key in this) {
                if (typeof this[key] !== 'function' && this.hasOwnProperty(key) && this[key].Value.toLowerCase() == val.toLowerCase()) {
                    return this[key].Id;
                }
            }
        }
        return this.BACK.Id;
    },
};

SY.Constants.LeadingEdgeAttributeValues = {
    UP: { Id: 0, Value: "Up", Angle: 0 },
    DOWN: { Id: 1, Value: "Down", Angle: 180 },
    LEFT: { Id: 2, Value: "Left", Angle: -90 },
    RIGHT: { Id: 3, Value: "Right", Angle: 90 },

    getAsArray: function () {
        var result = [];
        for (var key in this) {
            if (typeof this[key] !== 'function' && this.hasOwnProperty(key) && !isNaN(this[key].Id, 10) && isFinite(this[key].Id, 10)) {
                var obj = this[key];
                obj.Selected = obj.Id == 0;
                result.push(obj);
            }
        }
        return result;
    },

    getAngleById: function (id) {
        //convert to number anyway
        id = Number(id);
        var angle = 0;
        if (!isNaN(id)) {
            for (var key in this) {
                if (typeof key !== 'function' && this.hasOwnProperty(key)) {
                    if (this[key].Id == id) {
                        angle = this[key].Angle;
                        break;
                    }
                }
            }
        }
        return angle;
    }
};
SY.Constants.UnitOfLength = {
    Inches: { id: 0, displayName: "inches", displayUnit: "\"" }, Centimeter: { id: 1, displayName: "cm", displayUnit:"cm" }
};
//--------------------------------------------
// message dialog
//--------------------------------------------

// this creates a singleton message dialog instance:
SY.messageDialog = (function () {

    // this is the class itself
    function MessageDialogFactory() {

        function _createDialog(dialogType, selector, title, message, buttons, callback) {

            var dialog = {
                dialogType: dialogType,
                selector: selector,
                message: message,
                title: title,
                buttons: [],
                result: SY.Constants.messageDialogResult.NONE.Value
            };

            if (buttons.length > 0) {
                for (var b = 0; b < buttons.length; b++) {
                    var btn = {
                        text: buttons[b].Text,
                        result: buttons[b].Value,
                        click: function (event) {
                            var btn = $(event.target);
                            if (btn.prop("tagName").toLowerCase() !== 'button') {
                                btn = btn.parent('button');
                            }
                            dialog.result = parseInt(btn.attr('result'), 10);
                            $(this).dialog("close");
                        },
                        class: "btn btn-primary"
                    };

                    dialog.buttons.push(btn);
                }
            } else {
                var btn = {
                    text: SY.Constants.messageDialogResult.OK.Text,
                    result: SY.Constants.messageDialogResult.OK.Value,
                    click: function (event) {
                        var btn = $(event.target);
                        if (btn.prop("tagName").toLowerCase() !== 'button') {
                            btn = btn.parent('button');
                        }
                        dialog.result = parseInt(btn.attr('result'), 10);
                        $(this).dialog("close");
                    },
                    class: "btn btn-primary"
                };

                dialog.buttons.push(btn);
            }

            var options = {
                autoOpen: false,
                closeOnEscape: true,
                modal: true,
                draggable: true,
                resizable: false,
                title: dialog.title,
                show: {
                    effect: 'drop',
                    direction: 'down',
                    duration: 200
                },
                hide: {
                    effect: 'drop',
                    direction: 'up',
                    duration: 400
                },
                width: 375,
                dialogClass: 'ui-dialog',
                close: function () {
                    if (typeof callback === 'function' && callback != null) {
                        callback(dialog.result);
                    }
                },
                open: function () {
                    dialog.result = SY.Constants.messageDialogResult.NONE.Value;
                    $('.ui-dialog-titlebar-close').addClass('ui-button ui-widget ui-state-default ui-corner-all ui-button-icon-only');
                    $('.ui-dialog-titlebar-close').append('<span class="ui-button-icon-primary ui-icon ui-icon-closethick"></span>');
                }
            };

            $(dialog.selector).empty();
            var span = $('<span>');
            var para = $('<p>', { html: dialog.dialogType.HTML.replace(/\{message\-goes\-here\}/, dialog.message) });
            span.append(para);
            $(dialog.selector).append(span);
            $(dialog.selector).attr('title', dialog.title);

            $(dialog.selector).dialog(options);
            $(dialog.selector).dialog("option", "buttons", dialog.buttons);

            return dialog;
        }

        this.showDialogOK = function (selector, title, message, callback) {
            var dialog = _createDialog(
                SY.Constants.messageDialogType.NONE,
                selector,
                title,
                message,
                [SY.Constants.messageDialogResult.OK],
                callback
            );

            $(dialog.selector).dialog("open");
        };

        this.showDialogOKCancel = function (selector, title, message, callback) {
            var dialog = _createDialog(
                SY.Constants.messageDialogType.NONE,
                selector,
                title,
                message,
                [SY.Constants.messageDialogResult.OK, SY.Constants.messageDialogResult.CANCEL],
                callback
            );

            $(dialog.selector).dialog("open");
        };

        this.showDialogYesNo = function (selector, title, message, callback) {
            var dialog = _createDialog(
                SY.Constants.messageDialogType.NONE,
                selector,
                title,
                message,
                [SY.Constants.messageDialogResult.YES, SY.Constants.messageDialogResult.NO],
                callback
            );

            $(dialog.selector).dialog("open");
        };

        this.showDialogYesRemoveCancel = function (selector, title, message, callback) {
            var dialog = _createDialog(
                SY.Constants.messageDialogType.NONE,
                selector,
                title,
                message,
                [SY.Constants.messageDialogResult.YESREMOVE, SY.Constants.messageDialogResult.CANCEL],
                callback
            );

            $(dialog.selector).dialog("open");
        };

        this.showDialogLeaveCheckoutCancel = function (selector, title, message, callback) {
            var dialog = _createDialog(
                SY.Constants.messageDialogType.NONE,
                selector,
                title,
                message,
                [SY.Constants.messageDialogResult.LEAVECHECKOUT, SY.Constants.messageDialogResult.CANCEL],
                callback
            );

            $(dialog.selector).dialog("open");
        };

        this.showDialogYesNoWarning = function (selector, title, message, callback) {
            var dialog = _createDialog(
                SY.Constants.messageDialogType.WARNING,
                selector,
                title,
                message,
                [SY.Constants.messageDialogResult.YES, SY.Constants.messageDialogResult.NO],
                callback
            );

            $(dialog.selector).dialog("open");
        };

        this.showDialogYesNoCancel = function (selector, title, message, callback) {
            var dialog = _createDialog(
                SY.Constants.messageDialogType.NONE,
                selector,
                title,
                message,
                [SY.Constants.messageDialogResult.YES, SY.Constants.messageDialogResult.NO, SY.Constants.messageDialogResult.CANCEL],
                callback
            );

            $(dialog.selector).dialog("open");
        };
    }

    return new MessageDialogFactory();
}());

//--------------------------------------------
// ajax calling facilities
//--------------------------------------------

SY.NET.AjaxJsonPost = function (url, data, success, fail, always) {
    var withTheseOptions = {
        url: url,
        type: 'POST',
        contentType: 'application/json; charset=utf-8',
        data: data
    };

    if (typeof success === 'undefined' || typeof success !== 'function') {
        success = null;
    }

    if (typeof fail === 'undefined' || typeof fail !== 'function') {
        fail = null;
    }

    if (typeof always === 'undefined' || typeof always !== 'function') {
        always = null;
    }

    $.ajax(withTheseOptions).done(success).fail(fail).always(always);
};

SY.NET.HandleAjaxFailure = function (xhr, status, error) {
    SY.NET.LogFailureToConsole(error, xhr, status);
    var locErr = error;
    var statuses = { StatusCode: xhr.status };
    if (typeof xhr.responseText !== 'undefined' && xhr.responseText != null && xhr.responseText.length > 0) {
        try {
            var o = JSON.parse(xhr.responseText);
            if (typeof o.Message !== 'undefined' && o.Message != null) {
                locErr = o.Message;
            }
            statuses = o;
        } catch (ex) {
            var elems = $.grep($.parseHTML(xhr.responseText), function (e) { return e.nodeName.toLowerCase() == 'title'; });
            if (typeof elems !== 'undefined' && elems != null && elems.length > 0) {
                locErr = $(elems[0]).text();
            }
        }
    }
    locErr = locErr.length > 250 ? '{0}{1}'.format(locErr.substr(0, 250), '...') : locErr;
    if (statuses.StatusCode === 504) {
        SY.messageDialog.showDialogOK('#messageDialogSY', SY.CM.sessionExpired, locErr, function () {
            document.location.reload(true);
        });
    } else {
        SY.messageDialog.showDialogOK('#messageDialogSY', SY.CM.error, '{0}<br><br>{1}'.format(SY.CM.serverError, locErr));
    }
};

SY.NET.HandleAjaxFailureCustom = function (message) {
    SY.NET.LogFailureToConsole(message, null, null);
    SY.messageDialog.showDialogOK('#messageDialogSY', SY.CM.error, '{0}<br><br>{1}'.format(SY.CM.serverError, message));
};

SY.NET.LogFailureToConsole = function (error, xhr, status) {
    if (typeof SY.NET.debug === 'boolean' && SY.NET.debug === true) {
        console.info('error', error);
        if (typeof xhr !== 'undefined' && xhr != null) {
            console.info('xhr', xhr);
        }
        if (typeof status !== 'undefined' && status != null) {
            console.info('status', status);
        }
    }
};

SY.NET.browser = {
    isMobile: (function () {
        return /mobi|android|mini/i.test(navigator.userAgent.toLowerCase());
    })()
};

/**
 * The FileDownload endpoint/url must:
 * -- be HttpPost;
 * -- expose 'content-disposition' header:
 * e.g: Response.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");
 * -- respond with FileContentResult;
 * 
 * @param {string} url
 * @param {object} data
 * @param {string} filenameFallback
 * @param {string} mimeType
 * @param {Function} [preCallback]
 * @param {Function} [postCallback]
 */
SY.NET.FileDownload = (url, data, filenameFallback, mimeType, preCallback, postCallback) => {

    if (typeof preCallback === 'function' && preCallback != null) {
        preCallback();
    }

    var locFileName;
    fetch(url, {
        body: JSON.stringify(data),
        method: 'POST',
        headers: {
            'Content-Type': 'application/json; charset=utf-8'
        },
    })
    .then(response => {
        if (response.ok) {
            const cd = response.headers.get("content-disposition");
            //console.log("content-disposition = " + response.headers.get("content-disposition"));
            //console.log("content-type = " + response.headers.get("content-type"));
            try {
                locFileName = cd.match(/filename=[\s"\']*(.+)[\s"\']*/i)[1];
            } catch {
                locFileName = filenameFallback;
            }
            return response.blob();
        } else {
            console.error("Network response was: " + response.status + ".");
        }
    })
    .then(response => {
        try {
            if (response !== undefined && response != null) {
                const blob = new Blob([response], { type: mimeType });
                const downloadUrl = URL.createObjectURL(blob);
                const a = document.createElement("a");
                a.href = downloadUrl;
                a.download = locFileName;
                document.body.appendChild(a);
                a.click();
                window.setTimeout(() => { document.body.removeChild(a); }, 10);
            } else {
                console.error("Network response is null.");
            }
        } catch (err) {
            console.log(err);
        } finally {
            if (typeof postCallback === 'function' && postCallback != null) {
                postCallback();
            }
        }
    });
};

/**
 * Fetch the image bytes in a more deterministic way (mainly for Cloudinary previews).
 *
 * @param {string} url
 * @param {function} callbackSuccess
 * @param {function} callbackFail
 */
SY.NET.FetchImageBlob = (url, callbackSuccess, callbackFail) => {

    var invokeCallbackFail = () => {
        if (typeof callbackFail === "function" && callbackFail != null) {
            callbackFail();
        }
    };

    if (url === undefined || url == null || url == "") {
        invokeCallbackFail();
    }

    fetch(url)
        .then(response => {
            if (response.ok) {
                return response.blob();
            }
            return null;
        })
        .then(bytes => {
            if (bytes !== undefined && bytes != null) {

                var blobUrl = URL.createObjectURL(bytes);
                if (typeof callbackSuccess === "function" && callbackSuccess != null) {
                    callbackSuccess(blobUrl);
                }

            } else {
                invokeCallbackFail();
            }
        })
        .catch(error => {
            console.error('Error fetching image: ', error);
            invokeCallbackFail();
        });
};

//--------------------------------------------
// site-wide pubsub
//--------------------------------------------

(function () {
    SY.PubSub.Events = {
        currency: {
            changed: 'sy.currency.changed',
            controlCreated: 'sy.currency.controlCreated',
        },
    };

    SY.PubSub.EventBus = {
        on: function (event, handler) {
            return PubSub.subscribe(event, function (evt, context) {
                //console.log('%cEvent handled: ' + event /*+ '; context: ' + JSON.stringify(context)*/, 'border: 1px solid #00FF00; color: #00FF00; padding: 1px; background-color: #FFF;');
                handler(evt, context);
            });
        },
        off: function (token) {
            return PubSub.unsubscribe(token);
        },
        trigger: function (event, data) {
            //console.log('%cEvent triggered: ' + event /*+ '; data: ' + JSON.stringify(data)*/, 'border: 1px solid #0000FF; color: #0000FF; padding: 1px; background-color: #FFF;');
            PubSub.publish(event, data);
        }
    };
})();

//--------------------------------------------
// site-wide responsive and mobile friendly tooltip
//--------------------------------------------

SY.Tooltip.setup = function () {
    var targets = $("[rel~='tooltip']"),
        target = false,
        tooltip = false,
        title = false;

    targets.off('mouseenter').on('mouseenter', function () {
        target = $(this);
        title = target.attr('title');
        $('#tooltip-r').remove();
        tooltip = $('<div id="tooltip-r"></div>');

        if (!title || title == '')
            return false;

        target.removeAttr('title');
        tooltip.css('opacity', 0)
            .html(title)
            .appendTo('body');

        var init_tooltip = function () {
            if ($(window).width() < tooltip.outerWidth() * 1.5)
                tooltip.css('max-width', $(window).width() / 2);
            else
                tooltip.css('max-width', 340);

            var pos_left = target.offset().left + (target.outerWidth() / 2) - (tooltip.outerWidth() / 2),
                pos_top = target.offset().top - tooltip.outerHeight() - 20;

            if (pos_left < 0) {
                pos_left = target.offset().left + target.outerWidth() / 2 - 20;
                tooltip.addClass('left');
            }
            else
                tooltip.removeClass('left');

            if (pos_left + tooltip.outerWidth() > $(window).width()) {
                pos_left = target.offset().left - tooltip.outerWidth() + target.outerWidth() / 2 + 20;
                tooltip.addClass('right');
            }
            else
                tooltip.removeClass('right');

            if (pos_top < 0) {
                var pos_top = target.offset().top + target.outerHeight();
                tooltip.addClass('top');
            }
            else
                tooltip.removeClass('top');

            tooltip.css({ left: pos_left, top: pos_top })
                .animate({ top: '+=10', opacity: 1 }, 50);
        };

        init_tooltip();
        $(window).resize(init_tooltip);

        var remove_tooltip = function () {
            tooltip.animate({ top: '-=10', opacity: 0 }, 50, function () {
                $(this).remove();
            });

            target.attr('title', title);
        };

        target.on('mouseleave', remove_tooltip);
        tooltip.on('click', remove_tooltip);
    });
}

$(document).ready(SY.Tooltip.setup());
;
var ApiDataManagerClass = function() {
    this.WebAppRootURL= '/';
    this.GalleryApiUrl = '/gallery';
    this.StickerAppApiUrl = '/stickermaker';
    this.PageMakerApiUrl = '/pagemaker';
    this.StickerMakerApiUrl = '/makestickers';
    this.TemplateGalleryApiUrl = '/templategallery';
    this.CheckoutApiUrl = '/checkout';
    this.SYWebAppRootURL = window.location.host;
};

ApiDataManagerClass.prototype.JSException = function (message) {
    this.message = message;
    this.name = "ApiDataManagerJSException";
};

ApiDataManagerClass.prototype.PostJsonRequest = function (linkTo, successHandler, errorHandler) {
    if (linkTo != null) {
        $.ajax({
            url: linkTo,
            type: "POST",
            dataType: "json",
            success: successHandler,
            error: errorHandler
        });
    }
};

ApiDataManagerClass.prototype.PostJsonData = function (linkTo, dataSet, callingContext) {

    if (typeof linkTo !== 'undefined' && linkTo != null) {
        var o = {
            url: linkTo,
            type: "POST",
            dataType: "json",
            contentType: "application/json; charset=utf-8",
            data: dataSet,
        };

        var errorCallback;
        var successCallback;
        // DS Reminder: this (old) version of the post wrapper exists only because we sometimes pass the 'params' as a context object around the moon (!)
        // -- see how we build the successCallback function below --
        if (typeof callingContext !== 'undefined' && callingContext != null) {
            if (typeof callingContext.params !== 'undefined' && callingContext.params != null) {
                o.context = callingContext.params;
            } else {
                o.context = null;
            }
            if (typeof callingContext.errorHandler === 'function' && callingContext.errorHandler != null) {
                errorCallback = callingContext.errorHandler;
            }
            if (typeof callingContext.successHandler === 'function' && callingContext.successHandler != null) {
                successCallback = function (obj) {
                    callingContext.successHandler(obj, o.context);
                };
            }
        }
        $.ajax(o).done(successCallback).fail(errorCallback);
    }
};

ApiDataManagerClass.prototype.AjaxJsonPost = function (url, data, success, fail, always) {
    if (typeof url === 'undefined' || url == null) {
        throw new ApiDataManagerClass.JSException("Invalid URL in AJAX options");
    }
    var withTheseOptions = {
        url: url,
        type: 'POST',
        dataType: "json",
        contentType: 'application/json; charset=utf-8',
        data: data,
    };

    $.ajax(withTheseOptions).done(success).fail(fail).always(always);
};
/* Obsolete */
ApiDataManagerClass.prototype.LoadReadymadePages = function (stickerThemeId, onSuccessHandler) {
    this.PostJsonRequest(this.GalleryApiUrl + '/readymadepages/' + stickerThemeId + '/0', onSuccessHandler);
};

ApiDataManagerClass.prototype.LoadCategoryThemes = function (categoryId, startPage, onSuccessHandler) {
    this.PostJsonRequest(this.GalleryApiUrl + '/getcategoriesorthemes/' + categoryId + '/' + startPage, onSuccessHandler);
};
/* Obsolete */
ApiDataManagerClass.prototype.LoadThemeAssests = function (stickerThemeId, startPage, onSuccessHandler) {
    this.PostJsonRequest(this.GalleryApiUrl + '/themeassets/' + stickerThemeId + '/' + startPage, onSuccessHandler);
};
/* Obsolete */
ApiDataManagerClass.prototype.GetThemeAssetsCount = function (stickerThemeId, onSuccessHandler) {
    this.PostJsonRequest(this.GalleryApiUrl + '/themeassetscount/' + stickerThemeId, onSuccessHandler);
};

ApiDataManagerClass.prototype.LoadStickerCanvas = function (onSuccessHandler, onErrorHandler) {
    this.PostJsonRequest(this.StickerMakerApiUrl + '/loadstickercanvas', onSuccessHandler, onErrorHandler);
};

ApiDataManagerClass.prototype.IsUserAuthenticated = function (onSuccessHandler) {
    this.PostJsonRequest(this.StickerMakerApiUrl + '/isuserauthenticated', onSuccessHandler);
};

ApiDataManagerClass.prototype.ClearStickerCanvas = function (onSuccessHandler, onErrorHandler) {
    this.PostJsonRequest(this.StickerMakerApiUrl + '/clearstickercanvas', onSuccessHandler, onErrorHandler);
};

ApiDataManagerClass.prototype.SaveStickerCanvas = function (data, context) {
    this.PostJsonData(this.StickerMakerApiUrl + '/updatestickercanvas', data, context);
};

ApiDataManagerClass.prototype.CalculateFontSizeById = function (data, context) {
    this.PostJsonData(this.StickerMakerApiUrl + '/CalculateFontSizeById', data, context);
};

ApiDataManagerClass.prototype.GetDefaultFontSize = function (data, context) {
    this.PostJsonData(this.StickerMakerApiUrl + '/CalculateDefaultFontSize', data, context);
};

ApiDataManagerClass.prototype.CalculateFontSize = function (data, context) {
    this.PostJsonData(this.StickerMakerApiUrl + '/CalculateFontSize', data, context);
};

ApiDataManagerClass.prototype.LoadDesignGalleryMenu = function (onSuccessHandler) {
    this.PostJsonRequest(this.GalleryApiUrl + '/gallerymenu', onSuccessHandler);
};
/* Obsolete */
ApiDataManagerClass.prototype.GetLabelCollectionsCount = function (categoryId, onSuccessHandler) {
    this.PostJsonRequest(this.GalleryApiUrl + '/collectionscount/' + categoryId, onSuccessHandler);
};
/* Obsolete */
ApiDataManagerClass.prototype.LoadCategoryPageItems = function (categoryId, onSuccessHandler) {
    this.PostJsonRequest(this.GalleryApiUrl + '/themepage/' + categoryId, onSuccessHandler);
};
/* Obsolete */
ApiDataManagerClass.prototype.LoadLabelTemplateDesigns = function (categoryId, templateTag, onSuccessHandler) {
    this.PostJsonRequest(this.GalleryApiUrl + '/templatedesign/' + categoryId + '/' + templateTag + '/0', onSuccessHandler);
};
/* Obsolete */
ApiDataManagerClass.prototype.LoadThemeDesignsPageItems = function (categoryId, templateTag, startPage, onSuccessHandler) {
    this.PostJsonRequest(this.GalleryApiUrl + '/templatedesign/' + categoryId + '/' + templateTag + '/' + startPage, onSuccessHandler);
};
/* Obsolete */
ApiDataManagerClass.prototype.LoadDesignGalleryTemplateHeader = function (id, onSuccessHandler) {
    this.PostJsonRequest(this.GalleryApiUrl + '/templatedesigndetail/' + id, onSuccessHandler);
};

ApiDataManagerClass.prototype.LoadBasicShapeTemplates = function (onSuccessHandler) {
    this.PostJsonRequest(this.StickerMakerApiUrl + '/shapetemplates', onSuccessHandler);
};

ApiDataManagerClass.prototype.SelectBasicShapeTemplate = function (templateId, onSuccessHandler) {
    this.PostJsonRequest(this.StickerMakerApiUrl + '/setbasicshape/' + templateId, onSuccessHandler);
};

ApiDataManagerClass.prototype.SelectApplicationTemplate = function (templateId, onSuccessHandler) {
    this.PostJsonRequest(this.StickerMakerApiUrl + '/setappshape/' + templateId, onSuccessHandler);
};

ApiDataManagerClass.prototype.SelectDiecutTemplate = function (onSuccessHandler) {
    this.PostJsonRequest(this.StickerMakerApiUrl + '/setcustomdiecut', onSuccessHandler);
};

ApiDataManagerClass.prototype.GetFonts = function (onSuccessHandler) {
    this.PostJsonRequest(this.StickerMakerApiUrl + '/getfonts', onSuccessHandler);
};

ApiDataManagerClass.prototype.SetStickerSize = function (data, onSuccessHandler, onErrorHandler) {
    var context = { successHandler: onSuccessHandler, errorHandler: onErrorHandler, params: null };
    this.PostJsonData(this.StickerMakerApiUrl + '/setstickersize', data, context);
};

ApiDataManagerClass.prototype.SetBColor = function (data, onSuccessHandler, onErrorHandler) {
    var context = { successHandler: onSuccessHandler, errorHandler: onErrorHandler, params: null };
    this.PostJsonData(this.StickerMakerApiUrl + '/setbcolor', data, context);
};

//border related methods
ApiDataManagerClass.prototype.SetBorderColor = function (data, onSuccessHandler, onErrorHandler) {
    var context = { successHandler: onSuccessHandler, errorHandler: onErrorHandler, params: null };
    this.PostJsonData(this.StickerMakerApiUrl + '/setbordercolor', data, context);
};
ApiDataManagerClass.prototype.SetBorderThickness = function (data, onSuccessHandler, onErrorHandler) {
    var context = { successHandler: onSuccessHandler, errorHandler: onErrorHandler, params: null };
    this.PostJsonData(this.StickerMakerApiUrl + '/setborderthickness', data, context);
};
ApiDataManagerClass.prototype.AddRemoveBorder = function (data, onSuccessHandler, onErrorHandler) {
    var context = { successHandler: onSuccessHandler, errorHandler: onErrorHandler, params: null };
    this.PostJsonData(this.StickerMakerApiUrl + '/addremoveborder', data, context);
};
//border related methods end

ApiDataManagerClass.prototype.SaveStickerOrderDetails = function (data, onSuccessHandler, onErrorHandler) {
    var context = { successHandler: onSuccessHandler, errorHandler: onErrorHandler, params: null };
    this.PostJsonData(this.StickerMakerApiUrl + '/savestickerorderdetails', data, context);
};

ApiDataManagerClass.prototype.LoadInspirationPages = function (categoryId, onSuccessHandler) {
    this.PostJsonRequest(this.GalleryApiUrl + '/inspirationpage/' + categoryId, onSuccessHandler);
};

ApiDataManagerClass.prototype.Validate = function (data, onSuccessHandler) {
    var url = this.StickerMakerApiUrl + '/validate';
    this.AjaxJsonPost(url, data, onSuccessHandler);
};

ApiDataManagerClass.prototype.FixCondition = function (data, onSuccessHandler) {
    var context = { successHandler: onSuccessHandler, params: null };
    this.PostJsonData(this.StickerMakerApiUrl + '/fixcondition', data, context);
};

ApiDataManagerClass.prototype.IsAssetCustomizable = function (assetId, context) {
    this.PostJsonData(this.StickerMakerApiUrl + '/isassetcustomizable/' + assetId, assetId, context);
};

ApiDataManagerClass.prototype.SetMerrowColor = function (data, onSuccessHandler, onErrorHandler) {
    var context = { successHandler: onSuccessHandler, errorHandler: onErrorHandler, params: null };
    this.PostJsonData(this.StickerMakerApiUrl + '/setmerrowcolor', data, context);
};

/* Checkout methods */

ApiDataManagerClass.prototype.CheckoutSetShippingAddress = function (addressId, onSuccessHandler, onErrorHandler, onAlwaysHandler) {
    var data = JSON.stringify({ addressId: addressId });
    this.AjaxJsonPost('{0}/{1}'.format(this.CheckoutApiUrl, 'setshippingaddress'), data, onSuccessHandler, onErrorHandler, onAlwaysHandler);
};

ApiDataManagerClass.prototype.CheckoutSetShippingMethod = function (methodId, onSuccessHandler, onErrorHandler, onAlwaysHandler) {
    var data = JSON.stringify({ methodId: methodId });
    this.AjaxJsonPost('{0}/{1}'.format(this.CheckoutApiUrl, 'setshippingmethod'), data, onSuccessHandler, onErrorHandler, onAlwaysHandler);
};

ApiDataManagerClass.prototype.CheckoutSaveNewAddress = function (address, onSuccessHandler, onErrorHandler, onAlwaysHandler) {
    var data = JSON.stringify(address);
    this.AjaxJsonPost('{0}/{1}'.format(this.CheckoutApiUrl, 'saveshippingaddress'), data, onSuccessHandler, onErrorHandler, onAlwaysHandler);
};

ApiDataManagerClass.prototype.CheckoutDoneShipping = function (bag, onSuccessHandler, onErrorHandler, onAlwaysHandler) {
    var data = JSON.stringify(bag);
    this.AjaxJsonPost('{0}/{1}'.format(this.CheckoutApiUrl, 'doneshippingaddress'), data, onSuccessHandler, onErrorHandler, onAlwaysHandler);
};

ApiDataManagerClass.prototype.ApplyPromoCode = function (promoCode, onSuccessHandler, onErrorHandler, onAlwaysHandler) {
    var data = JSON.stringify({ promoCode: promoCode });
    this.AjaxJsonPost('{0}/{1}'.format(this.CheckoutApiUrl, 'trypromocode'), data, onSuccessHandler, onErrorHandler, onAlwaysHandler);
};

ApiDataManagerClass.prototype.RemovePromoCode = function (onSuccessHandler, onErrorHandler, onAlwaysHandler) {    
    this.AjaxJsonPost('{0}/{1}'.format(this.CheckoutApiUrl, 'removepromocode'), null, onSuccessHandler, onErrorHandler, onAlwaysHandler);
};

ApiDataManagerClass.prototype.ValidatePayment = function (obj, onSuccessHandler, onErrorHandler, onAlwaysHandler) {
    var data = JSON.stringify(obj);
    this.AjaxJsonPost('{0}/{1}'.format(this.CheckoutApiUrl, 'validatepayment'), data, onSuccessHandler, onErrorHandler, onAlwaysHandler);
};

ApiDataManagerClass.prototype.CheckoutDonePayment = function (obj, onSuccessHandler, onErrorHandler, onAlwaysHandler) {
    var data = JSON.stringify(obj);
    this.AjaxJsonPost('{0}/{1}'.format(this.CheckoutApiUrl, 'donepayment'), data, onSuccessHandler, onErrorHandler, onAlwaysHandler);
};

/* Checkout methods end */

var ApiDataManager = ApiDataManager || new ApiDataManagerClass();;
