<commit_before>
openerp.web.formats = function(openerp) {

/**
 * Formats a single atomic value based on a field descriptor
 *
 * @param {Object} value read from OpenERP
 * @param {Object} descriptor union of orm field and view field
 * @param {Object} [descriptor.widget] widget to use to display the value
 * @param {Object} descriptor.type fallback if no widget is provided, or if the provided widget is unknown
 * @param {Object} [descriptor.digits] used for the formatting of floats
 * @param {String} [value_if_empty=''] returned if the ``value`` argument is considered empty
 */
openerp.web.format_value = function (value, descriptor, value_if_empty) {
    // If NaN value, display as with a `false` (empty cell)
    if (typeof value === 'number' && isNaN(value)) {
        value = false;
    }
    switch (value) {
        case false:
        case Infinity:
        case -Infinity:
            return value_if_empty === undefined ?  '' : value_if_empty;
    }
    switch (descriptor.widget || descriptor.type) {
        case 'integer':
            return _.sprintf('%d', value);
        case 'float':
            var precision = descriptor.digits ? descriptor.digits[1] : 2;
            return _.sprintf('%.' + precision + 'f', value)
                .replace('.', openerp.web._t.database.parameters.decimal_point);
        case 'float_time':
            return _.sprintf("%02d:%02d",
                    Math.floor(value),
                    Math.round((value % 1) * 60));
        case 'progressbar':
            return _.sprintf(
                '<progress value="%.2f" max="100.0">%.2f%%</progress>',
                    value, value);
        case 'many2one':
            // name_get value format
            return value[1];
        case 'datetime':
            if (typeof(value) == "string")
                value = openerp.web.auto_str_to_date(value);
            try {
                return value.toString(_.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate,
                    Date.CultureInfo.formatPatterns.longTime));
            } catch (e) {
                return value.format("%m/%d/%Y %H:%M:%S");
            }
            return value;
        case 'date':
            if (typeof(value) == "string")
                value = openerp.web.auto_str_to_date(value);
            try {
                return value.toString(Date.CultureInfo.formatPatterns.shortDate);
            } catch (e) {
                return value.format("%m/%d/%Y");
            }
        case 'time':
            if (typeof(value) == "string")
                value = openerp.web.auto_str_to_date(value);
            try {
                return value.toString(Date.CultureInfo.formatPatterns.longTime);
            } catch (e) {
                return value.format("%H:%M:%S");
            }
        case 'selection':
            // Each choice is [value, label]
            var result = _(descriptor.selection).detect(function (choice) {
                return choice[0] === value;
            });
            if (result) { return result[1]; }
            return;
        default:
            return value;
    }
};

openerp.web.parse_value = function (value, descriptor, value_if_empty) {
    switch (value) {
        case false:
        case "":
            return value_if_empty === undefined ?  false : value_if_empty;
    }
    switch (descriptor.widget || descriptor.type) {
        case 'integer':
            var tmp;
            do {
                tmp = value;
                value = value.replace(openerp.web._t.database.parameters.thousands_sep, "");
            } while(tmp !== value);
            tmp = Number(value);
            if (isNaN(tmp))
                throw new Error(value + " is not a correct integer");
            return tmp;
        case 'float':
            var tmp = Number(value);
            if (!isNaN(tmp))
                return tmp;
            tmp = value.replace(openerp.web._t.database.parameters.decimal_point, ".");
            var tmp2 = tmp;
            do {
                tmp = tmp2;
                tmp2 = tmp.replace(openerp.web._t.database.parameters.thousands_sep, "");
            } while(tmp !== tmp2);
            tmp = Number(tmp);
            if (isNaN(tmp))
                throw new Error(value + " is not a correct float");
            return tmp;
        case 'float_time':
            var float_time_pair = value.split(":");
            if (float_time_pair.length != 2)
                throw new Error(value + " is not a correct float_time");
            var hours = openerp.web.parse_value(float_time_pair[0], {type: "integer"});
            var minutes = openerp.web.parse_value(float_time_pair[1], {type: "integer"});
            return hours + (minutes / 60);
        case 'progressbar':
            return openerp.web.parse_value(value, {type: "float"});
        case 'datetime':
            var datetime = Date.parseExact(value, _.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate,
                                                                     Date.CultureInfo.formatPatterns.longTime));
            if (datetime !== null)
                return openerp.web.datetime_to_str(datetime);
            datetime = Date.parse(value);
            if (datetime !== null)
                return openerp.web.datetime_to_str(datetime);
            throw new Error(value + " is not a valid datetime");
        case 'date':
            var date = Date.parseExact(value, Date.CultureInfo.formatPatterns.shortDate);
            if (date !== null)
                return openerp.web.date_to_str(date);
            date = Date.parse(value);
            if (date !== null)
                return openerp.web.date_to_str(date);
            throw new Error(value + " is not a valid date");
        case 'time':
            var time = Date.parseExact(value, Date.CultureInfo.formatPatterns.longTime);
            if (time !== null)
                return openerp.web.time_to_str(time);
            time = Date.parse(value);
            if (time !== null)
                return openerp.web.time_to_str(time);
            throw new Error(value + " is not a valid time");
    }
    return value;
};

openerp.web.auto_str_to_date = function(value, type) {
    try {
        return openerp.web.str_to_datetime(value);
    } catch(e) {}
    try {
        return openerp.web.str_to_date(value);
    } catch(e) {}
    try {
        return openerp.web.str_to_time(value);
    } catch(e) {}
    throw "'" + value + "' is not a valid date, datetime nor time"
};

openerp.web.auto_date_to_str = function(value, type) {
    switch(type) {
        case 'datetime':
            return openerp.web.datetime_to_str(value);
        case 'date':
            return openerp.web.date_to_str(value);
        case 'time':
            return openerp.web.time_to_str(value);
        default:
            throw type + " is not convertible to date, datetime nor time"
    }
};

/**
 * Formats a provided cell based on its field type
 *
 * @param {Object} row_data record whose values should be displayed in the cell
 * @param {Object} column column descriptor
 * @param {"button"|"field"} column.tag base control type
 * @param {String} column.type widget type for a field control
 * @param {String} [column.string] button label
 * @param {String} [column.icon] button icon
 * @param {String} [value_if_empty=''] what to display if the field's value is ``false``
 * @param {Boolean} [process_modifiers=true] should the modifiers be computed ?
 */
openerp.web.format_cell = function (row_data, column, value_if_empty, process_modifiers) {
    var attrs = {};
    if (process_modifiers !== false) {
        attrs = column.modifiers_for(row_data);
    }
    if (attrs.invisible) { return ''; }
    if (column.tag === 'button') {
        return [
            '<button type="button" title="', column.string || '', '">',
                '',
            '</button>'
        ].join('')
    }

    if (!row_data[column.id]) {
        return value_if_empty === undefined ? '' : value_if_empty;
    }
    return openerp.web.format_value(
            row_data[column.id].value, column, value_if_empty);
}

};
<commit_msg>[ADD] fallback float_time parsing on float parsing if the value does not match float_time's format<commit_after>
openerp.web.formats = function(openerp) {

/**
 * Formats a single atomic value based on a field descriptor
 *
 * @param {Object} value read from OpenERP
 * @param {Object} descriptor union of orm field and view field
 * @param {Object} [descriptor.widget] widget to use to display the value
 * @param {Object} descriptor.type fallback if no widget is provided, or if the provided widget is unknown
 * @param {Object} [descriptor.digits] used for the formatting of floats
 * @param {String} [value_if_empty=''] returned if the ``value`` argument is considered empty
 */
openerp.web.format_value = function (value, descriptor, value_if_empty) {
    // If NaN value, display as with a `false` (empty cell)
    if (typeof value === 'number' && isNaN(value)) {
        value = false;
    }
    switch (value) {
        case false:
        case Infinity:
        case -Infinity:
            return value_if_empty === undefined ?  '' : value_if_empty;
    }
    switch (descriptor.widget || descriptor.type) {
        case 'integer':
            return _.sprintf('%d', value);
        case 'float':
            var precision = descriptor.digits ? descriptor.digits[1] : 2;
            return _.sprintf('%.' + precision + 'f', value)
                .replace('.', openerp.web._t.database.parameters.decimal_point);
        case 'float_time':
            return _.sprintf("%02d:%02d",
                    Math.floor(value),
                    Math.round((value % 1) * 60));
        case 'progressbar':
            return _.sprintf(
                '<progress value="%.2f" max="100.0">%.2f%%</progress>',
                    value, value);
        case 'many2one':
            // name_get value format
            return value[1];
        case 'datetime':
            if (typeof(value) == "string")
                value = openerp.web.auto_str_to_date(value);
            try {
                return value.toString(_.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate,
                    Date.CultureInfo.formatPatterns.longTime));
            } catch (e) {
                return value.format("%m/%d/%Y %H:%M:%S");
            }
            return value;
        case 'date':
            if (typeof(value) == "string")
                value = openerp.web.auto_str_to_date(value);
            try {
                return value.toString(Date.CultureInfo.formatPatterns.shortDate);
            } catch (e) {
                return value.format("%m/%d/%Y");
            }
        case 'time':
            if (typeof(value) == "string")
                value = openerp.web.auto_str_to_date(value);
            try {
                return value.toString(Date.CultureInfo.formatPatterns.longTime);
            } catch (e) {
                return value.format("%H:%M:%S");
            }
        case 'selection':
            // Each choice is [value, label]
            var result = _(descriptor.selection).detect(function (choice) {
                return choice[0] === value;
            });
            if (result) { return result[1]; }
            return;
        default:
            return value;
    }
};

