<commit_before>var pk = pk || {};
/**
Utility class for converting color types and generating color schemes
@class pk.color
*/

(function(pk) {
    pk.color = {

        /**
        Convert a HEX color string to an RGB
        @method hex2rgb
        @param hex {String} HEX color string
        @return {Array} Returns array of red, clue and green components
        */
        hex2rgb: function(hex) {
            var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i,
                result, r, g, b;
            hex = hex.replace(shorthandRegex, function(r, g, b) {
                return r + r + g + g + b + b;
            });
            result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
            r = parseInt(result[1], 16);
            g = parseInt(result[2], 16);
            b = parseInt(result[3], 16);
            return [r, g, b];
        },
        /**
        Convert an RGB array to a HEX color string
        @method rgb2hex
        @param rgb {Array} Array of red, clue and green components
        @return {String} Returns HEX color string
        */
        rgb2hex: function(rgb) {
			rgb=pk.toArr(rgb);
            var hex = '',
                h, i, c;
            for (i = 0; i < rgb.length; i += 1) {
                c = rgb[i];
                h = c.toString(16);
                h = (h.length === 1) ? "0" + h : h;
                hex += h;
            }
            return '#' + hex;
        },
        /**
        Convert an RGB array to a HSV array
        @method rgb2hsv
        @param rgb {Array} Array of red, clue and green components
        @return {Array} Returns array of hue, saturation and value components
        */
        rgb2hsv: function(rgb) {
			rgb=pk.toArr(rgb);
            var
                r = rgb[0],
                g = rgb[1],
                b = rgb[2],
                min = Math.min(r, g, b),
                max = Math.max(r, g, b),
                delta = max - min,
                h, s, v = max;

            v = Math.floor(max / 255 * 100);

            if (max !== 0) {
                s = Math.floor(delta / max * 100);
            } else {
                return [0, 0, 0];
            }

            if (delta === 0) {
                h = 0;
            } else {
                if (r === max) {
                    h = delta(g - b) / delta;
                } else if (g === max) {
                    h = 2 + (b - r) / delta;

                } else {
                    h = 4 + (r - g) / delta;
                }
            }
            h = Math.floor(h * 60);
            if (h < 0) {
                h += 360;
            }
            return [h, s, v];
        },
        /**
        Convert an HSV array to a RGB array
        @method hsv2rgb
        @param hsv {Array} Array of hue, saturation and value components
        @return {Array} Returns array of red, clue and green components
        */
        hsv2rgb: function(hsv) {
			hsv=pk.toArr(hsv);
            var
                r, g, b, i, f, p, q, t, h = hsv[0],
                s = hsv[1],
                v = hsv[2];
            h = Math.max(0, Math.min(360, h));
            s = Math.max(0, Math.min(100, s));
            v = Math.max(0, Math.min(100, v));
            s /= 100;
            v /= 100;
            h = h === 360 ? 0 : h;
            if (s === 0) {
                r = g = b = v;
                return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
            }
            h /= 60;
            i = Math.floor(h);
            f = h - i;
            p = v * (1 - s);
            q = v * (1 - s * f);
            t = v * (1 - s * (1 - f));
            switch (i) {
                case 0:
                    r = v;
                    g = t;
                    b = p;
                    break;
                case 1:
                    r = q;
                    g = v;
                    b = p;
                    break;
                case 2:
                    r = p;
                    g = v;
                    b = t;
                    break;
                case 3:
                    r = p;
                    g = q;
                    b = v;
                    break;
                case 4:
                    r = t;
                    g = p;
                    b = v;
                    break;
                case 5:
                    r = v;
                    g = p;
                    b = q;
                    break;
            }
            r = Math.round(r * 255);
            g = Math.round(g * 255);
            b = Math.round(b * 255);
            return [r, g, b];
        },
        /**
        Convert an RGB array to a HSL array
        @method rgb2hsl
        @param RGB {Array} Array of red, green and blue components
        @return {Array} Returns array of hue, saturation and lightness components
        */
        rgb2hsl: function(rgb) {
			rgb=pk.toArr(rgb);
            var r = rgb[0],
                g = rgb[1],
                b = rgb[2];
            r /= 255;
            g /= 255;
            b /= 255;
            var max = Math.max(r, g, b),
                min = Math.min(r, g, b);
            var h, s, l = (max + min) / 2;
            if (max === min) {
                h = s = 0; // achromatic
            } else {
                var d = max - min;
                s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
                switch (max) {
                    case r:
                        h = (g - b) / d + (g < b ? 6 : 0);
                        break;
                    case g:
                        h = (b - r) / d + 2;
                        break;
                    case b:
                        h = (r - g) / d + 4;
                        break;
                }
                h /= 6;
            }
            return [h, s, l];
        },
        /**
        Convert an HSL array to a RGB array
        @method hsl2rgb
        @param HSL {Array} Array of hue, saturation and lightness components
        @return {Array} Returns array of red, green and blue components
        */
        hsl2rgb: function(hsl) {
			hsl=pk.toArr(hsl);
            var h = hsl[0],
                s = hsl[1],
                l = hsl[2],
                r, g, b;

            function hue2rgb(p, q, t) {
                if (t < 0) {
                    t += 1;
                }
                if (t > 1) {
                    t -= 1;
                }
                if (t < 1 / 6) {
                    return p + (q - p) * 6 * t;
                }
                if (t < 1 / 2) {
                    return q;
                }
                if (t < 2 / 3) {
                    return p + (q - p) * (2 / 3 - t) * 6;
                }
                return p;
            }
            if (s === 0) {
                r = g = b = l; // achromatic
            } else {

                var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
                var p = 2 * l - q;
                r = hue2rgb(p, q, h + 1 / 3);
                g = hue2rgb(p, q, h);
                b = hue2rgb(p, q, h - 1 / 3);
            }

            return [r * 255, g * 255, b * 255];
        },
        /**
        Convert a HEX color string to a HSL array
        @method hex2hsl
        @param hex {String} HEX color string
        @return {Array} Returns array of hue, saturation and lightness components
        */
        hex2hsl: function(hex) {
            return this.rgb2hsl(this.hex2rgb(hex));
        },
        /**
        Convert an HSL array to a HEX color string
        @method hsl2hex
        @param hsl {Array} Array of hue, saturation and lightness components
        @return {String} Returns HEX color string
        */
        hsl2hex: function(hsl) {
            return this.rgb2hex(this.hsl2rgb(pk.toArr(hsl)));
        },

        /**
        Convert an HSV array to HSL array
        @method hsv2hsl
        @param hsv {Array} Array of hue, saturation and value components
        @return {Array} Returns array of hue, saturation and lightness components
        */
        hsv2hsl: function(hsv) {
            return this.rgb2hsl(this.hsv2rgb(pk.toArr(hsv)));
        },

        /**
        Convert an HSL array to HSV array
        @method hsl2hsv
        @param hsl {Array} Array of hue, saturation and lightness components
        @return {Array} Returns array of hue, saturation and value components
        */
        hsl2hsv: function(hsl) {
            return this.rgb2hsv(this.hsl2rgb(pk.toArr(hsl)));
        },

        /**
        Convert a HEX color string to a HSV array
        @method hex2hsv
        @param hex {String} HEX color string
        @return {Array} Returns array of hue, saturation and value components
        */
        hex2hsv: function(hex) {
            return this.rgb2hsv(this.hex2rgb(hex));
        },
        /**
        Convert an HSV array to a HEX color string
        @method hsv2hex
        @param hsv {Array} Array of hue, saturation and value components
        @return {String} Returns HEX color string
        */
        hsv2hex: function(hsv) {
            return this.rgb2hex(this.hsv2rgb(pk.toArr(hsv)));
        },
        /**
        Generate a series of randomized HEX color strings
        @method random
        @param count {Number} Number of random colors to generate
        @return {Array} Returns Array of HEX color strings
        */
        random: function(count) {
            var palette = [],
                i;
            count = typeof count !== 'number' ? 1 : count;
            for (i = 0; i < count; i += 1) {
                palette.push('#' + Math.floor(Math.random() * 16777215).toString(16));
            }
            return palette;
        },
        /**
        Generate (palette of) complementary color(s) from passed HEX color string
        @method complement
        @param hex {String} HEX color string
        @param [type] {String} Type of complementary palette to create, either `split` or `double`
        @return {Array} Returns array of HEX color strings
        */
        complement: function(hex, type) {
            var count = 1,
                rotation = 180,
                scope = 0;
            switch (type) {
                case "split":
                    count = 3;
                    rotation = 180;
                    scope = 180;
                    break;
                case "double":
                    count = 5;
                    rotation = 180;
                    scope = 180;
                    break;
            }
            return this.algorithmic({
				hex:hex,
				count:count,
				scope:scope,
				rotation:180
			});
        },
        /**
        Generate triadic color palette
        @method triadic
        @param hex {String} HEX color string
        @return {Array} Returns array of HEX color strings
        */
        triadic: function(hex) {
            return this.algorithmic({hex:hex});
        },
        /**
        Generate tetradic color palette
        @method tetradic
        @param hex {String} HEX color string
        @return {Array} Returns array of HEX color strings
        */
        tetradic: function(hex) {
            return this.algorithmic({
				hex:hex,
				count:4
			});
        },
        /**
        Generate pentadic color palette
        @method pentadic
        @param hex {String} HEX color string
        @return {Array} Returns array of HEX color strings
        */
        pentadic: function(hex) {
            return this.algorithmic({
				hex:hex,
				count:5
			});
        },
        degrees: function(degrees, offset) {
            degrees += offset;
            if (degrees > 360) {
                degrees -= 360;
            } else if (degrees < 0) {
                degrees += 360;
            }
            return degrees;
        },
        /**
        Generate algorithmic color palette
        @method algorithmic
		@param options {Object} Algorithmic color transformation options
        @param options.hex {String} HEX color string
        @param [options.count=3] {Number} Number of colors to produce
        @param [options.type=hue] {String} Component to calculate on, either `hue`, `saturation` or `value`
        @param [options.scope=360] {Number} Number of degrees of rotation to consider
        @param [options.rotation=0] {Number} Number of degrees of rotation to calculate from
        @return {Array} Returns array of HEX color strings
        */
        // pick a point on the wheel, the number of degrees either side to cover and the split
        algorithmic: function(opt) {
            var count = opt.count && typeof opt.count !== 'number' ? 3 : opt.count;
				type = opt.type && typeof opt.type !== 'string' ? 'hue' : opt.type;
				scope = opt.scope && typeof opt.scope !== 'number' ? 360 : opt.scope;
				rotation = opt.rotation && typeof opt.rotation !== 'number' ? 0 : opt.rotation
				hex=opt.hex,
                hsv = this.hex2hsv(hex),
                h = hsv[0],
                s = hsv[1],
                v = hsv[2],
                origin, steps, palette = [],
                offset, i;
            // if scope is 360, the start and end point are the same color, so should be avoided, otherwise enlargen the steps
            steps = (type === "hue" && (scope === 360 || scope === 0)) ? scope / count : scope / (count - 1);
            // if scope is 360, start on the current color
            origin = (scope === 360) ? 0 : this.degrees(this.degrees(h, rotation), -1 * scope / 2);

            for (i = 0; i < count; i += 1) {
                offset = steps * i;
                switch (type) {
                    case "hue":
                        palette.push(this.hsv2hex([this.degrees(origin, offset, 360) === 360 ? 0 : this.degrees(origin, offset, 360), s, v]));
                        break;
                    case "saturation":
                        palette.push(this.hsv2hex([h, offset, v]));
                        break;
                    case "value":
                    case "lightness":
                    case "brightness":
                        palette.push(this.hsv2hex([h, s, offset]));
                        break;
                }
            }
            return palette;
        }
    };
    return pk;
})(pk);
<commit_msg>Update color.js<commit_after>var pk = pk || {};
/**
Utility class for converting color types and generating color schemes.

For color conversion methods, where the expected parameter is an array, the method can also be passed a comma separated value list from which an array will automatically be extrapolated.

@class pk.color
*/

