<commit_before>DisplaysManager = {

    instances: {},

    get: function(name, iTestCase, display, parent, params) {
        var k = name + iTestCase;
        if(!this.instances[k]) {
            this.instances[k] = window[name](params);
        }
        this.instances[k].init(parent, display);
        return this.instances[k];
    }
}

function ContextCursor(params) {

    var defaults = {
        color: 'rgb(255,128,0)'
    }
    params = Object.assign({}, defaults, params);

    this.position = false;

    this.set = function(x, y) {
        this.position = {
            x: x,
            y: y
        }
    }

    this.reset = function() {
        this.position = false;
    }

    this.render = function(ofs_left, scale) {
        if(!this.position || !params.context2d) {
            return;
        }
        params.context2d.beginPath();
        params.context2d.strokeStyle = params.color;
        params.context2d.lineWidth = scale > 5 ? 3 : 1;
        params.context2d.rect(
            ofs_left + scale * this.position.x + 0.5,
            scale * this.position.y + 0.5,
            scale,
            scale
        );
        params.context2d.stroke();
    }
}

function ContextGrid(params) {

    var defaults = {
        color: '#888',
        min_scale: 6
    }
    params = Object.assign({}, defaults, params);

    this.render = function(ofs_left, scale, cols, rows) {
        if(scale < params.min_scale) {
            return;
        }
        params.context2d.strokeStyle = params.color;
        params.context2d.lineWidth = 1;
        for(var x=1; x<cols; x++) {
            var dx = ofs_left + x * scale + 0.5;
            params.context2d.beginPath();
            params.context2d.moveTo(dx , 0);
            params.context2d.lineTo(dx, rows * scale);
            params.context2d.stroke();
        }
        for(var y=1; y<rows; y++) {
            var dy = y * scale + 0.5;
            params.context2d.beginPath();
            params.context2d.moveTo(ofs_left, dy);
            params.context2d.lineTo(ofs_left + cols * scale, dy);
            params.context2d.stroke();
        }
    }
}