openerp.web.parse_value = function (value, descriptor, value_if_empty) {
    switch (value) {
        case false:
        case "":
            return value_if_empty === undefined ?  false : value_if_empty;
    }
    switch (descriptor.widget || descriptor.type) {
        case 'integer':
            var tmp;
            do {
                tmp = value;
                value = value.replace(openerp.web._t.database.parameters.thousands_sep, "");
            } while(tmp !== value);
            tmp = Number(value);
            if (isNaN(tmp))
                throw new Error(value + " is not a correct integer");
            return tmp;
        case 'float':
            var tmp = Number(value);
            if (!isNaN(tmp))
                return tmp;
            tmp = value.replace(openerp.web._t.database.parameters.decimal_point, ".");
            var tmp2 = tmp;
            do {
                tmp = tmp2;
                tmp2 = tmp.replace(openerp.web._t.database.parameters.thousands_sep, "");
            } while(tmp !== tmp2);
            tmp = Number(tmp);
            if (isNaN(tmp))
                throw new Error(value + " is not a correct float");
            return tmp;
        case 'float_time':
            var float_time_pair = value.split(":");
            if (float_time_pair.length != 2)
                return openerp.web.parse_value(value, {type: "float"});
            var hours = openerp.web.parse_value(float_time_pair[0], {type: "integer"});
            var minutes = openerp.web.parse_value(float_time_pair[1], {type: "integer"});
            return hours + (minutes / 60);
        case 'progressbar':
            return openerp.web.parse_value(value, {type: "float"});
        case 'datetime':
            var datetime = Date.parseExact(value, _.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate,
                                                                     Date.CultureInfo.formatPatterns.longTime));
            if (datetime !== null)
                return openerp.web.datetime_to_str(datetime);
            datetime = Date.parse(value);
            if (datetime !== null)
                return openerp.web.datetime_to_str(datetime);
            throw new Error(value + " is not a valid datetime");
        case 'date':
            var date = Date.parseExact(value, Date.CultureInfo.formatPatterns.shortDate);
            if (date !== null)
                return openerp.web.date_to_str(date);
            date = Date.parse(value);
            if (date !== null)
                return openerp.web.date_to_str(date);
            throw new Error(value + " is not a valid date");
        case 'time':
            var time = Date.parseExact(value, Date.CultureInfo.formatPatterns.longTime);
            if (time !== null)
                return openerp.web.time_to_str(time);
            time = Date.parse(value);
            if (time !== null)
                return openerp.web.time_to_str(time);
            throw new Error(value + " is not a valid time");
    }
    return value;
};

openerp.web.auto_str_to_date = function(value, type) {
    try {
        return openerp.web.str_to_datetime(value);
    } catch(e) {}
    try {
        return openerp.web.str_to_date(value);
    } catch(e) {}
    try {
        return openerp.web.str_to_time(value);
    } catch(e) {}
    throw "'" + value + "' is not a valid date, datetime nor time"
};

openerp.web.auto_date_to_str = function(value, type) {
    switch(type) {
        case 'datetime':
            return openerp.web.datetime_to_str(value);
        case 'date':
            return openerp.web.date_to_str(value);
        case 'time':
            return openerp.web.time_to_str(value);
        default:
            throw type + " is not convertible to date, datetime nor time"
    }
};

/**
 * Formats a provided cell based on its field type
 *
 * @param {Object} row_data record whose values should be displayed in the cell
 * @param {Object} column column descriptor
 * @param {"button"|"field"} column.tag base control type
 * @param {String} column.type widget type for a field control
 * @param {String} [column.string] button label
 * @param {String} [column.icon] button icon
 * @param {String} [value_if_empty=''] what to display if the field's value is ``false``
 * @param {Boolean} [process_modifiers=true] should the modifiers be computed ?
 */
openerp.web.format_cell = function (row_data, column, value_if_empty, process_modifiers) {
    var attrs = {};
    if (process_modifiers !== false) {
        attrs = column.modifiers_for(row_data);
    }
    if (attrs.invisible) { return ''; }
    if (column.tag === 'button') {
        return [
            '<button type="button" title="', column.string || '', '">',
                '',
            '</button>'
        ].join('')
    }

    if (!row_data[column.id]) {
        return value_if_empty === undefined ? '' : value_if_empty;
    }
    return openerp.web.format_value(
            row_data[column.id].value, column, value_if_empty);
}

};
<|endoftext|>


