<commit_before>var DataTable = {
    CONTEXT_PATH : '/wine',
    /**
     * 编辑器配置
     * @param moduleId 模块编号
     * @param fields 字段定义
     * @returns {{idSrc: string, ajax: {create: {type: string, contentType: string, url: string, data: ajax.create.data}, edit: {type: string, contentType: string, url: string, data: ajax.edit.data}, remove: {type: string, contentType: string, url: string, data: ajax.remove.data}}, table: string, fields: *, i18n: {create: {button: string, title: string, submit: string}, edit: {button: string, title: string, submit: string}, remove: {button: string, title: string, submit: string, confirm: {_: string, 1: string}}, error: {system: string}, multi: {title: string, info: string, restore: string}, datetime: {previous: string, next: string, months: string[], weekdays: string[]}}}}
     */
    editorConfig : function(moduleId,fields,otherConfig){

        return $.extend({
            idSrc: "id",
            ajax: {
                create: {
                    type: 'POST',
                    contentType: "application/json",
                    url:  DataTable.CONTEXT_PATH+'/api/'+moduleId+'/create',
                    data: function ( d ) {
                        return JSON.stringify( d );
                    }
                },
                edit: {
                    type: 'PUT',
                    contentType: "application/json",
                    url:  DataTable.CONTEXT_PATH+'/api/'+moduleId+'/edit',
                    data: function ( d ) {
                        var id = editor.s.idSrc;
                        var data = d.data;
                        for(var k in data){
                            data[k][id] = k;
                        }
                        return JSON.stringify( d );
                    }
                },
                remove: {
                    type: 'POST',
                    contentType: "application/json",
                    url:  DataTable.CONTEXT_PATH+'/api/'+moduleId+'/remove',
                    data: function ( d ) {
                        var id = editor.s.idSrc;
                        var data = d.data;
                        for(var k in data){
                            data[k][id] = k;
                        }
                        return JSON.stringify( d );
                    }
                }
            },
            table: "#dataTable",
            fields: fields,
            i18n: {
                create: {
                    button: "新增",
                    title:  "新增条目",
                    submit: "保存"
                },
                edit: {
                    button: "编辑",
                    title:  "编辑条目",
                    submit: "更新"
                },
                remove: {
                    button: "删除",
                    title:  "删除条目",
                    submit: "删除",
                    confirm: {
                        _: "你确定删除这 %d 项吗?",
                        1: "你确定删除这1项吗?"
                    }
                },
                error: {
                    system: "系统出错,请联系管理员"
                },
                multi: {
                    title: "多个值",
                    info: "Les éléments sélectionnés contiennent des valeurs différentes pour cette entrée. Pour modifier et mettre tous les éléments pour cette entrée pour la même valeur, cliquez ou appuyez ici, sinon ils vont conserver leurs valeurs individuelles.",
                    restore: "Annuler les modifications"
                },
                datetime: {
                    previous: 'Précédent',
                    next:     'Premier',
                    months:   [ '一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月' ],
                    weekdays: [ '周一', '周二', '周三', '周四', '周五', '周六', '周日' ]
                }
            }
        },otherConfig)
    },
    /**
     * 列表配置
     * @param moduleId 模块编号
     * @param columnArray 字段定义
     * @param buttonGroup 按钮定义
     * @param otherConfig 其他dataTable配置
     * @returns {*}
     */
    dataTableConfig : function(moduleId,columnArray,buttonGroup,otherConfig){
        //前端一般只配置data,默认情况下data=name,设置name可以让后续table.column('xx:name')方法生效
        for(var k in columnArray){
            var temp = columnArray[k];
            if(temp['data'] && !temp['name']){//data有值 name没值
                temp['name'] = temp['data'];
            }
        }

        return $.extend({
            module:moduleId,
            dom: "Brtlip",
            pageLength:100,
            lengthMenu: [ 10, 25, 50, 75, 100 ,2500],
            language: {
                "sProcessing":   "处理中...",
                "sLengthMenu":   "显示 _MENU_ 项结果",
                "sZeroRecords":  "没有匹配结果",
                "sInfo":         "显示第 _START_ 至 _END_ 项结果，共 _TOTAL_ 项",
                "sInfoEmpty":    "显示第 0 至 0 项结果，共 0 项",
                "sInfoFiltered": "(由 _MAX_ 项结果过滤)",
                "sInfoPostFix":  "",
                "sSearch":       "搜索:",
                "sUrl":          "",
                "sEmptyTable":     "表中数据为空",
                "sLoadingRecords": "载入中...",
                "sInfoThousands":  ",",
                "oPaginate": {
                    "sFirst":    "首页",
                    "sPrevious": "上页",
                    "sNext":     "下页",
                    "sLast":     "末页"
                },
                "oAria": {
                    "sSortAscending":  ": 以升序排列此列",
                    "sSortDescending": ": 以降序排列此列"
                }
            },
            ajax: {
                url: DataTable.CONTEXT_PATH+"/api/"+moduleId+"/list",
                contentType: "application/json",
                cache: false,
                type: "POST",
                data: function ( d ) {
                    if(typeof d == 'undefined')return '';
                    var orderArr = d.order;
                    for(var k in orderArr){
                        if(!isNaN(orderArr[k].column)){
                            orderArr[k].column = columnArray[orderArr[k].column].data;
                        }
                    }
                    //将searchValue初始化到请求参数中
                    for(var k in columnArray){
                        var searchValue = columnArray[k].searchValue;
                        var nullable = columnArray[k].nullable;
                        if(typeof searchValue != 'undefined' && typeof nullable != 'undefined'){
                            //不看searchValue的取值,只要定义即可
                            if(nullable){//后台:where column is null
                                d.columns[k].nullable = true;
                            }else{//后台:where column is not null
                                d.columns[k].nullable = false;
                            }
                            d.columns[k].search.value = searchValue;
                        }else if(typeof searchValue != 'undefined' && typeof nullable == 'undefined'){
                            d.columns[k].search.value = searchValue;
                        }
                    }
                    return JSON.stringify( d );
                }
            },
            processing: true,
            serverSide: true,
            columns: columnArray,
            select: true,
            //scrollX: true,
            buttons: buttonGroup
        },otherConfig)
    },
    reload : function(table){
        table.ajax.reload();
    },
    /**
     * 启用字段搜索功能
     * @param table
     */
    enableColumnSearch : function(table){
        $('#dataTable tfoot th').each( function (i) {
            var $that = $(this);
            var searchType = table.init().columns[i].searchType || 'text';
            var category = table.init().columns[i].ddic || '';

            if(searchType == 'select'){
                var data = Ddic.get(category);
                if(!data || data.length == 0)return true;
                var selectHtml = [];
                selectHtml.push('<select class="selectpicker">');
                selectHtml.push('<option value="">-----全部-----</option>');
                for(var k in data){
                    selectHtml.push('<option value="'+data[k]['itemKey']+'">'+data[k]['itemValue']+'</option>');
                }
                selectHtml.push('</select>');
                $that.html(selectHtml.join('\n'));
                DataTable._bindSearchEvent(table);

            }else{//text & date
                var title = $(this).text();
                $(this).html( '<input type="'+searchType+'" placeholder="搜索 '+title+'" />' );

                DataTable._bindSearchEvent(table);
            }

        } );

        $('tfoot').css('display', 'table-header-group');
    },
    _bindSearchEvent : function(table){
        table.columns().every( function (i) {
            var that = this;
            if(table.init().columns[i] && table.init().columns[i].ddicRef){
                that = table.column(table.init().columns[i].ddicRef+':name');
            }

            $( 'input', this.footer() ).on( 'blur keyup', function (e) {
                if(e.keyCode){
                    if(e.keyCode == 13) that.search( this.value ).draw();
                }else if (that.search() !== this.value ) {
                    that.search( this.value ).draw();
                }
            } );
            $( 'select', this.footer() ).on( 'change', function (e) {
                that.search( this.value ).draw();
            } );
        } );
    },
    search : function(table){
        table.columns().search().draw();
    },
    searchByColumn : function(table,columnName,value){
        var column = table.column(columnName+':name');
        if(column.length < 1){
            console.log('cannot find column named "'+columnName+'",please add column name in dataTableConfig');
            return ;
        }
        var index = column.index();
        $('#dataTable tfoot th').eq(index).find('input').val(value);
        column.search(value).draw();
    },
    Editor : {
        readonly : function(fieldId){
            $('#DTE_Field_'+fieldId).attr('readonly',true);
        },
        showMsgOnError : function(editor){
            editor.on( 'submitError', function ( event, response, type, message, data) {
                editor.error(response.responseJSON.message);
            } );
        },
        newInstance : function(moduleName,fields,otherConfig){
            var editor = new $.fn.dataTable.Editor( DataTable.editorConfig(moduleName,fields,otherConfig));
            DataTable.Editor.showMsgOnError(editor);
            return editor;
        }
    }
}

var Ddic = {
    get : function (name) {
        var allDdicStr = localStorage.getItem('ddic');
        var data = JSON.parse(allDdicStr);
        if(!name){
            return data;
        }
        return data[name];
    },
    /**
     * 生成dataTable识别的select组件数据源
     * @param name
     * @returns {Array}
     */
    show : function (name) {
        var objList = this.get(name);
        if(!objList || objList.length == 0)return;
        var result = new Array();
        result.push({label:'-----请选择-----',value:''});
        for(var k in objList){
            var temp = new Object();
            temp.label = objList[k].itemValue;
            temp.value = objList[k].itemKey;
            result.push(temp);
        }
        return result;
    },
    init : function () {
        $.post(DataTable.CONTEXT_PATH+"/api/all/ddic?r="+new Date().getTime(),
            function(result){
                if(!result.success){
                    return;
                }
                var data = result.data;
                localStorage.setItem('ddic',JSON.stringify(data));
            },'json');
    }
}

/**
 * 后台返回List<Select>，该方法用于产生dataTable识别的组件元素（select radio checkbox）
 * @type {{init: Select.init}}
 */
var Select = {
    init : function(path){
        var jsonStr = $.ajax({
            url: DataTable.CONTEXT_PATH + path,
            async: false,
            timeout:3000
        }).responseText;
        if(jsonStr){
            var jsonObj = $.parseJSON(jsonStr);
            if(jsonObj.success){
                return jsonObj.data;
            }
        }
        return false;
    }
};