(function(pk) {
    pk.color = {

        /**
        Convert a HEX color string to an RGB
        @method hex2rgb
		@param hex {String} HEX color string
        @return {Array} Returns array of red, clue and green components
        */
        hex2rgb: function(hex) {
            var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i,
                result, r, g, b;
            hex = hex.replace(shorthandRegex, function(r, g, b) {
                return r + r + g + g + b + b;
            });
            result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
            r = parseInt(result[1], 16);
            g = parseInt(result[2], 16);
            b = parseInt(result[3], 16);
            return [r, g, b];
        },
        /**
        Convert an RGB array to a HEX color string
        @method rgb2hex
        @param rgb {Array} Array of red, clue and green components
        @return {String} Returns HEX color string
        */
        rgb2hex: function(rgb) {
			rgb=pk.toArr(rgb);
            var hex = '',
                h, i, c;
            for (i = 0; i < rgb.length; i += 1) {
                c = rgb[i];
                h = c.toString(16);
                h = (h.length === 1) ? "0" + h : h;
                hex += h;
            }
            return '#' + hex;
        },
        /**
        Convert an RGB array to a HSV array
        @method rgb2hsv
        @param rgb {Array} Array of red, clue and green components
        @return {Array} Returns array of hue, saturation and value components
        */
        rgb2hsv: function(rgb) {
			rgb=pk.toArr(rgb);
            var
                r = rgb[0],
                g = rgb[1],
                b = rgb[2],
                min = Math.min(r, g, b),
                max = Math.max(r, g, b),
                delta = max - min,
                h, s, v = max;

            v = Math.floor(max / 255 * 100);

            if (max !== 0) {
                s = Math.floor(delta / max * 100);
            } else {
                return [0, 0, 0];
            }

            if (delta === 0) {
                h = 0;
            } else {
                if (r === max) {
                    h = delta(g - b) / delta;
                } else if (g === max) {
                    h = 2 + (b - r) / delta;

                } else {
                    h = 4 + (r - g) / delta;
                }
            }
            h = Math.floor(h * 60);
            if (h < 0) {
                h += 360;
            }
            return [h, s, v];
        },
        /**
        Convert an HSV array to a RGB array
        @method hsv2rgb
        @param hsv {Array} Array of hue, saturation and value components
        @return {Array} Returns array of red, clue and green components
        */
        hsv2rgb: function(hsv) {
			hsv=pk.toArr(hsv);
            var
                r, g, b, i, f, p, q, t, h = hsv[0],
                s = hsv[1],
                v = hsv[2];
            h = Math.max(0, Math.min(360, h));
            s = Math.max(0, Math.min(100, s));
            v = Math.max(0, Math.min(100, v));
            s /= 100;
            v /= 100;
            h = h === 360 ? 0 : h;
            if (s === 0) {
                r = g = b = v;
                return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
            }
            h /= 60;
            i = Math.floor(h);
            f = h - i;
            p = v * (1 - s);
            q = v * (1 - s * f);
            t = v * (1 - s * (1 - f));
            switch (i) {
                case 0:
                    r = v;
                    g = t;
                    b = p;
                    break;
                case 1:
                    r = q;
                    g = v;
                    b = p;
                    break;
                case 2:
                    r = p;
                    g = v;
                    b = t;
                    break;
                case 3:
                    r = p;
                    g = q;
                    b = v;
                    break;
                case 4:
                    r = t;
                    g = p;
                    b = v;
                    break;
                case 5:
                    r = v;
                    g = p;
                    b = q;
                    break;
            }
            r = Math.round(r * 255);
            g = Math.round(g * 255);
            b = Math.round(b * 255);
            return [r, g, b];
        },
        /**
        Convert an RGB array to a HSL array
        @method rgb2hsl
        @param RGB {Array} Array of red, green and blue components
        @return {Array} Returns array of hue, saturation and lightness components
        */
        rgb2hsl: function(rgb) {
			rgb=pk.toArr(rgb);
            var r = rgb[0],
                g = rgb[1],
                b = rgb[2];
            r /= 255;
            g /= 255;
            b /= 255;
            var max = Math.max(r, g, b),
                min = Math.min(r, g, b);
            var h, s, l = (max + min) / 2;
            if (max === min) {
                h = s = 0; // achromatic
            } else {
                var d = max - min;
                s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
                switch (max) {
                    case r:
                        h = (g - b) / d + (g < b ? 6 : 0);
                        break;
                    case g:
                        h = (b - r) / d + 2;
                        break;
                    case b:
                        h = (r - g) / d + 4;
                        break;
                }
                h /= 6;
            }
            return [h, s, l];
        },
        /**
        Convert an HSL array to a RGB array
        @method hsl2rgb
        @param HSL {Array} Array of hue, saturation and lightness components
        @return {Array} Returns array of red, green and blue components
        */
        hsl2rgb: function(hsl) {
			hsl=pk.toArr(hsl);
            var h = hsl[0],
                s = hsl[1],
                l = hsl[2],
                r, g, b;

            function hue2rgb(p, q, t) {
                if (t < 0) {
                    t += 1;
                }
                if (t > 1) {
                    t -= 1;
                }
                if (t < 1 / 6) {
                    return p + (q - p) * 6 * t;
                }
                if (t < 1 / 2) {
                    return q;
                }
                if (t < 2 / 3) {
                    return p + (q - p) * (2 / 3 - t) * 6;
                }
                return p;
            }
            if (s === 0) {
                r = g = b = l; // achromatic
            } else {

                var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
                var p = 2 * l - q;
                r = hue2rgb(p, q, h + 1 / 3);
                g = hue2rgb(p, q, h);
                b = hue2rgb(p, q, h - 1 / 3);
            }

            return [r * 255, g * 255, b * 255];
        },
        /**
        Convert a HEX color string to a HSL array
        @method hex2hsl
        @param hex {String} HEX color string
        @return {Array} Returns array of hue, saturation and lightness components
        */
        hex2hsl: function(hex) {
            return this.rgb2hsl(this.hex2rgb(hex));
        },
        /**
        Convert an HSL array to a HEX color string
        @method hsl2hex
        @param hsl {Array} Array of hue, saturation and lightness components
        @return {String} Returns HEX color string
        */
        hsl2hex: function(hsl) {
            return this.rgb2hex(this.hsl2rgb(pk.toArr(hsl)));
        },

        /**
        Convert an HSV array to HSL array
        @method hsv2hsl
        @param hsv {Array} Array of hue, saturation and value components
        @return {Array} Returns array of hue, saturation and lightness components
        */
        hsv2hsl: function(hsv) {
            return this.rgb2hsl(this.hsv2rgb(pk.toArr(hsv)));
        },

        /**
        Convert an HSL array to HSV array
        @method hsl2hsv
        @param hsl {Array} Array of hue, saturation and lightness components
        @return {Array} Returns array of hue, saturation and value components
        */
        hsl2hsv: function(hsl) {
            return this.rgb2hsv(this.hsl2rgb(pk.toArr(hsl)));
        },

        /**
        Convert a HEX color string to a HSV array
        @method hex2hsv
        @param hex {String} HEX color string
        @return {Array} Returns array of hue, saturation and value components
        */
        hex2hsv: function(hex) {
            return this.rgb2hsv(this.hex2rgb(hex));
        },
        /**
        Convert an HSV array to a HEX color string
        @method hsv2hex
        @param hsv {Array} Array of hue, saturation and value components
        @return {String} Returns HEX color string
        */
        hsv2hex: function(hsv) {
            return this.rgb2hex(this.hsv2rgb(pk.toArr(hsv)));
        },
        /**
        Generate a series of randomized HEX color strings
        @method random
        @param count {Number} Number of random colors to generate
        @return {Array} Returns Array of HEX color strings
        */
        random: function(count) {
            var palette = [],
                i;
            count = typeof count !== 'number' ? 1 : count;
            for (i = 0; i < count; i += 1) {
                palette.push('#' + Math.floor(Math.random() * 16777215).toString(16));
            }
            return palette;
        },
        /**
        Generate (palette of) complementary color(s) from passed HEX color string
        @method complement
        @param hex {String} HEX color string
        @param [type] {String} Type of complementary palette to create, either `split` or `double`
        @return {Array} Returns array of HEX color strings
        */
        complement: function(hex, type) {
            var count = 1,
                rotation = 180,
                scope = 0;
            switch (type) {
                case "split":
                    count = 3;
                    rotation = 180;
                    scope = 180;
                    break;
                case "double":
                    count = 5;
                    rotation = 180;
                    scope = 180;
                    break;
            }
            return this.algorithmic({
				hex:hex,
				count:count,
				scope:scope,
				rotation:180
			});
        },
        /**
        Generate triadic color palette
        @method triadic
        @param hex {String} HEX color string
        @return {Array} Returns array of HEX color strings
        */
        triadic: function(hex) {
            return this.algorithmic({hex:hex});
        },
        /**
        Generate tetradic color palette
        @method tetradic
        @param hex {String} HEX color string
        @return {Array} Returns array of HEX color strings
        */
        tetradic: function(hex) {
            return this.algorithmic({
				hex:hex,
				count:4
			});
        },
        /**
        Generate pentadic color palette
        @method pentadic
        @param hex {String} HEX color string
        @return {Array} Returns array of HEX color strings
        */
        pentadic: function(hex) {
            return this.algorithmic({
				hex:hex,
				count:5
			});
        },
        degrees: function(degrees, offset) {
            degrees += offset;
            if (degrees > 360) {
                degrees -= 360;
            } else if (degrees < 0) {
                degrees += 360;
            }
            return degrees;
        },
        /**
        Generate algorithmic color palette
        @method algorithmic
		@param options {Object} Algorithmic color transformation options
        @param options.hex {String} HEX color string
        @param [options.count=3] {Number} Number of colors to produce
        @param [options.type=hue] {String} Component to calculate on, either `hue`, `saturation` or `value`
        @param [options.scope=360] {Number} Number of degrees of rotation to consider
        @param [options.rotation=0] {Number} Number of degrees of rotation to calculate from
        @return {Array} Returns array of HEX color strings
        */
        // pick a point on the wheel, the number of degrees either side to cover and the split
        algorithmic: function(opt) {
            var count = opt.count && typeof opt.count !== 'number' ? 3 : opt.count;
				type = opt.type && typeof opt.type !== 'string' ? 'hue' : opt.type;
				scope = opt.scope && typeof opt.scope !== 'number' ? 360 : opt.scope;
				rotation = opt.rotation && typeof opt.rotation !== 'number' ? 0 : opt.rotation
				hex=opt.hex,
                hsv = this.hex2hsv(hex),
                h = hsv[0],
                s = hsv[1],
                v = hsv[2],
                origin, steps, palette = [],
                offset, i;
            // if scope is 360, the start and end point are the same color, so should be avoided, otherwise enlargen the steps
            steps = (type === "hue" && (scope === 360 || scope === 0)) ? scope / count : scope / (count - 1);
            // if scope is 360, start on the current color
            origin = (scope === 360) ? 0 : this.degrees(this.degrees(h, rotation), -1 * scope / 2);

            for (i = 0; i < count; i += 1) {
                offset = steps * i;
                switch (type) {
                    case "hue":
                        palette.push(this.hsv2hex([this.degrees(origin, offset, 360) === 360 ? 0 : this.degrees(origin, offset, 360), s, v]));
                        break;
                    case "saturation":
                        palette.push(this.hsv2hex([h, offset, v]));
                        break;
                    case "value":
                    case "lightness":
                    case "brightness":
                        palette.push(this.hsv2hex([h, s, offset]));
                        break;
                }
            }
            return palette;
        }
    };
    return pk;
})(pk);
<|endoftext|>