<commit_before>;(function($, window) {
    var emptyFn = function() {};

    /**
     * Shopware AJAX variant
     *
     * @example
     * HTML:
     *

     *
     * JS:
     * $('*[data-ajax-variants-container="true"]').swAjaxVariant();
     */
    $.plugin('swAjaxVariant', {

        /**
         * Supports the browser the history api
         * @boolean
         */
        hasHistorySupport: Modernizr.history,

        /**
         * Safari specific property which prevent safari to do another request on page load.
         * @boolean
         */
        initialPopState: true,

        /**
         * Default configuration of the plugin
         * @object
         */
        defaults: {
            productDetailsSelector: '.product--detail-upper',
            configuratorFormSelector: '.configurator--form',
            orderNumberSelector: '.entry--sku .entry--content',
            historyIdentifier: 'sw-ajax-variants'
        },

        /**
         * Initializes the plugin and sets up the necessary event handler
         */
        init: function() {
            var me = this,
                ie;

            // Check if we have a variant configurator
            if (!me.$el.find('.product--configurator').length) {
                return;
            }

            me.applyDataAttributes();

            // Detecting IE version using feature detection (IE7+, browsers prior to IE7 are detected as 7)
            ie = (function (){
                if (window.ActiveXObject === undefined) return null;
                if (!document.querySelector) return 7;
                if (!document.addEventListener) return 8;
                if (!window.atob) return 9;
                if (!document.__proto__) return 10;
                return 11;
            })();

            if (ie && ie <= 9) {
                me.hasHistorySupport = false;
            }

            me.$el
                .on(me.getEventName('click'), '*[data-ajax-variants="true"]', $.proxy(me.onChange, me))
                .on(me.getEventName('change'), '*[data-ajax-select-variants="true"]', $.proxy(me.onChange, me))
                .on(me.getEventName('click'), '.reset--configuration', $.proxy(me.onChange, me));

            $(window).on("popstate", $.proxy(me.onPopState, me));

            if(me.hasHistorySupport) {
                me.publishInitialState();
            }
        },

        /**
         * Replaces the most recent history entry, when the user enters the page.
         *
         * @returns void
         */
        publishInitialState: function() {
            var me = this,
                stateObj = me._createHistoryStateObject();

            window.history.replaceState(stateObj.state, stateObj.title);
        },

        /**
         * Requests the HTML structure of the product detail page using AJAX and injects the returned
         * content into the page.
         *
         * @param {String} values
         * @param {Boolean} pushState
         */
        requestData: function(values, pushState) {
            var me = this,
                stateObj = me._createHistoryStateObject();

            $.loadingIndicator.open({
                closeOnClick: false,
                delay: 100
            });

            $.publish('plugin/swAjaxVariant/onBeforeRequestData', [ me, values, stateObj.location ]);

            values += '&template=ajax';

            if(stateObj.params.hasOwnProperty('c')) {
                values += '&c=' + stateObj.params.c;
            }

            $.ajax({
                url: stateObj.location,
                data: values,
                method: 'GET',
                success: function(response) {
                    var $response = $($.parseHTML(response)),
                        $productDetails,
                        ordernumber;

                    // Replace the content
                    $productDetails = $response.find(me.opts.productDetailsSelector);
                    $(me.opts.productDetailsSelector).html($productDetails.html());

                    // Get the ordernumber for the url
                    ordernumber = $.trim(me.$el.find(me.opts.orderNumberSelector).text());

                    StateManager.addPlugin('select:not([data-no-fancy-select="true"])', 'swSelectboxReplacement')
                        .addPlugin('*[data-image-slider="true"]', 'swImageSlider', { touchControls: true })
                        .addPlugin('.product--image-zoom', 'swImageZoom', 'xl')
                        .addPlugin('*[data-image-gallery="true"]', 'swImageGallery')
                        .addPlugin('*[data-add-article="true"]', 'swAddArticle')
                        .addPlugin('*[data-modalbox="true"]', 'swModalbox');

                    $.loadingIndicator.close();

                    // Plugin developers should subscribe to this event to update their plugins accordingly
                    $.publish('plugin/swAjaxVariant/onRequestData', [ me, response, values, stateObj.location ]);

                    if(pushState && me.hasHistorySupport) {
                        var location = stateObj.location + '?number=' + ordernumber;

                        if(stateObj.params.hasOwnProperty('c')) {
                            location += '&c=' + stateObj.params.c;
                        }

                        window.history.pushState(stateObj.state, stateObj.title, location);
                    }
                }
            });
        },

        /**
         * Event handler method which will be fired when the user click the back button
         * in it's browser.
         *
         * @param {EventObject} event
         * @returns {boolean}
         */
        onPopState: function(event) {
            var me = this,
                state = event.originalEvent.state;

            if (!state || !state.hasOwnProperty('type') || state.type !== 'sw-ajax-variants') {
                return;
            }

            if ($('html').hasClass('is--safari') && me.initialPopState) {
                me.initialPopState = false;
                return;
            }

            if (!state.values.length) {
                state = '';
            }

            // Prevents the scrolling to top in webkit based browsers
            if(state && state.scrollPos) {
                window.setTimeout(function() {
                    $(window).scrollTop(state.scrollPos);
                }, 10);
            }

            $.publish('plugin/swAjaxVariant/onPopState', [ me, state ]);

            me.requestData(state.values, false);
        },

        /**
         * Event handler which will fired when the user selects a variant in the storefront.
         * @param {EventObject} event
         */
        onChange: function(event) {
            var me = this,
                $target = $(event.target),
                $form = $target.parents('form'),
                values = $form.serialize();

            event.preventDefault();

            if (!me.hasHistorySupport) {
                $.loadingIndicator.open({
                    closeOnClick: false,
                    delay: 0
                });
                $form.submit();

                return false;
            }

            $.publish('plugin/swAjaxVariant/onChange', [ me, values, $target ]);

            me.requestData(values, true);
        },

        /**
         * Helper method which returns all available url parameters.
         * @returns {Object}
         * @private
         */
        _getUrlParams: function() {
            var url = window.decodeURIComponent(window.location.search.substring(1)),
                urlParams = url.split('&'),
                params = {};

            $.each(urlParams, function(i, param) {
                param = param.split('=');

                if(param[0].length && param[1].length && !params.hasOwnProperty(param[0])) {
                    params[param[0]] = param[1];
                }
            });

            return params;
        },

        /**
         * Helper method which returns the full URL of the shop
         * @returns {string}
         * @private
         */
        _getUrl: function() {
            return window.location.protocol + "//" + window.location.host + window.location.pathname;
        },

        /**
         * Provides a state object which can be used with the {@link Window.history} API.
         *
         * The ordernumber will be fetched every time 'cause we're replacing the upper part of the detail page and
         * therefore we have to get the ordernumber using the DOM.
         *
         * @returns {Object} state object including title and location
         * @private
         */
        _createHistoryStateObject: function() {
            var me = this,
                $form = me.$el.find(me.opts.configuratorFormSelector),
                urlParams = me._getUrlParams(),
                location = me._getUrl();

            return {
                state: {
                    type: me.opts.historyIdentifier,
                    values: $form.serialize(),
                    scrollPos: $(window).scrollTop()
                },
                title: document.title,
                location: location,
                params: urlParams
            };
        }
    });
})(jQuery, window);
<commit_msg>SW-15560 - Fix article question variant<commit_after>;(function($, window) {
    var emptyFn = function() {};

    /**
     * Shopware AJAX variant
     *
     * @example
     * HTML:
     *

     *
     * JS:
     * $('*[data-ajax-variants-container="true"]').swAjaxVariant();
     */
    $.plugin('swAjaxVariant', {

        /**
         * Supports the browser the history api
         * @boolean
         */
        hasHistorySupport: Modernizr.history,

        /**
         * Safari specific property which prevent safari to do another request on page load.
         * @boolean
         */
        initialPopState: true,

        /**
         * Default configuration of the plugin
         * @object
         */
        defaults: {
            productDetailsSelector: '.product--detail-upper',
            configuratorFormSelector: '.configurator--form',
            orderNumberSelector: '.entry--sku .entry--content',
            historyIdentifier: 'sw-ajax-variants',
            productDetailsDescriptionSelector: '.content--description'
        },

        /**
         * Initializes the plugin and sets up the necessary event handler
         */
        init: function() {
            var me = this,
                ie;

            // Check if we have a variant configurator
            if (!me.$el.find('.product--configurator').length) {
                return;
            }

            me.applyDataAttributes();

            // Detecting IE version using feature detection (IE7+, browsers prior to IE7 are detected as 7)
            ie = (function (){
                if (window.ActiveXObject === undefined) return null;
                if (!document.querySelector) return 7;
                if (!document.addEventListener) return 8;
                if (!window.atob) return 9;
                if (!document.__proto__) return 10;
                return 11;
            })();

            if (ie && ie <= 9) {
                me.hasHistorySupport = false;
            }

            me.$el
                .on(me.getEventName('click'), '*[data-ajax-variants="true"]', $.proxy(me.onChange, me))
                .on(me.getEventName('change'), '*[data-ajax-select-variants="true"]', $.proxy(me.onChange, me))
                .on(me.getEventName('click'), '.reset--configuration', $.proxy(me.onChange, me));

            $(window).on("popstate", $.proxy(me.onPopState, me));

            if(me.hasHistorySupport) {
                me.publishInitialState();
            }
        },

        /**
         * Replaces the most recent history entry, when the user enters the page.
         *
         * @returns void
         */
        publishInitialState: function() {
            var me = this,
                stateObj = me._createHistoryStateObject();

            window.history.replaceState(stateObj.state, stateObj.title);
        },

        /**
         * Requests the HTML structure of the product detail page using AJAX and injects the returned
         * content into the page.
         *
         * @param {String} values
         * @param {Boolean} pushState
         */
        requestData: function(values, pushState) {
            var me = this,
                stateObj = me._createHistoryStateObject();

            $.loadingIndicator.open({
                closeOnClick: false,
                delay: 100
            });

            $.publish('plugin/swAjaxVariant/onBeforeRequestData', [ me, values, stateObj.location ]);

            values += '&template=ajax';

            if(stateObj.params.hasOwnProperty('c')) {
                values += '&c=' + stateObj.params.c;
            }

            $.ajax({
                url: stateObj.location,
                data: values,
                method: 'GET',
                success: function(response) {
                    var $response = $($.parseHTML(response)),
                        $productDetails,
                        $productDescription,
                        ordernumber;

                    // Replace the content
                    $productDetails = $response.find(me.opts.productDetailsSelector);
                    $(me.opts.productDetailsSelector).html($productDetails.html());

                    // Replace the description box
                    $productDescription = $response.find(me.opts.productDetailsDescriptionSelector);
                    $(me.opts.productDetailsDescriptionSelector).html($productDescription.html());

                    // Get the ordernumber for the url
                    ordernumber = $.trim(me.$el.find(me.opts.orderNumberSelector).text());

                    StateManager.addPlugin('select:not([data-no-fancy-select="true"])', 'swSelectboxReplacement')
                        .addPlugin('*[data-image-slider="true"]', 'swImageSlider', { touchControls: true })
                        .addPlugin('.product--image-zoom', 'swImageZoom', 'xl')
                        .addPlugin('*[data-image-gallery="true"]', 'swImageGallery')
                        .addPlugin('*[data-add-article="true"]', 'swAddArticle')
                        .addPlugin('*[data-modalbox="true"]', 'swModalbox');

                    // Plugin developers should subscribe to this event to update their plugins accordingly
                    $.publish('plugin/swAjaxVariant/onRequestData', [ me, response, values, stateObj.location ]);

                    if(pushState && me.hasHistorySupport) {
                        var location = stateObj.location + '?number=' + ordernumber;

                        if(stateObj.params.hasOwnProperty('c')) {
                            location += '&c=' + stateObj.params.c;
                        }

                        window.history.pushState(stateObj.state, stateObj.title, location);
                    }
                },
                complete: function() {
                    $.loadingIndicator.close();
                }
            });
        },

        /**
         * Event handler method which will be fired when the user click the back button
         * in it's browser.
         *
         * @param {EventObject} event
         * @returns {boolean}
         */
        onPopState: function(event) {
            var me = this,
                state = event.originalEvent.state;

            if (!state || !state.hasOwnProperty('type') || state.type !== 'sw-ajax-variants') {
                return;
            }

            if ($('html').hasClass('is--safari') && me.initialPopState) {
                me.initialPopState = false;
                return;
            }

            if (!state.values.length) {
                state = '';
            }

            // Prevents the scrolling to top in webkit based browsers
            if(state && state.scrollPos) {
                window.setTimeout(function() {
                    $(window).scrollTop(state.scrollPos);
                }, 10);
            }

            $.publish('plugin/swAjaxVariant/onPopState', [ me, state ]);

            me.requestData(state.values, false);
        },

        /**
         * Event handler which will fired when the user selects a variant in the storefront.
         * @param {EventObject} event
         */
        onChange: function(event) {
            var me = this,
                $target = $(event.target),
                $form = $target.parents('form'),
                values = $form.serialize();

            event.preventDefault();

            if (!me.hasHistorySupport) {
                $.loadingIndicator.open({
                    closeOnClick: false,
                    delay: 0
                });
                $form.submit();

                return false;
            }

            $.publish('plugin/swAjaxVariant/onChange', [ me, values, $target ]);

            me.requestData(values, true);
        },

        /**
         * Helper method which returns all available url parameters.
         * @returns {Object}
         * @private
         */
        _getUrlParams: function() {
            var url = window.decodeURIComponent(window.location.search.substring(1)),
                urlParams = url.split('&'),
                params = {};

            $.each(urlParams, function(i, param) {
                param = param.split('=');

                if(param[0].length && param[1].length && !params.hasOwnProperty(param[0])) {
                    params[param[0]] = param[1];
                }
            });

            return params;
        },

        /**
         * Helper method which returns the full URL of the shop
         * @returns {string}
         * @private
         */
        _getUrl: function() {
            return window.location.protocol + "//" + window.location.host + window.location.pathname;
        },

        /**
         * Provides a state object which can be used with the {@link Window.history} API.
         *
         * The ordernumber will be fetched every time 'cause we're replacing the upper part of the detail page and
         * therefore we have to get the ordernumber using the DOM.
         *
         * @returns {Object} state object including title and location
         * @private
         */
        _createHistoryStateObject: function() {
            var me = this,
                $form = me.$el.find(me.opts.configuratorFormSelector),
                urlParams = me._getUrlParams(),
                location = me._getUrl();

            return {
                state: {
                    type: me.opts.historyIdentifier,
                    values: $form.serialize(),
                    scrollPos: $(window).scrollTop()
                },
                title: document.title,
                location: location,
                params: urlParams
            };
        }
    });
})(jQuery, window);
<|endoftext|>