var Invoker = {
    post : function (path,paramObj) {
        var jsonStr = $.ajax({
            url: DataTable.CONTEXT_PATH + path,
            async: false,
            contentType: 'application/json',
            type: 'POST',
            data: JSON.stringify(paramObj),
            timeout:3000
        }).responseText;
        if(jsonStr){
            return $.parseJSON(jsonStr);
        }
        return false;
    },
    get : function (path) {
        var jsonStr = $.ajax({
            url: DataTable.CONTEXT_PATH + path,
            async: false,
            type: 'GET',
            timeout:3000
        }).responseText;
        if(jsonStr){
            return $.parseJSON(jsonStr);
        }
        return false;
    }
};<commit_msg>pagination bug fix<commit_after>var DataTable = {
    CONTEXT_PATH : '/wine',
    /**
     * 编辑器配置
     * @param moduleId 模块编号
     * @param fields 字段定义
     * @returns {{idSrc: string, ajax: {create: {type: string, contentType: string, url: string, data: ajax.create.data}, edit: {type: string, contentType: string, url: string, data: ajax.edit.data}, remove: {type: string, contentType: string, url: string, data: ajax.remove.data}}, table: string, fields: *, i18n: {create: {button: string, title: string, submit: string}, edit: {button: string, title: string, submit: string}, remove: {button: string, title: string, submit: string, confirm: {_: string, 1: string}}, error: {system: string}, multi: {title: string, info: string, restore: string}, datetime: {previous: string, next: string, months: string[], weekdays: string[]}}}}
     */
    editorConfig : function(moduleId,fields,otherConfig){

        return $.extend({
            idSrc: "id",
            ajax: {
                create: {
                    type: 'POST',
                    contentType: "application/json",
                    url:  DataTable.CONTEXT_PATH+'/api/'+moduleId+'/create',
                    data: function ( d ) {
                        return JSON.stringify( d );
                    }
                },
                edit: {
                    type: 'PUT',
                    contentType: "application/json",
                    url:  DataTable.CONTEXT_PATH+'/api/'+moduleId+'/edit',
                    data: function ( d ) {
                        var id = editor.s.idSrc;
                        var data = d.data;
                        for(var k in data){
                            data[k][id] = k;
                        }
                        return JSON.stringify( d );
                    }
                },
                remove: {
                    type: 'POST',
                    contentType: "application/json",
                    url:  DataTable.CONTEXT_PATH+'/api/'+moduleId+'/remove',
                    data: function ( d ) {
                        var id = editor.s.idSrc;
                        var data = d.data;
                        for(var k in data){
                            data[k][id] = k;
                        }
                        return JSON.stringify( d );
                    }
                }
            },
            table: "#dataTable",
            fields: fields,
            i18n: {
                create: {
                    button: "新增",
                    title:  "新增条目",
                    submit: "保存"
                },
                edit: {
                    button: "编辑",
                    title:  "编辑条目",
                    submit: "更新"
                },
                remove: {
                    button: "删除",
                    title:  "删除条目",
                    submit: "删除",
                    confirm: {
                        _: "你确定删除这 %d 项吗?",
                        1: "你确定删除这1项吗?"
                    }
                },
                error: {
                    system: "系统出错,请联系管理员"
                },
                multi: {
                    title: "多个值",
                    info: "Les éléments sélectionnés contiennent des valeurs différentes pour cette entrée. Pour modifier et mettre tous les éléments pour cette entrée pour la même valeur, cliquez ou appuyez ici, sinon ils vont conserver leurs valeurs individuelles.",
                    restore: "Annuler les modifications"
                },
                datetime: {
                    previous: 'Précédent',
                    next:     'Premier',
                    months:   [ '一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月' ],
                    weekdays: [ '周一', '周二', '周三', '周四', '周五', '周六', '周日' ]
                }
            }
        },otherConfig)
    },
    /**
     * 列表配置
     * @param moduleId 模块编号
     * @param columnArray 字段定义
     * @param buttonGroup 按钮定义
     * @param otherConfig 其他dataTable配置
     * @returns {*}
     */
    dataTableConfig : function(moduleId,columnArray,buttonGroup,otherConfig){
        //前端一般只配置data,默认情况下data=name,设置name可以让后续table.column('xx:name')方法生效
        for(var k in columnArray){
            var temp = columnArray[k];
            if(temp['data'] && !temp['name']){//data有值 name没值
                temp['name'] = temp['data'];
            }
        }

        return $.extend({
            module:moduleId,
            dom: "Brtlip",
            pageLength:100,
            lengthMenu: [ 10, 25, 50, 75, 100 ,2500],
            language: {
                "sProcessing":   "处理中...",
                "sLengthMenu":   "显示 _MENU_ 项结果",
                "sZeroRecords":  "没有匹配结果",
                "sInfo":         "显示第 _START_ 至 _END_ 项结果，共 _TOTAL_ 项",
                "sInfoEmpty":    "显示第 0 至 0 项结果，共 0 项",
                "sInfoFiltered": "(由 _MAX_ 项结果过滤)",
                "sInfoPostFix":  "",
                "sSearch":       "搜索:",
                "sUrl":          "",
                "sEmptyTable":     "表中数据为空",
                "sLoadingRecords": "载入中...",
                "sInfoThousands":  ",",
                "oPaginate": {
                    "sFirst":    "首页",
                    "sPrevious": "上页",
                    "sNext":     "下页",
                    "sLast":     "末页"
                },
                "oAria": {
                    "sSortAscending":  ": 以升序排列此列",
                    "sSortDescending": ": 以降序排列此列"
                }
            },
            ajax: {
                url: DataTable.CONTEXT_PATH+"/api/"+moduleId+"/list",
                contentType: "application/json",
                cache: false,
                type: "POST",
                data: function ( d ) {
                    if(typeof d == 'undefined')return '';
                    var orderArr = d.order;
                    for(var k in orderArr){
                        if(!isNaN(orderArr[k].column)){
                            orderArr[k].column = columnArray[orderArr[k].column].data;
                        }
                    }
                    //将searchValue初始化到请求参数中
                    for(var k in columnArray){
                        var searchValue = columnArray[k].searchValue;
                        var nullable = columnArray[k].nullable;
                        if(typeof searchValue != 'undefined' && typeof nullable != 'undefined'){
                            //不看searchValue的取值,只要定义即可
                            if(nullable){//后台:where column is null
                                d.columns[k].nullable = true;
                            }else{//后台:where column is not null
                                d.columns[k].nullable = false;
                            }
                            d.columns[k].search.value = searchValue;
                        }else if(typeof searchValue != 'undefined' && typeof nullable == 'undefined'){
                            d.columns[k].search.value = searchValue;
                        }
                    }
                    return JSON.stringify( d );
                }
            },
            processing: true,
            serverSide: true,
            columns: columnArray,
            select: true,
            //scrollX: true,
            buttons: buttonGroup
        },otherConfig)
    },
    reload : function(table){
        table.ajax.reload();
    },
    /**
     * 启用字段搜索功能
     * @param table
     */
    enableColumnSearch : function(table){
        $('#dataTable tfoot th').each( function (i) {
            var $that = $(this);
            var searchType = table.init().columns[i].searchType || 'text';
            var category = table.init().columns[i].ddic || '';

            if(searchType == 'select'){
                var data = Ddic.get(category);
                if(!data || data.length == 0)return true;
                var selectHtml = [];
                selectHtml.push('<select class="selectpicker">');
                selectHtml.push('<option value="">-----全部-----</option>');
                for(var k in data){
                    selectHtml.push('<option value="'+data[k]['itemKey']+'">'+data[k]['itemValue']+'</option>');
                }
                selectHtml.push('</select>');
                $that.html(selectHtml.join('\n'));

            }else{//text & date
                var title = $(this).text();
                $(this).html( '<input type="'+searchType+'" placeholder="搜索 '+title+'" />' );

            }

        } );
        DataTable._bindSearchEvent(table);

        $('tfoot').css('display', 'table-header-group');
    },
    _bindSearchEvent : function(table){
        table.columns().every( function (i) {
            var that = this;
            if(table.init().columns[i] && table.init().columns[i].ddicRef){
                that = table.column(table.init().columns[i].ddicRef+':name');
            }

            $( 'input', this.footer() ).on( 'blur keyup', function (e) {
                if(e.keyCode){
                    if(e.keyCode == 13) that.search( this.value ).draw();
                }else if (that.search() !== this.value ) {
                    that.search( this.value ).draw();
                }
            } );
            $( 'select.selectpicker', this.footer() ).on( 'change', function (e) {
                that.search( this.value ).draw();
            } );
        } );
    },
    search : function(table){
        table.columns().search().draw();
    },
    searchByColumn : function(table,columnName,value){
        var column = table.column(columnName+':name');
        if(column.length < 1){
            console.log('cannot find column named "'+columnName+'",please add column name in dataTableConfig');
            return ;
        }
        var index = column.index();
        $('#dataTable tfoot th').eq(index).find('input').val(value);
        column.search(value).draw();
    },
    Editor : {
        readonly : function(fieldId){
            $('#DTE_Field_'+fieldId).attr('readonly',true);
        },
        showMsgOnError : function(editor){
            editor.on( 'submitError', function ( event, response, type, message, data) {
                editor.error(response.responseJSON.message);
            } );
        },
        newInstance : function(moduleName,fields,otherConfig){
            var editor = new $.fn.dataTable.Editor( DataTable.editorConfig(moduleName,fields,otherConfig));
            DataTable.Editor.showMsgOnError(editor);
            return editor;
        }
    }
}

var Ddic = {
    get : function (name) {
        var allDdicStr = localStorage.getItem('ddic');
        var data = JSON.parse(allDdicStr);
        if(!name){
            return data;
        }
        return data[name];
    },
    /**
     * 生成dataTable识别的select组件数据源
     * @param name
     * @returns {Array}
     */
    show : function (name) {
        var objList = this.get(name);
        if(!objList || objList.length == 0)return;
        var result = new Array();
        result.push({label:'-----请选择-----',value:''});
        for(var k in objList){
            var temp = new Object();
            temp.label = objList[k].itemValue;
            temp.value = objList[k].itemKey;
            result.push(temp);
        }
        return result;
    },
    init : function () {
        $.post(DataTable.CONTEXT_PATH+"/api/all/ddic?r="+new Date().getTime(),
            function(result){
                if(!result.success){
                    return;
                }
                var data = result.data;
                localStorage.setItem('ddic',JSON.stringify(data));
            },'json');
    }
}

/**
 * 后台返回List<Select>，该方法用于产生dataTable识别的组件元素（select radio checkbox）
 * @type {{init: Select.init}}
 */
var Select = {
    init : function(path){
        var jsonStr = $.ajax({
            url: DataTable.CONTEXT_PATH + path,
            async: false,
            timeout:3000
        }).responseText;
        if(jsonStr){
            var jsonObj = $.parseJSON(jsonStr);
            if(jsonObj.success){
                return jsonObj.data;
            }
        }
        return false;
    }
};

var Invoker = {
    post : function (path,paramObj) {
        var jsonStr = $.ajax({
            url: DataTable.CONTEXT_PATH + path,
            async: false,
            contentType: 'application/json',
            type: 'POST',
            data: JSON.stringify(paramObj),
            timeout:3000
        }).responseText;
        if(jsonStr){
            return $.parseJSON(jsonStr);
        }
        return false;
    },
    get : function (path) {
        var jsonStr = $.ajax({
            url: DataTable.CONTEXT_PATH + path,
            async: false,
            type: 'GET',
            timeout:3000
        }).responseText;
        if(jsonStr){
            return $.parseJSON(jsonStr);
        }
        return false;
    }
};<|endoftext|>


<commit_before>// This file is part of BenchExec, a framework for reliable benchmarking:
// https://github.com/sosy-lab/benchexec
//
// SPDX-FileCopyrightText: 2019-2020 Dirk Beyer <https://www.sosy-lab.org>
//
// SPDX-License-Identifier: Apache-2.0

import React from "react";
import "../../node_modules/react-vis/dist/style.css";
import {
  XYPlot,
  LineMarkSeries,
  VerticalGridLines,
  HorizontalGridLines,
  XAxis,
  YAxis,
  DiscreteColorLegend,
  Hint,
} from "react-vis";
import {
  getRunSetName,
  EXTENDED_DISCRETE_COLOR_RANGE,
  setParam,
  getHashSearch,
  stringAsBoolean,
  getFirstVisibles,
} from "../utils/utils";

const defaultValues = {
  quantile: "true",
  linear: "false",
  correct: "true",
};