<commit_before>import _ from 'lodash';
import format from 'date-fns/format';
import differenceInMilliseconds from 'date-fns/difference_in_milliseconds';
import startOfDay from 'date-fns/start_of_day';
import startOfYear from 'date-fns/start_of_year';
import subDays from 'date-fns/sub_days';

import { frontendPreferences as frontendPrefsConfig } from '../../config/config';
import * as PostVisibilityLevels from './post-visibility-levels';

export function getCookie(name) {
  const begin = document.cookie.indexOf(name);
  if (begin === -1) {
    return '';
  }
  const fromBegin = document.cookie.substr(begin);
  const tokenWithName = fromBegin.split(';');
  const tokenWithNameSplit = tokenWithName[0].split('=');
  const token = tokenWithNameSplit[1];
  return token.trim();
}

export function setCookie(name, value = '', expiresDays, path, domain) {
  const expiresDate = Date.now() + expiresDays * 24 * 60 * 60 * 1000;
  const expiresTime = new Date(expiresDate).toUTCString();
  const cookie = `${name}=${value}` +
    `;expires=${expiresTime}` +
    `;path=${path}` +
    (domain && domain !== 'localhost' ? `;domain=${domain}` : '');
  return document.cookie = cookie;
}

export function getISODate(timestamp) {
  return format(new Date(timestamp));
}

export function getRelativeDate(timestamp, long = true) {
  const m = new Date(timestamp);
  const now = new Date();
  const age = differenceInMilliseconds(now, m);

  // Just now (when age < 45s)
  if (age < 45 * 1000) {
    return 'Just now';
  }

  // 1-59 minutes ago (when 45s <= age < 59.5m)
  if (age < 59.5 * 60 * 1000) {
    const minutes = Math.round(age/60/1000);
    return (long
      ? pluralForm(minutes, 'minute') + ' ago'
      : pluralForm(minutes, 'min')
    );
  }

  // 1, 1.5, 2-8 hours ago (when 59.5m <= age < 8.5h)
  if (age < 8.5 * 3600 * 1000) {
    let hours = Math.round(age/1800/1000) / 2;
    if (hours > 2) {
      hours = Math.round(hours);
    }
    return (long
      ? pluralForm(hours, 'hour') + ' ago'
      : pluralForm(hours, 'hr')
    );
  }

  // Today at 15:37 (when age >= 8.5 hrs and it's today)
  if (m > startOfDay(now)) {
    return (long
      ? format(m, '[Today at] HH:mm')
      : format(m, 'HH:mm')
    );
  }

  // Yesterday at 15:37 (when age >= 8.5 hrs and it's yesterday)
  if (m > startOfDay(subDays(now, 1))) {
    return (long
      ? format(m, '[Yesterday at] HH:mm')
      : format(m, '[Yest] HH:mm')
    );
  }

  // Wed, 17 Feb (when yesterday < age < 14 days)
  if (m > subDays(now, 14)) {
    return (long
      ? format(m, 'ddd, D MMM')
      : format(m, 'D MMM')
    );
  }

  // 17 February (when age >= 14 days but it's still this year)
  if (m > startOfYear(now)) {
    return (long
      ? format(m, 'D MMMM')
      : format(m, 'D MMM')
    );
  }

  // 17 Feb 2016 (for everything else)
  return format(m, 'D MMM YYYY');
}