function CanvasTooltip(params) {

    this.element = null;
    this.bounds = null;

    this.render = function() {
        if(this.element) {
            return;
        }
        this.element = $('
')
            .css('position', 'fixed')
            .css('z-index', '10000')
            .css('background', '#4A90E2')
            .css('color', '#FFF')
            .css('padding', '10px')
            .css('border-radius', '5px');
        $(document.body).append(this.element);
    }

    this.setBounds = function(ofs_left, scale, cols, rows) {
        this.bounds = {
            ofs_left: ofs_left,
            scale: scale,
            cols: cols,
            rows: rows
        }
    }

    this.show = function(e) {
        if(!this.bounds) {
            return;
        }
        var canvas_offset = params.canvas.offset();
        var x = e.pageX - canvas_offset.left - this.bounds.ofs_left;
        var y = e.pageY - canvas_offset.top;
        if(x < 0 || x > this.bounds.cols * this.bounds.scale) {
            this.hide();
            return;
        }

        var col = Math.floor(x / this.bounds.scale);
        var row = Math.floor(y / this.bounds.scale);
        var luminocity = params.getPixelLuminosity(col, row);

        this.render();
        this.element.show();
        this.element.css({
            left: e.pageX + 10,
            top: e.pageY + 10
        });
        var str = params.strings.messages.tooltip;
        str = str.replace('%1', col).replace('%2', row).replace('%3', luminocity);
        this.element.text(str);
    }

    this.hide = function() {
        this.element && this.element.hide();
    }

    params.canvas.mouseleave(this.hide.bind(this));
    params.canvas.mousemove(this.show.bind(this));
}

function BarcodeDisplay(params) {

    var parent;
    var canvas;
    var context2d;
    var cursor;
    var grid;
    var tooltip;

    function init(new_parent, new_display) {
        parent = new_parent;
        display = new_display;
        if(!display) {
            return;
        }
        canvas = $('<canvas>');
        parent.append(canvas);
        context2d = canvas[0].getContext('2d');
        cursor = new ContextCursor({
            context2d: context2d
        });
        grid = new ContextGrid({
            context2d: context2d
        });
        tooltip = new CanvasTooltip({
            canvas: canvas,
            strings: params.strings,
            getPixelLuminosity: calculatePixelLuminosity
        });
        render();
    }

    var image_data = '';
    var image;
    var image_loaded;
    var image_canvas;
    var image_context2d;

    function render() {
        if(!image || !display) {
            return;
        }
        var w = canvas[0].width = Math.floor(parent.width());
        var h = canvas[0].height = Math.floor(parent.height() * 0.5 - 10);
        if(w == 0) {
            return;
        }
        var scale = Math.min(Math.floor(w / image.width), Math.floor(h / image.height));
        var image_w = Math.floor(image.width * scale);
        var image_h = Math.floor(image.height * scale);
        var ofs_left = Math.floor(0.5 * (w - image_w));

        context2d.imageSmoothingEnabled = false;
        //context2d.mozImageSmoothingEnabled = false;

        context2d.clearRect(0, 0, w, h);
        context2d.drawImage(image, ofs_left, 0, image_w, image_h);

        grid.render(ofs_left, scale, image.width, image.height);
        tooltip.setBounds(ofs_left, scale, image.width, image.height);
        cursor.render(ofs_left, scale);
    }

    function setImage(data, callback) {
        if(image_data === data) {
            return;
        }
        image = false;
        image_loaded = false;
        image_data = data;
        cursor && cursor.reset();
        if(!image_canvas) {
            image_canvas = document.createElement('canvas');
            image_context2d = image_canvas.getContext('2d');
        }
        loadImage(callback);
    }

    function loadImage(callback) {
        if(image_loaded) {
            return callback && callback();
        }
        image = new Image();
        image.onload = function() {
            image_context2d.drawImage(image, 0, 0);
            image_loaded = true;
            render();
            callback && callback();
        }
        image.src = image_data;
    }

    function calculatePixelLuminosity(x, y) {
        var d = image_context2d.getImageData(x, y, 1, 1).data;
        // ITU BT.601
        var l = 0.299 * d[0] + 0.587 * d[1] + 0.114 * d[2];
        return Math.round(l);
    }

    return {

        init: init,

        setImage: setImage,

        render: render,

        getSize: function(callback) {
            loadImage(function() {
                callback({
                    width: image ? image.width : 0,
                    height: image ? image.height : 0
                })
            });
        },

        getPixelLuminosity: function(x, y, callback) {
            loadImage(function() {
                cursor && cursor.set(x, y);
                render();
                callback(calculatePixelLuminosity(x, y));
            })
        }

    }
}

function UserDisplay(params) {

    var pixels = [];
    var canvas, context2d;
    var data_size;
    var parent;
    var cursor;
    var grid;
    var tooltip;

    function init(new_parent, new_display) {
        parent = new_parent;
        display = new_display;
        if(!display) {
            return;
        }
        canvas = $('<canvas>');
        parent.append(canvas);
        context2d = canvas[0].getContext('2d');
        cursor = new ContextCursor({
            context2d: context2d
        });
        grid = new ContextGrid({
            context2d: context2d
        });
        tooltip = new CanvasTooltip({
            canvas: canvas,
            strings: params.strings,
            getPixelLuminosity: getPixelLuminosity
        });
        render();
    }

    function getPixelLuminosity(x, y) {
        if(!data_size) {
            return 0;
        }
        var ofs = y * data_size.width + x;
        return pixels[ofs];
    }

    function render(valid_result) {
        if(!pixels || w == 0 || !data_size) {
            return;
        }

        if(display) {
            context2d.imageSmoothingEnabled = false;
            //context2d.mozImageSmoothingEnabled = false;

            var w = canvas[0].width = Math.floor(parent.width());
            var h = canvas[0].height = Math.floor(parent.height() * 0.5 - 10);
            if(w == 0) {
                return;
            }
            var scale = Math.min(Math.floor(w / data_size.width), Math.floor(h / data_size.height));
            var ofs_left = Math.floor(0.5 * (w - data_size.width * scale));
            context2d.clearRect(0, 0, w, h);

            var i=0;
            for(var y=0; y<data_size.height; y++) {
                for(var x=0; x<data_size.width; x++) {
                    if(pixels[i] != 255) {
                        context2d.fillStyle = 'rgb(' + pixels[i] + ',' + pixels[i] + ',' + pixels[i] + ')';
                        context2d.fillRect(
                            ofs_left + x * scale,
                            y * scale,
                            scale,
                            scale
                        );
                    }
                    i++;
                }
            }

            grid.render(ofs_left, scale, data_size.width, data_size.height);
            cursor.render(ofs_left, scale);
            tooltip.setBounds(ofs_left, scale, data_size.width, data_size.height);
        }

        if(valid_result && 'data' in valid_result) {
            var i=0;
            var threshold = valid_result.threshold || 0;
            for(var y=0; y<data_size.height; y++) {
                for(var x=0; x<data_size.width; x++) {
                    if(Math.abs(pixels[i] - valid_result.data[y][x]) > threshold) {
                        if(display) {
                            context2d.beginPath();
                            context2d.strokeStyle = '#F00';
                            context2d.lineWidth = scale > 20 ? 2 : 1;
                            context2d.rect(
                                ofs_left + x * scale,
                                y * scale,
                                scale,
                                scale
                            );
                            context2d.stroke();
                        }

                        var msg = params.strings.messages.mistake_pixel;
                        msg = msg.replace('%1', pixels[i]).replace('%2', valid_result.data[y][x]);
                        return {
                            success: false,
                            message: msg
                        }
                    }
                    i++;
                }
            }
            return {
                success: true,
                message: params.strings.messages.success
            }
        }
    }

    return {

        init: init,

        setPixelLuminosity: function(x, y, v) {
            cursor && cursor.set(x, y);
            var v = Math.max(0, Math.min(v, 255));
            pixels[y * data_size.width + x] = v;
            render();
        },

        setSize: function(new_data_size) {
            data_size = new_data_size;
            pixels = new Array(data_size.width * data_size.height).fill(255)
            render();
        },

        clear: function() {
            cursor && cursor.reset();
            data_size = null;
            pixels = [];
            context2d.clearRect(0, 0, canvas[0].width, canvas[0].height);
        },

        render: render,

        diff: function(valid_result) {
            return render(valid_result);
        }
    }
}

function StringDisplay(params) {

    var data = '';
    var diff = '';
    var element;
    var wrapper;
    var display;

    function init(parent, new_display) {
        display = new_display;
        data = '';
        if(!display) {
            return;
        }
        element = $('')
        wrapper = $('
' + params.strings.messages.result + '
');
        wrapper.append(element).hide();
        parent.append(wrapper);
    }

    function isEmpty() {
        return data == '';
    }

    function render(html) {
        if(!display) {
            return;
        }
        wrapper.toggle(data != '');
        element.html(html);
    }

    return {

        init: init,

        setData: function(str) {
            str = '' + str;
            data = str;
            render(str);
        },

        diff: function(valid_result) {
            diff = '';
            var valid = true;

            var l = Math.max(valid_result.data.length, data.length);
            for(var i=0; i<l; i++) {
                if(valid_result.data[i] !== data[i]) {
                    valid = false;
                    if(i < data.length) {
                        diff += '' + data[i] + '';
                    }
                } else {
                    diff += data[i];
                }
            }
            render(diff);
            return {
                success: valid,
                message: valid ? params.strings.messages.success : params.strings.messages.mistake_digit
            }
        }
    }

}<commit_msg>barcode<commit_after>DisplaysManager = {

    instances: {},

    get: function(name, iTestCase, display, parent, params) {
        var k = name + iTestCase;
        if(!this.instances[k]) {
            this.instances[k] = window[name](params);
        }
        this.instances[k].init(parent, display);
        return this.instances[k];
    }
}

function ContextCursor(params) {

    var defaults = {
        color: 'rgb(255,128,0)'
    }
    params = Object.assign({}, defaults, params);

    this.position = false;

    this.set = function(x, y) {
        this.position = {
            x: x,
            y: y
        }
    }

    this.reset = function() {
        this.position = false;
    }

    this.render = function(ofs_left, scale) {
        if(!this.position || !params.context2d) {
            return;
        }
        params.context2d.beginPath();
        params.context2d.strokeStyle = params.color;
        params.context2d.lineWidth = scale > 5 ? 3 : 1;
        params.context2d.rect(
            ofs_left + scale * this.position.x + 0.5,
            scale * this.position.y + 0.5,
            scale,
            scale
        );
        params.context2d.stroke();
    }
}

function ContextGrid(params) {

    var defaults = {
        color: '#888',
        min_scale: 6
    }
    params = Object.assign({}, defaults, params);

    this.render = function(ofs_left, scale, cols, rows) {
        if(scale < params.min_scale) {
            return;
        }
        params.context2d.strokeStyle = params.color;
        params.context2d.lineWidth = 1;
        for(var x=1; x<cols; x++) {
            var dx = ofs_left + x * scale + 0.5;
            params.context2d.beginPath();
            params.context2d.moveTo(dx , 0);
            params.context2d.lineTo(dx, rows * scale);
            params.context2d.stroke();
        }
        for(var y=1; y<rows; y++) {
            var dy = y * scale + 0.5;
            params.context2d.beginPath();
            params.context2d.moveTo(ofs_left, dy);
            params.context2d.lineTo(ofs_left + cols * scale, dy);
            params.context2d.stroke();
        }
    }
}

function CanvasTooltip(params) {

    this.element = null;
    this.bounds = null;

    this.render = function() {
        if(this.element) {
            return;
        }
        this.element = $('
')
            .css('position', 'fixed')
            .css('z-index', '10000')
            .css('background', '#4A90E2')
            .css('color', '#FFF')
            .css('padding', '10px')
            .css('border-radius', '5px');
        $(document.body).append(this.element);
    }

    this.setBounds = function(ofs_left, scale, cols, rows) {
        this.bounds = {
            ofs_left: ofs_left,
            scale: scale,
            cols: cols,
            rows: rows
        }
    }

    this.show = function(e) {
        if(!this.bounds) {
            return;
        }
        var canvas_offset = params.canvas.offset();
        var x = e.pageX - canvas_offset.left - this.bounds.ofs_left;
        var y = e.pageY - canvas_offset.top;
        if(x < 0 || x > this.bounds.cols * this.bounds.scale) {
            this.hide();
            return;
        }

        var col = Math.floor(x / this.bounds.scale);
        var row = Math.floor(y / this.bounds.scale);
        var luminocity = params.getPixelLuminosity(col, row);

        this.render();
        this.element.show();
        this.element.css({
            left: e.pageX + 10,
            top: e.pageY + 10
        });
        var str = params.strings.messages.tooltip;
        str = str.replace('%1', col).replace('%2', row).replace('%3', luminocity);
        this.element.text(str);
    }

    this.hide = function() {
        this.element && this.element.hide();
    }

    params.canvas.mouseleave(this.hide.bind(this));
    params.canvas.mousemove(this.show.bind(this));
}

function BarcodeDisplay(params) {

    var parent;
    var canvas;
    var context2d;
    var cursor;
    var grid;
    var tooltip;

    function init(new_parent, new_display) {
        parent = new_parent;
        display = new_display;
        if(!display) {
            return;
        }
        canvas = $('<canvas>');
        parent.append(canvas);
        context2d = canvas[0].getContext('2d');
        cursor = new ContextCursor({
            context2d: context2d
        });
        grid = new ContextGrid({
            context2d: context2d
        });
        tooltip = new CanvasTooltip({
            canvas: canvas,
            strings: params.strings,
            getPixelLuminosity: calculatePixelLuminosity
        });
        render();
    }

    var image_data = '';
    var image;
    var image_loaded;
    var image_canvas;
    var image_context2d;

    function render() {
        if(!image || !display) {
            return;
        }
        var w = canvas[0].width = Math.floor(parent.width());
        var h = canvas[0].height = Math.floor(parent.height() * 0.5 - 10);
        if(w == 0) {
            return;
        }
        var scale = Math.min(Math.floor(w / image.width), Math.floor(h / image.height));
        var image_w = Math.floor(image.width * scale);
        var image_h = Math.floor(image.height * scale);
        var ofs_left = Math.floor(0.5 * (w - image_w));

        context2d.imageSmoothingEnabled = false;
        //context2d.mozImageSmoothingEnabled = false;

        context2d.clearRect(0, 0, w, h);
        context2d.drawImage(image, ofs_left, 0, image_w, image_h);

        grid.render(ofs_left, scale, image.width, image.height);
        tooltip.setBounds(ofs_left, scale, image.width, image.height);
        cursor.render(ofs_left, scale);
    }

    function setImage(data, callback) {
        if(image_data === data) {
            return;
        }
        image = false;
        image_loaded = false;
        image_data = data;
        cursor && cursor.reset();
        if(!image_canvas) {
            image_canvas = document.createElement('canvas');
            image_context2d = image_canvas.getContext('2d');
        }
        loadImage(callback);
    }

    function loadImage(callback) {
        if(image_loaded) {
            return callback && callback();
        }
        image = new Image();
        image.onload = function() {
            image_context2d.drawImage(image, 0, 0);
            image_loaded = true;
            render();
            callback && callback();
        }
        image.src = image_data;
    }

    function calculatePixelLuminosity(x, y) {
        var d = image_context2d.getImageData(x, y, 1, 1).data;
        // ITU BT.601
        var l = 0.299 * d[0] + 0.587 * d[1] + 0.114 * d[2];
        return Math.round(l);
    }

    return {

        init: init,

        setImage: setImage,

        render: render,

        getSize: function(callback) {
            loadImage(function() {
                callback({
                    width: image ? image.width : 0,
                    height: image ? image.height : 0
                })
            });
        },

        getPixelLuminosity: function(x, y, callback) {
            loadImage(function() {
                cursor && cursor.set(x, y);
                render();
                callback(calculatePixelLuminosity(x, y));
            })
        }

    }
}

function UserDisplay(params) {

    var pixels = [];
    var canvas, context2d;
    var data_size;
    var parent;
    var cursor;
    var grid;
    var tooltip;

    function init(new_parent, new_display) {
        parent = new_parent;
        display = new_display;
        if(!display) {
            return;
        }
        canvas = $('<canvas>');
        parent.append(canvas);
        context2d = canvas[0].getContext('2d');
        cursor = new ContextCursor({
            context2d: context2d
        });
        grid = new ContextGrid({
            context2d: context2d
        });
        tooltip = new CanvasTooltip({
            canvas: canvas,
            strings: params.strings,
            getPixelLuminosity: getPixelLuminosity
        });
        render();
    }

    function getPixelLuminosity(x, y) {
        if(!data_size) {
            return 0;
        }
        var ofs = y * data_size.width + x;
        return pixels[ofs];
    }

    function render(valid_result) {
        if(!pixels || w == 0 || !data_size) {
            return;
        }

        if(display) {
            context2d.imageSmoothingEnabled = false;
            //context2d.mozImageSmoothingEnabled = false;

            var w = canvas[0].width = Math.floor(parent.width());
            var h = canvas[0].height = Math.floor(parent.height() * 0.5 - 10);
            if(w == 0) {
                return;
            }
            var scale = Math.min(Math.floor(w / data_size.width), Math.floor(h / data_size.height));
            var ofs_left = Math.floor(0.5 * (w - data_size.width * scale));
            context2d.clearRect(0, 0, w, h);

            var i=0;
            for(var y=0; y<data_size.height; y++) {
                for(var x=0; x<data_size.width; x++) {
                    if(pixels[i] != 255) {
                        context2d.fillStyle = 'rgb(' + pixels[i] + ',' + pixels[i] + ',' + pixels[i] + ')';
                        context2d.fillRect(
                            ofs_left + x * scale,
                            y * scale,
                            scale,
                            scale
                        );
                    }
                    i++;
                }
            }

            grid.render(ofs_left, scale, data_size.width, data_size.height);
            cursor.render(ofs_left, scale);
            tooltip.setBounds(ofs_left, scale, data_size.width, data_size.height);
        }

        if(valid_result && 'data' in valid_result) {
            var i=0;
            var threshold = valid_result.threshold || 0;
            for(var y=0; y<data_size.height; y++) {
                for(var x=0; x<data_size.width; x++) {
                    if(Math.abs(pixels[i] - valid_result.data[y][x]) > threshold) {
                        if(display) {
                            context2d.beginPath();
                            context2d.strokeStyle = '#F00';
                            context2d.lineWidth = scale > 20 ? 2 : 1;
                            context2d.rect(
                                ofs_left + x * scale,
                                y * scale,
                                scale,
                                scale
                            );
                            context2d.stroke();
                        }

                        var msg = params.strings.messages.mistake_pixel;
                        msg = msg.replace('%1', pixels[i]).replace('%2', valid_result.data[y][x]);
                        return {
                            success: false,
                            message: msg
                        }
                    }
                    i++;
                }
            }
            return {
                success: true,
                message: params.strings.messages.success
            }
        }
    }

    return {

        init: init,

        setPixelLuminosity: function(x, y, v) {
            cursor && cursor.set(x, y);
            var v = Math.max(0, Math.min(v, 255));
            pixels[y * data_size.width + x] = v;
            render();
        },

        setSize: function(new_data_size) {
            data_size = new_data_size;
            pixels = new Array(data_size.width * data_size.height).fill(255)
            render();
        },

        clear: function() {
            cursor && cursor.reset();
            data_size = null;
            pixels = [];
            context2d && context2d.clearRect(0, 0, canvas[0].width, canvas[0].height);
        },

        render: render,

        diff: function(valid_result) {
            return render(valid_result);
        }
    }
}

function StringDisplay(params) {

    var data = '';
    var diff = '';
    var element;
    var wrapper;
    var display;

    function init(parent, new_display) {
        display = new_display;
        data = '';
        if(!display) {
            return;
        }
        element = $('')
        wrapper = $('
' + params.strings.messages.result + '
');
        wrapper.append(element).hide();
        parent.append(wrapper);
    }

    function isEmpty() {
        return data == '';
    }

    function render(html) {
        if(!display) {
            return;
        }
        wrapper.toggle(data != '');
        element.html(html);
    }

    return {

        init: init,

        setData: function(str) {
            str = '' + str;
            data = str;
            render(str);
        },

        diff: function(valid_result) {
            diff = '';
            var valid = true;

            var l = Math.max(valid_result.data.length, data.length);
            for(var i=0; i<l; i++) {
                if(valid_result.data[i] !== data[i]) {
                    valid = false;
                    if(i < data.length) {
                        diff += '' + data[i] + '';
                    }
                } else {
                    diff += data[i];
                }
            }
            render(diff);
            return {
                success: valid,
                message: valid ? params.strings.messages.success : params.strings.messages.mistake_digit
            }
        }
    }

}<|endoftext|>


<commit_before>import '~/assets/stylesheets/App.scss';
import React, { Component } from 'react';
import MinmaxInput from './MinmaxInput';
import MinmaxOutput from './MinmaxOutput';
import MinmaxHeader from './MinmaxHeader';
import Options from '../Options';

export default class Minmax extends Component {
  constructor() {
    super();

    const options = JSON.parse(localStorage.getItem('options')) || {};

    this.state = {
      name: '',
      level: 0,
      wild: false,
      options,
    };

    this.onNameChange = this.onNameChange.bind(this);
    this.onLevelChange = this.onLevelChange.bind(this);
    this.onWildChange = this.onWildChange.bind(this);
    this.onOptionChange = this.onOptionChange.bind(this);
  }

  componentDidMount() {
    document.title = 'iv.minmax';
  }

  onNameChange(name) {
    this.setState({
      name,
    });
  }

  onLevelChange(level) {
    this.setState({
      level,
    });
  }

  onOptionChange(options) {
    this.setState({
      options,
    });
  }

  onWildChange(wild) {
    this.setState({
      wild,
    });
  }

  render() {
    return (

          <MinmaxHeader onOptionChangeCB={this.onOptionChange} />

          <MinmaxInput onNameChangeCB={this.onNameChange} onLevelChangeCB={this.onLevelChange}
            onWildChangeCB={this.onWildChange} />

          <MinmaxOutput {...this.state} />

		);
  }
}
<commit_msg>remove options from minmax main component<commit_after>import '~/assets/stylesheets/App.scss';
import React, { Component } from 'react';
import MinmaxInput from './MinmaxInput';
import MinmaxOutput from './MinmaxOutput';
import MinmaxHeader from './MinmaxHeader';

export default class Minmax extends Component {
  constructor() {
    super();

    const options = JSON.parse(localStorage.getItem('options')) || {};

    this.state = {
      name: '',
      level: 0,
      wild: false,
      options,
    };

    this.onNameChange = this.onNameChange.bind(this);
    this.onLevelChange = this.onLevelChange.bind(this);
    this.onWildChange = this.onWildChange.bind(this);
    this.onOptionChange = this.onOptionChange.bind(this);
  }

  componentDidMount() {
    document.title = 'iv.minmax';
  }

  onNameChange(name) {
    this.setState({
      name,
    });
  }

  onLevelChange(level) {
    this.setState({
      level,
    });
  }

  onOptionChange(options) {
    this.setState({
      options,
    });
  }

  onWildChange(wild) {
    this.setState({
      wild,
    });
  }

  render() {
    return (

          <MinmaxHeader onOptionChangeCB={this.onOptionChange} />

          <MinmaxInput onNameChangeCB={this.onNameChange} onLevelChangeCB={this.onLevelChange}
            onWildChangeCB={this.onWildChange} />

          <MinmaxOutput {...this.state} />

		);
  }
}
<|endoftext|>


<commit_before>"use strict";
let QueuePool = require("../../lib/util/QueuePool");
let promiseutil = require("../../lib/promiseutil");
let test = require("../util/test");

let nextTick = function() {
    return new Promise((resolve, reject) => {
        process.nextTick(() => {
            resolve();
        });
    });
}

describe("QueuePool", function() {
    const size = 3;
    let pool;
    let procFn;
    let itemToDeferMap;

    let resolveItem = function(id, resolveWith) {
        if (!itemToDeferMap[id]) {
            return;
        }
        itemToDeferMap[id].resolve(resolveWith);
        delete itemToDeferMap[id];
    }

    beforeEach(function() {
        procFn = jasmine.createSpy("procFn");
        pool = new QueuePool(size, procFn);
        itemToDeferMap = {
            // $item: Deferred
        };
        procFn.and.callFake((item) => {
            itemToDeferMap[item] = new promiseutil.defer();
            return itemToDeferMap[item].promise;
        });
    });

    it("should let multiple items be processed at once",
    test.coroutine(function*() {
        pool.enqueue("a", "a");
        pool.enqueue("b", "b");
        // procFn is called on the next tick so check they've been called after
        yield nextTick();
        expect(Object.keys(itemToDeferMap).length).toBe(2);
    }));

    it("should resolve enqueued items when they resolve",
    test.coroutine(function*() {
        pool.enqueue("a", "a");
        let promise = pool.enqueue("b", "b");
        yield nextTick();
        resolveItem("b", "stuff");
        let res = yield promise;
        expect(res).toEqual("stuff");
    }));

    it("should not let more items than the pool size be processed at once",
    test.coroutine(function*() {
        pool.enqueue("a", "a");
        pool.enqueue("b", "b");
        pool.enqueue("c", "c");
        pool.enqueue("d", "d");
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["a", "b", "c"]);
        resolveItem("b");
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["a", "c", "d"]);
    }));

    it("should wait until a queue is free", test.coroutine(function*() {
        pool.enqueue("a", "a");
        pool.enqueue("b", "b");
        pool.enqueue("c", "c");
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["a", "b", "c"]);
        yield nextTick();
        yield nextTick();
        pool.enqueue("d", "d");
        // wait a while
        yield nextTick();
        yield nextTick();
        yield nextTick();
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["a", "b", "c"]);
        resolveItem("c");
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["a", "b", "d"]);
    }));

    it("should process overflows FIFO", test.coroutine(function*() {
        pool.enqueue("a", "a");
        pool.enqueue("b", "b");
        pool.enqueue("c", "c");
        pool.enqueue("d", "d");
        pool.enqueue("e", "e");
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["a", "b", "c"]);
        resolveItem("b");
        pool.enqueue("f", "f");
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["a", "c", "d"]);
        resolveItem("a");
        resolveItem("c");
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["d", "e", "f"]);
    }));

    it("should repopulate empty queues", test.coroutine(function*() {
        pool.enqueue("a", "a");
        pool.enqueue("b", "b");
        pool.enqueue("c", "c");
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["a", "b", "c"]);
        resolveItem("a");
        resolveItem("b");
        resolveItem("c");
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual([]);
        pool.enqueue("d", "d");
        pool.enqueue("e", "e");
        pool.enqueue("f", "f");
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["d", "e", "f"]);
    }));

    it("should allow index-based queue manipulation", test.coroutine(function*() {
        pool.enqueue("a", "a", 0);
        pool.enqueue("b", "b", 0);
        pool.enqueue("c", "c", 0);
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["a"]);
        resolveItem("a");
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["b"]);
    }));
});
<commit_msg>Add test for waitingItems<commit_after>"use strict";
let QueuePool = require("../../lib/util/QueuePool");
let promiseutil = require("../../lib/promiseutil");
let test = require("../util/test");