export default class QuantilePlot extends React.Component {
  constructor(props) {
    super(props);
    this.state = this.setup();
    this.possibleValues = [];
    this.lineCount = 1;
  }

  setup() {
    const queryProps = getHashSearch();

    let { selection, quantile, linear, correct } = {
      ...defaultValues,
      ...queryProps,
    };

    quantile = stringAsBoolean(quantile);
    linear = stringAsBoolean(linear);
    correct = stringAsBoolean(correct);

    const initialSelection = selection;
    const toolIdxes = this.props.tools.map((tool) => tool.toolIdx).join("");
    const runsetPattern = new RegExp("runset-[" + toolIdxes + "]");

    const isValue = selection === undefined || !runsetPattern.test(selection);

    if (isValue) {
      let selectedCol = selection
        ? this.props.tools
            .map((tool) => tool.columns)
            .flat()
            .find((col) => col.display_title === selection)
        : this.props.preSelection;

      /* If the defined col does not match any of the columns of the runsets or is not visible in any of the runsets,
         the first visible column that is not of the type status of the first visible runset will be shown instead. In case
         there is no such column, the first column of the type status will be selected. */
      if (!selectedCol || !this.isColVisibleInAnyTool(selectedCol)) {
        const [firstVisibleTool, firstVisibleColumn] = getFirstVisibles(
          this.props.tools,
          this.props.hiddenCols,
        );
        selectedCol =
          firstVisibleTool !== undefined
            ? this.props.tools
                .find((tool) => tool.toolIdx === firstVisibleTool)
                .columns.find((col) => col.colIdx === firstVisibleColumn)
            : undefined;
      }

      selection = selectedCol && selectedCol.display_title;
    } else {
      let toolIdx = parseInt(selection.split("-")[1]);
      const selectedTool = this.props.tools.find(
        (tool) => tool.toolIdx === toolIdx,
      );
      const hasToolAnyVisibleCols = selectedTool.columns.some(
        (col) => !this.props.hiddenCols[toolIdx].includes(col.colIdx),
      );

      /* If the selected runset has no visible cols, i.e. the runset itself is hidden, the first visible runset will be
         shown instead. */
      if (!hasToolAnyVisibleCols) {
        toolIdx = getFirstVisibles(this.props.tools, this.props.hiddenCols)[0];
      }
      selection = toolIdx !== undefined ? "runset-" + toolIdx : undefined;
    }

    /* If there was an initial selection (= URl parameter) and there is still a selection (= a visible column/runset) and
     they differ, then the initial selection was a hidden column/runset and therefore another column/runset was selected
     to be shown. In this case, update the URL parameter to correctly define the selection that is actually being shown now. */
    if (initialSelection && selection && initialSelection !== selection) {
      setParam({ selection });
    }

    return {
      selection: selection,
      quantile: quantile,
      linear: linear,
      correct: correct,
      isValue: isValue, //two versions of plot: one Value more RunSets => isValue:true; oneRunSet more Values => isValue:false
      isInvisible: [],
      areAllColsHidden: selection === undefined,
    };
  }

  relevantColumn = (column) =>
    this.isColVisibleInAnyTool(column) &&
    column.type !== "text" &&
    column.type !== "status";

  relevantRunSet = (tool) =>
    tool.columns.length !== this.props.hiddenCols[tool.toolIdx].length &&
    tool.columns.some((c) => c.display_title === this.state.selection);

  // ----------------------resizer-------------------------------
  componentDidMount() {
    window.addEventListener("resize", this.updateDimensions);
    window.addEventListener("popstate", this.refreshUrlState);
  }

  componentWillUnmount() {
    window.removeEventListener("resize", this.updateDimensions);
    window.removeEventListener("popstate", this.refreshUrlState);
  }

  updateDimensions = () => {
    this.setState({
      width: window.innerWidth,
      height: window.innerHeight,
    });
  };

  refreshUrlState = () => {
    this.setState(this.setup());
  };

  isColVisibleInAnyTool(column) {
    return this.props.tools.some((tool) =>
      tool.columns.some(
        (col) =>
          col.colIdx === column.colIdx &&
          !this.props.hiddenCols[tool.toolIdx].includes(col.colIdx),
      ),
    );
  }

  // --------------------rendering-----------------------------
  renderLegend = () => {
    if (this.state.isValue) {
      return this.props.tools
        .filter(this.relevantRunSet)
        .map(getRunSetName)
        .map((c) => {
          return {
            title: c,
            disabled: this.state.isInvisible.some((el) => el === c),
          };
        });
    } else {
      return !this.state.areAllColsHidden
        ? this.props.tools[this.state.selection.split("-")[1]].columns
            .filter((col) => this.relevantColumn(col))
            .map((c) => {
              return {
                title: c.display_title,
                disabled: this.state.isInvisible.some(
                  (el) => el === c.display_title,
                ),
              };
            })
        : [];
    }
  };

  renderAll = () => {
    const task = this.state.selection;

    if (this.state.isValue) {
      //var 1: compare different RunSets on one value
      this.props.tools.forEach((tool, i) => this.renderData(task, i, task + i));
    } else {
      //var 2: compare different values of one RunSet
      if (!this.state.areAllColsHidden) {
        const index = this.state.selection.split("-")[1];
        this.props.tools[index].columns
          .filter((col) => this.relevantColumn(col))
          .forEach((column) =>
            this.renderData(column.display_title, index, column.display_title),
          );
      }
    }
  };

  renderData = (column, toolIdx, field) => {
    const isOrdinal = this.handleType() === "ordinal";
    let arrayY = [];
    const colIdx = this.props.tools[toolIdx].columns.findIndex(
      (value) => value.display_title === column,
    );

    if (
      !this.state.isValue ||
      (colIdx >= 0 && !this.props.hiddenCols[toolIdx].includes(colIdx))
    ) {
      arrayY = this.props.table.map((runSet) => {
        // Get y value if it should be shown and normalize it.
        // For correct x values, arrayY needs to have same length as table.
        const runResult = runSet.results[toolIdx];
        let value = null;
        if (!this.state.correct || runResult.category === "correct") {
          value = runResult.values[colIdx].raw;
          if (value === undefined) {
            value = null;
          }
          if (!isOrdinal && value !== null) {
            value = +value;
            if (!isFinite(value)) {
              value = null;
            }
          }
        }
        return [value, this.props.getRowName(runSet)];
      });

      if (this.state.quantile) {
        arrayY = arrayY.filter((element) => element[0] !== null);
        arrayY = this.sortArray(arrayY, column);
      }
    }

    this.hasInvalidLog = false;
    const newArray = [];

    arrayY.forEach((el, i) => {
      const value = el[0];
      const isLogAndInvalid = !this.state.linear && value <= 0;

      if (value !== null && !isLogAndInvalid) {
        newArray.push({
          x: i + 1,
          y: value,
          info: el[1],
        });
      }

      if (isLogAndInvalid) {
        this.hasInvalidLog = true;
      }
    });

    this[field] = newArray;
  };

  sortArray = (array, column) => {
    const currentValue = this.possibleValues.find(
      (value) => value.display_title === column,
    );

    return this.state.isValue && ["text", "status"].includes(currentValue.type)
      ? array.sort((a, b) => (a[0] > b[0] ? 1 : b[0] > a[0] ? -1 : 0))
      : array.sort((a, b) => +a[0] - +b[0]);
  };

  renderColumns = () => {
    this.props.tools.forEach((tool) => {
      tool.columns.forEach((column) => {
        if (
          !this.props.hiddenCols[tool.toolIdx].includes(column.colIdx) &&
          !this.possibleValues.some(
            (value) => value.display_title === column.display_title,
          )
        ) {
          this.possibleValues.push(column);
        }
      });
    });
    this.renderAll();
    return this.possibleValues.map((value) => {
      return (
        <option
          key={value.display_title}
          value={value.display_title}
          name={value.display_title}
        >
          {value.display_title}
        </option>
      );
    });
  };

  renderLines = () => {
    this.lineCount = 0;
    const color = () =>
      EXTENDED_DISCRETE_COLOR_RANGE[
        (this.lineCount - 1) % EXTENDED_DISCRETE_COLOR_RANGE.length
      ];

    if (this.state.isValue) {
      return this.props.tools
        .map((tool, i) => {
          // Cannot use filter() because we need original value of i
          if (!this.relevantRunSet(tool)) {
            return null;
          }
          const task = this.state.selection;
          const data = this[task + i];
          const id = getRunSetName(tool);
          this.lineCount++;

          return (
            <LineMarkSeries
              data={data}
              key={id}
              color={color()}
              opacity={this.handleLineState(id)}
              onValueMouseOver={(datapoint, event) =>
                this.setState({ value: datapoint })
              }
              onValueMouseOut={(datapoint, event) =>
                this.setState({ value: null })
              }
            />
          );
        })
        .filter((el) => !!el);
    } else {
      if (!this.state.areAllColsHidden) {
        const index = this.state.selection.split("-")[1];
        return this.props.tools[index].columns
          .filter((col) => this.relevantColumn(col))
          .map((column) => {
            const data = this[column.display_title];
            this.lineCount++;

            return (
              <LineMarkSeries
                data={data}
                key={column.display_title}
                color={color()}
                opacity={this.handleLineState(column.display_title)}
                onValueMouseOver={(datapoint, event) =>
                  this.setState({ value: datapoint })
                }
                onValueMouseOut={(datapoint, event) =>
                  this.setState({ value: null })
                }
              />
            );
          });
      }
    }
  };
  // ------------------------handeling----------------------------
  handleLineState = (line) => {
    return this.state.isInvisible.indexOf(line) < 0 ? 1 : 0;
  };

  handleColumn = (ev) => {
    setParam({ selection: ev.target.value });
  };
  toggleQuantile = () => {
    setParam({ quantile: !this.state.quantile });
  };
  toggleCorrect = () => {
    setParam({ correct: !this.state.correct });
  };
  toggleLinear = () => {
    setParam({ linear: !this.state.linear });
  };
  toggleShow = ({ target }) => {
    this.setState({
      [target.name]: target.checked,
    });
  };

  handleType = () => {
    const { selection } = this.state;
    const index = this.possibleValues.findIndex(
      (value) => value.display_title === selection,
    );
    const type =
      this.state.isValue && index >= 0 ? this.possibleValues[index].type : null;
    return this.state.isValue && (type === "text" || type === "status")
      ? "ordinal"
      : this.state.linear
      ? "linear"
      : "log";
  };