export function getFullDate(timestamp) {
  return format(new Date(timestamp), 'YYYY-MM-DD HH:mm:ss [UTC]Z');
}

export function userParser(user) {
  const newUser = { ...user };

  // Remove invisible characters from display name
  if (newUser.screenName) {
    newUser.screenName = newUser.screenName.replace(/[\u180E\u2000-\u200F\u2060\u2800\u3000\u3164\u{1D159}]/gu, '');
  }

  // Missing display name
  if (!newUser.screenName) {
    newUser.screenName = newUser.username;
  }

  return newUser;
}

export function meParser(user) {
  const newUser = userParser(user);

  // Frontend preferences (only use this client's subtree)
  const prefSubTree = user.frontendPreferences && user.frontendPreferences[frontendPrefsConfig.clientId];
  newUser.frontendPreferences = _.merge({}, frontendPrefsConfig.defaultValues, prefSubTree);

  return newUser;
}

export function postParser(post) {
  post.commentsDisabled = (post.commentsDisabled === '1');
  return { ...post };
}

export function preventDefault(realFunction) {
  return (event) => {
    // Check if it's a "click" (not "submit", "keydown" etc).
    // Also, check if it's a "fancy" one (made with middle button, or with Shift pressed etc).
    // Then, if it's a "fancy click", don't prevent default action.
    // Prevent custom action ("realFunction") instead.
    if (event.type === 'click' && (event.button !== 0 || event.shiftKey || event.ctrlKey || event.altKey || event.metaKey)) {
      return true;
    }

    event.preventDefault();
    return realFunction && realFunction(event);
  };
}

export function stopPropagation(event) {
  event.stopPropagation();
}

export function confirmFirst(realFunction) {
  return () => {
    if (confirm('Are you sure?')) {
      return realFunction && realFunction();
    }
  };
}

export function getCurrentRouteName(router) {
  return router && router.routes && router.routes[router.routes.length - 1].name;
}

export function pluralForm(n, singular, plural = null, format = 'n w') {
  let w;

  if (n == 1) {
    w = singular;
  } else if (plural) {
    w = plural;
  } else {
    w = singular + 's';
  }

  return format.replace('n', n).replace('w', w);
}

export function isMobile() {
  const viewportWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
  return (viewportWidth <= 991);
}

export function toggleSidebar(val = null) {
  if (val === true || val === false) {
    document.body.classList.toggle('mobile-sidebar-open', val); // if true, then add class, if not, remove class
  } else {
    document.body.classList.toggle('mobile-sidebar-open'); // if class exists, then remove it, if not, add it
  }

  if (document.body.classList.contains('mobile-sidebar-open')) {
    document.querySelector('.sidebar').scrollTop = 0;
  }
}

export function getPostVisibilityLevel(recipients, authorId) {
  // Calculate individual levels for recipients
  const recipientLevels = recipients.map((recipient) => {
    if (recipient.type === 'user' && recipient.id !== authorId) {
      return PostVisibilityLevels.DIRECT;
    }
    if (recipient.isPrivate === '1') {
      return PostVisibilityLevels.PRIVATE;
    }
    if (recipient.isProtected === '1') {
      return PostVisibilityLevels.PROTECTED;
    }
    return PostVisibilityLevels.PUBLIC;
  });

  // Calculate combined level for post
  return Math.min(...recipientLevels);
}

export function getSummaryPeriod(days) {
  switch (+days) {
    case 1: return 'day';
    case 7: return 'week';
    case 30: return 'month';
    default: return days + ' days';
  }
}
<commit_msg>Add another check for invisible characters rejection<commit_after>import _ from 'lodash';
import format from 'date-fns/format';
import differenceInMilliseconds from 'date-fns/difference_in_milliseconds';
import startOfDay from 'date-fns/start_of_day';
import startOfYear from 'date-fns/start_of_year';
import subDays from 'date-fns/sub_days';

import { frontendPreferences as frontendPrefsConfig } from '../../config/config';
import * as PostVisibilityLevels from './post-visibility-levels';

export function getCookie(name) {
  const begin = document.cookie.indexOf(name);
  if (begin === -1) {
    return '';
  }
  const fromBegin = document.cookie.substr(begin);
  const tokenWithName = fromBegin.split(';');
  const tokenWithNameSplit = tokenWithName[0].split('=');
  const token = tokenWithNameSplit[1];
  return token.trim();
}

export function setCookie(name, value = '', expiresDays, path, domain) {
  const expiresDate = Date.now() + expiresDays * 24 * 60 * 60 * 1000;
  const expiresTime = new Date(expiresDate).toUTCString();
  const cookie = `${name}=${value}` +
    `;expires=${expiresTime}` +
    `;path=${path}` +
    (domain && domain !== 'localhost' ? `;domain=${domain}` : '');
  return document.cookie = cookie;
}

export function getISODate(timestamp) {
  return format(new Date(timestamp));
}

export function getRelativeDate(timestamp, long = true) {
  const m = new Date(timestamp);
  const now = new Date();
  const age = differenceInMilliseconds(now, m);

  // Just now (when age < 45s)
  if (age < 45 * 1000) {
    return 'Just now';
  }

  // 1-59 minutes ago (when 45s <= age < 59.5m)
  if (age < 59.5 * 60 * 1000) {
    const minutes = Math.round(age/60/1000);
    return (long
      ? pluralForm(minutes, 'minute') + ' ago'
      : pluralForm(minutes, 'min')
    );
  }

  // 1, 1.5, 2-8 hours ago (when 59.5m <= age < 8.5h)
  if (age < 8.5 * 3600 * 1000) {
    let hours = Math.round(age/1800/1000) / 2;
    if (hours > 2) {
      hours = Math.round(hours);
    }
    return (long
      ? pluralForm(hours, 'hour') + ' ago'
      : pluralForm(hours, 'hr')
    );
  }

  // Today at 15:37 (when age >= 8.5 hrs and it's today)
  if (m > startOfDay(now)) {
    return (long
      ? format(m, '[Today at] HH:mm')
      : format(m, 'HH:mm')
    );
  }

  // Yesterday at 15:37 (when age >= 8.5 hrs and it's yesterday)
  if (m > startOfDay(subDays(now, 1))) {
    return (long
      ? format(m, '[Yesterday at] HH:mm')
      : format(m, '[Yest] HH:mm')
    );
  }

  // Wed, 17 Feb (when yesterday < age < 14 days)
  if (m > subDays(now, 14)) {
    return (long
      ? format(m, 'ddd, D MMM')
      : format(m, 'D MMM')
    );
  }

  // 17 February (when age >= 14 days but it's still this year)
  if (m > startOfYear(now)) {
    return (long
      ? format(m, 'D MMMM')
      : format(m, 'D MMM')
    );
  }

  // 17 Feb 2016 (for everything else)
  return format(m, 'D MMM YYYY');
}

export function getFullDate(timestamp) {
  return format(new Date(timestamp), 'YYYY-MM-DD HH:mm:ss [UTC]Z');
}

export function userParser(user) {
  const newUser = { ...user };

  // Remove invisible characters from display name
  if (newUser.screenName) {
    newUser.screenName = newUser.screenName
      .replace(/[\u180E\u2000-\u200F\u2060\u2800\u3000\u3164\u{1D159}]/gu, '')
      .trim();
  }

  // Missing display name
  if (!newUser.screenName) {
    newUser.screenName = newUser.username;
  }

  return newUser;
}

export function meParser(user) {
  const newUser = userParser(user);

  // Frontend preferences (only use this client's subtree)
  const prefSubTree = user.frontendPreferences && user.frontendPreferences[frontendPrefsConfig.clientId];
  newUser.frontendPreferences = _.merge({}, frontendPrefsConfig.defaultValues, prefSubTree);

  return newUser;
}

export function postParser(post) {
  post.commentsDisabled = (post.commentsDisabled === '1');
  return { ...post };
}

export function preventDefault(realFunction) {
  return (event) => {
    // Check if it's a "click" (not "submit", "keydown" etc).
    // Also, check if it's a "fancy" one (made with middle button, or with Shift pressed etc).
    // Then, if it's a "fancy click", don't prevent default action.
    // Prevent custom action ("realFunction") instead.
    if (event.type === 'click' && (event.button !== 0 || event.shiftKey || event.ctrlKey || event.altKey || event.metaKey)) {
      return true;
    }

    event.preventDefault();
    return realFunction && realFunction(event);
  };
}