let nextTick = function() {
    return new Promise((resolve, reject) => {
        process.nextTick(() => {
            resolve();
        });
    });
}

describe("QueuePool", function() {
    const size = 3;
    let pool;
    let procFn;
    let itemToDeferMap;

    let resolveItem = function(id, resolveWith) {
        if (!itemToDeferMap[id]) {
            return;
        }
        itemToDeferMap[id].resolve(resolveWith);
        delete itemToDeferMap[id];
    }

    beforeEach(function() {
        procFn = jasmine.createSpy("procFn");
        pool = new QueuePool(size, procFn);
        itemToDeferMap = {
            // $item: Deferred
        };
        procFn.and.callFake((item) => {
            itemToDeferMap[item] = new promiseutil.defer();
            return itemToDeferMap[item].promise;
        });
    });

    it("should let multiple items be processed at once",
    test.coroutine(function*() {
        pool.enqueue("a", "a");
        pool.enqueue("b", "b");
        // procFn is called on the next tick so check they've been called after
        yield nextTick();
        expect(Object.keys(itemToDeferMap).length).toBe(2);
    }));

    it("should resolve enqueued items when they resolve",
    test.coroutine(function*() {
        pool.enqueue("a", "a");
        let promise = pool.enqueue("b", "b");
        yield nextTick();
        resolveItem("b", "stuff");
        let res = yield promise;
        expect(res).toEqual("stuff");
    }));

    it("should not let more items than the pool size be processed at once",
    test.coroutine(function*() {
        pool.enqueue("a", "a");
        pool.enqueue("b", "b");
        pool.enqueue("c", "c");
        pool.enqueue("d", "d");
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["a", "b", "c"]);
        resolveItem("b");
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["a", "c", "d"]);
    }));

    it("should wait until a queue is free", test.coroutine(function*() {
        pool.enqueue("a", "a");
        pool.enqueue("b", "b");
        pool.enqueue("c", "c");
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["a", "b", "c"]);
        yield nextTick();
        yield nextTick();
        pool.enqueue("d", "d");
        // wait a while
        yield nextTick();
        yield nextTick();
        yield nextTick();
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["a", "b", "c"]);
        resolveItem("c");
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["a", "b", "d"]);
    }));

    it("should process overflows FIFO", test.coroutine(function*() {
        pool.enqueue("a", "a");
        pool.enqueue("b", "b");
        pool.enqueue("c", "c");
        pool.enqueue("d", "d");
        pool.enqueue("e", "e");
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["a", "b", "c"]);
        resolveItem("b");
        pool.enqueue("f", "f");
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["a", "c", "d"]);
        resolveItem("a");
        resolveItem("c");
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["d", "e", "f"]);
    }));

    it("should repopulate empty queues", test.coroutine(function*() {
        pool.enqueue("a", "a");
        pool.enqueue("b", "b");
        pool.enqueue("c", "c");
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["a", "b", "c"]);
        resolveItem("a");
        resolveItem("b");
        resolveItem("c");
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual([]);
        pool.enqueue("d", "d");
        pool.enqueue("e", "e");
        pool.enqueue("f", "f");
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["d", "e", "f"]);
    }));

    it("should allow index-based queue manipulation", test.coroutine(function*() {
        pool.enqueue("a", "a", 0);
        pool.enqueue("b", "b", 0);
        pool.enqueue("c", "c", 0);
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["a"]);
        resolveItem("a");
        yield nextTick();
        expect(Object.keys(itemToDeferMap).sort()).toEqual(["b"]);
    }));

    it("should accurately track waiting items", test.coroutine(function*() {
        for (let i = 0;i<10;i++) {
            pool.enqueue(i, i);
        }
        expect(pool.waitingItems).toEqual(7);
        for (let j = 0; j < 10; j++) {
            yield nextTick();
            resolveItem(j);
        }
        expect(pool.waitingItems).toEqual(0);
    }));
});
<|endoftext|>