  render() {
    return (

        {!this.state.areAllColsHidden && (
          <select
            name="Select Column"
            value={this.state.selection}
            onChange={this.handleColumn}
          >
            <optgroup label="Run sets">
              {this.props.tools.map((runset, i) => {
                return runset.columns.length !==
                  this.props.hiddenCols[runset.toolIdx].length ? (
                  <option
                    key={"runset-" + i}
                    value={"runset-" + i}
                    name={"runset-" + i}
                  >
                    {getRunSetName(runset)}
                  </option>
                ) : null;
              })}
            </optgroup>
            <optgroup label="Columns">{this.renderColumns()}</optgroup>
          </select>
        )}
        <XYPlot
          height={window.innerHeight - 200}
          width={window.innerWidth - 100}
          margin={{ left: 90 }}
          yType={this.handleType()}
        >
          <VerticalGridLines />
          <HorizontalGridLines />
          <XAxis tickFormat={(value) => value} />
          <YAxis tickFormat={(value) => value} />
          {this.state.value ? <Hint value={this.state.value} /> : null}
          <DiscreteColorLegend
            colors={EXTENDED_DISCRETE_COLOR_RANGE}
            items={this.renderLegend()}
            onItemClick={(Object, item) => {
              let line = "";
              line = Object.title.toString();
              if (this.state.isInvisible.indexOf(line) < 0) {
                this.setState({
                  isInvisible: this.state.isInvisible.concat([line]),
                });
              } else {
                return this.setState({
                  isInvisible: this.state.isInvisible.filter((l) => {
                    return l !== line;
                  }),
                });
              }
            }}
          />
          {this.renderLines()}
        </XYPlot>
        {this.state.areAllColsHidden ? (

No columns to show!

        ) : (
          this.lineCount === 0 && (

              {this.hasInvalidLog
                ? "All results have undefined values"
                : "No correct results"}

          )
        )}
        <button className="btn" onClick={this.toggleQuantile}>
          {this.state.quantile
            ? "Switch to Direct Plot"
            : "Switch to Quantile Plot"}
        </button>
        <button className="btn" onClick={this.toggleLinear}>
          {this.state.linear
            ? "Switch to Logarithmic Scale"
            : "Switch to Linear Scale"}
        </button>
        <button className="btn" onClick={this.toggleCorrect}>
          {this.state.correct
            ? "Switch to All Results"
            : "Switch to Correct Results Only"}
        </button>

    );
  }
}
<commit_msg>Hide hidden cols of runsets in Quantile Plot when runset is shown If a runset was selected in the Quantile Plot, all columns of the runset  were shown, even those that were actually hidden for this runset. This  is now fixed.<commit_after>// This file is part of BenchExec, a framework for reliable benchmarking:
// https://github.com/sosy-lab/benchexec
//
// SPDX-FileCopyrightText: 2019-2020 Dirk Beyer <https://www.sosy-lab.org>
//
// SPDX-License-Identifier: Apache-2.0

import React from "react";
import "../../node_modules/react-vis/dist/style.css";
import {
  XYPlot,
  LineMarkSeries,
  VerticalGridLines,
  HorizontalGridLines,
  XAxis,
  YAxis,
  DiscreteColorLegend,
  Hint,
} from "react-vis";
import {
  getRunSetName,
  EXTENDED_DISCRETE_COLOR_RANGE,
  setParam,
  getHashSearch,
  stringAsBoolean,
  getFirstVisibles,
} from "../utils/utils";

const defaultValues = {
  quantile: "true",
  linear: "false",
  correct: "true",
};

export default class QuantilePlot extends React.Component {
  constructor(props) {
    super(props);
    this.state = this.setup();
    this.possibleValues = [];
    this.lineCount = 1;
  }

  setup() {
    const queryProps = getHashSearch();

    let { selection, quantile, linear, correct } = {
      ...defaultValues,
      ...queryProps,
    };

    quantile = stringAsBoolean(quantile);
    linear = stringAsBoolean(linear);
    correct = stringAsBoolean(correct);

    const initialSelection = selection;
    const toolIdxes = this.props.tools.map((tool) => tool.toolIdx).join("");
    const runsetPattern = new RegExp("runset-[" + toolIdxes + "]");

    const isValue = selection === undefined || !runsetPattern.test(selection);

    if (isValue) {
      let selectedCol = selection
        ? this.props.tools
            .map((tool) => tool.columns)
            .flat()
            .find((col) => col.display_title === selection)
        : this.props.preSelection;

      /* If the defined col does not match any of the columns of the runsets or is not visible in any of the runsets,
         the first visible column that is not of the type status of the first visible runset will be shown instead. In case
         there is no such column, the first column of the type status will be selected. */
      if (!selectedCol || !this.isColVisibleInAnyTool(selectedCol)) {
        const [firstVisibleTool, firstVisibleColumn] = getFirstVisibles(
          this.props.tools,
          this.props.hiddenCols,
        );
        selectedCol =
          firstVisibleTool !== undefined
            ? this.props.tools
                .find((tool) => tool.toolIdx === firstVisibleTool)
                .columns.find((col) => col.colIdx === firstVisibleColumn)
            : undefined;
      }

      selection = selectedCol && selectedCol.display_title;
    } else {
      let toolIdx = parseInt(selection.split("-")[1]);
      const selectedTool = this.props.tools.find(
        (tool) => tool.toolIdx === toolIdx,
      );
      const hasToolAnyVisibleCols = selectedTool.columns.some(
        (col) => !this.props.hiddenCols[toolIdx].includes(col.colIdx),
      );

      /* If the selected runset has no visible cols, i.e. the runset itself is hidden, the first visible runset will be
         shown instead. */
      if (!hasToolAnyVisibleCols) {
        toolIdx = getFirstVisibles(this.props.tools, this.props.hiddenCols)[0];
      }
      selection = toolIdx !== undefined ? "runset-" + toolIdx : undefined;
    }

    /* If there was an initial selection (= URl parameter) and there is still a selection (= a visible column/runset) and
     they differ, then the initial selection was a hidden column/runset and therefore another column/runset was selected
     to be shown. In this case, update the URL parameter to correctly define the selection that is actually being shown now. */
    if (initialSelection && selection && initialSelection !== selection) {
      setParam({ selection });
    }

    return {
      selection: selection,
      quantile: quantile,
      linear: linear,
      correct: correct,
      isValue: isValue, //two versions of plot: one Value more RunSets => isValue:true; oneRunSet more Values => isValue:false
      isInvisible: [],
      areAllColsHidden: selection === undefined,
    };
  }

  isColRelevantForTool = (colIdx, toolIdx) =>
    !this.props.hiddenCols[toolIdx].includes(colIdx) &&
    colIdx.type !== "text" &&
    colIdx.type !== "status";

  relevantRunSet = (tool) =>
    tool.columns.length !== this.props.hiddenCols[tool.toolIdx].length &&
    tool.columns.some((c) => c.display_title === this.state.selection);

  // ----------------------resizer-------------------------------
  componentDidMount() {
    window.addEventListener("resize", this.updateDimensions);
    window.addEventListener("popstate", this.refreshUrlState);
  }

  componentWillUnmount() {
    window.removeEventListener("resize", this.updateDimensions);
    window.removeEventListener("popstate", this.refreshUrlState);
  }

  updateDimensions = () => {
    this.setState({
      width: window.innerWidth,
      height: window.innerHeight,
    });
  };

  refreshUrlState = () => {
    this.setState(this.setup());
  };

  isColVisibleInAnyTool(column) {
    return this.props.tools.some((tool) =>
      tool.columns.some(
        (col) =>
          col.colIdx === column.colIdx &&
          !this.props.hiddenCols[tool.toolIdx].includes(col.colIdx),
      ),
    );
  }

  // --------------------rendering-----------------------------
  renderLegend = () => {
    if (this.state.isValue) {
      return this.props.tools
        .filter(this.relevantRunSet)
        .map(getRunSetName)
        .map((c) => {
          return {
            title: c,
            disabled: this.state.isInvisible.some((el) => el === c),
          };
        });
    } else {
      const tool = this.props.tools[this.state.selection.split("-")[1]];
      return !this.state.areAllColsHidden
        ? tool.columns
            .filter((col) =>
              this.isColRelevantForTool(col.colIdx, tool.toolIdx),
            )
            .map((c) => {
              return {
                title: c.display_title,
                disabled: this.state.isInvisible.some(
                  (el) => el === c.display_title,
                ),
              };
            })
        : [];
    }
  };

  renderAll = () => {
    const task = this.state.selection;

    if (this.state.isValue) {
      //var 1: compare different RunSets on one value
      this.props.tools.forEach((tool, i) => this.renderData(task, i, task + i));
    } else {
      //var 2: compare different values of one RunSet
      if (!this.state.areAllColsHidden) {
        const index = this.state.selection.split("-")[1];
        const tool = this.props.tools[index];
        tool.columns
          .filter(
            (col) =>
              this.isColRelevantForTool(col.colIdx, tool.toolIdx) &&
              !this.props.hiddenCols[index].includes(col.colIdx),
          )
          .forEach((column) =>
            this.renderData(column.display_title, index, column.display_title),
          );
      }
    }
  };

  renderData = (column, toolIdx, field) => {
    const isOrdinal = this.handleType() === "ordinal";
    let arrayY = [];
    const colIdx = this.props.tools[toolIdx].columns.findIndex(
      (value) => value.display_title === column,
    );

    if (
      !this.state.isValue ||
      (colIdx >= 0 && !this.props.hiddenCols[toolIdx].includes(colIdx))
    ) {
      arrayY = this.props.table.map((runSet) => {
        // Get y value if it should be shown and normalize it.
        // For correct x values, arrayY needs to have same length as table.
        const runResult = runSet.results[toolIdx];
        let value = null;
        if (!this.state.correct || runResult.category === "correct") {
          value = runResult.values[colIdx].raw;
          if (value === undefined) {
            value = null;
          }
          if (!isOrdinal && value !== null) {
            value = +value;
            if (!isFinite(value)) {
              value = null;
            }
          }
        }
        return [value, this.props.getRowName(runSet)];
      });

      if (this.state.quantile) {
        arrayY = arrayY.filter((element) => element[0] !== null);
        arrayY = this.sortArray(arrayY, column);
      }
    }

    this.hasInvalidLog = false;
    const newArray = [];

    arrayY.forEach((el, i) => {
      const value = el[0];
      const isLogAndInvalid = !this.state.linear && value <= 0;

      if (value !== null && !isLogAndInvalid) {
        newArray.push({
          x: i + 1,
          y: value,
          info: el[1],
        });
      }

      if (isLogAndInvalid) {
        this.hasInvalidLog = true;
      }
    });

    this[field] = newArray;
  };

  sortArray = (array, column) => {
    const currentValue = this.possibleValues.find(
      (value) => value.display_title === column,
    );

    return this.state.isValue && ["text", "status"].includes(currentValue.type)
      ? array.sort((a, b) => (a[0] > b[0] ? 1 : b[0] > a[0] ? -1 : 0))
      : array.sort((a, b) => +a[0] - +b[0]);
  };

  renderColumns = () => {
    this.props.tools.forEach((tool) => {
      tool.columns.forEach((column) => {
        if (
          !this.props.hiddenCols[tool.toolIdx].includes(column.colIdx) &&
          !this.possibleValues.some(
            (value) => value.display_title === column.display_title,
          )
        ) {
          this.possibleValues.push(column);
        }
      });
    });
    this.renderAll();
    return this.possibleValues.map((value) => {
      return (
        <option
          key={value.display_title}
          value={value.display_title}
          name={value.display_title}
        >
          {value.display_title}
        </option>
      );
    });
  };