<commit_before>import React, { useState } from "react";
import styled from "styled-components";

import Page from "../components/page";
import Constellations from "../components/constellations";
import RetroStars from "../components/retrostars";
import Synthwave from "../components/synthwave";

const Art = () => {
  const [lightboxImage, setLightboxImage] = useState(null);
  const [lightboxLoaded, setLightboxLoaded] = useState(false);

  const openLightbox = image => {
    setLightboxImage(image);
    document.body.style.overflowY = "hidden";
  };

  const closeLightbox = () => {
    setLightboxImage(null);
    setLightboxLoaded(false);
    document.body.style.overflowY = "scroll";
  };

  return (
    <Page title="Art" description="Some of my art... what even is art...">
      <Background />
      <Heading>Acrylic Pours</Heading>
      <Paragraph>
        A bit more traditional than my usual art, acrylics mixed with water,
        glue, and silicone on canvas and hit with a heat gun.
      </Paragraph>
      <Cards>
        <Card onClick={() => openLightbox("/static/images/art/006.jpg")}>
          <CardImage
            src="/static/images/art/006-thumbnail.jpg"
            alt="Molten Copper"
          />
          <CardHeading>
            Molten Copper 006
          </CardHeading>
        </Card>
        <Card onClick={() => openLightbox("/static/images/art/005.jpg")}>
          <CardImage
            src="/static/images/art/005-thumbnail.jpg"
            alt="Nebulas in Triangulum"
          />
          <CardHeading>
            Nebulas in Triangulum 005
          </CardHeading>
        </Card>
        <Card onClick={() => openLightbox("/static/images/art/004.jpg")}>
          <CardImage
            src="/static/images/art/004-thumbnail.jpg"
            alt="Metal on Mars"
          />
          <CardHeading>
            Metal on Mars 004
          </CardHeading>
        </Card>
        <Card onClick={() => openLightbox("/static/images/art/003.jpg")}>
          <CardImage
            src="/static/images/art/003-thumbnail.jpg"
            alt="Water on Jupiter"
          />
          <CardHeading>
            Water on Jupiter 003
          </CardHeading>
        </Card>
        <Card onClick={() => openLightbox("/static/images/art/002.jpg")}>
          <CardImage
            src="/static/images/art/002-thumbnail.jpg"
            alt="Cracks in Clay"
          />
          <CardHeading>
            Cracks in Clay 002
          </CardHeading>
        </Card>
        <Card onClick={() => openLightbox("/static/images/art/001.jpg")}>
          <CardImage
            src="/static/images/art/001-thumbnail.jpg"
            alt="Reef Drop-off"
          />
          <CardHeading>
            Reef Drop-off 001
          </CardHeading>
        </Card>
        <Card onClick={() => openLightbox("/static/images/art/000.jpg")}>
          <CardImage
            src="/static/images/art/000-thumbnail.jpg"
            alt="Blood in Waves"
          />
          <CardHeading>
            Blood in Waves 000
          </CardHeading>
        </Card>
      </Cards>
      <Heading>Emergent Generative Art</Heading>
      <Paragraph>
        Autonomously generated entities that are observed to have qualities in a
        group that they do not have on their own.
      </Paragraph>
      <Subheading>
        000 Constellations
      </Subheading>
      <Paragraph>
        Moving stars, circles, on a canvas that attach to nearby stars, with a
        line, to generate constellations. Line opacity is based on star
        distance.
      </Paragraph>
      <ArtContainer>
        <Constellations options={{ numStars: 50 }} />
      </ArtContainer>
      <Link
        href="https://github.com/overshard/isaacbythewood.com/blob/master/components/constellations.js"
        rel="noopener noreferrer"
        target="_blank"
      >
        See the Code
      </Link>
      <Subheading>
        001 Retro Stars
      </Subheading>
      <Paragraph>
        Multiple parallax planes of stars that shift based on cursor position.
        Inspired by the retro art style of Celeste.
      </Paragraph>
      <ArtContainer>
        <RetroStars options={{ numStars: 50 }} />
      </ArtContainer>
      <Link
        href="https://github.com/overshard/isaacbythewood.com/blob/master/components/retrostars.js"
        rel="noopener noreferrer"
        target="_blank"
      >
        See the Code
      </Link>
      <Subheading>
        002 Synthwave
      </Subheading>
      <Paragraph>I just like Synthwave stuff, a work in progress.</Paragraph>
      <ArtContainer>
        <Synthwave />
      </ArtContainer>
      <Link
        href="https://github.com/overshard/isaacbythewood.com/blob/master/components/planets.js"
        rel="noopener noreferrer"
        target="_blank"
      >
        See the Code
      </Link>
      {lightboxImage !== null && (
        <Lightbox onClick={() => closeLightbox()}>
          <LightboxLoading className={lightboxLoaded && "hide"}>
            Loading...
          </LightboxLoading>
          <LightboxImage
            src={lightboxImage}
            className={lightboxLoaded && "show"}
            onLoad={() => setLightboxLoaded(true)}
          />
        </Lightbox>
      )}
    </Page>
  );
};

export default Art;

const Background = styled.div`
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: white;
  z-index: -2;
`;

const Heading = styled.h1`
  font-weight: 700;
  margin-top: 60px;
  margin-bottom: 20px;
  font-size: 2.5em;
  color: black;

  &::before {
    content: "";
    display: block;
    width: 50px;
    height: 5px;
    margin-bottom: 20px;
    background-color: ${props => props.theme.colors.blue};
  }
`;

const Subheading = styled.h2`
  font-weight: 700;
  margin-top: 60px;
  margin-bottom: 20px;
  font-size: 2em;
  color: black;
  position: relative;

  & > span {
    font-family: monospace;
    font-size: 0.8em;
    padding: 3px 9px;
    background-color: black;
    color: white;
    position: absolute;
    right: 100%;
    margin-right: 10px;
    top: 20%;

    @media (${props => props.theme.breakpoints.tablet}) {
      display: none;
    }
  }
`;

const Paragraph = styled.p`
  font-size: 1.5em;
  margin-top: 0;
  margin-bottom: 20px;
  font-weight: 300;
  color: black;
`;

const ArtContainer = styled.div`
  width: 100%;
  height: 500px;
  max-height: 100vh;
  background: black;
  margin-bottom: 20px;
`;

const Link = styled.a`
  padding: 10px 15px;
  font-size: 1.2em;
  text-decoration: none;
  background-color: black;
  margin-bottom: 20px;
  font-weight: 700;
  text-transform: uppercase;
  display: inline-block;
  letter-spacing: 2px;
  color: white;
  background-image: linear-gradient(
    to right,
    ${props => props.theme.colors.blue} 0,
    ${props => props.theme.colors.purple} 100%
  );
  transform: scale(1);
  transition-duration: 250ms;
  transition-property: transform;

  &:hover {
    transform: scale(1.2);
  }
`;

const Cards = styled.div`
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr;
  grid-gap: 20px;
  margin-bottom: 50px;

  @media (${props => props.theme.breakpoints.mobile}) {
    grid-template-columns: 1fr;
  }
`;