<commit_before>
// Reference to the root of the Firebase database
var database = new Firebase("https://conquiz.firebaseio.com/");
// Reference to the google sheets of questions
var questionsLink = 'https://spreadsheets.google.com/feeds/list/1C1POJrIlpm1R3muE0ImmI_ifxpH_aEfPP-QSyl3o2Kg/1/public/basic?alt=json';
var question;
var questionJSON;
var rows;

$("#upload").click(function() { // If the user clicks on the input with the id="upload"
	var name = $("#nameInput").val();
	var text = $("#messageInput").val();
	if (name.length != 0 && text.length != 0) { // Don't upload if there's no information in the textboxes
		console.log(name.length);
		console.log(text.length);

		database.push({name: name, text: text}); // Push the data onto the database

	}else { // warns user of their empty textbox
		console.log("Please input values into the textbox");
	}
});

function loadQuestions(){
    var newQuestion;
    database.on('child_added', function(update) {
        var questionJSON = update.val();
        console.log(questionJSON)
        newQuestion = new Question({
            id: generateNewID('question'),
            question: questionJSON['question'],
            answers: "["+questionJSON['correct']+", "+questionJSON['wa1']+", "+questionJSON['wa2']+", "+questionJSON['wa3']+"]"
        });
        game.push("questions", newQuestion);
    });
}

// Get an update once the database has new data
// database.on('child_added', function(update) {
// 	questions = update.val();

// 	console.log("Successfully retrieve questions from database.");
// });

// database.on("child_added", function(update) { // Get an update once the database has new data
// 			console.log("Callback function: New data has been added to the database");
// 			var message = update.val();
// 			displayUpdate(message.name, message.text);
// });

function displayUpdate(name, text) {
	$("<div/>").text(text).prepend($("<em/>").text(name+": ")).appendTo($("#messageDiv"));
	$("#messageDiv")[0].scrollTop = $("#messageDiv")[0].scrollHeight;
};

// One time push to update the questions on firebase
function getData() {
    $.ajax({
        url: questionsLink,
        success: function(data){
            uploadFirebase(data);
        }
    });
}
// upload data to firebase
function uploadFirebase(data){
    var cells = data.feed.entry;
    rows = [];

    for (var i = 0; i < cells.length; i++){
        var rowObj = {};
        rowObj.timestamp = cells[i].title.$t;
        var rowCols = cells[i].content.$t.split(',');
        for (var j = 0; j < rowCols.length; j++){
            var keyVal = rowCols[j].split(':');
            rowObj[keyVal[0].trim()] = keyVal[1].trim();
        }
        rows.push(rowObj);
    }
    for (var i = 0; i < rows.length; i++) {
    	database.push({question: rows[i]['timestamp'], correct: rows[i]['correct'], wa1: rows[i]['wa1'], wa2: rows[i]['wa2'], wa3: rows[i]['wa3']});
    }
}

console.log('LOADED BACKEND');<commit_msg>Formatted the code, added comment/sections<commit_after>
// Reference to the root of the Firebase database
var database = new Firebase("https://conquiz.firebaseio.com/");
// Reference to the google sheets of questions
var questionsLink = 'https://spreadsheets.google.com/feeds/list/1C1POJrIlpm1R3muE0ImmI_ifxpH_aEfPP-QSyl3o2Kg/1/public/basic?alt=json';

var question;
var questionJSON;
var rows;

/*--------------------------------------------*/
/*---> Download from Firebase <---------------*/
/*--------------------------------------------*/
// A function that can be call to get updates from firebase
function loadQuestions(){
    var newQuestion;
    database.on('child_added', function(update) {
        var questionJSON = update.val();
        console.log(questionJSON)
        newQuestion = new Question({
            id: generateNewID('question'),
            question: questionJSON['question'],
            answers: "["+questionJSON['correct']+", "+questionJSON['wa1']+", "+questionJSON['wa2']+", "+questionJSON['wa3']+"]"
        });
        game.push("questions", newQuestion);
    });
}

/*--------------------------------------------*/
/*---> Upload to Firebase <-------------------*/
/*--------------------------------------------*/

// ONE TIME push to update the questions on firebase
function getData() {
    $.ajax({
        url: questionsLink,
        success: function(data){
            uploadFirebase(data);
        }
    });
}
// upload data to firebase
function uploadFirebase(data){
    var cells = data.feed.entry;
    rows = [];

    for (var i = 0; i < cells.length; i++){
        var rowObj = {};
        rowObj.timestamp = cells[i].title.$t;
        var rowCols = cells[i].content.$t.split(',');
        for (var j = 0; j < rowCols.length; j++){
            var keyVal = rowCols[j].split(':');
            rowObj[keyVal[0].trim()] = keyVal[1].trim();
        }
        rows.push(rowObj);
    }
    for (var i = 0; i < rows.length; i++) {
    	database.push({question: rows[i]['timestamp'], correct: rows[i]['correct'], wa1: rows[i]['wa1'], wa2: rows[i]['wa2'], wa3: rows[i]['wa3']});
    }
}

console.log('LOADED BACKEND');

/* Legacy code

$("#upload").click(function() { // If the user clicks on the input with the id="upload"
	var name = $("#nameInput").val();
	var text = $("#messageInput").val();
	if (name.length != 0 && text.length != 0) { // Don't upload if there's no information in the textboxes
		console.log(name.length);
		console.log(text.length);

		database.push({name: name, text: text}); // Push the data onto the database

	}else { // warns user of their empty textbox
		console.log("Please input values into the textbox");
	}
});

function displayUpdate(name, text) {
	$("<div/>").text(text).prepend($("<em/>").text(name+": ")).appendTo($("#messageDiv"));
	$("#messageDiv")[0].scrollTop = $("#messageDiv")[0].scrollHeight;
};

database.on("child_added", function(update) { // Get an update once the database has new data
	console.log("Callback function: New data has been added to the database");
	var message = update.val();
	displayUpdate(message.name, message.text);
});

*/<|endoftext|>