export function stopPropagation(event) {
  event.stopPropagation();
}

export function confirmFirst(realFunction) {
  return () => {
    if (confirm('Are you sure?')) {
      return realFunction && realFunction();
    }
  };
}

export function getCurrentRouteName(router) {
  return router && router.routes && router.routes[router.routes.length - 1].name;
}

export function pluralForm(n, singular, plural = null, format = 'n w') {
  let w;

  if (n == 1) {
    w = singular;
  } else if (plural) {
    w = plural;
  } else {
    w = singular + 's';
  }

  return format.replace('n', n).replace('w', w);
}

export function isMobile() {
  const viewportWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
  return (viewportWidth <= 991);
}

export function toggleSidebar(val = null) {
  if (val === true || val === false) {
    document.body.classList.toggle('mobile-sidebar-open', val); // if true, then add class, if not, remove class
  } else {
    document.body.classList.toggle('mobile-sidebar-open'); // if class exists, then remove it, if not, add it
  }

  if (document.body.classList.contains('mobile-sidebar-open')) {
    document.querySelector('.sidebar').scrollTop = 0;
  }
}

export function getPostVisibilityLevel(recipients, authorId) {
  // Calculate individual levels for recipients
  const recipientLevels = recipients.map((recipient) => {
    if (recipient.type === 'user' && recipient.id !== authorId) {
      return PostVisibilityLevels.DIRECT;
    }
    if (recipient.isPrivate === '1') {
      return PostVisibilityLevels.PRIVATE;
    }
    if (recipient.isProtected === '1') {
      return PostVisibilityLevels.PROTECTED;
    }
    return PostVisibilityLevels.PUBLIC;
  });

  // Calculate combined level for post
  return Math.min(...recipientLevels);
}

export function getSummaryPeriod(days) {
  switch (+days) {
    case 1: return 'day';
    case 7: return 'week';
    case 30: return 'month';
    default: return days + ' days';
  }
}
<|endoftext|>


<commit_before>/* @flow */
import config from '../config';
import timing from './timing';

export function logSlowReducers<O: Object>(reducers: O): O {
  Object.keys(reducers).forEach((name: string) => {
    const originalReducer = reducers[name];
    reducers[name] = (state, action) => {
      const startMs = Date.now();
      const result = originalReducer(state, action);
      const endMs = Date.now();
      if (endMs - startMs >= config.slowReducersThreshold) {
        timing.add({
          text: `${action.type} @ ${name}`,
          startMs,
          endMs,
        });
      }
      return result;
    };
  });
  return reducers;
}
<commit_msg>utils/redux: Fix type and mark as strict-local.<commit_after>/* @flow strict-local */
import config from '../config';
import timing from './timing';

export function logSlowReducers<O: {}>(reducers: O): O {
  Object.keys(reducers).forEach((name: string) => {
    const originalReducer = reducers[name];
    reducers[name] = (state, action) => {
      const startMs = Date.now();
      const result = originalReducer(state, action);
      const endMs = Date.now();
      if (endMs - startMs >= config.slowReducersThreshold) {
        timing.add({
          text: `${action.type} @ ${name}`,
          startMs,
          endMs,
        });
      }
      return result;
    };
  });
  return reducers;
}
<|endoftext|>


<commit_before>/*
 * MelonJS Game Engine
 * Copyright (C) 2012, Olivier BIOT
 * http://www.melonjs.org
 *
 */