const Card = styled.div`
  background-color: black;
  color: white;
  box-shadow: 0 5px 0 rgba(0, 0, 0, 0);
  transition-duration: 200ms;
  transition-property: box-shadow;
  transition-timing-function: ease-in;

  &:hover {
    box-shadow: 0 5px 25px rgba(0, 0, 0, 0.4);
  }
`;

const CardHeading = styled.h2`
  margin: 0;
  margin-top: -5px;
  padding: 10px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-weight: 900;

  & > span {
    color: black;
    font-family: monospace;
    font-weight: 100;
    font-size: 0.9em;
    background-color: white;
    padding: 3px 7px;
  }
`;

const CardImage = styled.img`
  object-fit: cover;
  object-position: center;
  width: 100%;
  height: 30vh;
`;

const Lightbox = styled.div`
  width: 100vw;
  height: 100vh;
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 3;
  background-color: rgba(0, 0, 0, 0.7);
  display: flex;
  justify-content: center;
  align-items: center;
`;

const LightboxImage = styled.img`
  position: absolute;
  max-width: 100%;
  max-height: 100%;
  padding: 5vw;
  box-sizing: border-box;
  visibility: hidden;
  opacity: 0;
  transition-property: opacity;
  transition-duration: 250ms;

  &.show {
    opacity: 1;
    visibility: visible;
  }
`;

const LightboxLoading = styled.div`
  position: absolute;
  max-width: 100%;
  max-height: 100%;
  box-sizing: border-box;
  color: white;
  font-family: monospace;
  font-size: 3em;
  visibility: visible;
  opacity: 1;
  transition-property: opacity;
  transition-duration: 250ms;

  &.hide {
    opacity: 0;
    visibility: hidden;
  }
`;
<commit_msg>Custom URLs for art<commit_after>import React, { useState, useEffect } from "react";
import styled from "styled-components";

import Page from "../components/page";
import Constellations from "../components/constellations";
import RetroStars from "../components/retrostars";
import Synthwave from "../components/synthwave";

const Art = () => {
  const [lightboxImage, setLightboxImage] = useState(null);
  const [lightboxLoaded, setLightboxLoaded] = useState(false);

  const openLightbox = image => {
    setLightboxImage(image);
    history.replaceState(
      null,
      null,
      "#" +
        image
          .split("/")
          .pop()
          .replace(".jpg", "")
    );

    document.body.style.overflowY = "hidden";
  };

  const closeLightbox = () => {
    setLightboxImage(null);
    setLightboxLoaded(false);
    history.replaceState(null, null, " ");
    document.body.style.overflowY = "scroll";
  };

  useEffect(() => {
    const validImageIds = ["001", "002", "003", "004", "005", "006"];
    const imageId = window.location.hash.replace("#", "");
    if (validImageIds.indexOf(imageId) > -1) {
      openLightbox(`/static/images/art/${imageId}.jpg`);
    }
  }, []);

  return (
    <Page title="Art" description="Some of my art... what even is art...">
      <Background />
      <Heading>Acrylic Pours</Heading>
      <Paragraph>
        A bit more traditional than my usual art, acrylics mixed with water,
        glue, and silicone on canvas and hit with a heat gun.
      </Paragraph>
      <Cards>
        <Card onClick={() => openLightbox("/static/images/art/006.jpg")}>
          <CardImage
            src="/static/images/art/006-thumbnail.jpg"
            alt="Molten Copper"
          />
          <CardHeading>
            Molten Copper 006
          </CardHeading>
        </Card>
        <Card onClick={() => openLightbox("/static/images/art/005.jpg")}>
          <CardImage
            src="/static/images/art/005-thumbnail.jpg"
            alt="Nebulas in Triangulum"
          />
          <CardHeading>
            Nebulas in Triangulum 005
          </CardHeading>
        </Card>
        <Card onClick={() => openLightbox("/static/images/art/004.jpg")}>
          <CardImage
            src="/static/images/art/004-thumbnail.jpg"
            alt="Metal on Mars"
          />
          <CardHeading>
            Metal on Mars 004
          </CardHeading>
        </Card>
        <Card onClick={() => openLightbox("/static/images/art/003.jpg")}>
          <CardImage
            src="/static/images/art/003-thumbnail.jpg"
            alt="Water on Jupiter"
          />
          <CardHeading>
            Water on Jupiter 003
          </CardHeading>
        </Card>
        <Card onClick={() => openLightbox("/static/images/art/002.jpg")}>
          <CardImage
            src="/static/images/art/002-thumbnail.jpg"
            alt="Cracks in Clay"
          />
          <CardHeading>
            Cracks in Clay 002
          </CardHeading>
        </Card>
        <Card onClick={() => openLightbox("/static/images/art/001.jpg")}>
          <CardImage
            src="/static/images/art/001-thumbnail.jpg"
            alt="Reef Drop-off"
          />
          <CardHeading>
            Reef Drop-off 001
          </CardHeading>
        </Card>
        <Card onClick={() => openLightbox("/static/images/art/000.jpg")}>
          <CardImage
            src="/static/images/art/000-thumbnail.jpg"
            alt="Blood in Waves"
          />
          <CardHeading>
            Blood in Waves 000
          </CardHeading>
        </Card>
      </Cards>
      <Heading>Emergent Generative Art</Heading>
      <Paragraph>
        Autonomously generated entities that are observed to have qualities in a
        group that they do not have on their own.
      </Paragraph>
      <Subheading>
        000 Constellations
      </Subheading>
      <Paragraph>
        Moving stars, circles, on a canvas that attach to nearby stars, with a
        line, to generate constellations. Line opacity is based on star
        distance.
      </Paragraph>
      <ArtContainer>
        <Constellations options={{ numStars: 50 }} />
      </ArtContainer>
      <Link
        href="https://github.com/overshard/isaacbythewood.com/blob/master/components/constellations.js"
        rel="noopener noreferrer"
        target="_blank"
      >
        See the Code
      </Link>
      <Subheading>
        001 Retro Stars
      </Subheading>
      <Paragraph>
        Multiple parallax planes of stars that shift based on cursor position.
        Inspired by the retro art style of Celeste.
      </Paragraph>
      <ArtContainer>
        <RetroStars options={{ numStars: 50 }} />
      </ArtContainer>
      <Link
        href="https://github.com/overshard/isaacbythewood.com/blob/master/components/retrostars.js"
        rel="noopener noreferrer"
        target="_blank"
      >
        See the Code
      </Link>
      <Subheading>
        002 Synthwave
      </Subheading>
      <Paragraph>I just like Synthwave stuff, a work in progress.</Paragraph>
      <ArtContainer>
        <Synthwave />
      </ArtContainer>
      <Link
        href="https://github.com/overshard/isaacbythewood.com/blob/master/components/planets.js"
        rel="noopener noreferrer"
        target="_blank"
      >
        See the Code
      </Link>
      {lightboxImage !== null && (
        <Lightbox onClick={() => closeLightbox()}>
          <LightboxLoading className={lightboxLoaded && "hide"}>
            Loading...
          </LightboxLoading>
          <LightboxImage
            src={lightboxImage}
            className={lightboxLoaded && "show"}
            onLoad={() => setLightboxLoaded(true)}
          />
        </Lightbox>
      )}
    </Page>
  );
};

export default Art;

const Background = styled.div`
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: white;
  z-index: -2;
`;

const Heading = styled.h1`
  font-weight: 700;
  margin-top: 60px;
  margin-bottom: 20px;
  font-size: 2.5em;
  color: black;

  &::before {
    content: "";
    display: block;
    width: 50px;
    height: 5px;
    margin-bottom: 20px;
    background-color: ${props => props.theme.colors.blue};
  }
`;

const Subheading = styled.h2`
  font-weight: 700;
  margin-top: 60px;
  margin-bottom: 20px;
  font-size: 2em;
  color: black;
  position: relative;

  & > span {
    font-family: monospace;
    font-size: 0.8em;
    padding: 3px 9px;
    background-color: black;
    color: white;
    position: absolute;
    right: 100%;
    margin-right: 10px;
    top: 20%;

    @media (${props => props.theme.breakpoints.tablet}) {
      display: none;
    }
  }
`;

const Paragraph = styled.p`
  font-size: 1.5em;
  margin-top: 0;
  margin-bottom: 20px;
  font-weight: 300;
  color: black;
`;

const ArtContainer = styled.div`
  width: 100%;
  height: 500px;
  max-height: 100vh;
  background: black;
  margin-bottom: 20px;
`;

const Link = styled.a`
  padding: 10px 15px;
  font-size: 1.2em;
  text-decoration: none;
  background-color: black;
  margin-bottom: 20px;
  font-weight: 700;
  text-transform: uppercase;
  display: inline-block;
  letter-spacing: 2px;
  color: white;
  background-image: linear-gradient(
    to right,
    ${props => props.theme.colors.blue} 0,
    ${props => props.theme.colors.purple} 100%
  );
  transform: scale(1);
  transition-duration: 250ms;
  transition-property: transform;

  &:hover {
    transform: scale(1.2);
  }
`;