<commit_before>/*global defineSuite*/
defineSuite([
         'Scene/TileMapServiceImageryProvider',
         'Core/jsonp',
         'Core/loadImage',
         'Core/DefaultProxy',
         'Core/Extent',
         'Core/Math',
         'Scene/Imagery',
         'Scene/ImageryLayer',
         'Scene/ImageryProvider',
         'Scene/ImageryState',
         'Scene/WebMercatorTilingScheme',
         'ThirdParty/when'
     ], function(
         TileMapServiceImageryProvider,
         jsonp,
         loadImage,
         DefaultProxy,
         Extent,
         CesiumMath,
         Imagery,
         ImageryLayer,
         ImageryProvider,
         ImageryState,
         WebMercatorTilingScheme,
         when) {
    "use strict";
    /*global jasmine,describe,xdescribe,it,xit,expect,beforeEach,afterEach,beforeAll,afterAll,spyOn,runs,waits,waitsFor*/

    afterEach(function() {
        jsonp.loadAndExecuteScript = jsonp.defaultLoadAndExecuteScript;
        loadImage.createImage = loadImage.defaultCreateImage;
    });

    it('conforms to ImageryProvider interface', function() {
        expect(TileMapServiceImageryProvider).toConformToInterface(ImageryProvider);
    });

    it('requires the url to be specified', function() {
        function createWithoutUrl() {
            return new TileMapServiceImageryProvider({});
        }
        expect(createWithoutUrl).toThrow();
    });

    it('supports a slash at the end of the URL', function() {
        var provider = new TileMapServiceImageryProvider({
            url : 'made/up/tms/server/'
        });

        waitsFor(function() {
            return provider.isReady();
        }, 'imagery provider to become ready');

        runs(function() {
            var calledLoadImage = false;
            loadImage.createImage = function(url, crossOrigin, deferred) {
                var doubleSlashIndex = url.indexOf('//');
                expect(doubleSlashIndex).toBeLessThan(0);

                calledLoadImage = true;
                deferred.resolve();
                return undefined;
            };

            provider.requestImage(0, 0, 0);
            expect(calledLoadImage).toEqual(true);
        });
    });

    it('supports no slash at the endof the URL', function() {
        var provider = new TileMapServiceImageryProvider({
            url : 'made/up/tms/server'
        });

        waitsFor(function() {
            return provider.isReady();
        }, 'imagery provider to become ready');

        runs(function() {
            var calledLoadImage = false;
            loadImage.createImage = function(url, crossOrigin, deferred) {
                var index = url.indexOf('made/up/tms/server/');
                expect(index).toBeGreaterThan(-1);

                calledLoadImage = true;
                deferred.resolve();
                return undefined;
            };

            provider.requestImage(0, 0, 0);
            expect(calledLoadImage).toEqual(true);
        });
    });

    it('requestImage returns a promise for an image and loads it for cross-origin use', function() {
        var provider = new TileMapServiceImageryProvider({
            url : 'made/up/tms/server/'
        });

        expect(provider.getUrl()).toEqual('made/up/tms/server/');

        waitsFor(function() {
            return provider.isReady();
        }, 'imagery provider to become ready');

        var tile000Image;

        runs(function() {
            expect(provider.getTileWidth()).toEqual(256);
            expect(provider.getTileHeight()).toEqual(256);
            expect(provider.getMaximumLevel()).toEqual(18);
            expect(provider.getTilingScheme()).toBeInstanceOf(WebMercatorTilingScheme);
            expect(provider.getExtent()).toEqual(new WebMercatorTilingScheme().getExtent());

            loadImage.createImage = function(url, crossOrigin, deferred) {
                expect(crossOrigin).toEqual(true);

                // Just return any old image.
                return loadImage.defaultCreateImage('Data/Images/Red16x16.png', crossOrigin, deferred);
            };

            when(provider.requestImage(0, 0, 0), function(image) {
                tile000Image = image;
            });
        });

        waitsFor(function() {
            return typeof tile000Image !== 'undefined';
        }, 'requested tile to be loaded');

        runs(function() {
            expect(tile000Image).toBeInstanceOf(Image);
        });
    });

    it('when no credit is supplied, a default one is used', function() {
        var provider = new TileMapServiceImageryProvider({
            url : 'made/up/tms/server'
        });
        expect(provider.getLogo()).not.toBeUndefined();
    });

    it('turns the supplied credit into a logo', function() {
        var providerWithCredit = new TileMapServiceImageryProvider({
            url : 'made/up/gms/server',
            credit : 'Thanks to our awesome made up source of this imagery!'
        });
        expect(providerWithCredit.getLogo()).not.toBeUndefined();
    });

    it('routes requests through a proxy if one is specified', function() {
        var proxy = new DefaultProxy('/proxy/');
        var provider = new TileMapServiceImageryProvider({
            url : 'made/up/tms/server',
            proxy : proxy
        });

        waitsFor(function() {
            return provider.isReady();
        }, 'imagery provider to become ready');

        var tile000Image;

        runs(function() {
            loadImage.createImage = function(url, crossOrigin, deferred) {
                expect(url.indexOf(proxy.getURL('made/up/tms/server'))).toEqual(0);
                expect(crossOrigin).toEqual(true);

                // Just return any old image.
                return loadImage.defaultCreateImage('Data/Images/Red16x16.png', crossOrigin, deferred);
            };

            when(provider.requestImage(0, 0, 0), function(image) {
                tile000Image = image;
            });
        });

        waitsFor(function() {
            return typeof tile000Image !== 'undefined';
        }, 'requested tile to be loaded');

        runs(function() {
            expect(tile000Image).toBeInstanceOf(Image);
        });
    });

    it('extent passed to constructor does not affect tile numbering', function() {
        var extent = new Extent(0.1, 0.2, 0.3, 0.4);
        var provider = new TileMapServiceImageryProvider({
            url : 'made/up/tms/server',
            extent : extent
        });

        waitsFor(function() {
            return provider.isReady();
        }, 'imagery provider to become ready');

        runs(function() {
            expect(provider.getTileWidth()).toEqual(256);
            expect(provider.getTileHeight()).toEqual(256);
            expect(provider.getMaximumLevel()).toEqual(18);
            expect(provider.getTilingScheme()).toBeInstanceOf(WebMercatorTilingScheme);
            expect(provider.getExtent()).toEqual(extent);
            expect(provider.getTileDiscardPolicy()).toBeUndefined();

            var calledLoadImage = false;
            loadImage.createImage = function(url, crossOrigin, deferred) {
                expect(url.indexOf('/0/0/0')).not.toBeLessThan(0);
                calledLoadImage = true;
                deferred.resolve();
                return undefined;
            };

            provider.requestImage(0, 0, 0);
            expect(calledLoadImage).toEqual(true);
        });
    });

    it('uses maximumLevel passed to constructor', function() {
        var provider = new TileMapServiceImageryProvider({
            url : 'made/up/tms/server',
            maximumLevel : 5
        });
        expect(provider.getMaximumLevel()).toEqual(5);
    });

    it('raises error event when image cannot be loaded', function() {
        var provider = new TileMapServiceImageryProvider({
            url : 'made/up/tms/server'
        });

        var layer = new ImageryLayer(provider);

        var tries = 0;
        provider.getErrorEvent().addEventListener(function(error) {
            expect(error.timesRetried).toEqual(tries);
            ++tries;
            if (tries < 3) {
                error.retry = true;
            }
        });

        loadImage.createImage = function(url, crossOrigin, deferred) {
            // Succeed after 2 tries
            if (tries === 2) {
                // valid URL
                return loadImage.defaultCreateImage('Data/Images/Red16x16.png', crossOrigin, deferred);
            }

            // invalid URL
            return loadImage.defaultCreateImage(url, crossOrigin, deferred);
        };

        waitsFor(function() {
            return provider.isReady();
        }, 'imagery provider to become ready');

        var imagery;
        runs(function() {
            imagery = new Imagery(layer, 0, 0, 0);
            imagery.addReference();
            layer._requestImagery(imagery);
        });

        waitsFor(function() {
            return imagery.state === ImageryState.RECEIVED;
        }, 'image to load');

        runs(function() {
            expect(imagery.image).toBeInstanceOf(Image);
            expect(tries).toEqual(2);
            imagery.releaseReference();
        });
    });
});
<commit_msg>Fix test failures in the TMS imagery provider.<commit_after>/*global defineSuite*/
defineSuite([
         'Scene/TileMapServiceImageryProvider',
         'Core/jsonp',
         'Core/loadImage',
         'Core/DefaultProxy',
         'Core/Extent',
         'Core/Math',
         'Scene/Imagery',
         'Scene/ImageryLayer',
         'Scene/ImageryProvider',
         'Scene/ImageryState',
         'Scene/WebMercatorTilingScheme',
         'ThirdParty/when'
     ], function(
         TileMapServiceImageryProvider,
         jsonp,
         loadImage,
         DefaultProxy,
         Extent,
         CesiumMath,
         Imagery,
         ImageryLayer,
         ImageryProvider,
         ImageryState,
         WebMercatorTilingScheme,
         when) {
    "use strict";
    /*global jasmine,describe,xdescribe,it,xit,expect,beforeEach,afterEach,beforeAll,afterAll,spyOn,runs,waits,waitsFor*/

    afterEach(function() {
        jsonp.loadAndExecuteScript = jsonp.defaultLoadAndExecuteScript;
        loadImage.createImage = loadImage.defaultCreateImage;
    });

    it('conforms to ImageryProvider interface', function() {
        expect(TileMapServiceImageryProvider).toConformToInterface(ImageryProvider);
    });

    it('requires the url to be specified', function() {
        function createWithoutUrl() {
            return new TileMapServiceImageryProvider({});
        }
        expect(createWithoutUrl).toThrow();
    });

    it('supports a slash at the end of the URL', function() {
        var provider = new TileMapServiceImageryProvider({
            url : 'made/up/tms/server/'
        });

        waitsFor(function() {
            return provider.isReady();
        }, 'imagery provider to become ready');

        runs(function() {
            var calledLoadImage = false;
            loadImage.createImage = function(url, crossOrigin, deferred) {
                var doubleSlashIndex = url.indexOf('//');
                expect(doubleSlashIndex).toBeLessThan(0);

                calledLoadImage = true;
                deferred.resolve();
                return undefined;
            };

            provider.requestImage(0, 0, 0);
            expect(calledLoadImage).toEqual(true);
        });
    });

    it('supports no slash at the endof the URL', function() {
        var provider = new TileMapServiceImageryProvider({
            url : 'made/up/tms/server'
        });

        waitsFor(function() {
            return provider.isReady();
        }, 'imagery provider to become ready');

        runs(function() {
            var calledLoadImage = false;
            loadImage.createImage = function(url, crossOrigin, deferred) {
                var index = url.indexOf('made/up/tms/server/');
                expect(index).toBeGreaterThan(-1);

                calledLoadImage = true;
                deferred.resolve();
                return undefined;
            };

            provider.requestImage(0, 0, 0);
            expect(calledLoadImage).toEqual(true);
        });
    });

    it('requestImage returns a promise for an image and loads it for cross-origin use', function() {
        var provider = new TileMapServiceImageryProvider({
            url : 'made/up/tms/server/'
        });

        expect(provider.getUrl()).toEqual('made/up/tms/server/');

        waitsFor(function() {
            return provider.isReady();
        }, 'imagery provider to become ready');

        var tile000Image;

        runs(function() {
            expect(provider.getTileWidth()).toEqual(256);
            expect(provider.getTileHeight()).toEqual(256);
            expect(provider.getMaximumLevel()).toEqual(18);
            expect(provider.getTilingScheme()).toBeInstanceOf(WebMercatorTilingScheme);
            expect(provider.getExtent()).toEqual(new WebMercatorTilingScheme().getExtent());

            loadImage.createImage = function(url, crossOrigin, deferred) {
                expect(crossOrigin).toEqual(true);

                // Just return any old image.
                return loadImage.defaultCreateImage('Data/Images/Red16x16.png', crossOrigin, deferred);
            };

            when(provider.requestImage(0, 0, 0), function(image) {
                tile000Image = image;
            });
        });

        waitsFor(function() {
            return typeof tile000Image !== 'undefined';
        }, 'requested tile to be loaded');

        runs(function() {
            expect(tile000Image).toBeInstanceOf(Image);
        });
    });

    it('when no credit is supplied, the provider has no logo', function() {
        var provider = new TileMapServiceImageryProvider({
            url : 'made/up/tms/server'
        });
        expect(provider.getLogo()).toBeUndefined();
    });

    it('turns the supplied credit into a logo', function() {
        var providerWithCredit = new TileMapServiceImageryProvider({
            url : 'made/up/gms/server',
            credit : 'Thanks to our awesome made up source of this imagery!'
        });
        expect(providerWithCredit.getLogo()).not.toBeUndefined();
    });

    it('routes requests through a proxy if one is specified', function() {
        var proxy = new DefaultProxy('/proxy/');
        var provider = new TileMapServiceImageryProvider({
            url : 'made/up/tms/server',
            proxy : proxy
        });

        waitsFor(function() {
            return provider.isReady();
        }, 'imagery provider to become ready');

        var tile000Image;

        runs(function() {
            loadImage.createImage = function(url, crossOrigin, deferred) {
                expect(url.indexOf(proxy.getURL('made/up/tms/server'))).toEqual(0);
                expect(crossOrigin).toEqual(true);

                // Just return any old image.
                return loadImage.defaultCreateImage('Data/Images/Red16x16.png', crossOrigin, deferred);
            };

            when(provider.requestImage(0, 0, 0), function(image) {
                tile000Image = image;
            });
        });

        waitsFor(function() {
            return typeof tile000Image !== 'undefined';
        }, 'requested tile to be loaded');

        runs(function() {
            expect(tile000Image).toBeInstanceOf(Image);
        });
    });

    it('extent passed to constructor does not affect tile numbering', function() {
        var extent = new Extent(0.1, 0.2, 0.3, 0.4);
        var provider = new TileMapServiceImageryProvider({
            url : 'made/up/tms/server',
            extent : extent
        });

        waitsFor(function() {
            return provider.isReady();
        }, 'imagery provider to become ready');

        runs(function() {
            expect(provider.getTileWidth()).toEqual(256);
            expect(provider.getTileHeight()).toEqual(256);
            expect(provider.getMaximumLevel()).toEqual(18);
            expect(provider.getTilingScheme()).toBeInstanceOf(WebMercatorTilingScheme);
            expect(provider.getExtent()).toEqual(extent);
            expect(provider.getTileDiscardPolicy()).toBeUndefined();

            var calledLoadImage = false;
            loadImage.createImage = function(url, crossOrigin, deferred) {
                expect(url.indexOf('/0/0/0')).not.toBeLessThan(0);
                calledLoadImage = true;
                deferred.resolve();
                return undefined;
            };

            provider.requestImage(0, 0, 0);
            expect(calledLoadImage).toEqual(true);
        });
    });

    it('uses maximumLevel passed to constructor', function() {
        var provider = new TileMapServiceImageryProvider({
            url : 'made/up/tms/server',
            maximumLevel : 5
        });

        waitsFor(function() {
            return provider.isReady();
        }, 'imagery provider to become ready');

        runs(function() {
            expect(provider.getMaximumLevel()).toEqual(5);
        });
    });

    it('raises error event when image cannot be loaded', function() {
        var provider = new TileMapServiceImageryProvider({
            url : 'made/up/tms/server'
        });

        var layer = new ImageryLayer(provider);

        var tries = 0;
        provider.getErrorEvent().addEventListener(function(error) {
            expect(error.timesRetried).toEqual(tries);
            ++tries;
            if (tries < 3) {
                error.retry = true;
            }
        });

        loadImage.createImage = function(url, crossOrigin, deferred) {
            // Succeed after 2 tries
            if (tries === 2) {
                // valid URL
                return loadImage.defaultCreateImage('Data/Images/Red16x16.png', crossOrigin, deferred);
            }

            // invalid URL
            return loadImage.defaultCreateImage(url, crossOrigin, deferred);
        };

        waitsFor(function() {
            return provider.isReady();
        }, 'imagery provider to become ready');

        var imagery;
        runs(function() {
            imagery = new Imagery(layer, 0, 0, 0);
            imagery.addReference();
            layer._requestImagery(imagery);
        });

        waitsFor(function() {
            return imagery.state === ImageryState.RECEIVED;
        }, 'image to load');

        runs(function() {
            expect(imagery.image).toBeInstanceOf(Image);
            expect(tries).toEqual(2);
            imagery.releaseReference();
        });
    });
});
<|endoftext|>