  renderLines = () => {
    this.lineCount = 0;
    const color = () =>
      EXTENDED_DISCRETE_COLOR_RANGE[
        (this.lineCount - 1) % EXTENDED_DISCRETE_COLOR_RANGE.length
      ];

    if (this.state.isValue) {
      return this.props.tools
        .map((tool, i) => {
          // Cannot use filter() because we need original value of i
          if (!this.relevantRunSet(tool)) {
            return null;
          }
          const task = this.state.selection;
          const data = this[task + i];
          const id = getRunSetName(tool);
          this.lineCount++;

          return (
            <LineMarkSeries
              data={data}
              key={id}
              color={color()}
              opacity={this.handleLineState(id)}
              onValueMouseOver={(datapoint, event) =>
                this.setState({ value: datapoint })
              }
              onValueMouseOut={(datapoint, event) =>
                this.setState({ value: null })
              }
            />
          );
        })
        .filter((el) => !!el);
    } else {
      if (!this.state.areAllColsHidden) {
        const index = this.state.selection.split("-")[1];
        const tool = this.props.tools[index];
        return tool.columns
          .filter((col) => this.isColRelevantForTool(col.colIdx, tool.toolIdx))
          .map((column) => {
            const data = this[column.display_title];
            this.lineCount++;

            return (
              <LineMarkSeries
                data={data}
                key={column.display_title}
                color={color()}
                opacity={this.handleLineState(column.display_title)}
                onValueMouseOver={(datapoint, event) =>
                  this.setState({ value: datapoint })
                }
                onValueMouseOut={(datapoint, event) =>
                  this.setState({ value: null })
                }
              />
            );
          });
      }
    }
  };
  // ------------------------handeling----------------------------
  handleLineState = (line) => {
    return this.state.isInvisible.indexOf(line) < 0 ? 1 : 0;
  };

  handleColumn = (ev) => {
    setParam({ selection: ev.target.value });
  };
  toggleQuantile = () => {
    setParam({ quantile: !this.state.quantile });
  };
  toggleCorrect = () => {
    setParam({ correct: !this.state.correct });
  };
  toggleLinear = () => {
    setParam({ linear: !this.state.linear });
  };
  toggleShow = ({ target }) => {
    this.setState({
      [target.name]: target.checked,
    });
  };

  handleType = () => {
    const { selection } = this.state;
    const index = this.possibleValues.findIndex(
      (value) => value.display_title === selection,
    );
    const type =
      this.state.isValue && index >= 0 ? this.possibleValues[index].type : null;
    return this.state.isValue && (type === "text" || type === "status")
      ? "ordinal"
      : this.state.linear
      ? "linear"
      : "log";
  };

  render() {
    return (

        {!this.state.areAllColsHidden && (
          <select
            name="Select Column"
            value={this.state.selection}
            onChange={this.handleColumn}
          >
            <optgroup label="Run sets">
              {this.props.tools.map((runset, i) => {
                return runset.columns.length !==
                  this.props.hiddenCols[runset.toolIdx].length ? (
                  <option
                    key={"runset-" + i}
                    value={"runset-" + i}
                    name={"runset-" + i}
                  >
                    {getRunSetName(runset)}
                  </option>
                ) : null;
              })}
            </optgroup>
            <optgroup label="Columns">{this.renderColumns()}</optgroup>
          </select>
        )}
        <XYPlot
          height={window.innerHeight - 200}
          width={window.innerWidth - 100}
          margin={{ left: 90 }}
          yType={this.handleType()}
        >
          <VerticalGridLines />
          <HorizontalGridLines />
          <XAxis tickFormat={(value) => value} />
          <YAxis tickFormat={(value) => value} />
          {this.state.value ? <Hint value={this.state.value} /> : null}
          <DiscreteColorLegend
            colors={EXTENDED_DISCRETE_COLOR_RANGE}
            items={this.renderLegend()}
            onItemClick={(Object, item) => {
              let line = "";
              line = Object.title.toString();
              if (this.state.isInvisible.indexOf(line) < 0) {
                this.setState({
                  isInvisible: this.state.isInvisible.concat([line]),
                });
              } else {
                return this.setState({
                  isInvisible: this.state.isInvisible.filter((l) => {
                    return l !== line;
                  }),
                });
              }
            }}
          />
          {this.renderLines()}
        </XYPlot>
        {this.state.areAllColsHidden ? (

No columns to show!

        ) : (
          this.lineCount === 0 && (

              {this.hasInvalidLog
                ? "All results have undefined values"
                : "No correct results"}

          )
        )}
        <button className="btn" onClick={this.toggleQuantile}>
          {this.state.quantile
            ? "Switch to Direct Plot"
            : "Switch to Quantile Plot"}
        </button>
        <button className="btn" onClick={this.toggleLinear}>
          {this.state.linear
            ? "Switch to Logarithmic Scale"
            : "Switch to Linear Scale"}
        </button>
        <button className="btn" onClick={this.toggleCorrect}>
          {this.state.correct
            ? "Switch to All Results"
            : "Switch to Correct Results Only"}
        </button>

    );
  }
}
<|endoftext|>


<commit_before>/*jslint nomen : true */

var
	Query = require('mongoose').Query,

	config = require('../../config');

Query.prototype.page = function (options, callback) {
	'use strict';

	var defaults = {
			start : 0,
			count : config.database.maxDocs
		},
		query = this,
		wrap = {};

	options = options || defaults;

	// fix to keep from no max being specified slipping through
	if (!options.max) {
		options.max = defaults.max;
	}

	query.model.count(query._conditions, function (err, total) {
		query
			.skip(options.start)
			.limit(options.count)
			.execFind(function (err, results) {
				if (err) { return callback(err); }

				wrap = {
					options : options,
					results : results || [],
					total : total
				};

				callback(err, wrap);
			});
	});
};<commit_msg>Finished config DI refactor by adding initialize methods to modules where needed.<commit_after>/*jslint nomen : true */

var
	Query = require('mongoose').Query,

	config = {};

exports.initialize = function (options) {
	'use strict';

	config = options.config;
};

Query.prototype.page = function (options, callback) {
	'use strict';

	var defaults = {
			start : 0,
			count : config.database.maxDocs
		},
		query = this,
		wrap = {};

	options = options || defaults;

	// fix to keep from no max being specified slipping through
	if (!options.max) {
		options.max = defaults.max;
	}

	query.model.count(query._conditions, function (err, total) {
		query
			.skip(options.start)
			.limit(options.count)
			.execFind(function (err, results) {
				if (err) { return callback(err); }

				wrap = {
					options : options,
					results : results || [],
					total : total
				};

				callback(err, wrap);
			});
	});
};
<|endoftext|>


<commit_before>'use strict';
/*******************************************************************************
 * Copyright 2012 Pawel Psztyc
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 ******************************************************************************/
/* global chrome */
/**
 * Advanced Rest Client namespace
 */
var arc = arc || {};
/**
 * ARC app's namespace
 */
arc.app = arc.app || {};
/**
 * A namespace for the app server API
 */
arc.app.server = arc.app.server || {};
/**
 * Currently logged in user ID.
 */
arc.app.server.applicationUserId = null;
/**
 * Check if the user has session set on the server.
 */
arc.app.server.hasSession = function(callback) {
  arc.app.server.request.pingRequest()
    .then(function(json) {
      if (json.error) {
        return {
          'error': true,
          'message': json.error
        };
      }
      var data = {
        state: 2, //unknown
        uid: null //unknown
      };
      if ('hasSession' in json) {
        data.state = json.hasSession ? 1 : 0;
        if (json.hasSession) {
          data.uid = json.userId;
        }
      }
      return data;
    })
    .then(callback);
};
/**
 * Opened auth tab id.
 */
arc.app.server._authTab = null;
/**
 * Authorize the user in the app.
 */
arc.app.server.auth = function() {
  var returnPath = '';
  if (arc.app.utils.isProdMode()) {
    returnPath = 'chrome-extension://' + chrome.runtime.id + '/auth.html#auth';
  } else {
    returnPath = 'http://127.0.0.1:8888/auth.html#auth';
  }
  var url = arc.app.server.request.AUTH_URL;
  url += '/signin?ret=';
  var regexp = /%20/g;
  url = url + encodeURIComponent(returnPath).replace(regexp, '+');
  chrome.tabs.create({
    url: url
  }, function(tab) {
    arc.app.server._authTab = tab.id;
  });
};
/**
 * A chrome storage state changes listener.
 * Listen for changes in storage and check if auth object changed.
 */
arc.app.server.authStateMayChanged = function(changes) {
  if (Object.keys(changes).indexOf('applogin')) {
    arc.app.server.hasSession(function(session) {
      if (window.arcGwtCallbacks && ('sessionchange' in window.arcGwtCallbacks)) {
        window.arcGwtCallbacks.sessionchange(session);
      }
      if (arc.app.server._authTab) {
        chrome.tabs.remove(arc.app.server._authTab);
        arc.app.server._authTab = null;
      }
    });
  }
};
/**
 * Get developer messages from the server.
 */
arc.app.server.getMessages = function(since, callback) {
  arc.app.server.request.messagesRequest(since)
    .then(callback);
};
/**
 * Get user stored data projection from the server.
 *
 * @param {String} uid Uid of the user to import data from.
 */
arc.app.server.getImportSuggestions = function(uid, callback) {
  arc.app.server.request.importSuggestionsRequest(uid)
    .then(function(result) {
      callback(result);
    });
};

/**
 * Get user stored data from the server.
 *
 * @param {Array} uids A list of datastore IDs to import
 */
arc.app.server.getImportData = function(uids, callback) {
  arc.app.server.request.getImportData(uids)
    .then(function(result) {
      callback(result);
    });
};

chrome.storage.onChanged.addListener(arc.app.server.authStateMayChanged);
<commit_msg>Fixed server session state check after making a request<commit_after>'use strict';
/*******************************************************************************
 * Copyright 2012 Pawel Psztyc
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 ******************************************************************************/
/* global chrome */
/**
 * Advanced Rest Client namespace
 */
var arc = arc || {};
/**
 * ARC app's namespace
 */
arc.app = arc.app || {};
/**
 * A namespace for the app server API
 */
arc.app.server = arc.app.server || {};
/**
 * Currently logged in user ID.
 */
arc.app.server.applicationUserId = null;
/**
 * Check if the user has session set on the server.
 */
arc.app.server.hasSession = function(callback) {
  arc.app.server.request.pingRequest()
    .then(function(json) {
      if (json.error) {
        return {
          'error': true,
          'message': json.error
        };
      }
      var data = {
        state: 2, //unknown
        uid: null //unknown
      };
      if ('hasSession' in json) {
        data.state = json.hasSession ? 1 : 0;
        if (json.hasSession) {
          data.uid = json.userId;
        }
      }
      return data;
    })
    .then(callback);
};
/**
 * Opened auth tab id.
 */
arc.app.server._authTab = null;
/**
 * Authorize the user in the app.
 */
arc.app.server.auth = function() {
  var returnPath = '';
  if (arc.app.utils.isProdMode()) {
    returnPath = 'chrome-extension://' + chrome.runtime.id + '/auth.html#auth';
  } else {
    returnPath = 'http://127.0.0.1:8888/auth.html#auth';
  }
  var url = arc.app.server.request.AUTH_URL;
  url += '/signin?ret=';
  var regexp = /%20/g;
  url = url + encodeURIComponent(returnPath).replace(regexp, '+');
  chrome.tabs.create({
    url: url
  }, function(tab) {
    arc.app.server._authTab = tab.id;
  });
};
/**
 * A chrome storage state changes listener.
 * Listen for changes in storage and check if auth object changed.
 */
arc.app.server.authStateMayChanged = function(changes) {
  if (Object.keys(changes).indexOf('applogin') !== -1) {
    arc.app.server.hasSession(function(session) {
      if (window.arcGwtCallbacks && ('sessionchange' in window.arcGwtCallbacks)) {
        window.arcGwtCallbacks.sessionchange(session);
      }
      if (arc.app.server._authTab) {
        chrome.tabs.remove(arc.app.server._authTab);
        arc.app.server._authTab = null;
      }
    });
  }
};
/**
 * Get developer messages from the server.
 */
arc.app.server.getMessages = function(since, callback) {
  arc.app.server.request.messagesRequest(since)
    .then(callback);
};
/**
 * Get user stored data projection from the server.
 *
 * @param {String} uid Uid of the user to import data from.
 */