(function($, undefined) {

	/**
	 *  Base64 decoding
	 *  @see http://www.webtoolkit.info/
	 */
	var Base64 = (function() {

		// hold public stuff in our singleton
		var singleton = {};

		// private property
		var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

		// public method for decoding
		singleton.decode = function(input) {

			// make sure our input string has the right format
			input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

			if (me.sys.nativeBase64) {
				// use native decoder
				return $.atob(input);
			}
			else {
				// use cross-browser decoding
				var output = [], chr1, chr2, chr3, enc1, enc2, enc3, enc4, i = 0;

				while (i < input.length) {
					enc1 = _keyStr.indexOf(input.charAt(i++));
					enc2 = _keyStr.indexOf(input.charAt(i++));
					enc3 = _keyStr.indexOf(input.charAt(i++));
					enc4 = _keyStr.indexOf(input.charAt(i++));

					chr1 = (enc1 << 2) | (enc2 >> 4);
					chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
					chr3 = ((enc3 & 3) << 6) | enc4;

					output.push(String.fromCharCode(chr1));

					if (enc3 != 64) {
						output.push(String.fromCharCode(chr2));
					}
					if (enc4 != 64) {
						output.push(String.fromCharCode(chr3));
					}
				}

				output = output.join('');
				return output;
			}
		};

		return singleton;

	})();

	/**
	 * a collection of utility Function
	 * @final
	 * @memberOf me
	 * @private
	 * @constructor Should not be called by the user.
	 */

	me.utils = (function() {
		// hold public stuff in our singletong
		var api = {};

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

		   PRIVATE STUFF

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

		// cache rgb converted value
		var rgbCache = {};

		// guid default value
		var GUID_base  = "";
		var GUID_index = 0;

		// regexp to deal with file name & path
		var removepath = /^.*(\\|\/|\:)/;
		var removeext = /\.[^\.]*$/;

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

			PUBLIC STUFF

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

		/**
		 * Decode a base64 encoded string into a binary string
		 *
		 * @param {String} input Base64 encoded data
		 * @return {String} Binary string
		 */
		api.decodeBase64 = function(input) {
			return Base64.decode(input);
		};

		/**
		 * Decode a base64 encoded string into a byte array
		 *
		 * @param {String} input Base64 encoded data
		 * @param {Int} [bytes] number of bytes per array entry
		 * @return {Int[]} Array of bytes
		 */
		api.decodeBase64AsArray = function(input, bytes) {
			bytes = bytes || 1;

			var dec = Base64.decode(input), ar = [], i, j, len;

			for (i = 0, len = dec.length / bytes; i < len; i++) {
				ar[i] = 0;
				for (j = bytes - 1; j >= 0; --j) {
					ar[i] += dec.charCodeAt((i * bytes) + j) << (j << 3);
				}
			}
			return ar;
		};

		/**
		 * Decode a CSV encoded array into a binary array
		 *
		 * @param  {String} input CSV formatted data
		 * @param  {Int} limit row split limit
		 * @return {Int[]} Int Array
		 */
		api.decodeCSV = function(input, limit) {
			input = input.trim().split("\n");

			var result = [];
			for ( var i = 0; i < input.length; i++) {
				entries = input[i].split(",", limit);
				for ( var e = 0; e < entries.length; e++) {
					result.push(+entries[e]);
				}
			}
			return result;
		};

		/**
		 * return the base name of the file without path info.

		 *
		 * @param  {String} path path containing the filename
		 * @return {String} basename returns the base name without path information.
		 */
		api.getBasename = function(path) {
			return path.replace(removepath, '').replace(removeext, '');
		};

		/* ---

			enable the nocache mechanism

		  ---*/
		api.setNocache = function(enable) {
			me.nocache = enable ? "?" + parseInt(Math.random() * 10000000) : '';
		};

		// a Hex to RGB color function
		api.HexToRGB = function(h, a) {
			// remove the # if present
			h = (h.charAt(0) == "#") ? h.substring(1, 7) : h;
			// check if we already have the converted value cached
			if (rgbCache[h] == null) {
				// else add it (format : "r,g,b")
				rgbCache[h] = parseInt(h.substring(0, 2), 16) + ","
						+ parseInt(h.substring(2, 4), 16) + ","
						+ parseInt(h.substring(4, 6), 16);
			}
			return (a ? "rgba(" : "rgb(") + rgbCache[h]
					+ (a ? "," + a + ")" : ")");
		};

		// a Hex to RGB color function
		api.RGBToHex = function(r, g, b) {
			return r.toHex() + g.toHex() + b.toHex();
		};

		// return the given canvas or image pixels
		api.getPixels = function(arg) {
			if (arg instanceof HTMLImageElement) {
				var c = me.video.createCanvasSurface(arg.width, arg.height);
				c.drawImage(arg, 0, 0);
				return c.getImageData(0, 0, arg.width, arg.height);
			} else {
				// canvas !
				return arg.getContext('2d').getImageData(0, 0, arg.width, arg.height);
			}
		};

		// reset the GUID Base Name
		// the idea here being to have a unique ID
		// per level / object
		api.resetGUID = function(base) {
			// also ensure it's only 8bit ASCII characters
			GUID_base  = base.toString().toUpperCase().toHex();
			GUID_index = 0;
		};

		// create and return a very simple GUID
		// Game Unique ID
		api.createGUID = function() {
			return GUID_base + "-" + (GUID_index++);
		};

		// apply friction to a force
		api.applyFriction = function(v, f) {
			return (v+f<0)?v+(f*me.timer.tick):(v-f>0)?v-(f*me.timer.tick):0;
		};

		// return our object
		return api;

	})();

	/*---------------------------------------------------------*/
	// END END END
	/*---------------------------------------------------------*/
})(window);
<commit_msg>Fixed HexToRGB (Issue #76) : only convert hexadecimal strings (starting with "h") and added support for the 3 char format (#hhh)<commit_after>/*
 * MelonJS Game Engine
 * Copyright (C) 2012, Olivier BIOT
 * http://www.melonjs.org
 *
 */

(function($, undefined) {

	/**
	 *  Base64 decoding
	 *  @see http://www.webtoolkit.info/
	 */
	var Base64 = (function() {

		// hold public stuff in our singleton
		var singleton = {};

		// private property
		var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

		// public method for decoding
		singleton.decode = function(input) {

			// make sure our input string has the right format
			input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

			if (me.sys.nativeBase64) {
				// use native decoder
				return $.atob(input);
			}
			else {
				// use cross-browser decoding
				var output = [], chr1, chr2, chr3, enc1, enc2, enc3, enc4, i = 0;

				while (i < input.length) {
					enc1 = _keyStr.indexOf(input.charAt(i++));
					enc2 = _keyStr.indexOf(input.charAt(i++));
					enc3 = _keyStr.indexOf(input.charAt(i++));
					enc4 = _keyStr.indexOf(input.charAt(i++));

					chr1 = (enc1 << 2) | (enc2 >> 4);
					chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
					chr3 = ((enc3 & 3) << 6) | enc4;

					output.push(String.fromCharCode(chr1));

					if (enc3 != 64) {
						output.push(String.fromCharCode(chr2));
					}
					if (enc4 != 64) {
						output.push(String.fromCharCode(chr3));
					}
				}

				output = output.join('');
				return output;
			}
		};

		return singleton;

	})();

	/**
	 * a collection of utility Function
	 * @final
	 * @memberOf me
	 * @private
	 * @constructor Should not be called by the user.
	 */

	me.utils = (function() {
		// hold public stuff in our singletong
		var api = {};

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

		   PRIVATE STUFF

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

		// cache rgb converted value
		var rgbCache = {};

		// guid default value
		var GUID_base  = "";
		var GUID_index = 0;

		// regexp to deal with file name & path
		var removepath = /^.*(\\|\/|\:)/;
		var removeext = /\.[^\.]*$/;

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

			PUBLIC STUFF

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

		/**
		 * Decode a base64 encoded string into a binary string
		 *
		 * @param {String} input Base64 encoded data
		 * @return {String} Binary string
		 */
		api.decodeBase64 = function(input) {
			return Base64.decode(input);
		};

		/**
		 * Decode a base64 encoded string into a byte array
		 *
		 * @param {String} input Base64 encoded data
		 * @param {Int} [bytes] number of bytes per array entry
		 * @return {Int[]} Array of bytes
		 */
		api.decodeBase64AsArray = function(input, bytes) {
			bytes = bytes || 1;

			var dec = Base64.decode(input), ar = [], i, j, len;

			for (i = 0, len = dec.length / bytes; i < len; i++) {
				ar[i] = 0;
				for (j = bytes - 1; j >= 0; --j) {
					ar[i] += dec.charCodeAt((i * bytes) + j) << (j << 3);
				}
			}
			return ar;
		};

		/**
		 * Decode a CSV encoded array into a binary array
		 *
		 * @param  {String} input CSV formatted data
		 * @param  {Int} limit row split limit
		 * @return {Int[]} Int Array
		 */
		api.decodeCSV = function(input, limit) {
			input = input.trim().split("\n");

			var result = [];
			for ( var i = 0; i < input.length; i++) {
				entries = input[i].split(",", limit);
				for ( var e = 0; e < entries.length; e++) {
					result.push(+entries[e]);
				}
			}
			return result;
		};

		/**
		 * return the base name of the file without path info.

		 *
		 * @param  {String} path path containing the filename
		 * @return {String} basename returns the base name without path information.
		 */
		api.getBasename = function(path) {
			return path.replace(removepath, '').replace(removeext, '');
		};

		/* ---

			enable the nocache mechanism

		  ---*/
		api.setNocache = function(enable) {
			me.nocache = enable ? "?" + parseInt(Math.random() * 10000000) : '';
		};

		// a Hex to RGB color function
		api.HexToRGB = function(h, a) {
			if (h.charAt(0) !== "#") {
				// this is not a hexadecimal string
				return h;
			}
			// remove the #
			h = h.substring(1, h.length);

			// check if we already have the converted value cached
			if (rgbCache[h] == null) {
				// else add it (format : "r,g,b")
				if (h.length < 6)  {
					// 3 char shortcut is used, double each char
					var h1 = h.charAt(0)+h.charAt(0);
					var h2 = h.charAt(1)+h.charAt(1);
					var h3 = h.charAt(2)+h.charAt(2);
				}
				else {
					var h1 = h.substring(0, 2);
					var h2 = h.substring(2, 4);
					var h3 = h.substring(4, 6);
				}
				// set the value in our cache
				rgbCache[h] = parseInt(h1, 16) + "," + parseInt(h2, 16) + "," + parseInt(h3, 16);
			}
			return (a ? "rgba(" : "rgb(") + rgbCache[h] + (a ? "," + a + ")" : ")");
		};

		// a Hex to RGB color function
		api.RGBToHex = function(r, g, b) {
			return r.toHex() + g.toHex() + b.toHex();
		};

		// return the given canvas or image pixels
		api.getPixels = function(arg) {
			if (arg instanceof HTMLImageElement) {
				var c = me.video.createCanvasSurface(arg.width, arg.height);
				c.drawImage(arg, 0, 0);
				return c.getImageData(0, 0, arg.width, arg.height);
			} else {
				// canvas !
				return arg.getContext('2d').getImageData(0, 0, arg.width, arg.height);
			}
		};

		// reset the GUID Base Name
		// the idea here being to have a unique ID
		// per level / object
		api.resetGUID = function(base) {
			// also ensure it's only 8bit ASCII characters
			GUID_base  = base.toString().toUpperCase().toHex();
			GUID_index = 0;
		};

		// create and return a very simple GUID
		// Game Unique ID
		api.createGUID = function() {
			return GUID_base + "-" + (GUID_index++);
		};

		// apply friction to a force
		api.applyFriction = function(v, f) {
			return (v+f<0)?v+(f*me.timer.tick):(v-f>0)?v-(f*me.timer.tick):0;
		};

		// return our object
		return api;

	})();

	/*---------------------------------------------------------*/
	// END END END
	/*---------------------------------------------------------*/
})(window);
<|endoftext|>


<commit_before>import Obj from 'snew/obj/class';

export default Obj({
	////-----------------------------------------------------------------------------------------
	// In which package does requirejs use the templates
	templatePrefix: 'templates/',
	////-----------------------------------------------------------------------------------------
	// Jquery selector where the this.startPath controller and view are added
	entrance: '#app',
	////-----------------------------------------------------------------------------------------
	// Controller which is added at startup
	startPath: 'main/app',
	////-----------------------------------------------------------------------------------------
	// domnode-attribute for start uid node
	uidDomNode: 'SCRIPT',
	////-----------------------------------------------------------------------------------------
	// domnode-attribute for start uid node
	uidAttrStart: 'data-begin',
	////-----------------------------------------------------------------------------------------
	// domnode-attribute for end uid node
	uidAttrEnd: 'data-end',
	////-----------------------------------------------------------------------------------------
	// Existing classes collection
	list: {},
	////-----------------------------------------------------------------------------------------
	// saves which views changed
	dirties: [],
	////-----------------------------------------------------------------------------------------
	// Decides which instances are asked for handling events
	eventSpaces: [ 'controllerHelper', 'helperHelper' ],
	////-----------------------------------------------------------------------------------------
	// JQuery events which the framework is listening for
	eventListeners: ['keydown', 'keypress', 'keyup'],
	////-----------------------------------------------------------------------------------------
	// maps e.g. keypresses to trigger shortevents for enter and escape-keys
	eventMap: {
		keydown: {
			keyCode: {
				13: 'view.enterkey',
				27: 'view.escapekey'
			}

		}
	},
	_meta: {
		contentSpace: false
	},
	////-----------------------------------------------------------------------------------------
	// adds dirtychecking to runloop and inserts first view this.startPath and starts document event listener
	init() {
		tempartCompiler.partial = this.partialHandling; // Thats how you configure tempart...
		if( this.dirtyHandling !== false ){
			this.addJob({callback: this.dirtyChecking});
		}
		this.checkValidity();
		this.insertApp();
		this.addEvents();
	},
	////-----------------------------------------------------------------------------------------
	// adds dirtychecking to runloop and inserts first view this.startPath and starts document event listener
	partialHandling(block, context, currentValues, dirties, path) {
		// @TODO add uid to currentValues
		currentValues[ block.id ] = {path, uid: 1 + snew.controllerHelper.id};
		return snew.controllerHelper.create( path, context ).html;
	},
	////-----------------------------------------------------------------------------------------
	// creates instance of view
	create(path, opt) {
		return this.getEntity(path);
	},
	////-----------------------------------------------------------------------------------------
	// inserts first view to this.entrance
	insertApp() {
		const dom = document.querySelector( this.entrance );
		if( dom ) {
			const result = snew.controllerHelper.create( this.startPath, null, {} );
			dom.outerHTML = result.html;
		} else {
			console.error('snew.viewHelper.entrance was not represented in dom properly', dom);
		}
	},
	////-----------------------------------------------------------------------------------------
	// gets class and returns instance
	getEntity(path) {
		if( !this.list[ path ]){
			console.log(`View ${path} does not exist`);
			snew.View(path, {_meta: {pseudo: true}});
		}
		return snew.utilHelper.clone( this.list[ path ] );
	},
	////-----------------------------------------------------------------------------------------
	// start uid
	// @TODO move this to the templating engine
	scriptStart(id, path) {
		return `<${this.uidDomNode} ${this.uidAttrStart}="${id}" data-template="${path}"></${this.uidDomNode}>`;
	},
	////-----------------------------------------------------------------------------------------
	// end uid
	scriptEnd(id) {
		return `<${this.uidDomNode} ${this.uidAttrEnd}="${id}"></${this.uidDomNode}>`;
	},
	////-----------------------------------------------------------------------------------------
	// some basic checking if values are correct
	checkValidity() {
		if( !this.entrance ){
			throw "App entrance is not defined";
		}
	},
	////-----------------------------------------------------------------------------------------
	// checks which views are dirty, to asynchronoesly render them
	dirtyChecking() {
		if(snew.viewHelper.dirties) {

			for( let i = 0; i < snew.viewHelper.dirties.length; i++ ){
				const uid = snew.viewHelper.dirties[i];
				const controllers = snew.controllerHelper.search(uid);
				for( let controllerIndex = 0; controllerIndex < controllers.length; controllerIndex++ ){
					const controller = controllers[ controllerIndex ];
					controller.view._handleDirties();
				}
			}
			snew.viewHelper.dirties = [];
		}
	},
	////-----------------------------------------------------------------------------------------
	// iterates through all dom-nodes to the top and returns an array of controllers
	getUids(obj) {
		const result    = [];
		const excludes  = [];
		do {
			const endUid = this.isUidEndObj( obj );
			const uid = this.isUidObj( obj );

			if( endUid ){
				excludes.push(endUid); // Needed to handle siblings, which do not surround the target
			} else if( uid && excludes.indexOf( uid ) === -1 ){
				result.push(uid);
			}
			if(obj.previousSibling) {
				obj = obj.previousSibling;
			} else {
				obj = obj.parentNode;
			}
		} while(obj)

		return result;
	},
	////-----------------------------------------------------------------------------------------
	// checks if dom-node is an uid-obj
	isUidObj(obj) {
		return this._getAttributeValue(obj, this.uidDomNode, this.uidAttrStart);
	},
	////-----------------------------------------------------------------------------------------
	// checks if dom-node is an uid-end-obj
	isUidEndObj(obj) {
		return this._getAttributeValue(obj, this.uidDomNode, this.uidAttrEnd);
	},
	////-----------------------------------------------------------------------------------------
	// expects node type and an attribute key, returns this when exists
	_getAttributeValue(obj, nodeName, attributeName) {
		if(obj.nodeName === nodeName) { // @FIXME
			for( let i = 0; i < obj.attributes.length; i++ ) {
				if( obj.attributes[ i ].nodeName === attributeName ){
					return obj.attributes[ i ].nodeValue;
				}
			}
		}
	},
	////-----------------------------------------------------------------------------------------
	// adds all dom events which the framework ist listening for
	addEvents() {
		for(let i = 0; i < this.eventListeners.length; i++) {
			document.body.addEventListener(this.eventListeners[ i ], evt => {
				return snew.viewHelper.handleEvent( evt );
			});
		}
		window.addEventListener('hashchange', () => {
			this.trigger('hashchange', location.hash);
		});
	},
	////-----------------------------------------------------------------------------------------
	// wrapper for triggering events, selects corresponding parent-controllers
	handleEvent(evt) {
		const uids = this.getUids( evt.target );
		this.triggerExtra(evt);
		this.updateData(evt);
	},
	////-----------------------------------------------------------------------------------------
	// way binding from dom
	updateData(evt) {
		if( evt.type == 'keypress' || evt.type == 'keyup' ){
			const identifier = evt.target.getAttribute('tempartstart');
			if( identifier && evt.keyCode !== 13 ){ // Enter button don't bring changes into the values
				const pos = identifier.indexOf( '-' );
				const uid = identifier.slice( 0, pos );
				const blockId = identifier.slice( pos + 1, identifier.length );
				const controllers = snew.search( uid );
				if( controllers.length === 1 ){
					const controller = controllers[ 0 ];
					let value = evt.target.value
					if(evt.type == 'keypress') {
						value += String.fromCharCode(evt.keyCode);
					}
					controller.view._updateCurrent(blockId, 'value', value);
				} else {
					throw 'Getting the correct controller failed somehow';
				}
			}
		}
	},
	////-----------------------------------------------------------------------------------------
	// triggers eventmaps like keypresses to shortevents like "enterkey" and escapekey
	triggerExtra(evt) {
		if( this.eventMap[ evt.type ] ){
			for( const index in this.eventMap[ evt.type ] ) {
				const eventValue = evt[ index ];
				if( eventValue ) {
					const mapValue = this.eventMap[ evt.type ][ index ][ eventValue ];
					if( mapValue ){
						this.trigger(mapValue, evt); // @TODO does this evt needs a clone?
					}
				}
			}
		}
	},
	////-----------------------------------------------------------------------------------------
	// recusively goes upside in the dom, to collect dataattributes
	getAttributes(target, result) {
		if(!result) result = {};

		if(target) {
			const attributes = target.attributes;

			if(result.id === undefined && target.attr('id') && attributes['data-id'] === undefined) {
				result.id = target.attr('id');
			}

			const excludes = ['ember-extension'];

			for (const index in attributes) {
				if (attributes.hasOwnProperty(index)) {
					const name  = attributes[index].name, value = attributes[index].value;
					if(name && name.search('data-') === 0) {
						let key = name.replace(/data-/, '');
						if(result[key] === undefined && excludes.indexOf(key) == -1) { // SHould only overwrite when not set
							result[key] = value || null;
						}
					}
				}
			}
			if(target.parentNode) {
				result = this.getAttributes(target.parentNode, result);
			}
		}
		return result;
	}
});<commit_msg>[events] changed to bugfree keydown version<commit_after>import Obj from 'snew/obj/class';

export default Obj({
	////-----------------------------------------------------------------------------------------
	// In which package does requirejs use the templates
	templatePrefix: 'templates/',
	////-----------------------------------------------------------------------------------------
	// Jquery selector where the this.startPath controller and view are added
	entrance: '#app',
	////-----------------------------------------------------------------------------------------
	// Controller which is added at startup
	startPath: 'main/app',
	////-----------------------------------------------------------------------------------------
	// domnode-attribute for start uid node
	uidDomNode: 'SCRIPT',
	////-----------------------------------------------------------------------------------------
	// domnode-attribute for start uid node
	uidAttrStart: 'data-begin',
	////-----------------------------------------------------------------------------------------
	// domnode-attribute for end uid node
	uidAttrEnd: 'data-end',
	////-----------------------------------------------------------------------------------------
	// Existing classes collection
	list: {},
	////-----------------------------------------------------------------------------------------
	// saves which views changed
	dirties: [],
	////-----------------------------------------------------------------------------------------
	// Decides which instances are asked for handling events
	eventSpaces: [ 'controllerHelper', 'helperHelper' ],
	////-----------------------------------------------------------------------------------------
	// JQuery events which the framework is listening for
	eventListeners: ['keydown'],
	////-----------------------------------------------------------------------------------------
	// maps e.g. keypresses to trigger shortevents for enter and escape-keys
	eventMap: {
		keydown: {
			keyCode: {
				13: 'view.enterkey',
				27: 'view.escapekey'
			}

		}
	},
	_meta: {
		contentSpace: false
	},
	////-----------------------------------------------------------------------------------------
	// adds dirtychecking to runloop and inserts first view this.startPath and starts document event listener
	init() {
		tempartCompiler.partial = this.partialHandling; // Thats how you configure tempart...
		if( this.dirtyHandling !== false ){
			this.addJob({callback: this.dirtyChecking});
		}
		this.checkValidity();
		this.insertApp();
		this.addEvents();
	},
	////-----------------------------------------------------------------------------------------
	// adds dirtychecking to runloop and inserts first view this.startPath and starts document event listener
	partialHandling(block, context, currentValues, dirties, path) {
		// @TODO add uid to currentValues
		currentValues[ block.id ] = {path, uid: 1 + snew.controllerHelper.id};
		return snew.controllerHelper.create( path, context ).html;
	},
	////-----------------------------------------------------------------------------------------
	// creates instance of view
	create(path, opt) {
		return this.getEntity(path);
	},
	////-----------------------------------------------------------------------------------------
	// inserts first view to this.entrance
	insertApp() {
		const dom = document.querySelector( this.entrance );
		if( dom ) {
			const result = snew.controllerHelper.create( this.startPath, null, {} );
			dom.outerHTML = result.html;
		} else {
			console.error('snew.viewHelper.entrance was not represented in dom properly', dom);
		}
	},
	////-----------------------------------------------------------------------------------------
	// gets class and returns instance
	getEntity(path) {
		if( !this.list[ path ]){
			console.log(`View ${path} does not exist`);
			snew.View(path, {_meta: {pseudo: true}});
		}
		return snew.utilHelper.clone( this.list[ path ] );
	},
	////-----------------------------------------------------------------------------------------
	// start uid
	// @TODO move this to the templating engine
	scriptStart(id, path) {
		return `<${this.uidDomNode} ${this.uidAttrStart}="${id}" data-template="${path}"></${this.uidDomNode}>`;
	},
	////-----------------------------------------------------------------------------------------
	// end uid
	scriptEnd(id) {
		return `<${this.uidDomNode} ${this.uidAttrEnd}="${id}"></${this.uidDomNode}>`;
	},
	////-----------------------------------------------------------------------------------------
	// some basic checking if values are correct
	checkValidity() {
		if( !this.entrance ){
			throw "App entrance is not defined";
		}
	},
	////-----------------------------------------------------------------------------------------
	// checks which views are dirty, to asynchronoesly render them
	dirtyChecking() {
		if(snew.viewHelper.dirties) {

			for( let i = 0; i < snew.viewHelper.dirties.length; i++ ){
				const uid = snew.viewHelper.dirties[i];
				const controllers = snew.controllerHelper.search(uid);
				for( let controllerIndex = 0; controllerIndex < controllers.length; controllerIndex++ ){
					const controller = controllers[ controllerIndex ];
					controller.view._handleDirties();
				}
			}
			snew.viewHelper.dirties = [];
		}
	},
	////-----------------------------------------------------------------------------------------
	// iterates through all dom-nodes to the top and returns an array of controllers
	getUids(obj) {
		const result    = [];
		const excludes  = [];
		do {
			const endUid = this.isUidEndObj( obj );
			const uid = this.isUidObj( obj );

			if( endUid ){
				excludes.push(endUid); // Needed to handle siblings, which do not surround the target
			} else if( uid && excludes.indexOf( uid ) === -1 ){
				result.push(uid);
			}
			if(obj.previousSibling) {
				obj = obj.previousSibling;
			} else {
				obj = obj.parentNode;
			}
		} while(obj)

		return result;
	},
	////-----------------------------------------------------------------------------------------
	// checks if dom-node is an uid-obj
	isUidObj(obj) {
		return this._getAttributeValue(obj, this.uidDomNode, this.uidAttrStart);
	},
	////-----------------------------------------------------------------------------------------
	// checks if dom-node is an uid-end-obj
	isUidEndObj(obj) {
		return this._getAttributeValue(obj, this.uidDomNode, this.uidAttrEnd);
	},
	////-----------------------------------------------------------------------------------------
	// expects node type and an attribute key, returns this when exists
	_getAttributeValue(obj, nodeName, attributeName) {
		if(obj.nodeName === nodeName) { // @FIXME
			for( let i = 0; i < obj.attributes.length; i++ ) {
				if( obj.attributes[ i ].nodeName === attributeName ){
					return obj.attributes[ i ].nodeValue;
				}
			}
		}
	},
	////-----------------------------------------------------------------------------------------
	// adds all dom events which the framework ist listening for
	addEvents() {
		for(let i = 0; i < this.eventListeners.length; i++) {
			document.body.addEventListener(this.eventListeners[ i ], evt => {
				return snew.viewHelper.handleEvent( evt );
			});
		}
		window.addEventListener('hashchange', () => {
			this.trigger('hashchange', location.hash);
		});
	},
	////-----------------------------------------------------------------------------------------
	// wrapper for triggering events, selects corresponding parent-controllers
	handleEvent(evt) {
		const uids = this.getUids( evt.target );
		this.triggerExtra(evt);
		this.updateData(evt);
	},
	////-----------------------------------------------------------------------------------------
	// way binding from dom
	updateData(evt) {
		if( evt.type == 'keydown'){ // Keydown is fired before the input has its value => using setTimeout (because its more responsive then keypress/keyup)
			setTimeout(function() {
				const identifier = evt.target.getAttribute('tempartstart');
				if( identifier && evt.keyCode !== 13 ){ // Enter button don't bring changes into the values
					const pos = identifier.indexOf( '-' );
					const uid = identifier.slice( 0, pos );
					const blockId = identifier.slice( pos + 1, identifier.length );
					const controllers = snew.search( uid );
					if( controllers.length === 1 ){
						const controller = controllers[ 0 ];
						let value = evt.target.value
						controller.view._updateCurrent(blockId, 'value', value);
					} else {
						throw 'Getting the correct controller failed somehow';
					}
				}
			}, 0);
		}
	},
	////-----------------------------------------------------------------------------------------
	// triggers eventmaps like keypresses to shortevents like "enterkey" and escapekey
	triggerExtra(evt) {
		if( this.eventMap[ evt.type ] ){
			for( const index in this.eventMap[ evt.type ] ) {
				const eventValue = evt[ index ];
				if( eventValue ) {
					const mapValue = this.eventMap[ evt.type ][ index ][ eventValue ];
					if( mapValue ){
						this.trigger(mapValue, evt); // @TODO does this evt needs a clone?
					}
				}
			}
		}
	},
	////-----------------------------------------------------------------------------------------
	// recusively goes upside in the dom, to collect dataattributes
	getAttributes(target, result) {
		if(!result) result = {};

		if(target) {
			const attributes = target.attributes;

			if(result.id === undefined && target.attr('id') && attributes['data-id'] === undefined) {
				result.id = target.attr('id');
			}

			const excludes = ['ember-extension'];

			for (const index in attributes) {
				if (attributes.hasOwnProperty(index)) {
					const name  = attributes[index].name, value = attributes[index].value;
					if(name && name.search('data-') === 0) {
						let key = name.replace(/data-/, '');
						if(result[key] === undefined && excludes.indexOf(key) == -1) { // SHould only overwrite when not set
							result[key] = value || null;
						}
					}
				}
			}
			if(target.parentNode) {
				result = this.getAttributes(target.parentNode, result);
			}
		}
		return result;
	}
});<|endoftext|>


<commit_before>/**
 * Copyright 2014 IBM Corp. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';

var initSessionPermissions = require('./sessionpermissions').initSessionPermissions;
var initSelectModel = require('./selectmodel').initSelectModel;
var initAnimatePanel = require('./animatepanel').initAnimatePanel;
var initShowTab = require('./showtab').initShowTab;
var initDragDrop = require('./dragdrop').initDragDrop;
var initPlaySample = require('./playsample').initPlaySample;
var initRecordButton = require('./recordbutton').initRecordButton;
var initFileUpload = require('./fileupload').initFileUpload;
var initDisplayMetadata = require('./displaymetadata').initDisplayMetadata;

exports.initViews = function(ctx) {
  console.log('Initializing views...');
  initSelectModel(ctx);
  initPlaySample(ctx);
  initDragDrop(ctx);
  initRecordButton(ctx);
  initFileUpload(ctx);
  initSessionPermissions();
  initShowTab();
  initAnimatePanel();
  initShowTab();
  initDisplayMetadata();
};
<commit_msg>Update index.js<commit_after>/**
 * Copyright 2014 IBM Corp. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';

var initSessionPermissions = require('./sessionpermissions').initSessionPermissions;
var initAnimatePanel = require('./animatepanel').initAnimatePanel;
var initShowTab = require('./showtab').initShowTab;
var initDragDrop = require('./dragdrop').initDragDrop;
var initPlaySample = require('./playsample').initPlaySample;
var initRecordButton = require('./recordbutton').initRecordButton;
var initFileUpload = require('./fileupload').initFileUpload;
var initDisplayMetadata = require('./displaymetadata').initDisplayMetadata;

exports.initViews = function(ctx) {
  console.log('Initializing views...');
  initPlaySample(ctx);
  initDragDrop(ctx);
  initRecordButton(ctx);
  initFileUpload(ctx);
  initSessionPermissions();
  initShowTab();
  initAnimatePanel();
  initShowTab();
  initDisplayMetadata();
};
<|endoftext|>