<commit_before>module.exports = {
  up: async (knex) => {
    await knex.schema.createTable("emails", table => {
      table.increments()
      table.timestamps()

      table.uuid("uuid")
        .notNullable()
        .unique()
        .defaultTo(knex.raw('uuid_generate_v4()'))

      table.index("uuid")

      table.string("value").notNullable()
      table.unique("value")
    })
  },

  down: async (knex) => {
    await knex.schema.dropTable("emails")
  }
}
<commit_msg>associate emails with users<commit_after>module.exports = {
  up: async (knex) => {
    await knex.schema.createTable("emails", table => {
      table.increments()
      table.timestamps()

      table.uuid("uuid")
        .notNullable()
        .unique()
        .defaultTo(knex.raw('uuid_generate_v4()'))

      table.index("uuid")

      table.string("value").notNullable()
      table.unique("value")

      table.integer("user_id")
        .notNullable()
        .unique()
        .references("users.id")
    })
  },

  down: async (knex) => {
    await knex.schema.dropTable("emails")
  }
}
<|endoftext|>


<commit_before>import { isString } from 'core/util';
import { createEl } from 'core/util/dom';
import Point from 'geo/Point';
import { Geometry, Marker } from 'geometry';
import UIComponent from './UI';

/**
 * @property {Object} options
 * @property {Boolean} [options.autoPan=true]  - set it to false if you don't want the map to do panning animation to fit the opened window.
 * @property {Number}  [options.width=300]     - default width
 * @property {Number}  [options.minHeight=120] - minimun height
 * @property {Boolean} [options.custom=false]  - set it to true if you want a customized infowindow, customized html codes or a HTMLElement is set to content.
 * @property {String}  [options.title=null]    - title of the infowindow.
 * @property {String|HTMLElement}  options.content - content of the infowindow.
 * @memberOf ui.InfoWindow
 * @instance
 */
const options = {
    'autoPan': true,
    'width': 300,
    'minHeight': 120,
    'custom': false,
    'title': null,
    'content': null
};

/**
 * @classdesc
 * Class for info window, a popup on the map to display any useful infomation you wanted.
 * @category ui
 * @extends ui.UIComponent
 * @param {Object} options - options defined in [InfoWindow]{@link InfoWindow#options}
 * @memberOf ui
 */
class InfoWindow extends UIComponent {

    // TODO: obtain class in super
    _getClassName() {
        return 'InfoWindow';
    }

    /**
     * Adds the UI Component to a geometry or a map
     * @param {Geometry|Map} owner - geometry or map to addto.
     * @returns {UIComponent} this
     * @fires UIComponent#add
     */
    addTo(owner) {
        if (owner instanceof Geometry) {
            if (owner.getInfoWindow() && owner.getInfoWindow() !== this) {
                owner.removeInfoWindow();
            }
            owner._infoWindow = this;
        }
        return super.addTo(owner);
    }

    /**
     * Set the content of the infowindow.
     * @param {String|HTMLElement} content - content of the infowindow.
     * return {InfoWindow} this
     * @fires InfoWindow#contentchange
     */
    setContent(content) {
        var old = this.options['content'];
        this.options['content'] = content;
        /**
         * contentchange event.
         *
         * @event InfoWindow#contentchange
         * @type {Object}
         * @property {String} type - contentchange
         * @property {InfoWindow} target - InfoWindow
         * @property {String|HTMLElement} old      - old content
         * @property {String|HTMLElement} new      - new content
         */
        this.fire('contentchange', {
            'old': old,
            'new': content
        });
        if (this.isVisible()) {
            this.show(this._coordinate);
        }
        return this;
    }

    /**
     * Get content of  the infowindow.
     * @return {String|HTMLElement} - content of the infowindow
     */
    getContent() {
        return this.options['content'];
    }

    /**
     * Set the title of the infowindow.
     * @param {String|HTMLElement} title - title of the infowindow.
     * return {InfoWindow} this
     * @fires InfoWindow#titlechange
     */
    setTitle(title) {
        var old = title;
        this.options['title'] = title;
        /**
         * titlechange event.
         *
         * @event InfoWindow#titlechange
         * @type {Object}
         * @property {String} type - titlechange
         * @property {InfoWindow} target - InfoWindow
         * @property {String} old      - old content
         * @property {String} new      - new content
         */
        this.fire('contentchange', {
            'old': old,
            'new': title
        });
        if (this.isVisible()) {
            this.show(this._coordinate);
        }
        return this;
    }

    /**
     * Get title of  the infowindow.
     * @return {String|HTMLElement} - content of the infowindow
     */
    getTitle() {
        return this.options['title'];
    }

    buildOn() {
        var dom;
        if (this.options['custom']) {
            if (isString(this.options['content'])) {
                dom = createEl('div');
                dom.innerHTML = this.options['content'];
                return dom;
            } else {
                return this.options['content'];
            }
        } else {
            dom = createEl('div');
            dom.className = 'maptalks-msgBox';
            dom.style.width = this._getWindowWidth() + 'px';
            var content = '';
            if (this.options['title']) {
                content += '
' + this.options['title'] + '
';
            }
            content += '
' + this.options['content'] + '
';
            dom.innerHTML = content;
            return dom;
        }
    }

    /**
     * Gets InfoWindow's transform origin for animation transform
     * @protected
     * @return {Point} transform origin
     */
    getTransformOrigin() {
        var size = this.getSize();
        var o = new Point(size['width'] / 2, size['height']);
        if (!this.options['custom']) {
            o._add(4, 12);
        }
        return o;
    }

    getOffset() {
        var size = this.getSize();
        var o = new Point(-size['width'] / 2, -size['height']);
        if (!this.options['custom']) {
            o._sub(4, 12);
        }
        if (this.getOwner() instanceof Marker) {
            var markerSize = this.getOwner().getSize();
            if (markerSize) {
                o._add(0, -markerSize['height']);
            }
        }
        return o;
    }

    show(coordinate) {
        if (!this.getMap()) {
            return this;
        }
        if (!this.getMap().options['enableInfoWindow']) {
            return this;
        }
        return super.show(coordinate);
    }

    _getWindowWidth() {
        var defaultWidth = 300;
        var width = this.options['width'];
        if (!width) {
            width = defaultWidth;
        }
        return width;
    }
}

InfoWindow.mergeOptions(options);

export default InfoWindow;
<commit_msg>close infowindow by touchend<commit_after>import { isString } from 'core/util';
import { createEl } from 'core/util/dom';
import Point from 'geo/Point';
import { Geometry, Marker } from 'geometry';
import UIComponent from './UI';

/**
 * @property {Object} options
 * @property {Boolean} [options.autoPan=true]  - set it to false if you don't want the map to do panning animation to fit the opened window.
 * @property {Number}  [options.width=300]     - default width
 * @property {Number}  [options.minHeight=120] - minimun height
 * @property {Boolean} [options.custom=false]  - set it to true if you want a customized infowindow, customized html codes or a HTMLElement is set to content.
 * @property {String}  [options.title=null]    - title of the infowindow.
 * @property {String|HTMLElement}  options.content - content of the infowindow.
 * @memberOf ui.InfoWindow
 * @instance
 */
const options = {
    'autoPan': true,
    'width': 300,
    'minHeight': 120,
    'custom': false,
    'title': null,
    'content': null
};

/**
 * @classdesc
 * Class for info window, a popup on the map to display any useful infomation you wanted.
 * @category ui
 * @extends ui.UIComponent
 * @param {Object} options - options defined in [InfoWindow]{@link InfoWindow#options}
 * @memberOf ui
 */