const Cards = styled.div`
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr;
  grid-gap: 20px;
  margin-bottom: 50px;

  @media (${props => props.theme.breakpoints.mobile}) {
    grid-template-columns: 1fr;
  }
`;

const Card = styled.div`
  background-color: black;
  color: white;
  box-shadow: 0 5px 0 rgba(0, 0, 0, 0);
  transition-duration: 200ms;
  transition-property: box-shadow;
  transition-timing-function: ease-in;

  &:hover {
    box-shadow: 0 5px 25px rgba(0, 0, 0, 0.4);
  }
`;

const CardHeading = styled.h2`
  margin: 0;
  margin-top: -5px;
  padding: 10px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-weight: 900;

  & > span {
    color: black;
    font-family: monospace;
    font-weight: 100;
    font-size: 0.9em;
    background-color: white;
    padding: 3px 7px;
  }
`;

const CardImage = styled.img`
  object-fit: cover;
  object-position: center;
  width: 100%;
  height: 30vh;
`;

const Lightbox = styled.div`
  width: 100vw;
  height: 100vh;
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 3;
  background-color: rgba(0, 0, 0, 0.7);
  display: flex;
  justify-content: center;
  align-items: center;
`;

const LightboxImage = styled.img`
  position: absolute;
  max-width: 100%;
  max-height: 100%;
  padding: 5vw;
  box-sizing: border-box;
  visibility: hidden;
  opacity: 0;
  transition-property: opacity;
  transition-duration: 250ms;

  &.show {
    opacity: 1;
    visibility: visible;
  }
`;

const LightboxLoading = styled.div`
  position: absolute;
  max-width: 100%;
  max-height: 100%;
  box-sizing: border-box;
  color: white;
  font-family: monospace;
  font-size: 3em;
  visibility: visible;
  opacity: 1;
  transition-property: opacity;
  transition-duration: 250ms;

  &.hide {
    opacity: 0;
    visibility: hidden;
  }
`;
<|endoftext|>


<commit_before>var gameModule = angular.module('app', []).
	controller("gameTheoryControl", function gameTheoryControl($scope){

	    	function number(num){
	    		this.name = num;
	    		this.selected = false;
	    		return this;
	    	}

	    	$scope.numbers=[];
	    	$scope.solutions=[];

	    	$scope.getStarter = function(){
	    		var isEven = ($scope.solutions.length % 2) == 0;

	    		if(isEven){
	    			return "Alice";
	    		}
	    		else{
	    			return "Bob";
	    		}
	    	}

	    	function solution(x, parts){
	    		this.number = x;
	    		this.parts = parts;
	    	}

	    	$scope.amount = 5;

	    	$scope.newNumbers = function(){
			$scope.numbers = [];

			intAmount = parseInt($scope.amount);

			for(var i = 1; i < intAmount + 1; i++){
				$scope.numbers.push(new number(i));
			}
		}

		$scope.deleteSelected = function(){
			for(var num in $scope.numbers){
				if($scope.numbers[num].selected){
					$scope.numbers.splice(num, 1);
					num--;
				}
			}
		}

		function sumOf(parts){
			var num = 0;
			for(var i = 0; i < parts.length; i++){
				num += parts[i];
			}
			return num;
		}

		function getSmallerNumbers(number){
			var newArray = [];
			for(var i = 0; i < $scope.numbers.length; i++){
				if($scope.numbers[i].name <= number){
					newArray.push($scope.numbers[i].name);
				}
				else{
					break;
				}
			}
			return newArray;
		}

		var getCombinations2 = function(firstParts, parts, solutions) {
			var results = [];
		    	for (var i = 0; i < parts.length; i++) {
			      solutions.push(firstParts.concat(parts[i]));
			      solutions.concat(getCombinations(firstParts.concat(parts[i]), parts.splice(i + 1)), solutions);
		    	}
		   return solutions;
		}

		var getCombinations = function(startArray, arrayOfNumbers){
			var results = [];
			for(var i = 0; i < arrayOfNumbers.length; i++){
				results.push(startArray.concat(arrayOfNumbers[i]));

				var tempArray = [];
				for(var j = 0; j < arrayOfNumbers.length; j++){
					if(j > i){
						tempArray.push(arrayOfNumbers[j]);
					}
				}

				results = results.concat(getCombinations(startArray.concat(arrayOfNumbers[i]), tempArray));
			}
			return results;
		}

		$scope.getSolutions = function(){
			$scope.solutions = [];
			var calculable = true;
			var currentNumber = 1;

			while(calculable){
				parts = [];

				var solved = false;

				var smallerNums = getSmallerNumbers(currentNumber);

				if(smallerNums.length == 0){
					calculable = false; break;
				}

				for(var i = 0; i < $scope.numbers.length; i++){
					if($scope.numbers[i].name == currentNumber)
					solved = true;
					$scope.solutions.push(new solution(currentNumber, [$scope.numbers[i].name]));
				}

				if(!solved){
					var combinations = getCombinations([], smallerNums);

						for(var i = 0; i < combinations.length; i++){
							if(sumOf(combinations[i]) == currentNumber){
								$scope.solutions.push(new solution(currentNumber, combinations[i]));
								solved = true;
								break;
							}
							if(solved){break;}
						}

					if(!solved){
						calculable = false; break;
					}
				}

				currentNumber++;
			}
		}

		$scope.newNumbers();

	});
<commit_msg>Update gameTheoryController.js<commit_after>var gameModule = angular.module('app', []).
	controller("gameTheoryControl", function gameTheoryControl($scope){

	    	function number(num){
	    		this.name = num;
	    		this.selected = false;
	    		return this;
	    	}

	    	$scope.numbers=[];
	    	$scope.solutions=[];

	    	$scope.getStarter = function(){
	    		var isEven = ($scope.solutions.length % 2) == 0;

	    		if(isEven){
	    			return "Alice";
	    		}
	    		else{
	    			return "Bob";
	    		}
	    	}

	    	function solution(x, parts){
	    		this.number = x;
	    		this.parts = parts;
	    	}

	    	$scope.amount = 5;

	    	$scope.newNumbers = function(){
			$scope.numbers = [];

			intAmount = parseInt($scope.amount);

			for(var i = 1; i < intAmount + 1; i++){
				$scope.numbers.push(new number(i));
			}
		}

		$scope.deleteSelected = function(){
			for(var num in $scope.numbers){
				if($scope.numbers[num].selected){
					$scope.numbers.splice(num, 1);
					num--;
				}
			}
		}

		function sumOf(parts){
			var num = 0;
			for(var i = 0; i < parts.length; i++){
				num += parts[i];
			}
			return num;
		}

		function getSmallerNumbers(number){
			var newArray = [];
			for(var i = 0; i < $scope.numbers.length; i++){
				if($scope.numbers[i].name <= number){
					newArray.push($scope.numbers[i].name);
				}
				else{
					break;
				}
			}
			return newArray;
		}

		var getCombinations2 = function(firstParts, parts, solutions) {
			var results = [];
		    	for (var i = 0; i < parts.length; i++) {
			      solutions.push(firstParts.concat(parts[i]));
			      solutions.concat(getCombinations(firstParts.concat(parts[i]), parts.splice(i + 1)), solutions);
		    	}
		   return solutions;
		}

		var getCombinations = function(startArray, arrayOfNumbers){
			var results = [];
			for(var i = 0; i < arrayOfNumbers.length; i++){
				results.push(startArray.concat(arrayOfNumbers[i]));

				var tempArray = [];
				for(var j = 0; j < arrayOfNumbers.length; j++){
					if(j > i){
						tempArray.push(arrayOfNumbers[j]);
					}
				}

				results = results.concat(getCombinations(startArray.concat(arrayOfNumbers[i]), tempArray));
			}
			return results;
		}

		$scope.getSolutions = function(){
			$scope.solutions = [];
			var calculable = true;
			var currentNumber = 1;

			while(calculable){
				parts = [];

				var solved = false;

				var smallerNums = getSmallerNumbers(currentNumber);

				if(smallerNums.length == 0){
					calculable = false; break;
				}

				for(var i = 0; i < $scope.numbers.length; i++){
					if($scope.numbers[i].name == currentNumber)
					{
						solved = true;
						$scope.solutions.push(new solution(currentNumber, [$scope.numbers[i].name]));
					}
				}

				if(!solved){
					var combinations = getCombinations([], smallerNums);

						for(var i = 0; i < combinations.length; i++){
							if(sumOf(combinations[i]) == currentNumber){
								$scope.solutions.push(new solution(currentNumber, combinations[i]));
								solved = true;
								break;
							}
							if(solved){break;}
						}

					if(!solved){
						calculable = false; break;
					}
				}

				currentNumber++;
			}
		}

		$scope.newNumbers();

	});
<|endoftext|>


<commit_before>import 'babel-polyfill'
import React from 'react'
import ReactDOM from 'react-dom'
import FastClick from 'fastclick'   // TODO verify working?
import { resolve } from 'universal-router'
import queryString from 'query-string'

import config from '../config'
import history from '../utils/history'
import { updateHead } from './head'
import App from '../shared/components/App'