arc.app.server.getImportSuggestions = function(uid, callback) {
  arc.app.server.request.importSuggestionsRequest(uid)
    .then(function(result) {
      callback(result);
    });
};

/**
 * Get user stored data from the server.
 *
 * @param {Array} uids A list of datastore IDs to import
 */
arc.app.server.getImportData = function(uids, callback) {
  arc.app.server.request.getImportData(uids)
    .then(function(result) {
      callback(result);
    });
};

chrome.storage.onChanged.addListener(arc.app.server.authStateMayChanged);
<|endoftext|>


<commit_before>/**
 * Created by ermrk on 09.02.2016.
 */

function showAnswerToQuestion (r) {
    questionText=r.text;
    //shows answers
    if (r.answers && gen_answers != r.gen_answers) {
        var container = createList("#answers_area"+numberOfCards, "answers"+numberOfCards, null, false, true);
        showResultAnswers(container, r.answers, r.snippets, r.sources);
        gen_answers = r.gen_answers;
    }

    //shows concepts and summary
    if (r.summary) {
        if (r.summary.concepts.length) {
            var container = createList("#concept_area"+numberOfCards, "concepts"+numberOfCards, "Concepts", true, false);
            showConcept(container, r.summary.concepts);
        } else {
            $("#concept_area"+numberOfCards).empty();
        }
        showAnswerType(r.summary);
    }

    //shows sources
    if (!$.isEmptyObject(r.sources) && gen_sources != r.gen_sources) {
        var container = createList("#sources_area"+numberOfCards, "questionSources"+numberOfCards, "Answer sources", true, false);
        showSources(container, r.sources);
        gen_sources = r.gen_sources;
    }

    if (r.finished) {
        if (r.answerSentence) {
            $("#answers_area"+numberOfCards).prepend('
' + r.answerSentence + '
');
        }
        if (showFeedbackBool) {
            showFeedback(numberOfShowedAnswers);
        }
        $("#spinner"+numberOfCards).hide();
        showArtificialConcepts(r.summary.concepts);
    } else {
        // keep watching
        setTimeout(getQuestionJson, 500);
    }
}

/* Create a table with answers. */
function showResultAnswers(container, answers, snippets, sources) {
    container.empty();

    //Special case, nothing has been founded
    if (answers.length == 1 && answers[0].text == "") {
        showNoAnswer();
    }
    //normal case
    else {
        showAnswers(container, answers, snippets, sources);
    }
}

function showNoAnswer(){
    $("#answers_area"+numberOfCards).html("
No answers found, we are sorry.
");
}

function showAnswers(container, answers, snippets, sources){
    var i = 1;
    answers.forEach(function (a) {
        // FIXME: also deal with < > &
        //text = a.text.replace(/"/g, """);
        if (i <= DIRECTLY_SHOWED_QUESTIONS) {
            showOneAnswer(a, i, container, snippets, sources);
        } else {
            showAnswersInDropDown(a, i, container, snippets, sources);
        }
        i++;
    });
    numberOfShowedAnswers = i;
    $("#moreAnswers"+numberOfCards).collapsibleset();
    $("#answers"+numberOfCards).collapsibleset();

    if (!$('#spinner'+numberOfCards).length) {
        $("#answers_area"+numberOfCards).append('');
    }
}

/* Shows best answers directly */
function showOneAnswer(a, i, container, snippets, sources) {
    text = a.text.replace(/"/g, """);
    var toAppend = $('' +
        '
' +
        '
' +
        '' + (a.confidence * 100).toFixed(1) + '%' + '' +
        '' +
        '' +
        '' +
        text +
        '' +
        score_bar(a.confidence) +
        '
' +
        '
' + showSnippets(a, snippets, sources) + '
' +
        '
')
    container.append(toAppend);
}

/* Shows answers in drop down menu */
function showAnswersInDropDown(a, i, container, snippets, sources) {
    var dropDownList = $("#moreAnswers"+numberOfCards);
    if (!dropDownList.length) {
        createDropDownList(container, "answersDropDownLI"+numberOfCards, "More answers...", "moreAnswers"+numberOfCards);
        dropDownList = $("#moreAnswers");
    }
    showOneAnswer(a, i, dropDownList, snippets, sources);
}

/* Creates base for drop down menu */
function createDropDownList(container, liID, title, divID) {
    container.append('' +
        '
' +
        '
' + title + '
 ' +
        '
 ' +
        '
' +
        '
');
}

/* Returns color for score */
function score_color(score) {
    var hue = 120 * score;
    var saturation = 75 + 25 * score;
    var light = 25 + 30 * (1 - score);
    return 'hsl(' + hue + ', ' + saturation + '%, ' + light + '%);';
}

/* Create a fancy score bar representing confidence of an answer. */
function score_bar(score) {
    return '
 ';
}

/* Show snippets in answer collapsible */
function showSnippets(a, snippets, sources) {
    var texts = "";
    var snippetIDs = a.snippetIDs;
    var len = snippetIDs.length;
    for (var i = 0; i < len; i++) {
        var snippet = snippets[snippetIDs[i]];
        var source = sources[snippet.sourceID];
        texts += '
';
        texts += createURLButton(source);
        texts += '
' +
            createPassageText(a, snippet, source) + createPropertyLabel(a, snippet) + createOrigin(source) + '
';
        texts += "
";
        if (i != len - 1) {
            texts += '
';
        }
    }
    return texts;
}

/* Creates text of snippet */
function createPassageText(a, snipet, source) {
    var text = "";
    if (!(typeof (snipet.passageText) === "undefined")) {
        text = highlight(a.text.replace(/"/g, """), snipet.passageText);
    }
    return text;
}

/* Creates property label of snippet */
function createPropertyLabel(a, snipet) {
    var text = "";
    if (!(typeof (snipet.propertyLabel) === "undefined")) {
        text = highlight(a.text.replace(/"/g, """), snipet.propertyLabel);
    }
    if (!(typeof (snipet.witnessLabel) ==="undefined")) {
        text += " (" + snipet.witnessLabel + ")";
    }
    return text;
}

/* Highlight word in text */
function highlight(word, text) {
    var wordForRGXP = word.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
    var rgxp = new RegExp(wordForRGXP, 'g');
    var repl = '' + word + '';
    return text.replace(rgxp, repl);
}

/* Creates origin of snippet */
function createOrigin(source) {
    var text = "";
    if (!(typeof (source.origin) === "undefined")) {
        text = ' (' + source.origin + ')';
    }
    return text;
}

/* Creates url button for snippet */
function createURLButton(source) {
    var text = "";
    var image = "";
    if (!(typeof (source.URL) === "undefined")) {
        image = createButtonImage(source);
        text = '' +
            image +
            source.title + '';
    }
    return text;
}

/* Creates image for snippet's button */
function createButtonImage(source) {
    if (!(typeof (source.type) === "undefined")) {
        var imageSource;
        var alt;
        var size;
        if (source.type == "enwiki") {
            imageSource = "img/wikipedia-w-logo.png";
            alt = "Wikipedia";
            size = 1;
        } else if (source.type == "freebase") {
            imageSource = "img/freebase_logo.png";
            alt = "Freebase";
            size = 1;
        } else if (source.type == "dbpedia") {
            imageSource = "img/dbpedia_logo.png";
            alt = "DBpedia";
            size = 1.5;
        } else if (source.type == "bing") {
            imageSource = "img/bing_logo.png";
            alt = "Bing";
            size = 1;
        } else {
            return '[' + source.type + '] '; // return at least type text if we have no icon
        }
        return ''
    }
    return "";
}

/* Shows concepts on main page */
function showConcept(container, concepts) {
    container.empty();
    var i = 1;
    concepts.forEach(function (a) {
        container.append('' +
            '
' +
            '   ' +
            '       '
            + a.title +
            '   ' +
            '   ' +
            '
');
        i++;
    });
    $("#concepts"+numberOfCards).listview().listview("refresh");
}

/* Shows answer type */
function showAnswerType(summary) {
    var container = $("#answerType_area");
    container.empty();
    if (summary.lats.length) {
        container.append('
');
        container.append('
Answer types
');
        container.append('
' + summary.lats.join(', ').capitalizeFirstLetter() + '
');
    }
}

/* Create a box with answer sources. */
function showSources(container, sources) {
    container.empty();
    var map = [];
    var indexes = [];
    $.each(sources, function (sid, source) {
        if (source.origin != "document title") {
            deduplicateSources(map, indexes, source);
        }
    });
    var toAppend = "";
    indexes.forEach(function (index) {
        var source = map[index];
        var url;
        if (source.type == "enwiki") {
            url = 'http://en.wikipedia.org/?curid=' + source.pageId;
        } else {
            url = source.URL;
        }
        toAppend += '
' +
            '' +
            createButtonImage(source) +
            source.title + ' (' + source.origin + ')' +
            '' +
            '
';
    });
    container.append(toAppend);
    $('#questionSources'+numberOfCards).listview().listview("refresh");
}

/* Deduplicate sources and connects origins */
function deduplicateSources(map, indexes, source) {
    var id = source.type == "enwiki" ? source.pageId : source.URL;
    if (id in map) {
        map[id].origin += ", " + source.origin;
    } else {
        indexes.push(id);
        map[id] = JSON.parse(JSON.stringify(source)); // copy object
    }
}<commit_msg>Speedup of showing answers, by not showing "more answers" until answer is finished<commit_after>/**
 * Created by ermrk on 09.02.2016.
 */

function showAnswerToQuestion (r) {
    questionText=r.text;
    //shows answers
    if (r.answers && gen_answers != r.gen_answers) {
        var container = createList("#answers_area"+numberOfCards, "answers"+numberOfCards, null, false, true);
        showResultAnswers(container, r.answers, r.snippets, r.sources, r.finished);
        gen_answers = r.gen_answers;
    }

    //shows concepts and summary
    if (r.summary) {
        if (r.summary.concepts.length) {
            var container = createList("#concept_area"+numberOfCards, "concepts"+numberOfCards, "Concepts", true, false);
            showConcept(container, r.summary.concepts);
        } else {
            $("#concept_area"+numberOfCards).empty();
        }
        showAnswerType(r.summary);
    }

    //shows sources
    if (!$.isEmptyObject(r.sources) && gen_sources != r.gen_sources) {
        var container = createList("#sources_area"+numberOfCards, "questionSources"+numberOfCards, "Answer sources", true, false);
        showSources(container, r.sources);
        gen_sources = r.gen_sources;
    }

    if (r.finished) {
        if (r.answerSentence) {
            $("#answers_area"+numberOfCards).prepend('
' + r.answerSentence + '
');
        }
        if (showFeedbackBool) {
            showFeedback(numberOfShowedAnswers);
        }
        $("#spinner"+numberOfCards).hide();
        showArtificialConcepts(r.summary.concepts);
    } else {
        // keep watching
        setTimeout(getQuestionJson, 500);
    }
}

/* Create a table with answers. */
function showResultAnswers(container, answers, snippets, sources, finished) {
    container.empty();

    //Special case, nothing has been founded
    if (answers.length == 1 && answers[0].text == "") {
        showNoAnswer();
    }
    //normal case
    else {
        showAnswers(container, answers, snippets, sources, finished);
    }
}

function showNoAnswer(){
    $("#answers_area"+numberOfCards).html("
No answers found, we are sorry.
");
}

function showAnswers(container, answers, snippets, sources, showMoreAnswers){
    var i = 1;
    answers.forEach(function (a) {
        // FIXME: also deal with < > &
        //text = a.text.replace(/"/g, """);
        if (i <= DIRECTLY_SHOWED_QUESTIONS) {
            showOneAnswer(a, i, container, snippets, sources);
        } else {
            if (showMoreAnswers){
                showAnswersInDropDown(a, i, container, snippets, sources);}
        }
        i++;
    });
    numberOfShowedAnswers = i;
    if (showMoreAnswers){
        $("#moreAnswers"+numberOfCards).collapsibleset();}
    $("#answers"+numberOfCards).collapsibleset();

    if (!$('#spinner'+numberOfCards).length) {
        $("#answers_area"+numberOfCards).append('');
    }
}

/* Shows best answers directly */
function showOneAnswer(a, i, container, snippets, sources) {
    text = a.text.replace(/"/g, """);
    var toAppend = $('' +
        '
' +
        '
' +
        '' + (a.confidence * 100).toFixed(1) + '%' + '' +
        '' +
        '' +
        '' +
        text +
        '' +
        score_bar(a.confidence) +
        '
' +
        '
' + showSnippets(a, snippets, sources) + '
' +
        '
')
    container.append(toAppend);
}

/* Shows answers in drop down menu */
function showAnswersInDropDown(a, i, container, snippets, sources) {
    var dropDownList = $("#moreAnswers"+numberOfCards);
    if (!dropDownList.length) {
        createDropDownList(container, "answersDropDownLI"+numberOfCards, "More answers...", "moreAnswers"+numberOfCards);
        dropDownList = $("#moreAnswers");
    }
    showOneAnswer(a, i, dropDownList, snippets, sources);
}

/* Creates base for drop down menu */
function createDropDownList(container, liID, title, divID) {
    container.append('' +
        '
' +
        '
' + title + '
 ' +
        '
 ' +
        '
' +
        '
');
}

/* Returns color for score */
function score_color(score) {
    var hue = 120 * score;
    var saturation = 75 + 25 * score;
    var light = 25 + 30 * (1 - score);
    return 'hsl(' + hue + ', ' + saturation + '%, ' + light + '%);';
}

/* Create a fancy score bar representing confidence of an answer. */
function score_bar(score) {
    return '
 ';
}

/* Show snippets in answer collapsible */
function showSnippets(a, snippets, sources) {
    var texts = "";
    var snippetIDs = a.snippetIDs;
    var len = snippetIDs.length;
    for (var i = 0; i < len; i++) {
        var snippet = snippets[snippetIDs[i]];
        var source = sources[snippet.sourceID];
        texts += '
';
        texts += createURLButton(source);
        texts += '
' +
            createPassageText(a, snippet, source) + createPropertyLabel(a, snippet) + createOrigin(source) + '
';
        texts += "
";
        if (i != len - 1) {
            texts += '
';
        }
    }
    return texts;
}

/* Creates text of snippet */
function createPassageText(a, snipet, source) {
    var text = "";
    if (!(typeof (snipet.passageText) === "undefined")) {
        text = highlight(a.text.replace(/"/g, """), snipet.passageText);
    }
    return text;
}

/* Creates property label of snippet */
function createPropertyLabel(a, snipet) {
    var text = "";
    if (!(typeof (snipet.propertyLabel) === "undefined")) {
        text = highlight(a.text.replace(/"/g, """), snipet.propertyLabel);
    }
    if (!(typeof (snipet.witnessLabel) ==="undefined")) {
        text += " (" + snipet.witnessLabel + ")";
    }
    return text;
}

/* Highlight word in text */
function highlight(word, text) {
    var wordForRGXP = word.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
    var rgxp = new RegExp(wordForRGXP, 'g');
    var repl = '' + word + '';
    return text.replace(rgxp, repl);
}

/* Creates origin of snippet */
function createOrigin(source) {
    var text = "";
    if (!(typeof (source.origin) === "undefined")) {
        text = ' (' + source.origin + ')';
    }
    return text;
}

/* Creates url button for snippet */
function createURLButton(source) {
    var text = "";
    var image = "";
    if (!(typeof (source.URL) === "undefined")) {
        image = createButtonImage(source);
        text = '' +
            image +
            source.title + '';
    }
    return text;
}

/* Creates image for snippet's button */
function createButtonImage(source) {
    if (!(typeof (source.type) === "undefined")) {
        var imageSource;
        var alt;
        var size;
        if (source.type == "enwiki") {
            imageSource = "img/wikipedia-w-logo.png";
            alt = "Wikipedia";
            size = 1;
        } else if (source.type == "freebase") {
            imageSource = "img/freebase_logo.png";
            alt = "Freebase";
            size = 1;
        } else if (source.type == "dbpedia") {
            imageSource = "img/dbpedia_logo.png";
            alt = "DBpedia";
            size = 1.5;
        } else if (source.type == "bing") {
            imageSource = "img/bing_logo.png";
            alt = "Bing";
            size = 1;
        } else {
            return '[' + source.type + '] '; // return at least type text if we have no icon
        }
        return ''
    }
    return "";
}

/* Shows concepts on main page */
function showConcept(container, concepts) {
    container.empty();
    var i = 1;
    concepts.forEach(function (a) {
        container.append('' +
            '
' +
            '   ' +
            '       '
            + a.title +
            '   ' +
            '   ' +
            '
');
        i++;
    });
    $("#concepts"+numberOfCards).listview().listview("refresh");
}

/* Shows answer type */
function showAnswerType(summary) {
    var container = $("#answerType_area");
    container.empty();
    if (summary.lats.length) {
        container.append('
');
        container.append('
Answer types
');
        container.append('
' + summary.lats.join(', ').capitalizeFirstLetter() + '
');
    }
}

/* Create a box with answer sources. */
function showSources(container, sources) {
    container.empty();
    var map = [];
    var indexes = [];
    $.each(sources, function (sid, source) {
        if (source.origin != "document title") {
            deduplicateSources(map, indexes, source);
        }
    });
    var toAppend = "";
    indexes.forEach(function (index) {
        var source = map[index];
        var url;
        if (source.type == "enwiki") {
            url = 'http://en.wikipedia.org/?curid=' + source.pageId;
        } else {
            url = source.URL;
        }
        toAppend += '
' +
            '' +
            createButtonImage(source) +
            source.title + ' (' + source.origin + ')' +
            '' +
            '
';
    });
    container.append(toAppend);
    $('#questionSources'+numberOfCards).listview().listview("refresh");
}

/* Deduplicate sources and connects origins */
function deduplicateSources(map, indexes, source) {
    var id = source.type == "enwiki" ? source.pageId : source.URL;
    if (id in map) {
        map[id].origin += ", " + source.origin;
    } else {
        indexes.push(id);
        map[id] = JSON.parse(JSON.stringify(source)); // copy object
    }
}<|endoftext|>


<commit_before>
var fs = require('fs');
var koa = require('koa');

var app = module.exports = koa();

/**
 * Create the `GET /stream` route that streams this file.
 * In node.js, the current file is available as a variable `__filename`.
 */

app.use(function* (next) {
  if (this.request.path !== '/stream') return yield* next;

  // this.response.type =
  // this.response.body =
});

/**
 * Create the `GET /json` route that sends `{message:'hello world'}`.
 */

app.use(function* (next) {
  if (this.request.path !== '/json') return yield* next;

  // this.response.body =
});
<commit_msg>finished 04-bodies<commit_after>var fs = require('fs');
var koa = require('koa');

var app = module.exports = koa();

//Bonus require 01-co stat function to get Content-Length

var stat = require('../01-co/index').stat;

/**
 * Create the `GET /stream` route that streams this file.
 * In node.js, the current file is available as a variable `__filename`.
 */

app.use(function * (next) {
	if (this.request.path !== '/stream') return yield * next;

	this.response.type = 'application/javascript';
	this.response.body = fs.createReadStream(__filename);
	this.response.length = (yield stat(__filename)).size;
});

/**
 * Create the `GET /json` route that sends `{message:'hello world'}`.
 */

app.use(function * (next) {
	if (this.request.path !== '/json') return yield * next;

	this.response.body = {
		message: 'hello world'
	};
});

app.listen(3000);<|endoftext|>


<commit_before>// ==UserScript==
// @name        0chan webm
// @namespace   https://0chan.hk/webm
// @description Replace external WebM links with video tag.
// @downloadURL https://raw.githubusercontent.com/Kagami/video-tools/master/0chan-webm.user.js
// @updateURL   https://raw.githubusercontent.com/Kagami/video-tools/master/0chan-webm.user.js
// @include     https://0chan.hk/*
// @include     http://nullchan7msxi257.onion/*
// @version     0.1.7
// @grant       GM_xmlhttpRequest
// @grant       unsafeWindow
// @connect     mixtape.moe
// @connect     u.nya.is
// @connect     a.safe.moe
// @connect     a.pomf.cat
// @connect     gfycat.com
// @connect     0x0.st
// ==/UserScript==

var THUMB_SIZE = 200;
var ALLOWED_HOSTS = [
  "[a-z0-9]+.mixtape.moe", "u.nya.is",
  "a.safe.moe", "a.pomf.cat",
  "[a-z]+.gfycat.com",
  "0x0.st",
];
var ALLOWED_LINKS = ALLOWED_HOSTS.map(function(host) {
  host = host.replace(/\./g, "\\.");
  return new RegExp("^https?://" + host + "/.+\\.(webm|mp4)$");
});

function makeThumbnail(screenshot) {
  return new Promise(function(resolve, reject) {
    var img = document.createElement("img");
    img.addEventListener("load", function () {
      var c = document.createElement("canvas");
      var ctx = c.getContext("2d");
      var arrow = "\u25B6";
      var circle = "\u26AB";
      var textWidth = 0;
      var textHeight = THUMB_SIZE / 4;
      if (img.width > img.height) {
        c.width = THUMB_SIZE;
        c.height = (img.height*THUMB_SIZE) / img.width;
      } else {
        c.width = (img.width*THUMB_SIZE) / img.height;
        c.height = THUMB_SIZE;
      }
      ctx.drawImage(img, 0, 0, c.width, c.height);
      ctx.font = textHeight + "px sans-serif";
      ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
      textWidth = ctx.measureText(circle).width;
      ctx.fillText(circle, c.width/2 - textWidth*0.55, c.height/2 + textHeight*0.45);
      textHeight /= 2;
      ctx.font = textHeight + "px sans-serif";
      ctx.fillStyle = "rgba(0, 0, 0, 0.8)";
      textWidth = ctx.measureText(arrow).width;
      ctx.fillText(arrow, c.width/2 - textWidth/2, c.height/2 + textHeight/2);
      resolve(c.toDataURL("image/png", 1.0));
    });
    img.addEventListener("error", reject);
    img.src = screenshot;
  });
}

function loadVideoDataFromURL(url) {
  return new Promise(function(resolve, reject) {
    GM_xmlhttpRequest({
      method: "GET",
      responseType: "blob",
      url: url,
      headers: {
        Range: "bytes=0-250000"  // Should be enough to get first frame
      },
      onload: function(response) {
        resolve(response.response);
      },
      onerror: function(e) {
        reject(e);
      },
    });
  });
}

function loadVideo(videoData) {
  return new Promise(function(resolve, reject) {
    var vid = document.createElement("video");
    vid.muted = true;
    vid.autoplay = false;
    vid.addEventListener("error", function() {
      // err.message is empty for these kind of errors.
      reject(new Error("failed to load video"));
    });
    vid.addEventListener("loadedmetadata", function() {
      resolve(vid);
    });
    vid.src = URL.createObjectURL(videoData);
  });
}

function getVideoScreenshot(vid) {
  var timePos = 0.0;
  return new Promise(function(resolve, reject) {
    var makeScreenshot = function() {
      var c = document.createElement("canvas");
      var ctx = c.getContext("2d");
      try {
        c.width = vid.videoWidth;
        c.height = vid.videoHeight;
        ctx.drawImage(vid, 0, 0, c.width, c.height);
      } catch (e) {
        reject(e);
        return;
      }
      resolve(c.toDataURL("image/png", 1.0));
    };
    if (vid.currentTime === timePos) {
      var HAVE_CURRENT_DATA = 2;
      var HAVE_METADATA = 1;
      if (vid.readyState >= HAVE_CURRENT_DATA) {
        makeScreenshot();
      } else if (vid.readyState === HAVE_METADATA) {
        vid.addEventListener("error", reject);
        vid.addEventListener("seeked", makeScreenshot);
        vid.currentTime = timePos;
      } else {
        reject(new Error("no video data"));
      }
    } else {
      vid.addEventListener("error", reject);
      vid.addEventListener("seeked", makeScreenshot);
      vid.currentTime = timePos;
    }
  });
}

function createVideoElement(link, thumbnail) {
  var div = document.createElement("div");
  div.className = "post-img";

  var vid = document.createElement("video");
  vid.style.display = "block";
  vid.style.maxWidth = "200px";
  vid.style.maxHeight = "350px";
  vid.style.cursor = "pointer";
  vid.poster = thumbnail;
  vid.preload = "none";
  vid.loop = true;
  vid.controls = false;
  vid.addEventListener("click", function() {
    if (vid.controls) {
      vid[vid.paused ? "play" : "pause"]();
    } else {
      close.style.display = "block";
      vid.style.maxWidth = "none";
      vid.controls = true;
      vid.play();
    }
  });
  vid.src = link.href;

  var close = document.createElement("div");
  var span = document.createElement("span");
  var i = document.createElement("i");
  close.className = "post-img-buttons";
  span.className = "post-img-button";
  i.className = "fa fa-times";
  close.style.display = "none";
  close.addEventListener("click", function() {
    close.style.display = "none";
    vid.controls = false;
    vid.style.maxWidth = "200px";
    vid.load();
  });

  div.appendChild(vid);
  span.appendChild(i);
  close.appendChild(span);
  div.appendChild(close);
  return div;
}

function embedVideo(link) {
  loadVideoDataFromURL(link.href)
    .then(loadVideo)
    .then(getVideoScreenshot)
    .then(makeThumbnail)
    .then(function(thumbnail) {
      var div = createVideoElement(link, thumbnail);
      link.parentNode.replaceChild(div, link);
    }).catch(function(err) {
      console.error("[0chan-webm] Failed to embed " + link.href +
                    " : " + err.message);
    });
}

function handlePost(post) {
  var links = post.querySelectorAll("a[target=_blank]");
  Array.prototype.filter.call(links, function(link) {
    return ALLOWED_LINKS.some(function(re) {
      return re.test(link.href);
    });
  }).forEach(embedVideo);
}

// TODO: Handle OP post.
function handleThread(container) {
  var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
      Array.prototype.filter.call(mutation.addedNodes, function(node) {
        return node.tagName === "DIV";
      }).forEach(handlePost);
    });
  });
  observer.observe(container, {childList: true});
  Array.prototype.forEach.call(container.children, handlePost);
}

unsafeWindow.webmHandler = exportFunction(function() {
  // TODO: Handle multiple threads.
  handleThread(document.querySelector(".thread-tree"));
}, unsafeWindow);

function handleApp(container) {
  // XXX: $bus is not yet available on DOMContentLoaded so wait for the
  // first mutation.
  var observer = new MutationObserver(function(mutations) {
    var app = unsafeWindow.app;
    if (!app.$bus) return;
    observer.disconnect();
    app.$bus.on("refreshContentDone", unsafeWindow.webmHandler);
  });
  observer.observe(container, {childList: true});
}

handleApp(document.body);
<commit_msg>[0chan-webm] 0.1.8<commit_after>// ==UserScript==
// @name        0chan webm
// @namespace   https://0chan.hk/webm
// @description Replace external WebM links with video tag.
// @downloadURL https://raw.githubusercontent.com/Kagami/video-tools/master/0chan-webm.user.js
// @updateURL   https://raw.githubusercontent.com/Kagami/video-tools/master/0chan-webm.user.js
// @include     https://0chan.hk/*
// @include     http://nullchan7msxi257.onion/*
// @version     0.1.8
// @grant       GM_xmlhttpRequest
// @grant       unsafeWindow
// @connect     mixtape.moe
// @connect     u.nya.is
// @connect     a.safe.moe
// @connect     a.pomf.cat
// @connect     gfycat.com
// @connect     0x0.st
// ==/UserScript==

var THUMB_SIZE = 200;
var ALLOWED_HOSTS = [
  "[a-z0-9]+.mixtape.moe", "u.nya.is",
  "a.safe.moe", "a.pomf.cat",
  "[a-z]+.gfycat.com",
  "0x0.st",
];
var ALLOWED_LINKS = ALLOWED_HOSTS.map(function(host) {
  host = host.replace(/\./g, "\\.");
  return new RegExp("^https?://" + host + "/.+\\.(webm|mp4)$");
});

function makeThumbnail(screenshot) {
  return new Promise(function(resolve, reject) {
    var img = document.createElement("img");
    img.addEventListener("load", function () {
      var c = document.createElement("canvas");
      var ctx = c.getContext("2d");
      var arrow = "\u25B6";
      var circle = "\u26AB";
      var textWidth = 0;
      var textHeight = THUMB_SIZE / 4;
      if (img.width > img.height) {
        c.width = THUMB_SIZE;
        c.height = (img.height*THUMB_SIZE) / img.width;
      } else {
        c.width = (img.width*THUMB_SIZE) / img.height;
        c.height = THUMB_SIZE;
      }
      ctx.drawImage(img, 0, 0, c.width, c.height);
      ctx.font = textHeight + "px sans-serif";
      ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
      textWidth = ctx.measureText(circle).width;
      ctx.fillText(circle, c.width/2 - textWidth*0.55, c.height/2 + textHeight*0.45);
      textHeight /= 2;
      ctx.font = textHeight + "px sans-serif";
      ctx.fillStyle = "rgba(0, 0, 0, 0.8)";
      textWidth = ctx.measureText(arrow).width;
      ctx.fillText(arrow, c.width/2 - textWidth/2, c.height/2 + textHeight/2);
      resolve(c.toDataURL("image/png", 1.0));
    });
    img.addEventListener("error", reject);
    img.src = screenshot;
  });
}

function loadVideoDataFromURL(url) {
  return new Promise(function(resolve, reject) {
    GM_xmlhttpRequest({
      method: "GET",
      responseType: "blob",
      url: url,
      headers: {
        Range: "bytes=0-250000"  // Should be enough to get first frame
      },
      onload: function(response) {
        resolve(response.response);
      },
      onerror: function(e) {
        reject(e);
      },
    });
  });
}

function loadVideo(videoData) {
  return new Promise(function(resolve, reject) {
    var vid = document.createElement("video");
    vid.muted = true;
    vid.autoplay = false;
    vid.addEventListener("error", function() {
      // err.message is empty for these kind of errors.
      reject(new Error("failed to load video"));
    });
    vid.addEventListener("loadedmetadata", function() {
      resolve(vid);
    });
    vid.src = URL.createObjectURL(videoData);
  });
}

function getVideoScreenshot(vid) {
  var timePos = 0.0;
  return new Promise(function(resolve, reject) {
    var makeScreenshot = function() {
      var c = document.createElement("canvas");
      var ctx = c.getContext("2d");
      try {
        c.width = vid.videoWidth;
        c.height = vid.videoHeight;
        ctx.drawImage(vid, 0, 0, c.width, c.height);
      } catch (e) {
        reject(e);
        return;
      }
      resolve(c.toDataURL("image/png", 1.0));
    };
    if (vid.currentTime === timePos) {
      var HAVE_CURRENT_DATA = 2;
      var HAVE_METADATA = 1;
      if (vid.readyState >= HAVE_CURRENT_DATA) {
        makeScreenshot();
      } else if (vid.readyState === HAVE_METADATA) {
        vid.addEventListener("error", reject);
        vid.addEventListener("seeked", makeScreenshot);
        vid.currentTime = timePos;
      } else {
        reject(new Error("no video data"));
      }
    } else {
      vid.addEventListener("error", reject);
      vid.addEventListener("seeked", makeScreenshot);
      vid.currentTime = timePos;
    }
  });
}

function createVideoElement(link, thumbnail) {
  var div = document.createElement("div");
  div.className = "post-img";

  var vid = document.createElement("video");
  vid.style.display = "block";
  vid.style.maxHeight = "350px";
  vid.style.cursor = "pointer";
  vid.poster = thumbnail;
  vid.preload = "none";
  vid.loop = true;
  vid.controls = false;
  vid.addEventListener("click", function() {
    if (!vid.controls) {
      close.style.display = "block";
      vid.controls = true;
      vid.play();
    }
  });
  vid.src = link.href;

  var close = document.createElement("div");
  var span = document.createElement("span");
  var i = document.createElement("i");
  close.className = "post-img-buttons";
  span.className = "post-img-button";
  i.className = "fa fa-times";
  close.style.display = "none";
  close.addEventListener("click", function() {
    close.style.display = "none";
    vid.controls = false;
    vid.src = link.href;
  });

  div.appendChild(vid);
  span.appendChild(i);
  close.appendChild(span);
  div.appendChild(close);
  return div;
}

function embedVideo(link) {
  loadVideoDataFromURL(link.href)
    .then(loadVideo)
    .then(getVideoScreenshot)
    .then(makeThumbnail)
    .then(function(thumbnail) {
      var div = createVideoElement(link, thumbnail);
      link.parentNode.replaceChild(div, link);
    }).catch(function(err) {
      console.error("[0chan-webm] Failed to embed " + link.href +
                    " : " + err.message);
    });
}

function handlePost(post) {
  var links = post.querySelectorAll("a[target=_blank]");
  Array.prototype.filter.call(links, function(link) {
    return ALLOWED_LINKS.some(function(re) {
      return re.test(link.href);
    });
  }).forEach(embedVideo);
}

// TODO: Handle OP post.
function handleThread(container) {
  var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
      Array.prototype.filter.call(mutation.addedNodes, function(node) {
        return node.tagName === "DIV";
      }).forEach(handlePost);
    });
  });
  observer.observe(container, {childList: true});
  Array.prototype.forEach.call(container.children, handlePost);
}

unsafeWindow.webmHandler = exportFunction(function() {
  // TODO: Handle multiple threads.
  handleThread(document.querySelector(".thread-tree"));
}, unsafeWindow);

function handleApp(container) {
  // XXX: $bus is not yet available on DOMContentLoaded so wait for the
  // first mutation.
  var observer = new MutationObserver(function(mutations) {
    var app = unsafeWindow.app;
    if (!app.$bus) return;
    observer.disconnect();
    app.$bus.on("refreshContentDone", unsafeWindow.webmHandler);
  });
  observer.observe(container, {childList: true});
}

handleApp(document.body);
<|endoftext|>