class InfoWindow extends UIComponent {

    // TODO: obtain class in super
    _getClassName() {
        return 'InfoWindow';
    }

    /**
     * Adds the UI Component to a geometry or a map
     * @param {Geometry|Map} owner - geometry or map to addto.
     * @returns {UIComponent} this
     * @fires UIComponent#add
     */
    addTo(owner) {
        if (owner instanceof Geometry) {
            if (owner.getInfoWindow() && owner.getInfoWindow() !== this) {
                owner.removeInfoWindow();
            }
            owner._infoWindow = this;
        }
        return super.addTo(owner);
    }

    /**
     * Set the content of the infowindow.
     * @param {String|HTMLElement} content - content of the infowindow.
     * return {InfoWindow} this
     * @fires InfoWindow#contentchange
     */
    setContent(content) {
        var old = this.options['content'];
        this.options['content'] = content;
        /**
         * contentchange event.
         *
         * @event InfoWindow#contentchange
         * @type {Object}
         * @property {String} type - contentchange
         * @property {InfoWindow} target - InfoWindow
         * @property {String|HTMLElement} old      - old content
         * @property {String|HTMLElement} new      - new content
         */
        this.fire('contentchange', {
            'old': old,
            'new': content
        });
        if (this.isVisible()) {
            this.show(this._coordinate);
        }
        return this;
    }

    /**
     * Get content of  the infowindow.
     * @return {String|HTMLElement} - content of the infowindow
     */
    getContent() {
        return this.options['content'];
    }

    /**
     * Set the title of the infowindow.
     * @param {String|HTMLElement} title - title of the infowindow.
     * return {InfoWindow} this
     * @fires InfoWindow#titlechange
     */
    setTitle(title) {
        var old = title;
        this.options['title'] = title;
        /**
         * titlechange event.
         *
         * @event InfoWindow#titlechange
         * @type {Object}
         * @property {String} type - titlechange
         * @property {InfoWindow} target - InfoWindow
         * @property {String} old      - old content
         * @property {String} new      - new content
         */
        this.fire('contentchange', {
            'old': old,
            'new': title
        });
        if (this.isVisible()) {
            this.show(this._coordinate);
        }
        return this;
    }

    /**
     * Get title of  the infowindow.
     * @return {String|HTMLElement} - content of the infowindow
     */
    getTitle() {
        return this.options['title'];
    }

    buildOn() {
        var dom;
        if (this.options['custom']) {
            if (isString(this.options['content'])) {
                dom = createEl('div');
                dom.innerHTML = this.options['content'];
                return dom;
            } else {
                return this.options['content'];
            }
        } else {
            dom = createEl('div');
            dom.className = 'maptalks-msgBox';
            dom.style.width = this._getWindowWidth() + 'px';
            var content = '';
            if (this.options['title']) {
                content += '
' + this.options['title'] + '
';
            }
            const onClose = '"this.parentNode.style.display=\'none\';return false;"';
            content += '
' + this.options['content'] + '
';
            dom.innerHTML = content;
            return dom;
        }
    }

    /**
     * Gets InfoWindow's transform origin for animation transform
     * @protected
     * @return {Point} transform origin
     */
    getTransformOrigin() {
        var size = this.getSize();
        var o = new Point(size['width'] / 2, size['height']);
        if (!this.options['custom']) {
            o._add(4, 12);
        }
        return o;
    }

    getOffset() {
        var size = this.getSize();
        var o = new Point(-size['width'] / 2, -size['height']);
        if (!this.options['custom']) {
            o._sub(4, 12);
        }
        if (this.getOwner() instanceof Marker) {
            var markerSize = this.getOwner().getSize();
            if (markerSize) {
                o._add(0, -markerSize['height']);
            }
        }
        return o;
    }

    show(coordinate) {
        if (!this.getMap()) {
            return this;
        }
        if (!this.getMap().options['enableInfoWindow']) {
            return this;
        }
        return super.show(coordinate);
    }

    _getWindowWidth() {
        var defaultWidth = 300;
        var width = this.options['width'];
        if (!width) {
            width = defaultWidth;
        }
        return width;
    }
}

InfoWindow.mergeOptions(options);

export default InfoWindow;
<|endoftext|>


<commit_before>import times from 'lodash/times';
import range from 'lodash/range';
import has from 'lodash/has';

import PropTypes from 'prop-types';

import React, {Component} from 'react';
import Rheostat from 'rheostat';
import cx from 'classnames';

import Pit from './Pit.js';

import autoHideContainerHOC from '../../decorators/autoHideContainer.js';
import headerFooterHOC from '../../decorators/headerFooter.js';

class Slider extends Component {

  static propTypes = {
    refine: PropTypes.func.isRequired,
    min: PropTypes.number.isRequired,
    max: PropTypes.number.isRequired,
    values: PropTypes.arrayOf(PropTypes.number).isRequired,
    pips: PropTypes.oneOfType([
      PropTypes.bool,
      PropTypes.object,
    ]),
    step: PropTypes.number.isRequired,
    tooltips: PropTypes.oneOfType([
      PropTypes.bool,
      PropTypes.shape({format: PropTypes.func.isRequired}),
    ]),
  }

  handleChange = ({values}) => {
    const {refine} = this.props;
    refine(values);
  }

  // creates an array number where to display a pit point on the slider
  computeDefaultPitPoints({min, max}) {
    const totalLength = max - min;
    const steps = 34;
    const stepsLength = totalLength / steps;

    const pitPoints = [min, ...times(steps - 1, step => min + stepsLength * (step + 1)), max]
      // bug with `key={ 0 }` and preact, see https://github.com/developit/preact/issues/642
      .map(pitPoint => pitPoint === 0 ? 0.00001 : pitPoint);

    return pitPoints;
  }

  // creates an array of values where the slider should snap to
  computeSnapPoints({min, max, step}) {
    return [...range(min, max, step), max];
  }

  createHandleComponent = tooltips => props => {
    const value = has(tooltips, 'format')
      ? tooltips.format(props['aria-valuenow'])
      : props['aria-valuenow'];

    return (

        { tooltips
            ?
{value}

            : null }

    );
  }

  render() {
    const {tooltips, step, pips, values, min, max} = this.props;

    const snapPoints = this.computeSnapPoints({min, max, step});
    const pitPoints = pips === true || pips === undefined || pips === false
      ? this.computeDefaultPitPoints({min, max})
      : pips;

    return (
      <Rheostat
        handle={ this.createHandleComponent(tooltips) }
        onChange={ this.handleChange }
        min={ min }
        max={ max }
        pitComponent={ Pit }
        pitPoints={ pitPoints }
        snap={ true }
        snapPoints={ snapPoints }
        values={ values }
        disabled={ min === max }
      />
    );
  }

}

export default autoHideContainerHOC(headerFooterHOC(Slider));
<commit_msg>fix(Slider): restore `slider--handle-lower` && `slider--handle-upper`<commit_after>import times from 'lodash/times';
import range from 'lodash/range';
import has from 'lodash/has';

import PropTypes from 'prop-types';

import React, {Component} from 'react';
import Rheostat from 'rheostat';
import cx from 'classnames';

import Pit from './Pit.js';

import autoHideContainerHOC from '../../decorators/autoHideContainer.js';
import headerFooterHOC from '../../decorators/headerFooter.js';

class Slider extends Component {

  static propTypes = {
    refine: PropTypes.func.isRequired,
    min: PropTypes.number.isRequired,
    max: PropTypes.number.isRequired,
    values: PropTypes.arrayOf(PropTypes.number).isRequired,
    pips: PropTypes.oneOfType([
      PropTypes.bool,
      PropTypes.object,
    ]),
    step: PropTypes.number.isRequired,
    tooltips: PropTypes.oneOfType([
      PropTypes.bool,
      PropTypes.shape({format: PropTypes.func.isRequired}),
    ]),
  }

  handleChange = ({values}) => {
    const {refine} = this.props;
    refine(values);
  }

  // creates an array number where to display a pit point on the slider
  computeDefaultPitPoints({min, max}) {
    const totalLength = max - min;
    const steps = 34;
    const stepsLength = totalLength / steps;

    const pitPoints = [min, ...times(steps - 1, step => min + stepsLength * (step + 1)), max]
      // bug with `key={ 0 }` and preact, see https://github.com/developit/preact/issues/642
      .map(pitPoint => pitPoint === 0 ? 0.00001 : pitPoint);

    return pitPoints;
  }

  // creates an array of values where the slider should snap to
  computeSnapPoints({min, max, step}) {
    return [...range(min, max, step), max];
  }

  createHandleComponent = tooltips => props => {
    const value = has(tooltips, 'format')
      ? tooltips.format(props['aria-valuenow'])
      : props['aria-valuenow'];

    const className = cx('ais-range-slider--handle', props.className, {
      'ais-range-slider--handle-lower': props['data-handle-key'] === 0,
      'ais-range-slider--handle-upper': props['data-handle-key'] === 1,
    });

    return (

        { tooltips
            ?
{value}

            : null }

    );
  }

  render() {
    const {tooltips, step, pips, values, min, max} = this.props;

    const snapPoints = this.computeSnapPoints({min, max, step});
    const pitPoints = pips === true || pips === undefined || pips === false
      ? this.computeDefaultPitPoints({min, max})
      : pips;

    return (
      <Rheostat
        handle={ this.createHandleComponent(tooltips) }
        onChange={ this.handleChange }
        min={ min }
        max={ max }
        pitComponent={ Pit }
        pitPoints={ pitPoints }
        snap={ true }
        snapPoints={ snapPoints }
        values={ values }
        disabled={ min === max }
      />
    );
  }

}

export default autoHideContainerHOC(headerFooterHOC(Slider));
<|endoftext|>