// Global (context) variables that can be easily accessed from any React component
// https://facebook.github.io/react/docs/context.html
const context = {
  // Enables critical path CSS rendering
  // https://github.com/kriasoft/isomorphic-style-loader
  insertCss: (...styles) => {
    // eslint-disable-next-line no-underscore-dangle
    const removeCss = styles.map(x => x._insertCss())
    return () => { removeCss.forEach(f => f()) }
  },
}

// Switch off the native scroll restoration behavior and handle it manually
// https://developers.google.com/web/updates/2015/09/history-api-scroll-restoration
const scrollPositionsHistory = {}
if (window.history && 'scrollRestoration' in window.history) {
  window.history.scrollRestoration = 'manual'
}

/*
 * ReactDOM.render callback
 * change page head and scroll that ReactDOM.render cannot treat
 * 1. init: remove server-side-rendered css (in head)
 * 2. update head
 * 3. update scroll
 */
let onRenderComplete = function initialRenderComplete() {
  // after first ssr, remove originl server-rendered css, because later client.js will load bundled css module
  // first render complete, clean server rendered stuff
  firstRender = false
  const cssElem = document.getElementById('server-rendered-css')
  if (cssElem) cssElem.parentNode.removeChild(cssElem)
  const serilizedElem = document.getElementById('server-rendered-serialized')
  if (serilizedElem) serilizedElem.parentNode.removeChild(serilizedElem)

  onRenderComplete = function renderComplete(route, location) {
    updateHead(
      route.head,
      document.getElementById("delta-head"),
      //(newState) => console.log(newState),
      //() => { console.log('html head rerendered')},
    )

    let scrollX = 0
    let scrollY = 0
    const pos = scrollPositionsHistory[location.key]
    if (pos) {
      scrollX = pos.scrollX
      scrollY = pos.scrollY
    }
    else {
      const targetHash = location.hash.substr(1)
      if (targetHash) {
        const target = document.getElementById(targetHash)
        if (target) {
          scrollY = window.pageYOffset + target.getBoundingClientRect().top
        }
      }
    }

    // Restore the scroll position if it was saved into the state
    // or scroll to the given #hash anchor
    // or scroll to top of the page
    window.scrollTo(scrollX, scrollY)
  }
}

// Make taps on links and buttons work fast on mobiles
FastClick.attach(document.body)

let appInstance
let currentLocation = history.location
let routes = require('../shared/routes').default

let firstRender = true

// Re-render the app when window.location changes
async function onLocationChange(location) {
  // Remember the latest scroll position for the previous location
  scrollPositionsHistory[currentLocation.key] = {
    scrollX: window.pageXOffset,
    scrollY: window.pageYOffset,
  }
  // Delete stored scroll position for next page if any
  if (history.action === 'PUSH') {
    delete scrollPositionsHistory[location.key]
  }
  currentLocation = location

  try {
    // Traverses the list of routes in the order they are defined until
    // it finds the first route that matches provided URL path string
    // and whose action method returns anything other than `undefined`.
    let needFetch = true
    if (firstRender && __serializedObject__.fetched) needFetch = false

    const route = await resolve(routes, {
      path: location.pathname,
      query: queryString.parse(location.search),
      fetch: needFetch,
    })

    // Prevent multiple page renders during the routing process
    if (currentLocation.key !== location.key) {
      console.log('route processing... ignored')
      return
    }

    if (route.redirect) {
      history.replace(route.redirect)
      return
    }

    let routeElement = null
    if (needFetch) {
      routeElement = <route.element.component {...route.element.props}/>
    }
    else {
      let routeElementProps = {
        ...route.element.props,
        fetched: __serializedObject__.fetched,
      }
      routeElement = <route.element.component {...routeElementProps}/>
    }
    appInstance = ReactDOM.render(
      <App context={context}>

{routeElement}

      </App>,
      document.getElementById(config.WEBAPP_MOUNT_DOCROOT_ID),
      () => onRenderComplete(route, location),
    )
  } catch (error) {
    console.error(error) // eslint-disable-line no-console

    // Current url has been changed during navigation process, do nothing
    if (currentLocation.key !== location.key) {
      return
    }

    // Display the error in full-screen for development mode
    /* TODO
    if (process.env.NODE_ENV !== 'production') {
      appInstance = null
      document.title = `Error: ${error.message}`
      ReactDOM.render(<ErrorReporter error={error} />, container)
      return
    }
    */

    // Avoid broken navigation in production mode by a full page reload on error
    //window.location.reload()
  }
}

// Handle client-side navigation by using HTML5 History API
// For more information visit https://github.com/mjackson/history#readme
history.listen(onLocationChange)
onLocationChange(currentLocation)
<commit_msg>serialzied object check<commit_after>import 'babel-polyfill'
import React from 'react'
import ReactDOM from 'react-dom'
import FastClick from 'fastclick'   // TODO verify working?
import { resolve } from 'universal-router'
import queryString from 'query-string'

import config from '../config'
import history from '../utils/history'
import { updateHead } from './head'
import App from '../shared/components/App'

// Global (context) variables that can be easily accessed from any React component
// https://facebook.github.io/react/docs/context.html
const context = {
  // Enables critical path CSS rendering
  // https://github.com/kriasoft/isomorphic-style-loader
  insertCss: (...styles) => {
    // eslint-disable-next-line no-underscore-dangle
    const removeCss = styles.map(x => x._insertCss())
    return () => { removeCss.forEach(f => f()) }
  },
}

// Switch off the native scroll restoration behavior and handle it manually
// https://developers.google.com/web/updates/2015/09/history-api-scroll-restoration
const scrollPositionsHistory = {}
if (window.history && 'scrollRestoration' in window.history) {
  window.history.scrollRestoration = 'manual'
}

/*
 * ReactDOM.render callback
 * change page head and scroll that ReactDOM.render cannot treat
 * 1. init: remove server-side-rendered css (in head)
 * 2. update head
 * 3. update scroll
 */
let onRenderComplete = function initialRenderComplete() {
  // after first ssr, remove originl server-rendered css, because later client.js will load bundled css module
  // first render complete, clean server rendered stuff
  firstRender = false
  const cssElem = document.getElementById('server-rendered-css')
  if (cssElem) cssElem.parentNode.removeChild(cssElem)
  const serilizedElem = document.getElementById('server-rendered-serialized')
  if (serilizedElem) serilizedElem.parentNode.removeChild(serilizedElem)

  onRenderComplete = function renderComplete(route, location) {
    updateHead(
      route.head,
      document.getElementById("delta-head"),
      //(newState) => console.log(newState),
      //() => { console.log('html head rerendered')},
    )

    let scrollX = 0
    let scrollY = 0
    const pos = scrollPositionsHistory[location.key]
    if (pos) {
      scrollX = pos.scrollX
      scrollY = pos.scrollY
    }
    else {
      const targetHash = location.hash.substr(1)
      if (targetHash) {
        const target = document.getElementById(targetHash)
        if (target) {
          scrollY = window.pageYOffset + target.getBoundingClientRect().top
        }
      }
    }

    // Restore the scroll position if it was saved into the state
    // or scroll to the given #hash anchor
    // or scroll to top of the page
    window.scrollTo(scrollX, scrollY)
  }
}

// Make taps on links and buttons work fast on mobiles
FastClick.attach(document.body)

let appInstance
let currentLocation = history.location
let routes = require('../shared/routes').default

let firstRender = true

// Re-render the app when window.location changes
async function onLocationChange(location) {
  // Remember the latest scroll position for the previous location
  scrollPositionsHistory[currentLocation.key] = {
    scrollX: window.pageXOffset,
    scrollY: window.pageYOffset,
  }
  // Delete stored scroll position for next page if any
  if (history.action === 'PUSH') {
    delete scrollPositionsHistory[location.key]
  }
  currentLocation = location

  try {
    // Traverses the list of routes in the order they are defined until
    // it finds the first route that matches provided URL path string
    // and whose action method returns anything other than `undefined`.
    let needFetch = true
    if (firstRender
        && typeof(__serializedObject__) !== 'undefined'
        && __serializedObject__.fetched) {
      needFetch = false
    }

    const route = await resolve(routes, {
      path: location.pathname,
      query: queryString.parse(location.search),
      fetch: needFetch,
    })

    // Prevent multiple page renders during the routing process
    if (currentLocation.key !== location.key) {
      console.log('route processing... ignored')
      return
    }

    if (route.redirect) {
      history.replace(route.redirect)
      return
    }

    let routeElement = null
    if (needFetch) {
      routeElement = <route.element.component {...route.element.props}/>
    }
    else {
      let routeElementProps = {
        ...route.element.props,
        fetched: __serializedObject__.fetched,
      }
      routeElement = <route.element.component {...routeElementProps}/>
    }
    appInstance = ReactDOM.render(
      <App context={context}>

{routeElement}

      </App>,
      document.getElementById(config.WEBAPP_MOUNT_DOCROOT_ID),
      () => onRenderComplete(route, location),
    )
  } catch (error) {
    console.error(error) // eslint-disable-line no-console

    // Current url has been changed during navigation process, do nothing
    if (currentLocation.key !== location.key) {
      return
    }

    // Display the error in full-screen for development mode
    /* TODO
    if (process.env.NODE_ENV !== 'production') {
      appInstance = null
      document.title = `Error: ${error.message}`
      ReactDOM.render(<ErrorReporter error={error} />, container)
      return
    }
    */

    // Avoid broken navigation in production mode by a full page reload on error
    //window.location.reload()
  }
}