<commit_before>define(function (require, exports, module) {
    "use strict";

    var derive = require("base/derive");
    var assert = require("base/assert");
    var trim = require("base/trim");
    var each = require("base/each");
    var copyProperties = require("base/copyProperties");
    var boost = require("boost/boost");
    var Text = require("boost/Text");
    var TextInput = require("boost/TextInput");
    var EventTarget = require("boost/EventTarget");
    var Event = require("boost/Event");

    function onStateChanged() {
        if (this.readyState == 4) {
            process(this.responseXML);
        }
    }

    function loadFromURL(url) {
        console.log(+new Date, "loadFromURL:" + url);
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = onStateChanged;
        xhr.open("GET", url, true);
        xhr.send(null);
    }

    function loadFromString(str) {
        console.profile("React Profile");
        console.log(+new Date, "loadFromString:...");
        var parser = new DOMParser();
        var xmlDoc = parser.parseFromString(str, "text/xml");
        process(xmlDoc);
        console.profileEnd();
    }

    function process(document) {
        console.log(+new Date, "process", document);
        console.log(performance.timing);
        //processElement(document.documentElement, boost.rootElement);
        walkElement(document.documentElement, boost.documentElement);
        applyStyle();

        var event = new Event(xml, "domready");
        xml.dispatchEvent(event);
        //boost.dispatchEvent();
    }

    function processElement(element, nativeParentElement) {
        var str;
        var nativeElement;
        var attributes;
        var attribute;
        var count;
        var index;
        if (element.nodeType === 3) {
            str = trim(element.nodeValue);
            if (str) {
                assert(nativeParentElement instanceof Text || nativeParentElement instanceof TextInput, "文本只能添加到 <Text> 或者 <TextInput> 节点中");
                nativeParentElement.value += str;
            }
        } else if (element.nodeType === 1) {
            switch (element.tagName.toUpperCase()) {
            case "STYLE":
                parseStyle(element.firstChild.nodeValue);
                break;
            default:
                nativeElement = boost.createElement(element.tagName);
                nativeParentElement.appendChild(nativeElement);
                attributes = element.attributes;
                count = attributes.length;
                for (index = 0; index < count; index++) {
                    attribute = attributes[index];
                    nativeElement.setAttribute(attribute.name, attribute.value);
                }

                walkElement(element, nativeElement);
            }
        }
    }

    function walkElement(element, nativeParentElement) {
        var child;
        var tag;
        for (child = element.firstChild; child !== null; child = child.nextSibling) {
            processElement(child, nativeParentElement);
        }
    }

    function toCamelCase(str) {
        return str.replace(/-+(.)?/g, function (match, chr) {
            return chr ? chr.toUpperCase() : '';
        });
    }

    var parser = null;
    var ruleList = [];

    function parseStyle(str) {
        if (parser === null) {
            parser = new StyleParser();
        }
        parser.parse(str, ruleList);
    }

    function applyStyle() {
        each(ruleList, function (item) {
            var selector = item.selector;
            var elements = boost.querySelectorAll(selector);
            each(elements, function (element) {
                copyProperties(element.style, item.rule);
            });
        });
    }

    var StyleParser = derive(Object, function () {
        var _code = null;
        var _codeChar = null;
        var _index = 0;
        var _count = 0;
    }, {
        parse: function (str, ret) {
            this._code = this.preProcess(str);
            this._codeChar = this._code.split("");
            this._index = 0;
            this._count = this._codeChar.length;
            var selector;
            var rule;

            ret = ret || [];
            while (true) {
                this.ignoreWhiteSpace();
                selector = this.getSelector();
                rule = this.getRule();
                if (selector && rule) {
                    ret.push({
                        selector: selector,
                        rule: rule
                    });
                    continue;
                }
                break;
            }
            return ret;
        },
        preProcess: function (str) {
            return str.replace(/\/\*[\s\S]*?\*\//g, "");
        },
        ignoreWhiteSpace: function () {
            var count = this._count;
            var _codeChar = this._codeChar;
            var code;
            var index;

            for (index = this._index; index < count; index++) {
                code = _codeChar[index];
                if (code !== " " && code !== "\t" && code !== "\r" && code !== "\n") {
                    break;
                }
            }
            this._index = index;
        },
        getSelector: function () {
            var code = this._code;
            var end = code.indexOf("{", this._index);
            var selector;
            if (end < 0) {
                this.end();
                return false;
            }
            selector = code.substring(this._index, end);
            this._index = end;
            return trim(selector);
        },
        getRule: function () {
            var code = this._code;
            var index = this._index;
            var start = code.indexOf("{", index);
            var end;

            if (start < 0) {
                this.end();
                return false;
            }

            end = code.indexOf("}", start);
            if (end < 0) {
                this.end();
                return false;
            }

            this._index = end + 1;
            return this.parseRule(code.substring(start + 1, end));
        },
        parseRule: function (str) {
            var list = str.split(";");
            var count = list.length;
            var index;
            var item;
            var parts;
            var key;
            var ret = {};

            for (index = 0; index < count; index++) {
                item = list[index];
                parts = item.split(":");
                key = toCamelCase(trim(parts[0]));
                ret[key] = trim(parts[1]);
            }
            return ret;
        },
        end: function () {
            this._index = this._count;
        }
    });

    //loadFromURL("test/cart.xml");
    //loadFromString(getXml("cartXml"));
    var xml = new EventTarget();
    xml.loadFromURL = loadFromURL;
    xml.loadFromString = loadFromString;

    module.exports = xml;
});
<commit_msg>添加性能分析打点<commit_after>define(function (require, exports, module) {
    "use strict";

    var derive = require("base/derive");
    var assert = require("base/assert");
    var trim = require("base/trim");
    var each = require("base/each");
    var copyProperties = require("base/copyProperties");
    var boost = require("boost/boost");
    var Text = require("boost/Text");
    var TextInput = require("boost/TextInput");
    var EventTarget = require("boost/EventTarget");
    var Event = require("boost/Event");
    var nativeGlobal = require("boost/NativeObject").global;

    function onStateChanged() {
        if (this.readyState == 4) {
            process(this.responseXML);
        }
    }

    function loadFromURL(url) {
        console.log(+new Date, "loadFromURL:" + url);
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = onStateChanged;
        xhr.open("GET", url, true);
        xhr.send(null);
    }

    function loadFromString(str) {
        //console.profile("React Profile");
        //console.log(+new Date, "loadFromString:...");
        console.time("解析XML");
        var parser = new DOMParser();
        var xmlDoc = parser.parseFromString(str, "text/xml");
        console.timeEnd("解析XML");

        process(xmlDoc);

        //console.profileEnd();
    }

    function process(document) {
        //console.log(+new Date, "process", document);
        //console.log(performance.timing);
        //processElement(document.documentElement, boost.rootElement);
        console.time("构建ViewTree");
        walkElement(document.documentElement, boost.documentElement);
        console.timeEnd("构建ViewTree");

        console.time("应用样式");
        applyStyle();
        console.timeEnd("应用样式");

        var event = new Event(xml, "domready");
        xml.dispatchEvent(event);
        //boost.dispatchEvent();
    }

    function processElement(element, nativeParentElement) {
        var str;
        var nativeElement;
        var attributes;
        var attribute;
        var count;
        var index;
        if (element.nodeType === 3) {
            str = trim(element.nodeValue);
            if (str) {
                assert(nativeParentElement instanceof Text || nativeParentElement instanceof TextInput, "文本只能添加到 <Text> 或者 <TextInput> 节点中");
                nativeParentElement.value += str;
            }
        } else if (element.nodeType === 1) {
            switch (element.tagName.toUpperCase()) {
            case "STYLE":
                console.time("解析样式");
                parseStyle(element.firstChild.nodeValue);
                console.timeEnd("解析样式");
                break;
            case "FLUSH":
                nativeGlobal.flush();
                break;
            default:
                nativeElement = boost.createElement(element.tagName);
                nativeParentElement.appendChild(nativeElement);
                attributes = element.attributes;
                count = attributes.length;
                for (index = 0; index < count; index++) {
                    attribute = attributes[index];
                    nativeElement.setAttribute(attribute.name, attribute.value);
                }

                walkElement(element, nativeElement);
            }
        }
    }

    function walkElement(element, nativeParentElement) {
        var child;
        var tag;
        for (child = element.firstChild; child !== null; child = child.nextSibling) {
            processElement(child, nativeParentElement);
        }
    }

    function toCamelCase(str) {
        return str.replace(/-+(.)?/g, function (match, chr) {
            return chr ? chr.toUpperCase() : '';
        });
    }

    var parser = null;
    var ruleList = [];

    function parseStyle(str) {
        if (parser === null) {
            parser = new StyleParser();
        }
        parser.parse(str, ruleList);
    }

    function applyStyle() {
        each(ruleList, function (item) {
            var selector = item.selector;
            var elements = boost.querySelectorAll(selector);
            each(elements, function (element) {
                copyProperties(element.style, item.rule);
            });
        });
    }

    var StyleParser = derive(Object, function () {
        var _code = null;
        var _codeChar = null;
        var _index = 0;
        var _count = 0;
    }, {
        parse: function (str, ret) {
            this._code = this.preProcess(str);
            this._codeChar = this._code.split("");
            this._index = 0;
            this._count = this._codeChar.length;
            var selector;
            var rule;

            ret = ret || [];
            while (true) {
                this.ignoreWhiteSpace();
                selector = this.getSelector();
                rule = this.getRule();
                if (selector && rule) {
                    ret.push({
                        selector: selector,
                        rule: rule
                    });
                    continue;
                }
                break;
            }
            return ret;
        },
        preProcess: function (str) {
            return str.replace(/\/\*[\s\S]*?\*\//g, "");
        },
        ignoreWhiteSpace: function () {
            var count = this._count;
            var _codeChar = this._codeChar;
            var code;
            var index;

            for (index = this._index; index < count; index++) {
                code = _codeChar[index];
                if (code !== " " && code !== "\t" && code !== "\r" && code !== "\n") {
                    break;
                }
            }
            this._index = index;
        },
        getSelector: function () {
            var code = this._code;
            var end = code.indexOf("{", this._index);
            var selector;
            if (end < 0) {
                this.end();
                return false;
            }
            selector = code.substring(this._index, end);
            this._index = end;
            return trim(selector);
        },
        getRule: function () {
            var code = this._code;
            var index = this._index;
            var start = code.indexOf("{", index);
            var end;

            if (start < 0) {
                this.end();
                return false;
            }

            end = code.indexOf("}", start);
            if (end < 0) {
                this.end();
                return false;
            }

            this._index = end + 1;
            return this.parseRule(code.substring(start + 1, end));
        },
        parseRule: function (str) {
            var list = str.split(";");
            var count = list.length;
            var index;
            var item;
            var parts;
            var key;
            var ret = {};

            for (index = 0; index < count; index++) {
                item = list[index];
                parts = item.split(":");
                key = toCamelCase(trim(parts[0]));
                ret[key] = trim(parts[1]);
            }
            return ret;
        },
        end: function () {
            this._index = this._count;
        }
    });

    //loadFromURL("test/cart.xml");
    //loadFromString(getXml("cartXml"));
    var xml = new EventTarget();
    xml.loadFromURL = loadFromURL;
    xml.loadFromString = loadFromString;

    module.exports = xml;
});
<|endoftext|>