// Handle client-side navigation by using HTML5 History API
// For more information visit https://github.com/mjackson/history#readme
history.listen(onLocationChange)
onLocationChange(currentLocation)
<|endoftext|>


<commit_before>'use strict';
// Dependencies
var util = require('util');
var path = require('path');
var fs = require('fs');
var yeoman = require('yeoman-generator');
var LineByLineReader = require('line-by-line')

var chalk = require('chalk');

var foldername = path.basename(process.cwd());

// Export generator
var DjangoRouteGenerator = module.exports = function DjangoRouteGenerator(args, options, config) {
  yeoman.generators.Base.apply(this, arguments);
  if(!args[0]) {
    throw 'App name is required';
  }
  this.APPNAME = args[0];
  this.appDir = 'apps/' + args[0];
  this.urlsFile = this.appDir + '/urls.py';
  this.viewsFile = this.appDir + '/views.py';
  this.on('end', function () {
  });

  this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json')));
};

util.inherits(DjangoRouteGenerator, yeoman.generators.Base);

// Create files needed
DjangoRouteGenerator.prototype.createFile = function createFile() {
    if(fs.existsSync(this.urlsFile)){
      this.log(chalk.green('Url file already exists'));
    } else {
      this.template('urls.py', this.urlsFile);
    }
    if(fs.existsSync(this.viewsFile)){
      this.log(chalk.green('Test file already exists'));
    } else {
      this.copy('views.py', this.viewsFile);
    }
}

// Check whether this app's urls have already been added

DjangoRouteGenerator.prototype._urlsExists = function _urlExists(cb) {
    // Open read url file
    var lr = new LineByLineReader('urls.py');
    var term = "'apps."+this.APPNAME+".urls'";
    lr.on('line', function(line) {
        if(line.indexOf(term) !== -1) {
            cb(null);
        }
    });
    lr.on('end', function(){
        return cb('urls not found');
    });
};

DjangoRouteGenerator.prototype.urls = function urls() {
    var cb = this.async();
    this._urlsExists(function(found) {
        if(!found) {
            this.needsUrls = true;
        } else {
            this.log(chalk.green('App urls already added to main urls'));
        }
        cb();
    }.bind(this));
};

DjangoRouteGenerator.prototype.subdirectory = function subdirectory() {
    var cb = this.async();
    if(this.needsUrls) {
        // prompt for new url sub folder
        this.prompt({
            name: 'subdirectory',
            message: 'Subdirectory',
        }, function(props){
            this.subdirectory = props.subdirectory;
            cb();
        }.bind(this));
    } else {
        cb();
    }
};

DjangoRouteGenerator.prototype._namespaceExists = function _namespaceExists(ns, cb) {
    // Open read url file
    var lr = new LineByLineReader('urls.py');
    var term = "namespace='"+ns+"'";
    lr.on('line', function(line) {
        if(line.indexOf(term) !== -1) {
            cb(null);
        }
    });
    lr.on('end', function(){
        return cb('namespace not found');
    });
};

DjangoRouteGenerator.prototype.namespace = function namespace() {
    var cb = this.async();
    if(this.needsUrls) {
      var prompts = [{
        name: 'namespace',
        message: 'Namespace [leaving blank means no namespace]',
        default: this.subdirectory
      }];
      this.prompt(prompts, function(props) {
        // If namespace, check if new
        this.namespace = props.namespace;
        if(props.namespace) {
            this._namespaceExists(props.namespace, function gotNamespace(found) {
                if(found) {
                    this.log(chalk.yellow('Namespace already exists'));
                }
            }.bind(this));
        } else {

        }
        cb();
      }.bind(this));

    } else {
        cb();
    }
};

DjangoRouteGenerator.prototype.writeurls = function writeurls() {
    if(this.needsUrls) {
        // Prepare the line
        var line = "    url(r'<%= subdir %>', include('apps.<%= appName %>.urls', namespace='<%= ns %>')),";
        line = this._.template(line, {
            subdir: this.subdirectory ? '^' + this.subdirectory + '/' : '',
            ns: this.namespace,
            appName: this.APPNAME
        });
        // Find right place
        var content = fs.readFileSync('urls.py', {encoding: 'utf8'});
        var patterns = content.indexOf('patterns(');
        var lastBracket = content.indexOf(')', patterns) - 1;

    }
};
<commit_msg>Switch found false/true<commit_after>'use strict';
// Dependencies
var util = require('util');
var path = require('path');
var fs = require('fs');
var yeoman = require('yeoman-generator');
var LineByLineReader = require('line-by-line')

var chalk = require('chalk');

var foldername = path.basename(process.cwd());

// Export generator
var DjangoRouteGenerator = module.exports = function DjangoRouteGenerator(args, options, config) {
  yeoman.generators.Base.apply(this, arguments);
  if(!args[0]) {
    throw 'App name is required';
  }
  this.APPNAME = args[0];
  this.appDir = 'apps/' + args[0];
  this.urlsFile = this.appDir + '/urls.py';
  this.viewsFile = this.appDir + '/views.py';
  this.on('end', function () {
  });

  this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json')));
};

util.inherits(DjangoRouteGenerator, yeoman.generators.Base);

// Create files needed
DjangoRouteGenerator.prototype.createFile = function createFile() {
    if(fs.existsSync(this.urlsFile)){
      this.log(chalk.green('Url file already exists'));
    } else {
      this.template('urls.py', this.urlsFile);
    }
    if(fs.existsSync(this.viewsFile)){
      this.log(chalk.green('Test file already exists'));
    } else {
      this.copy('views.py', this.viewsFile);
    }
}

// Check whether this app's urls have already been added

DjangoRouteGenerator.prototype._urlsExists = function _urlExists(cb) {
    // Open read url file
    var lr = new LineByLineReader('urls.py');
    var term = "'apps."+this.APPNAME+".urls'";
    var found = false;
    lr.on('line', function(line) {
        if(line.indexOf(term) !== -1) {
            found = true;
            cb(true);
        }
    });
    lr.on('end', function(){
        if(!found) {
            return cb(false);
        }
    });
};

DjangoRouteGenerator.prototype.urls = function urls() {
    var cb = this.async();
    this._urlsExists(function(found) {
        if(!found) {
            this.needsUrls = true;
        } else {
            this.log(chalk.green('App urls already added to main urls'));
        }
        cb();
    }.bind(this));
};

DjangoRouteGenerator.prototype.subdirectory = function subdirectory() {
    var cb = this.async();
    if(this.needsUrls) {
        // prompt for new url sub folder
        this.prompt({
            name: 'subdirectory',
            message: 'Subdirectory',
        }, function(props){
            this.subdirectory = props.subdirectory;
            cb();
        }.bind(this));
    } else {
        cb();
    }
};

DjangoRouteGenerator.prototype._namespaceExists = function _namespaceExists(ns, cb) {
    // Open read url file
    var lr = new LineByLineReader('urls.py');
    var term = "namespace='"+ns+"'";
    lr.on('line', function(line) {
        if(line.indexOf(term) !== -1) {
            cb(null);
        }
    });
    lr.on('end', function(){
        return cb('namespace not found');
    });
};

DjangoRouteGenerator.prototype.namespace = function namespace() {
    if(this.needsUrls) {
        var cb = this.async();
        var prompts = [{
            name: 'namespace',
            message: 'Namespace [leaving blank means no namespace]',
            default: this.subdirectory
          }];
      this.prompt(prompts, function(props) {
        // If namespace, check if new
        this.namespace = props.namespace;
        if(props.namespace) {
            this._namespaceExists(props.namespace, function gotNamespace(found) {
                if(found) {
                    this.log(chalk.yellow('Namespace already exists'));
                }
            }.bind(this));
        } else {

        }
        cb();
      }.bind(this));

    }
};

DjangoRouteGenerator.prototype.writeurls = function writeurls() {
    if(this.needsUrls) {
        // Prepare the line
        var line = "    url(r'<%= subdir %>', include('apps.<%= appName %>.urls', namespace='<%= ns %>')),";
        line = this._.template(line, {
            subdir: this.subdirectory ? '^' + this.subdirectory + '/' : '',
            ns: this.namespace,
            appName: this.APPNAME
        });
        // Find right place
        var content = this.readFileAsString('urls.py');
        var patterns = content.indexOf('patterns(');
        var nextComma = content.indexOf(',', patterns) + 1;
        var newContent = (content.slice(0,nextComma) + '\n' + line + content.slice(nextComma));
        this.writeFileFromString(newContent, 'urls.py');

    }
};
<|endoftext|>