<commit_before>var app=getApp();
var BISUTIME=require("../../lib/bisutime");
//声明全局bisutime对象
var bisutime={};
// console.log(bisutime.getWeekth(),bisutime.getTime());
//全局语言索引，默认中文展示
var langIndex=wx.getStorageSync('langIndex')?wx.getStorageSync('langIndex'):0;
//全局语言属性数组
var langs=[
    {
        id:"zh",
        type:"default",
        name:"中文",
        title:"二外时间",
        loading:"玩命加载中"
    },
    {
        id:"en",
        type:"default",
        name:"English",
        title:"BISU TIME",
        loading:"loading"
    },
    {
        id:"jp",
        type:"default",
        name:"日本語",
        title:"二外タイム",
        loading:"お帰り"
    },
    {
        id:"ru",
        type:"default",
        name:"Русский",
        title:"Университетское время",
        loading:"погрузки"
    }
];
//加载提示
wx.showLoading({
    title:langs[langIndex].loading,
    mask:true
});
//远程配置
var config={};
//注册页面
Page({
    data:{
        btns:{}
    },
    onLoad:function(){
        //绑定setData
        var setData=this.setData.bind(this);
        //获取配置
        getConfig(function(res){
            //更新全局远程配置
            config=res;
            console.log('当前配置：',config);
            //设置公告
            setData({
                notification:config.notification
            });
            //声明起始日期
            var start=new Date;
            start.setHours(0);
            start.setMinutes(0);
            start.setSeconds(0);
            start.setFullYear(config.start.year);
            start.setDate(config.start.date);
            start.setMonth(config.start.month);
            console.log("本学期开始时间：%s",start);
            bisutime=new BISUTIME(start);
            //根据当前语言索引刷新界面
            refreshUI();
            //设置定时刷新时间显示
            setInterval(function(){
                setData({
                    content:getDisplay()
                });
            },1000);
            //关闭加载框
            wx.hideLoading();
        });
    },
    onShareAppMessage:function(){
        return {
            title:langs[langIndex].title,
            path:"/pages/index/index"
        }
    },
    //切换语言
    changeLang:function(e){
        // console.log(e);
        var checkedlan=e.currentTarget.id;
        //找出选中语言的index
        for(var i=0;i<langs.length;i++){
            if(checkedlan==langs[i].id){
                break;
            }
        }
        //设置当前语言索引
        langIndex=i;
        //刷新视图
        refreshUI();

    },
    //随机切换图片
    changeImg:function(){
        this.setData({
            image:getImg()
        });
    }
});

//根据当前语言索引，设置对应语言type为primary,并刷新试图
function refreshUI(){
    var currentPages=getCurrentPages();
    var currentPage=currentPages[currentPages.length-1];
    for(var i=0;i<langs.length;i++ ){
        if(i==langIndex){
            langs[i].type="primary";
        }else{
            langs[i].type="default";
        }
    }
    //保存语言索引到缓存
    wx.setStorageSync('langIndex', langIndex);
    //刷新界面语言
    currentPage.setData({
        btns:langs,
        content:getDisplay(),
        image:getImg()
    });
    //刷新导航条标题
    wx.setNavigationBarTitle({
        title:langs[langIndex].title
    });
}

//根据语言显示content展示内容
function getDisplay(){
    var res=[];
    var now=new Date;
    var lan=langs[langIndex].id;
    //星期几 映射表
    var dayNames={
        zh:['星期一','星期二','星期三','星期四','星期五','星期六','星期日'],
        en:['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'],
        jp:['月曜日','火曜日','水曜日','木曜日','金曜日','土曜日','日曜日'],
        ru:["Понедельник","вторник","среда","четверг","пятница","суббота","воскресенье"]
    };
    //序数词映射表
    var ordinal=["first","second","third","fourth","fifth","sixth","seventh","eighth","ninth","tenth","eleventh","twelfth","thirteenth","fourteenth","fifteenth","sixteenth","seventeenth","eighteenth","nineteenth","twentieth","twenty-first","twenty-second","twenty-third","twenty-forth","twenty-fifth","twenty-sixth","twenty-seventh","twenty-eighth","twenty-ninth","thirtieth","thirty-first"];
    var dayIndex=bisutime.getDay()-1;
    var time=bisutime.getTime();
    var weekth=bisutime.getWeekth();
    if(lan=='en'){
        //英语序数需要特殊处理
        time=ordinal[time-1];
        weekth=ordinal[weekth-1];
        var before=ordinal[parseInt(time)-1];
        var next=ordinal[parseInt(time)];
    }else{
        var before=parseInt(time);
        var next=parseInt(time)+1;
    }
    var next_time=formatHM(bisutime.getNext());
    //构建tokens
    var tokens={
        day:dayNames[langs[langIndex].id][dayIndex],
        weekth:weekth,
        next_time:next_time,
        before:before,
        next:next,
        time:time
    };
    res.push(parseFormat({flag:"day",tokens}));
    if(bisutime.getWeekth()>17){
        //放寒暑假
        res.push(parseFormat({flag:"holiday",tokens}));
        return res.join("\n");
    }
    //没有放假，上课期间
    res.push(parseFormat({flag:"weekth",tokens}));
    if (dayIndex>=5) {
        //周末
        if(dayIndex==6){
            //星期天
            res.push(parseFormat({flag:"sunday",tokens}));
        }else{
            //星期六
            res.push(parseFormat({flag:"saturday",tokens}));
        }
        return res,join("\n");
    }
    if (bisutime.getTime()<=0) {
        //还未上课
        res.push(parseFormat({flag:"morning",tokens}));
        return res.join("\n");
    }else if (bisutime.getTime()>0 && bisutime.getTime()<=12 && parseInt(bisutime.getTime())==bisutime.getTime()) {
        //上课中
        res.push(parseFormat({flag:"lesson",tokens}));
        return res;
    }else if(bisutime.getTime()>12){
        //放学
        res.push(parseFormat({flag:"evening",tokens}));
        if(dayIndex==4){
            //星期五
            res.push(parseFormat({flag:"friday",tokens}));
        }else{
            //非周五要断电
            res.push(parseFormat({flag:"notfriday",tokens}));
        }
        return res.join("\n");
    }else if(bisutime.getTime()==5.5){
        //午饭
        res.push(parseFormat({flag:"noon",tokens}));
        return res.join("\n");
    }else if(bisutime.getTime()==10.5){
        //晚饭
        res.push(parseFormat({flag:"dinner",tokens}));
        return res.join("\n");
    }else{
        //课间休息时间
        res.push(parseFormat({flag:"break",tokens}));
        return res.join("\n");
    }
    return 'hello bisutime';
}

//从全局config对象中随机返回一个图片对象，{src:xx,photographer:xx}
function getImg(){
    var imgs=config.imgs;
    var index=parseInt(Math.random()*imgs.length);
    return imgs[index];
}
//更具语言格式化时间 xx小时xx分钟 或者 xx分钟，需要提供一个HM{hours:xx,mins:xx}对象
function formatHM(hm){
    var lan=langs[langIndex].id;
    var hours={
        "zh":"小时",
        "en":" hours",
        "jp":"時",
        "ru":"ч."
    };
    var mins={
        "zh":"分钟",
        "en":" mins",
        "jp":"分間",
        "ru":" мин."
    };
    if(hm.hours){
        if(hm.mins){
            if(lan=='en' || lan=='ru'){
                //英语和俄语有空格
                return hm.hours+hours[lan]+" "+hm.mins+mins[lan];
            }else{
                return hm.hours+hours[lan]+hm.mins+mins[lan];
            }
        }else{
            if(lan=='jp'){
                //日语要特殊出里
                return hm.hours+hours[lan]+"間";
            }else{
                return hm.hours+hours[lan];
            }
        }
    }else{
        return hm.mins+mins[lan];
    }
}

//获取远程配置并储存到Storage['config']中，结果传递到callback中
function getConfig(callback){
    var config={};
    wx.request({
        url:app.data.server+'config.json',
        success:function(res){
            // console.log(res);
            if (res.statusCode==200) {
                //微信貌似会自动转换json对象
                config=typeof(res.data)=='object'?res.data:JSON.parse(res.data);
                //写入缓存
                wx.setStorageSync('config',config);
            }else{
                //返回缓存
                config=wx.getStorageSync('config');

            }
        },
        fail:function(){
            config=wx.getStorageSync('config');
        },
        complete:function(){
            callback(config);
        }
    });
}

/*根据当前语言环境解析时间格式
*传入一个{flag:xx,tokens:{token1:xx,token2:xx}}对象
*tokens属性非必需
*/
function parseFormat(data){
    var lan=langs[langIndex].id;
    if(data.hasOwnProperty('tokens')){
        //需要处理token
        var tokens=data.tokens;
        var flag=data.flag;
        var res=config.format[flag][lan];
        for(var token in tokens){
            var regexp=new RegExp("{{"+token+"}}","g");
            res=res.replace(regexp,tokens[token]);
        }
        return res;
    }else{
        //不需要处理token
        return config.format[flag][lan];
    }
}<commit_msg>上传v0.1.0版本<commit_after>var app=getApp();
var BISUTIME=require("../../lib/bisutime");
//声明全局bisutime对象
var bisutime={};
// console.log(bisutime.getWeekth(),bisutime.getTime());
//全局语言索引，默认中文展示
var langIndex=wx.getStorageSync('langIndex')?wx.getStorageSync('langIndex'):0;
//全局语言属性数组
var langs=[
    {
        id:"zh",
        type:"default",
        name:"中文",
        title:"二外时间",
        loading:"玩命加载中"
    },
    {
        id:"en",
        type:"default",
        name:"English",
        title:"BISU TIME",
        loading:"loading"
    },
    {
        id:"jp",
        type:"default",
        name:"日本語",
        title:"二外タイム",
        loading:"お帰り"
    },
    {
        id:"ru",
        type:"default",
        name:"Русский",
        title:"Университетское время",
        loading:"погрузки"
    }
];
//加载提示
wx.showLoading({
    title:langs[langIndex].loading,
    mask:true
});
//远程配置
var config={};
//注册页面
Page({
    data:{
        btns:{}
    },
    onLoad:function(){
        //绑定setData
        var setData=this.setData.bind(this);
        //获取配置
        getConfig(function(res){
            //更新全局远程配置
            config=res;
            console.log('当前配置：',config);
            //设置公告
            setData({
                notification:config.notification
            });
            //声明起始日期
            var start=new Date;
            start.setHours(0);
            start.setMinutes(0);
            start.setSeconds(0);
            start.setFullYear(config.start.year);
            start.setDate(config.start.date);
            start.setMonth(config.start.month);
            console.log("本学期开始时间：%s",start);
            bisutime=new BISUTIME(start);
            //根据当前语言索引刷新界面
            refreshUI();
            //设置定时刷新时间显示
            setInterval(function(){
                setData({
                    content:getDisplay()
                });
            },1000);
            //关闭加载框
            wx.hideLoading();
        });
    },
    onShareAppMessage:function(){
        return {
            title:langs[langIndex].title,
            path:"/pages/index/index"
        }
    },
    //切换语言
    changeLang:function(e){
        // console.log(e);
        var checkedlan=e.currentTarget.id;
        //找出选中语言的index
        for(var i=0;i<langs.length;i++){
            if(checkedlan==langs[i].id){
                break;
            }
        }
        //设置当前语言索引
        langIndex=i;
        //刷新视图
        refreshUI();

    },
    //随机切换图片
    changeImg:function(){
        this.setData({
            image:getImg()
        });
    }
});

//根据当前语言索引，设置对应语言type为primary,并刷新试图
function refreshUI(){
    var currentPages=getCurrentPages();
    var currentPage=currentPages[currentPages.length-1];
    for(var i=0;i<langs.length;i++ ){
        if(i==langIndex){
            langs[i].type="primary";
        }else{
            langs[i].type="default";
        }
    }
    //保存语言索引到缓存
    wx.setStorageSync('langIndex', langIndex);
    //刷新界面语言
    currentPage.setData({
        btns:langs,
        content:getDisplay(),
        image:getImg()
    });
    //刷新导航条标题
    wx.setNavigationBarTitle({
        title:langs[langIndex].title
    });
}

//根据语言显示content展示内容
function getDisplay(){
    var res=[];
    var now=new Date;
    var lan=langs[langIndex].id;
    //星期几 映射表
    var dayNames={
        zh:['星期一','星期二','星期三','星期四','星期五','星期六','星期日'],
        en:['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'],
        jp:['月曜日','火曜日','水曜日','木曜日','金曜日','土曜日','日曜日'],
        ru:["Понедельник","вторник","среда","четверг","пятница","суббота","воскресенье"]
    };
    //序数词映射表
    var ordinal=["first","second","third","fourth","fifth","sixth","seventh","eighth","ninth","tenth","eleventh","twelfth","thirteenth","fourteenth","fifteenth","sixteenth","seventeenth","eighteenth","nineteenth","twentieth","twenty-first","twenty-second","twenty-third","twenty-forth","twenty-fifth","twenty-sixth","twenty-seventh","twenty-eighth","twenty-ninth","thirtieth","thirty-first"];
    var dayIndex=bisutime.getDay()-1;
    var time=bisutime.getTime();
    var weekth=bisutime.getWeekth();
    var before=parseInt(time);
    var next=parseInt(time)+1;
    if(lan=='en'){
        //英语序数需要特殊处理
        var before=ordinal[parseInt(time)-1];
        var next=ordinal[parseInt(time)];
        time=ordinal[time-1];
        weekth=ordinal[weekth-1];
    }
    var next_time=formatHM(bisutime.getNext());
    //构建tokens
    var tokens={
        day:dayNames[langs[langIndex].id][dayIndex],
        weekth:weekth,
        next_time:next_time,
        before:before,
        next:next,
        time:time
    };
    res.push(parseFormat({flag:"day",tokens}));
    if(bisutime.getWeekth()>17){
        //放寒暑假
        res.push(parseFormat({flag:"holiday",tokens}));
        return res.join("\n");
    }
    //没有放假，上课期间
    res.push(parseFormat({flag:"weekth",tokens}));
    if (dayIndex>=5) {
        //周末
        if(dayIndex==6){
            //星期天
            res.push(parseFormat({flag:"sunday",tokens}));
        }else{
            //星期六
            res.push(parseFormat({flag:"saturday",tokens}));
        }
        return res,join("\n");
    }
    if (bisutime.getTime()<=0) {
        //还未上课
        res.push(parseFormat({flag:"morning",tokens}));
        return res.join("\n");
    }else if (bisutime.getTime()>0 && bisutime.getTime()<=12 && parseInt(bisutime.getTime())==bisutime.getTime()) {
        //上课中
        res.push(parseFormat({flag:"lesson",tokens}));
        return res.join("\n");
    }else if(bisutime.getTime()>12){
        //放学
        res.push(parseFormat({flag:"evening",tokens}));
        if(dayIndex==4){
            //星期五
            res.push(parseFormat({flag:"friday",tokens}));
        }else{
            //非周五要断电
            res.push(parseFormat({flag:"notfriday",tokens}));
        }
        return res.join("\n");
    }else if(bisutime.getTime()==5.5){
        //午饭
        res.push(parseFormat({flag:"noon",tokens}));
        return res.join("\n");
    }else if(bisutime.getTime()==10.5){
        //晚饭
        res.push(parseFormat({flag:"dinner",tokens}));
        return res.join("\n");
    }else{
        //课间休息时间
        res.push(parseFormat({flag:"break",tokens}));
        return res.join("\n");
    }
    return 'hello bisutime';
}

//从全局config对象中随机返回一个图片对象，{src:xx,photographer:xx}
function getImg(){
    var imgs=config.imgs;
    var index=parseInt(Math.random()*imgs.length);
    return imgs[index];
}
//更具语言格式化时间 xx小时xx分钟 或者 xx分钟，需要提供一个HM{hours:xx,mins:xx}对象
function formatHM(hm){
    var lan=langs[langIndex].id;
    var hours={
        "zh":"小时",
        "en":" hours",
        "jp":"時",
        "ru":"ч."
    };
    var mins={
        "zh":"分钟",
        "en":" mins",
        "jp":"分間",
        "ru":" мин."
    };
    if(hm.hours){
        if(hm.mins){
            if(lan=='en' || lan=='ru'){
                //英语和俄语有空格
                return hm.hours+hours[lan]+" "+hm.mins+mins[lan];
            }else{
                return hm.hours+hours[lan]+hm.mins+mins[lan];
            }
        }else{
            if(lan=='jp'){
                //日语要特殊出里
                return hm.hours+hours[lan]+"間";
            }else{
                return hm.hours+hours[lan];
            }
        }
    }else{
        return hm.mins+mins[lan];
    }
}

//获取远程配置并储存到Storage['config']中，结果传递到callback中
function getConfig(callback){
    var config={};
    wx.request({
        url:app.data.server+'config.json',
        success:function(res){
            // console.log(res);
            if (res.statusCode==200) {
                //微信貌似会自动转换json对象
                config=typeof(res.data)=='object'?res.data:JSON.parse(res.data);
                //写入缓存
                wx.setStorageSync('config',config);
            }else{
                //返回缓存
                config=wx.getStorageSync('config');

            }
        },
        fail:function(){
            config=wx.getStorageSync('config');
        },
        complete:function(){
            callback(config);
        }
    });
}

/*根据当前语言环境解析时间格式
*传入一个{flag:xx,tokens:{token1:xx,token2:xx}}对象
*tokens属性非必需
*/
function parseFormat(data){
    var lan=langs[langIndex].id;
    if(data.hasOwnProperty('tokens')){
        //需要处理token
        var tokens=data.tokens;
        var flag=data.flag;
        var res=config.format[flag][lan];
        for(var token in tokens){
            var regexp=new RegExp("{{"+token+"}}","g");
            res=res.replace(regexp,tokens[token]);
        }
        return res;
    }else{
        //不需要处理token
        return config.format[flag][lan];
    }
}<|endoftext|>


<commit_before>"use strict";
let vscode = require('vscode');
let linters = require('./lint/lint');
const severities = {
	refactor: vscode.DiagnosticSeverity.Hint,
	convention: vscode.DiagnosticSeverity.Information,
	info: vscode.DiagnosticSeverity.Information,
	warning: vscode.DiagnosticSeverity.Warning,
	error: vscode.DiagnosticSeverity.Error,
	fatal: vscode.DiagnosticSeverity.Error
};
let timer;

function deferReport(uri, lint, diagnostic) {
	if (lint.error) {
		console.log("Linter error:", lint.source, lint.error);
		return;
	}
	if ((!lint.result || !lint.result.length) && (!lint.lintError || !lint.lintError.length)) return;
	let allOf = lint.result.concat(lint.lintError)
		.map(offense => {
			let tail = offense.location.column + offense.location.length;
			let d = new vscode.Diagnostic(new vscode.Range(
					offense.location.line - 1, offense.location.column - 1,
					offense.location.line - 1, tail - 1),
				offense.message, severities[offense.severity] || vscode.DiagnosticSeverity.Error);
			d.source = offense.cop_name || lint.linter;
			return d;
		});
	diagnostic.set(uri, allOf);
}

const langConfig = {
	comments: {
		lineComment: "#",
		blockComment: ["=begin", "=end"]
	},
	brackets: [
		["{", "}"],
		["[", "]"],
		["(", ")"]
	],
	indentationRules: {
		increaseIndentPattern: /^\s*((begin|class|def|else|elsif|ensure|for|if|module|rescue|unless|until|when|while)|(.*\sdo\b))\b[^\{;]*$/
	},
	wordPattern: /(-?\d+(?:\.\d+))|(:?[A-Za-z][^-`~@#%^&()=+[{}|;:'",<>/\]\.\*\s\\!?]+[!?]?)/
};

let pairedEnds = [];

const highligher = {
	provideDocumentHighlights: (doc, pos) => {
		const word = doc.getText(doc.getWordRangeAtPosition(pos));
		let result;
		if (
			(/\b(begin|class|def|for|if|module|unless|until|case|while|do)\b/.test(doc.lineAt(pos.line)
					.text) &&
				pairedEnds.some(pair => (result = (pair.entry.start.line === pos.line) ? pair : null))) ||
			(word === 'end' && pairedEnds.some(pair => (result = (pair.end.start.line === pos.line) ? pair : null)))
		) {
			return [new vscode.DocumentHighlight(result.entry,2), new vscode.DocumentHighlight(result.end,2)];
		}
	}
};

function getEnd(line) {
	//end must be on a line by itself, or followed directly by a dot
	let match = line.text.match(/^(\s*)(end|(end\..*))\s*$/);
	if (match) {
		return new vscode.Range(line.lineNumber, match[1].length, line.lineNumber, match[1].length + 3);
	}
}

function getEntry(line) {
	//only lines that start with the entry
	let match = line.text.match(/^(\s*)(begin|class|def|for|if|module|unless|until|case|while)\b[^\{;]*$/);
	if (match) {
		return new vscode.Range(line.lineNumber, match[1].length, line.lineNumber, match[1].length + match[2].length);
	} else {
		//check for do
		match = line.text.match(/\b(do)\b\s*(\|.*\|[^;]*)?$/);
		if (match) {
			return new vscode.Range(line.lineNumber, match.index, line.lineNumber, match.index + 2);
		}
	}
}

function balancePairs(doc) {
	pairedEnds = [];
	if (doc.languageId !== 'ruby') return;

	let waitingEntries = [];
	let entry, end;
	for (let i = 0; i < doc.lineCount; i++) {
		if ((entry = getEntry(doc.lineAt(i)))) {
			waitingEntries.push(entry);
		} else if (waitingEntries.length && (end = getEnd(doc.lineAt(i)))) {
			pairedEnds.push({
				entry: waitingEntries.pop(),
				end: end
			});
		}
	}
}

function balanceEvent(event) {
	pairedEnds = [];
	if (event && event.document) balancePairs(event.document);
}

function activate(context) {
	//add language config
	vscode.languages.setLanguageConfiguration('ruby', langConfig);

	let activeLinters = {};
	let linterTimers = {};
	let activeDiagnostics = {};

	function changeTrigger(changed) {
		timer = process.hrtime();
		if (!changed || !changed.document) return;
		if (changed.document.languageId !== 'ruby') return;

		const doc = changed.document;
		let lintConfig = vscode.workspace.getConfiguration("ruby.lint");

		if (lintConfig) {
			clearTimeout(linterTimers[doc.fileName]);

			if (activeLinters[doc.fileName]) {
				try {
					activeLinters[doc.fileName].send('stop');
				} catch (e) {}
				delete activeLinters[doc.fileName];
			}
			linterTimers[doc.fileName] = setTimeout(() => {
				activeLinters[doc.fileName] = linters.runCollection(lintConfig, doc.fileName, doc.getText(), result => {
					if (!activeDiagnostics[result.linter]) {
						activeDiagnostics[result.linter] = vscode.languages.createDiagnosticCollection(result.linter);
						context.subscriptions.push(activeDiagnostics[result.linter]);
					}
					activeDiagnostics[result.linter].delete(doc.uri);
					deferReport(doc.uri, result, activeDiagnostics[result.linter]);
				});
			}, 200);
		}
	}
	context.subscriptions.push(vscode.languages.registerDocumentHighlightProvider('ruby', highligher));

	context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(changeTrigger));
	context.subscriptions.push(vscode.workspace.onDidChangeTextDocument(changeTrigger));
	context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(
		() => vscode.window.visibleTextEditors.forEach(changeTrigger)));

	vscode.window.visibleTextEditors.forEach(changeTrigger);

	context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(balanceEvent));
	context.subscriptions.push(vscode.workspace.onDidChangeTextDocument(balanceEvent));
	context.subscriptions.push(vscode.workspace.onDidOpenTextDocument(balancePairs));

	balancePairs(vscode.window.activeTextEditor.document);

}

exports.activate = activate;
<commit_msg>remove unnecessary tests, tidy wordPattern<commit_after>"use strict";
let vscode = require('vscode');
let linters = require('./lint/lint');
const severities = {
	refactor: vscode.DiagnosticSeverity.Hint,
	convention: vscode.DiagnosticSeverity.Information,
	info: vscode.DiagnosticSeverity.Information,
	warning: vscode.DiagnosticSeverity.Warning,
	error: vscode.DiagnosticSeverity.Error,
	fatal: vscode.DiagnosticSeverity.Error
};
let timer;

function deferReport(uri, lint, diagnostic) {
	if (lint.error) {
		console.log("Linter error:", lint.source, lint.error);
		return;
	}
	if ((!lint.result || !lint.result.length) && (!lint.lintError || !lint.lintError.length)) return;
	let allOf = lint.result.concat(lint.lintError)
		.map(offense => {
			let tail = offense.location.column + offense.location.length;
			let d = new vscode.Diagnostic(new vscode.Range(
					offense.location.line - 1, offense.location.column - 1,
					offense.location.line - 1, tail - 1),
				offense.message, severities[offense.severity] || vscode.DiagnosticSeverity.Error);
			d.source = offense.cop_name || lint.linter;
			return d;
		});
	diagnostic.set(uri, allOf);
}

const langConfig = {
	comments: {
		lineComment: "#",
		blockComment: ["=begin", "=end"]
	},
	brackets: [
		["{", "}"],
		["[", "]"],
		["(", ")"]
	],
	indentationRules: {
		increaseIndentPattern: /^\s*((begin|class|def|else|elsif|ensure|for|if|module|rescue|unless|until|when|while)|(.*\sdo\b))\b[^\{;]*$/
	},
	wordPattern: /(-?\d+(?:\.\d+))|(:?[A-Za-z][^-`~@#%^&()=+[{}|;:'",<>/.*\]\s\\!?]*[!?]?)/
};

let pairedEnds = [];

const highligher = {
	provideDocumentHighlights: (doc, pos) => {
		let result = pairedEnds.find(pair => (
			pair.entry.start.line === pos.line ||
			pair.end.start.line === pos.line));
		if (result) {
			return [new vscode.DocumentHighlight(result.entry, 2), new vscode.DocumentHighlight(result.end, 2)];
		}
	}
};

function getEnd(line) {
	//end must be on a line by itself, or followed directly by a dot
	let match = line.text.match(/^(\s*)end\b[\.\s#]?\s*$/);
	if (match) {
		return new vscode.Range(line.lineNumber, match[1].length, line.lineNumber, match[1].length + 3);
	}
}

function getEntry(line) {
	//only lines that start with the entry
	let match = line.text.match(/^(\s*)(begin|class|def|for|if|module|unless|until|case|while)\b[^\{;]*$/);
	if (match) {
		return new vscode.Range(line.lineNumber, match[1].length, line.lineNumber, match[1].length + match[2].length);
	} else {
		//check for do
		match = line.text.match(/\b(do)\b\s*(\|.*\|[^;]*)?$/);
		if (match) {
			return new vscode.Range(line.lineNumber, match.index, line.lineNumber, match.index + 2);
		}
	}
}

function balancePairs(doc) {
	pairedEnds = [];
	if (doc.languageId !== 'ruby') return;

	let waitingEntries = [];
	let entry, end;
	for (let i = 0; i < doc.lineCount; i++) {
		if ((entry = getEntry(doc.lineAt(i)))) {
			waitingEntries.push(entry);
		} else if (waitingEntries.length && (end = getEnd(doc.lineAt(i)))) {
			pairedEnds.push({
				entry: waitingEntries.pop(),
				end: end
			});
		}
	}
}

function balanceEvent(event) {
	pairedEnds = [];
	if (event && event.document) balancePairs(event.document);
}

function activate(context) {
	//add language config
	vscode.languages.setLanguageConfiguration('ruby', langConfig);

	let activeLinters = {};
	let linterTimers = {};
	let activeDiagnostics = {};

	function changeTrigger(changed) {
		timer = process.hrtime();
		if (!changed || !changed.document) return;
		if (changed.document.languageId !== 'ruby') return;

		const doc = changed.document;
		let lintConfig = vscode.workspace.getConfiguration("ruby.lint");

		if (lintConfig) {
			clearTimeout(linterTimers[doc.fileName]);

			if (activeLinters[doc.fileName]) {
				try {
					activeLinters[doc.fileName].send('stop');
				} catch (e) {}
				delete activeLinters[doc.fileName];
			}
			linterTimers[doc.fileName] = setTimeout(() => {
				activeLinters[doc.fileName] = linters.runCollection(lintConfig, doc.fileName, doc.getText(), result => {
					if (!activeDiagnostics[result.linter]) {
						activeDiagnostics[result.linter] = vscode.languages.createDiagnosticCollection(result.linter);
						context.subscriptions.push(activeDiagnostics[result.linter]);
					}
					activeDiagnostics[result.linter].delete(doc.uri);
					deferReport(doc.uri, result, activeDiagnostics[result.linter]);
				});
			}, 200);
		}
	}
	context.subscriptions.push(vscode.languages.registerDocumentHighlightProvider('ruby', highligher));

	context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(changeTrigger));
	context.subscriptions.push(vscode.workspace.onDidChangeTextDocument(changeTrigger));
	context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(
		() => vscode.window.visibleTextEditors.forEach(changeTrigger)));

	vscode.window.visibleTextEditors.forEach(changeTrigger);

	context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(balanceEvent));
	context.subscriptions.push(vscode.workspace.onDidChangeTextDocument(balanceEvent));
	context.subscriptions.push(vscode.workspace.onDidOpenTextDocument(balancePairs));
	if (vscode.window && vscode.window.activeTextEditor) {
		balancePairs(vscode.window.activeTextEditor.document);
	}

}

exports.activate = activate;
<|endoftext|>


<commit_before>// @ts-nocheck
import React from 'react'
import { Component } from 'react'
import * as PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { isEmpty, debounce } from 'lodash'
import { Icon } from '../../components'
import Autosuggest from 'react-autosuggest'
import Modal from 'antd/lib/modal'
import 'antd/lib/modal/style/index.less'
import Button from 'antd/lib/button'
import 'antd/lib/button/style/index.less'
import Checkbox from 'antd/lib/checkbox'
import 'antd/lib/checkbox/style/index.less'
import Form from 'antd/lib/form'
import 'antd/lib/form/style/'
import Input from 'antd/lib/input'
import 'antd/lib/input/style/'

import {
  handleNewLanguageDisplay,
  handleLoadSuggestion,
  handleSaveNewLanguage
} from '../../actions/languages-actions'

class NewLanguageModal extends Component {
  static propTypes = {
    show: PropTypes.bool,
    saving: PropTypes.bool,
    searchResults: PropTypes.array,
    handleOnClose: PropTypes.func,
    handleOnSave: PropTypes.func,
    loadSuggestion: PropTypes.func,
    form: PropTypes.any
  }

  constructor (props) {
    super(props)
    this.state = {
      details: {
        enabledByDefault: true,
        enabled: true,
        displayName: '',
        nativeName: '',
        pluralForms: ''
      },
      query: '',
      validFields: true,
      suggestions: props.searchResults
    }
  }

  handleCancel = () => {
    this.resetFields()
    this.props.handleOnClose()
  }

  resetFields = () => {
    this.setState({
      details: {
        enabledByDefault: true,
        enabled: true,
        displayName: '',
        nativeName: '',
        pluralForms: ''
      },
      validFields: true,
      suggestions: [],
      query: ''
    })
  }

  updateField = (field, e) => {
    const value = e.target.value
    this.props.form.setFieldsValue({
      [field]: value
    })
    this.setState(prevState => ({
      details: {
        ...prevState.details,
        [field]: value
      }
    }))
  }

  updateCheckbox = (field) => {
    this.setState(prevState => ({
      details: {
        ...prevState.details,
        [field]: !prevState.details[field]
      }
    }))
  }

  validateDetails = () => {
    const displayName = this.state.details.displayName
    const query = this.state.query
    if (isEmpty(displayName) && isEmpty(query)) {
      this.setState({
        validFields: false
      })
    } else {
      const details = {
        ...this.state.details,
        localeId: query.replace('_', '-')
      }
      this.props.handleOnSave(details)
      this.resetFields()
    }
  }

  onSearchChange = (event, { newValue }) => {
    this.setState({
      query: newValue
    })
  }

  onSuggestionsClearRequested = () => {
  }

  getSuggestionValue = (selectedLocale) => {
    return selectedLocale.localeId
  }

  renderSuggestion = (suggestion) => {
    return (

          {suggestion.displayName}

          {suggestion.localeId}

    )
  }

  onSuggestionSelected = (event, {
     suggestion, suggestionValue, sectionIndex, method }) => {
    // eslint-disable-next-line
    const { enabled, enabledByDefault, rtl, localeId, ...fieldValues } =
      suggestion
    this.props.form.setFieldsValue({ ...fieldValues })
    this.setState({
      details: {
        ...suggestion,
        enabledByDefault: true,
        enabled: true
      }
    })
  }

  /* eslint-disable react/jsx-no-bind, react/jsx-boolean-value */
  render () {
    const {show, saving, loadSuggestion, searchResults} = this.props
    const { details, query } = this.state
    const { getFieldDecorator } = this.props.form
    const inputProps = {
      placeholder: 'Search for languages',
      maxLength: 256,
      onChange: this.onSearchChange,
      value: query
    }

    const showPluralFormsWarning = isEmpty(searchResults) && !isEmpty(query)

    return (
      <Modal
        width={'48rem'}
        title={'Add a new language'}
        id='newLang'
        visible={show}
        onCancel={this.handleCancel}
        footer={[
          <Button
            key='back'
            aria-label='button'
            id='btn-new-language-cancel'
            disabled={saving}
            onClick={this.handleCancel}>
            Close
          </Button>,
          <Button
            key='ok'
            aria-label='button'
            loading={saving}
            disabled={(isEmpty(query) || isEmpty(details.nativeName) ||
              isEmpty(details.displayName || isEmpty(details.pluralForms)))}
            id='btn-new-language-save'
            type='primary'
            onClick={this.validateDetails}>
            Save
          </Button>
        ]}>
        <Form layout='vertical'>
          <Form.Item label={'Language Code'} title={'Language Code'}>
            <Autosuggest
              name='new-language-code'
              suggestions={searchResults}
              onSuggestionSelected={this.onSuggestionSelected}
              getSuggestionValue={this.getSuggestionValue}
              onSuggestionsFetchRequested={loadSuggestion}
              onSuggestionsClearRequested={this.onSuggestionsClearRequested}
              renderSuggestion={this.renderSuggestion}
              inputProps={inputProps}
            />
          </Form.Item>
          <Form.Item label={'Name'} title={'Name'}>
            {getFieldDecorator('displayName', {
              setFieldsInitialValue: details.displayName,
              rules: [{required: true,
                message: 'Please input a Language Display Name'}]
            })(
              <Input
                // id='displayName' set by getFieldDecorator
                maxLength={100}
                onChange={(e) => this.updateField('displayName', e)}
                placeholder='Display name' />
            )}
          </Form.Item>
          <Form.Item label={'Native Name'} title={'Native Name'}>
            {getFieldDecorator('nativeName', {
              setFieldsInitialValue: details.nativeName,
              rules: [{required: true,
                message: 'Please input a Language Native Name'}]
            })(
              <Input
                // id='nativeName' set by getFieldDecorator
                maxLength={100}
                onChange={(e) => this.updateField('nativeName', e)}
                placeholder='Native name' />
            )}
          </Form.Item>
          <Form.Item
            title={'Plural Forms'}
            label={
              Plural forms {' '}

                  <Icon name='info' className='s0' parentClassName='iconInfo'
                    title='Help' />

                {showPluralFormsWarning &&

                    No plural information available. Assuming no plurals.

                }
              }>
              {getFieldDecorator('pluralForms', {
                setFieldsInitialValue: details.pluralForms,
                rules: [{required: true,
                  message: 'Please input the languages Plural Forms'}]
              })(
                <Input
                  maxLength={255}
                  onChange={(e) => this.updateField('pluralForms', e)}
                  placeholder='Plural forms' />
              )}
          </Form.Item>
          <Form.Item>
            <Checkbox
              id='chk-new-language-enabled'
              onChange={() => this.updateCheckbox('enabledByDefault')}
              checked={details.enabledByDefault}>
              Enabled by default
            </Checkbox>
            <Checkbox
              onChange={() => this.updateCheckbox('enabled')}
              checked={details.enabled}>
              Enabled language
            </Checkbox>
          </Form.Item>
        </Form>
      </Modal>
    )
    /* eslint-enable react/jsx-no-bind, react/jsx-boolean-value */
  }
}

const mapStateToProps = (state) => {
  const {
    show,
    saving,
    searchResults
  } = state.languages.newLanguage
  return {
    show,
    saving,
    searchResults
  }
}

const mapDispatchToProps = (dispatch) => {
  const updateSuggestion = debounce((val) =>
    dispatch(handleLoadSuggestion(val)), 300)

  return {
    handleOnClose: () => {
      dispatch(handleNewLanguageDisplay(false))
    },
    handleOnSave: (details) => {
      dispatch(handleSaveNewLanguage(details))
    },
    loadSuggestion: (query) => {
      updateSuggestion(query.value)
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(
  Form.create()(NewLanguageModal))
<commit_msg>fix(ZNTA-2608): reset new language form fields on close or submit (#885)<commit_after>// @ts-nocheck
import React from 'react'
import { Component } from 'react'
import * as PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { isEmpty, debounce } from 'lodash'
import { Icon } from '../../components'
import Autosuggest from 'react-autosuggest'
import Modal from 'antd/lib/modal'
import 'antd/lib/modal/style/index.less'
import Button from 'antd/lib/button'
import 'antd/lib/button/style/index.less'
import Checkbox from 'antd/lib/checkbox'
import 'antd/lib/checkbox/style/index.less'
import Form from 'antd/lib/form'
import 'antd/lib/form/style/'
import Input from 'antd/lib/input'
import 'antd/lib/input/style/'

import {
  handleNewLanguageDisplay,
  handleLoadSuggestion,
  handleSaveNewLanguage
} from '../../actions/languages-actions'

class NewLanguageModal extends Component {
  static propTypes = {
    show: PropTypes.bool,
    saving: PropTypes.bool,
    searchResults: PropTypes.array,
    handleOnClose: PropTypes.func,
    handleOnSave: PropTypes.func,
    loadSuggestion: PropTypes.func,
    form: PropTypes.any
  }

  constructor (props) {
    super(props)
    this.state = {
      details: {
        enabledByDefault: true,
        enabled: true,
        displayName: '',
        nativeName: '',
        pluralForms: ''
      },
      query: '',
      validFields: true,
      suggestions: props.searchResults
    }
  }

  handleCancel = () => {
    this.resetFields()
    this.props.handleOnClose()
  }

  resetFields = () => {
    this.props.form.resetFields()
    this.setState({
      details: {
        enabledByDefault: true,
        enabled: true,
        displayName: '',
        nativeName: '',
        pluralForms: ''
      },
      validFields: true,
      suggestions: [],
      query: ''
    })
  }

  updateField = (field, e) => {
    const value = e.target.value
    this.props.form.setFieldsValue({
      [field]: value
    })
    this.setState(prevState => ({
      details: {
        ...prevState.details,
        [field]: value
      }
    }))
  }

  updateCheckbox = (field) => {
    this.setState(prevState => ({
      details: {
        ...prevState.details,
        [field]: !prevState.details[field]
      }
    }))
  }

  validateDetails = () => {
    const displayName = this.state.details.displayName
    const query = this.state.query
    if (isEmpty(displayName) && isEmpty(query)) {
      this.setState({
        validFields: false
      })
    } else {
      const details = {
        ...this.state.details,
        localeId: query.replace('_', '-')
      }
      this.props.handleOnSave(details)
      this.resetFields()
    }
  }

  onSearchChange = (event, { newValue }) => {
    this.setState({
      query: newValue
    })
  }

  onSuggestionsClearRequested = () => {
  }

  getSuggestionValue = (selectedLocale) => {
    return selectedLocale.localeId
  }

  renderSuggestion = (suggestion) => {
    return (

          {suggestion.displayName}

          {suggestion.localeId}

    )
  }

  onSuggestionSelected = (event, {
     suggestion, suggestionValue, sectionIndex, method }) => {
    // eslint-disable-next-line
    const { enabled, enabledByDefault, rtl, localeId, ...fieldValues } =
      suggestion
    this.props.form.setFieldsValue({ ...fieldValues })
    this.setState({
      details: {
        ...suggestion,
        enabledByDefault: true,
        enabled: true
      }
    })
  }

  /* eslint-disable react/jsx-no-bind, react/jsx-boolean-value */
  render () {
    const {show, saving, loadSuggestion, searchResults} = this.props
    const { details, query } = this.state
    const { getFieldDecorator } = this.props.form
    const inputProps = {
      placeholder: 'Search for languages',
      maxLength: 256,
      onChange: this.onSearchChange,
      value: query
    }

    const showPluralFormsWarning = isEmpty(searchResults) && !isEmpty(query)

    return (
      <Modal
        width={'48rem'}
        title={'Add a new language'}
        id='newLang'
        visible={show}
        onCancel={this.handleCancel}
        footer={[
          <Button
            key='back'
            aria-label='button'
            id='btn-new-language-cancel'
            disabled={saving}
            onClick={this.handleCancel}>
            Close
          </Button>,
          <Button
            key='ok'
            aria-label='button'
            loading={saving}
            disabled={(isEmpty(query) || isEmpty(details.nativeName) ||
              isEmpty(details.displayName || isEmpty(details.pluralForms)))}
            id='btn-new-language-save'
            type='primary'
            onClick={this.validateDetails}>
            Save
          </Button>
        ]}>
        <Form layout='vertical'>
          <Form.Item label={'Language Code'} title={'Language Code'}>
            <Autosuggest
              name='new-language-code'
              suggestions={searchResults}
              onSuggestionSelected={this.onSuggestionSelected}
              getSuggestionValue={this.getSuggestionValue}
              onSuggestionsFetchRequested={loadSuggestion}
              onSuggestionsClearRequested={this.onSuggestionsClearRequested}
              renderSuggestion={this.renderSuggestion}
              inputProps={inputProps}
            />
          </Form.Item>
          <Form.Item label={'Name'} title={'Name'}>
            {getFieldDecorator('displayName', {
              setFieldsInitialValue: details.displayName,
              rules: [{required: true,
                message: 'Please input a Language Display Name'}]
            })(
              <Input
                // id='displayName' set by getFieldDecorator
                maxLength={100}
                onChange={(e) => this.updateField('displayName', e)}
                placeholder='Display name' />
            )}
          </Form.Item>
          <Form.Item label={'Native Name'} title={'Native Name'}>
            {getFieldDecorator('nativeName', {
              setFieldsInitialValue: details.nativeName,
              rules: [{required: true,
                message: 'Please input a Language Native Name'}]
            })(
              <Input
                // id='nativeName' set by getFieldDecorator
                maxLength={100}
                onChange={(e) => this.updateField('nativeName', e)}
                placeholder='Native name' />
            )}
          </Form.Item>
          <Form.Item
            title={'Plural Forms'}
            label={
              Plural forms {' '}

                  <Icon name='info' className='s0' parentClassName='iconInfo'
                    title='Help' />

                {showPluralFormsWarning &&

                    No plural information available. Assuming no plurals.

                }
              }>
              {getFieldDecorator('pluralForms', {
                setFieldsInitialValue: details.pluralForms,
                rules: [{required: true,
                  message: 'Please input the languages Plural Forms'}]
              })(
                <Input
                  maxLength={255}
                  onChange={(e) => this.updateField('pluralForms', e)}
                  placeholder='Plural forms' />
              )}
          </Form.Item>
          <Form.Item>
            <Checkbox
              id='chk-new-language-enabled'
              onChange={() => this.updateCheckbox('enabledByDefault')}
              checked={details.enabledByDefault}>
              Enabled by default
            </Checkbox>
            <Checkbox
              onChange={() => this.updateCheckbox('enabled')}
              checked={details.enabled}>
              Enabled language
            </Checkbox>
          </Form.Item>
        </Form>
      </Modal>
    )
    /* eslint-enable react/jsx-no-bind, react/jsx-boolean-value */
  }
}

const mapStateToProps = (state) => {
  const {
    show,
    saving,
    searchResults
  } = state.languages.newLanguage
  return {
    show,
    saving,
    searchResults
  }
}

const mapDispatchToProps = (dispatch) => {
  const updateSuggestion = debounce((val) =>
    dispatch(handleLoadSuggestion(val)), 300)

  return {
    handleOnClose: () => {
      dispatch(handleNewLanguageDisplay(false))
    },
    handleOnSave: (details) => {
      dispatch(handleSaveNewLanguage(details))
    },
    loadSuggestion: (query) => {
      updateSuggestion(query.value)
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(
  Form.create()(NewLanguageModal))
<|endoftext|>


<commit_before>/**
 * @jsx React.DOM
 */
'use strict';

var assert = require('assert');
var schema = require('../schema');

var Property = schema.Property;
var List = schema.List;
var Schema = schema.Schema;

describe('forms', () => {

  describe('schema', () => {

    describe('Schema construction', () => {

      it('constructs Schema with no children', () => {
        var s = <Schema></Schema>;
        assert.deepEqual(s.children, {});
      });

      it('constructs Schema ignoring falsy children', function() {

        function getSchema(city) {
          return (
            <Schema>
              <Property name="address_1" required />
              {city === 'OTHER' ? <Property name="city" required /> : null}
            </Schema>
          );
        }

        assert.doesNotThrow(function() {
          var schema = getSchema('LON');
          assert.equal(Object.keys(schema.children).length, 1);
        });

        assert.doesNotThrow(function() {
          var schema = getSchema('OTHER');
          assert.equal(Object.keys(schema.children).length, 2);
        });
      });

      it('constructs with children as arguments', () => {
        var s = (
          <Schema>
            <Property name="name" />
            <Property name="name2" />
          </Schema>
        );
        assert.ok(s.children);
        assert.ok(s.children.name);
        assert.ok(s.children.name2);
      });

      it('constructs with children as an array', () => {
        var props = [
          <Property name="name" />,
          <Property name="name2" />
        ];
        var s = <Schema>{props}</Schema>;
        assert.ok(s.children);
        assert.ok(s.children.name);
        assert.ok(s.children.name2);
      });

      it('constructs with children as a deeply nested array', () => {
        var props = [
          <Property name="name" />,
          [<Property name="name2" />],
          [[<Property name="name3" />]]
        ];
        var s = <Schema>{props}</Schema>;
        assert.ok(s.children);
        assert.ok(s.children.name);
        assert.ok(s.children.name2);
        assert.ok(s.children.name3);
      });

      it('throws when one of the properties does not have name', () => {
        assert.throws(() => {
          return <Schema><Property /></Schema>;
        });
      });
    });

    describe('List construction', () => {

      it('constructs with children schema as argument', () => {
        var s = <List><Property /></List>;
        assert.ok(s.children);
      });

      it('throws when no children is defined', () => {
        assert.throws(() => {
          return <List></List>;
        });
      });

      it('throws when more than one child is defined', () => {
        assert.throws(() => {
          return (
            <List>
              <Property />
              <Property />
            </List>
          );
        });
      });

    });

  });
});
<commit_msg>tests: make lint happy<commit_after>/**
 * @jsx React.DOM
 */
'use strict';

var assert = require('assert');
var schema = require('../schema');

var Property = schema.Property;
var List = schema.List;
var Schema = schema.Schema;

describe('forms', () => {

  describe('schema', () => {

    describe('Schema construction', () => {

      it('constructs Schema with no children', () => {
        var s = <Schema></Schema>;
        assert.deepEqual(s.children, {});
      });

      it('constructs Schema ignoring falsy children', function() {

        function getSchema(city) {
          return (
            <Schema>
              <Property name="address_1" required />
              {city === 'OTHER' ? <Property name="city" required /> : null}
            </Schema>
          );
        }

        assert.doesNotThrow(function() {
          var s = getSchema('LON');
          assert.equal(Object.keys(s.children).length, 1);
        });

        assert.doesNotThrow(function() {
          var s = getSchema('OTHER');
          assert.equal(Object.keys(s.children).length, 2);
        });
      });

      it('constructs with children as arguments', () => {
        var s = (
          <Schema>
            <Property name="name" />
            <Property name="name2" />
          </Schema>
        );
        assert.ok(s.children);
        assert.ok(s.children.name);
        assert.ok(s.children.name2);
      });

      it('constructs with children as an array', () => {
        var props = [
          <Property name="name" />,
          <Property name="name2" />
        ];
        var s = <Schema>{props}</Schema>;
        assert.ok(s.children);
        assert.ok(s.children.name);
        assert.ok(s.children.name2);
      });

      it('constructs with children as a deeply nested array', () => {
        var props = [
          <Property name="name" />,
          [<Property name="name2" />],
          [[<Property name="name3" />]]
        ];
        var s = <Schema>{props}</Schema>;
        assert.ok(s.children);
        assert.ok(s.children.name);
        assert.ok(s.children.name2);
        assert.ok(s.children.name3);
      });

      it('throws when one of the properties does not have name', () => {
        assert.throws(() => {
          return <Schema><Property /></Schema>;
        });
      });
    });

    describe('List construction', () => {

      it('constructs with children schema as argument', () => {
        var s = <List><Property /></List>;
        assert.ok(s.children);
      });

      it('throws when no children is defined', () => {
        assert.throws(() => {
          return <List></List>;
        });
      });

      it('throws when more than one child is defined', () => {
        assert.throws(() => {
          return (
            <List>
              <Property />
              <Property />
            </List>
          );
        });
      });

    });

  });
});
<|endoftext|>


<commit_before>var POLLING_INTERVAL = 3500, // Milliseconds
    VICINITY_STRENGTH = -8, // B/T RSSI
    BUTTON_HOLD_TIME = 2000, // Milliseconds
    DISCONNECTION_DURATION = 24500, // Milliseconds
    CONF_FILE = 'BLUETOOTH-HW.CONF';

var execSync = require('child_process').execSync,
    fs = require("fs"),
    GPIO = require('rpi').GPIO;

var mac = fs.readFileSync(CONF_FILE);

var unlockPin = new GPIO(0, 'out'),
    lockPin = new GPIO(7, 'out');

var changeButton = new GPIO(8, 'in');

var inRange = false,
    lastConnectionTime = 0;

var disconnectionCount = 0;

/*changeButton.on('change', function(value) {
    if (value == 1) {
        console.log("Request to Change Bluetooth Device Received.");
        exec("hcitool scan", function(error, stdout, stderr) {
            console.log(" - Scanning...");
            var mac_addr_line = stdout.split("\n")

            if(mac_addr_line[1] != ""){
                var temp_mac = mac_addr_line[1].split("\t")[1];

                if(temp_mac.length = 17){
                    console.log("   - Device found: " + mac);
                    mac = temp_mac;
                    fs.writeFileSync(CONF_FILE, mac);
                } else {
                    console.log("   - No Device was Found.");
                }
            }
        });
    }
});*/

function switchPower(pin) {
    pin.high();
    setTimeout(function() {
        pin.low();
    }, BUTTON_HOLD_TIME);
}

function cmd() {
    return "hcitool cc " + mac + " && hcitool rssi " + mac;
}

function parseConnectionStrength(resp) {
    var rawRSSI = resp.split(": ")[1];
    console.log("    - raw RSSI: " + rawRSSI);

    if (rawRSSI != "") {
        console.log(Math.round(rawRSSI));
        return Math.round(rawRSSI); // Math.round is applied to convert string to number, returns RSSI from command
    } else {
        console.log(-2056);
        return -2056;               // Device is not is range, return number that is guaranteed to far out of the RSSI range
    }
}

// Probe for Device Presence
setInterval(function() {
    console.log("Probing for Connection...");
    console.log(" - " + Date.now());
    if (mac.length == 17) {
        console.log(" - Valid MAC Address was found in Config, detecting signal strength.");
        var stdout = execSync(cmd());
        console.log("Stdout: "+stdout);
        var connectionStrength = parseConnectionStrength(stdout);
        console.log(connectionStrength);
        console.log(inRange);
        console.log(VICINITY_STRENGTH);
        // Check if phone is in valid range
        if ((inRange == false) && (connectionStrength > VICINITY_STRENGTH)) {
            console.log(" - Phone is in the disconnected state and device is within preconfigured vicinity.");
            console.log("    - Unlocking Car");
            switchPower(unlockPin);
            console.log("    - Reconfiguring Variables");
            inRange = true;
            lastConnectionTime = Date.now();
            disconnectionCount = 0;
            console.log("       - Connection Time: " + lastConnectionTime);
        }
        // If the signal is weaker than that, treat it as though the phone is not in valid range
        else if ((inRange == true) && (connectionStrength < VICINITY_STRENGTH)) {
            console.log(" - Phone is in the connected state and device is not within preconfigured vicinity.");
            disconnectionCount++;
            console.log("    - Increment Disconnection Count: " + disconnectionCount);
            // Calculate approx. how many times hardware should be probed before disconnect is acknowledged
            if (disconnectionCount >= Math.ceil(DISCONNECTION_DURATION / POLLING_INTERVAL)) {
                console.log("    - Locking Car");
                switchPower(lockPin);
                inRange = false;
            }
        }
    }
    console.log("--------------");
}, POLLING_INTERVAL);<commit_msg>Catch Errors<commit_after>var POLLING_INTERVAL = 3500, // Milliseconds
    VICINITY_STRENGTH = -8, // B/T RSSI
    BUTTON_HOLD_TIME = 2000, // Milliseconds
    DISCONNECTION_DURATION = 24500, // Milliseconds
    CONF_FILE = 'BLUETOOTH-HW.CONF';

var execSync = require('child_process').execSync,
    fs = require("fs"),
    GPIO = require('rpi').GPIO;

var mac = fs.readFileSync(CONF_FILE);

var unlockPin = new GPIO(0, 'out'),
    lockPin = new GPIO(7, 'out');

var changeButton = new GPIO(8, 'in');

var inRange = false,
    lastConnectionTime = 0;

var disconnectionCount = 0;

/*changeButton.on('change', function(value) {
    if (value == 1) {
        console.log("Request to Change Bluetooth Device Received.");
        exec("hcitool scan", function(error, stdout, stderr) {
            console.log(" - Scanning...");
            var mac_addr_line = stdout.split("\n")

            if(mac_addr_line[1] != ""){
                var temp_mac = mac_addr_line[1].split("\t")[1];

                if(temp_mac.length = 17){
                    console.log("   - Device found: " + mac);
                    mac = temp_mac;
                    fs.writeFileSync(CONF_FILE, mac);
                } else {
                    console.log("   - No Device was Found.");
                }
            }
        });
    }
});*/

function switchPower(pin) {
    pin.high();
    setTimeout(function() {
        pin.low();
    }, BUTTON_HOLD_TIME);
}

function cmd() {
    return "hcitool cc " + mac + " && hcitool rssi " + mac;
}

function parseConnectionStrength(resp) {
    var rawRSSI = resp.split(": ")[1];
    console.log("    - raw RSSI: " + rawRSSI);

    if (rawRSSI != "") {
        console.log(Math.round(rawRSSI));
        return Math.round(rawRSSI); // Math.round is applied to convert string to number, returns RSSI from command
    } else {
        console.log(-2056);
        return -2056;               // Device is not is range, return number that is guaranteed to far out of the RSSI range
    }
}

// Probe for Device Presence
setInterval(function() {
    try {
    console.log("Probing for Connection...");
    console.log(" - " + Date.now());
    if (mac.length == 17) {
        console.log(" - Valid MAC Address was found in Config, detecting signal strength.");
        var stdout = execSync(cmd());
        console.log("Stdout: "+stdout);
        var connectionStrength = parseConnectionStrength(stdout);
        console.log(connectionStrength);
        console.log(inRange);
        console.log(VICINITY_STRENGTH);
        // Check if phone is in valid range
        if ((inRange == false) && (connectionStrength > VICINITY_STRENGTH)) {
            console.log(" - Phone is in the disconnected state and device is within preconfigured vicinity.");
            console.log("    - Unlocking Car");
            switchPower(unlockPin);
            console.log("    - Reconfiguring Variables");
            inRange = true;
            lastConnectionTime = Date.now();
            disconnectionCount = 0;
            console.log("       - Connection Time: " + lastConnectionTime);
        }
        // If the signal is weaker than that, treat it as though the phone is not in valid range
        else if ((inRange == true) && (connectionStrength < VICINITY_STRENGTH)) {
            console.log(" - Phone is in the connected state and device is not within preconfigured vicinity.");
            disconnectionCount++;
            console.log("    - Increment Disconnection Count: " + disconnectionCount);
            // Calculate approx. how many times hardware should be probed before disconnect is acknowledged
            if (disconnectionCount >= Math.ceil(DISCONNECTION_DURATION / POLLING_INTERVAL)) {
                console.log("    - Locking Car");
                switchPower(lockPin);
                inRange = false;
            }
        }
    }
    catch(e){
        console.log(e);
    }
    console.log("--------------");
}, POLLING_INTERVAL);<|endoftext|>


<commit_before>'use strict';

import React from 'react';
import PropTypes from 'prop-types';
import _ from 'underscore';
import url from 'url';
import queryString from 'query-string';
import * as d3 from 'd3';
import * as vizUtil from './utilities';
import { expFxn, Filters, console, object, isServerSide, layout, analytics, navigate } from '../util';
import { Toggle } from '../inputs';
import * as store from './../../store';
import { ActiveFiltersBar } from './components/ActiveFiltersBar';
import { ChartDataController } from './chart-data-controller';
import ReactTooltip from 'react-tooltip';

/**
 * Bar shown below header on home and browse pages.
 * Shows counts of selected experiment_sets, experiments, and files against those properties' total counts.
 *
 * Possible todo: Remove functions for updating counts, instead wrap in ChartDataController.provider and aggregate, using shouldComponentUpdate
 * More likely todo: Do chart-stuff aggregation on back-end, display context.charts.aggregations.counts.files, ...experiments, ...experiment_sets, etc. here instead.
 *
 * @module {Component} viz/QuickInfoBar
 * @prop {string} href - Current location/href passed down from Redux store. Used for determining whether to display QuickInfoBar or not.
 */

export default class QuickInfoBar extends React.Component {

    static isInvisibleForHref(href){
        // If have href, only show for /browse/, /search/, and / & /home
        var urlParts = url.parse(href);
        if (urlParts.hash && urlParts.hash.indexOf('!impersonate-user') > -1) return true;
        // Doing replace twice should be faster than one time with /g regex flag (3 steps each or 15 steps combined w/ '/g')
        var pathParts = urlParts.pathname.replace(/^\//, "").replace(/\/$/, "").split('/');
        if (pathParts[0] === 'browse') return false;
        if (pathParts[0] === 'search') return true;
        if (pathParts[0] === 'home') return false;
        if (pathParts.length === 1 && pathParts[0] === "") return false;
        return true;
    }

    static getCountsFromProps(props){
        var defaultNullCounts = { 'experiment_sets' : null, 'experiments' : null, 'files' : null };
        var current = (props.barplot_data_filtered && props.barplot_data_filtered.total) || defaultNullCounts,
            total = (props.barplot_data_unfiltered && props.barplot_data_unfiltered.total) || defaultNullCounts;
        return { current, total };
    }

    static defaultProps = {
        'offset' : {},
        'id' : 'stats',
        'className' : null,
        'showCurrent' : true
    }

    /**
     * Sets this.state, containing counts for filtered & total experiments, experiment_sets, and files.
     * Counts are set to null by default, and instance's updateCurrentAndTotalCounts method must be called
     * each time stats are updated from some high-level component.
     *
     * Currently this is done by having refs...updateCurrentAndTotalCounts being accessible
     * through refs.navigation on app component/module, which makes an 'updateStats' instance function available,
     * which is provided to ChartDataController.
     *
     * Additionally holds {boolean|string} 'show' property, describing what is shown in bottom part; and a {boolean} 'mounted' property.
     *
     * @constructor
     */
    constructor(props){
        super(props);
        this.componentWillReceiveProps = this.componentWillReceiveProps.bind(this);
        this.componentDidMount = this.componentDidMount.bind(this);
        this.componentDidUpdate = this.componentDidUpdate.bind(this);
        this.isInvisible = this.isInvisible.bind(this);
        this.anyFiltersSet = this.anyFiltersSet.bind(this);
        this.className = this.className.bind(this);
        this.onIconMouseEnter = _.debounce(this.onIconMouseEnter.bind(this), 500, true);
        this.onBrowseStateToggle = this.onBrowseStateToggle.bind(this);
        this.onPanelAreaMouseLeave = this.onPanelAreaMouseLeave.bind(this);
        this.renderStats = this.renderStats.bind(this);
        this.renderHoverBar = this.renderHoverBar.bind(this);
        this.state = {
            'mounted'               : false,
            'show'                  : false,
            'reallyShow'            : false
        };
    }

    /**
     * Updates state.show if no filters are selected.
     *
     * @private
     * @instance
     * @param {Object} nextProps - Next props.
     * @returns {undefined}
     */
    componentWillReceiveProps(nextProps){
        if (!(nextProps.expSetFilters && _.keys(nextProps.expSetFilters).length > 0) && this.state.show){
            this.setState({ 'show' : false });
        }
    }

    /** @private */
    componentDidMount(){
        this.setState({'mounted' : true});
    }

    componentDidUpdate(pastProps, pastState){
        if (this.anyFiltersSet() !== this.anyFiltersSet(pastProps)) ReactTooltip.rebuild();
    }

    /**
     * Check if QuickInfoBar instance is currently invisible, i.e. according to props.href.
     *
     * @public
     * @instance
     * @returns {boolean} True if counts are null or on a 'href' is not of a page for which searching or summary is applicable.
     */
    isInvisible(props = this.props, state = this.state){
        var { total, current } = QuickInfoBar.getCountsFromProps(props);
        if (
            !state.mounted ||
            props.invisible ||
            total === null ||
            (
                (current.experiment_sets === null && total.experiment_sets === null) &&
                (current.experiments === null     && total.experiments === null) &&
                (current.files === null           && total.files === null)
            )
        ) return true;

        if (typeof props.href === 'string'){
            return QuickInfoBar.isInvisibleForHref(props.href);
        }

        return false;
    }

    anyFiltersSet(props = this.props){
        return (props.expSetFilters && _.keys(props.expSetFilters).length > 0);
    }

    className(){
        var cn = "explanation";
        if (typeof this.props.className === 'string') cn += ' ' + this.props.className;
        if (this.isInvisible()) cn += ' invisible';
        return cn;
    }

    onIconMouseEnter(e){
        var areAnyFiltersSet = this.anyFiltersSet();
        if (this.timeout) clearTimeout(this.timeout);
        if (areAnyFiltersSet) this.setState({ 'show' : 'activeFilters', 'reallyShow' : true });
        analytics.event('QuickInfoBar', 'Hover over Filters Icon', {
            'eventLabel' : ( areAnyFiltersSet ? "Some filters are set" : "No filters set" ),
            'dimension1' : analytics.getStringifiedCurrentFilters(this.props.expSetFilters)
        });
    }

    onPanelAreaMouseLeave(e){
        e.preventDefault();
        this.setState({ 'show' : false }, ()=>{
            this.timeout = setTimeout(this.setState.bind(this), 500, { 'reallyShow' : false });
        });
    }

    renderStats(extraClassName = null){
        var areAnyFiltersSet = this.anyFiltersSet();
        var { total, current } = QuickInfoBar.getCountsFromProps(this.props);

        var stats;
        if (current && (typeof current.experiment_sets === 'number' || typeof current.experiments === 'number' || typeof current.files === 'number')) {
            stats = {
                'experiment_sets'   : { current.experiment_sets } / { total.experiment_sets || 0 },
                'experiments'       : { current.experiments } / {total.experiments || 0},
                'files'             : { current.files } / {total.files || 0}
            };
        } else {
            stats = {
                'experiment_sets'   : total.experiment_sets || 0,
                'experiments'       : total.experiments || 0,
                'files'             : total.files || 0
            };
        }
        var statProps = _.pick(this.props, 'id', 'expSetFilters', 'href', 'isLoadingChartData');
        return (

                <Stat {...statProps} shortLabel="Experiment Sets" longLabel="Experiment Sets" classNameID="expsets" value={stats.experiment_sets} key="expsets" />
                <Stat {...statProps} shortLabel="Experiments" longLabel="Experiments" classNameID="experiments" value={stats.experiments} key="experiments" />
                <Stat {...statProps} shortLabel="Files" longLabel="Files in Experiments" classNameID="files" value={stats.files} key="files" />

        );
    }

    onBrowseStateToggle(){
        navigate.setBrowseBaseStateAndRefresh(this.props.browseBaseState === 'only_4dn' ? 'all' : 'only_4dn', this.props.href, this.props.context);
    }

    renderBrowseStateToggle(){
        var checked = this.props.browseBaseState === 'all';
        return (

                    <Toggle checked={checked} onChange={this.onBrowseStateToggle} />
                    Include External Data

        );
    }

    renderHoverBar(){
        if (this.state.show === 'activeFilters' || (this.state.show === false && this.state.reallyShow)) {
            return (

                        Filtered by

                    <ActiveFiltersBar
                        expSetFilters={this.props.expSetFilters}
                        orderedFieldNames={null}
                        href={this.props.href}
                        showTitle={false}
                        schemas={this.props.schemas}
                        context={this.props.context}
                    />

{ this.setState({ show : 'mosaicCharts' }); },1000)*/}>

            );
        } else return null;
    }

    renderBar(){
        var { show, mounted } = this.state;
        if (!mounted) return null;

        var className = "inner container";
        if (show !== false) className += ' showing';
        if (show === 'activeFilters') className += ' showing-filters';
        if (show === 'mosaicCharts') className += ' showing-charts';

        return (

                    { this.renderStats('col-xs-8') }
                    { this.renderBrowseStateToggle() }

                { this.renderHoverBar() }

        );
    }

    render(){
        return
{ this.renderBar() }
;
    }

}

class Stat extends React.Component {

    static defaultProps = {
        'value' : 0,
        'longLabel' : 'Experiments',
        'classNameID': 'experiments',
        'id' : null
    }

    /**
     * { classNameID : @type }
     */
    static typesPathMap = {
        'experiments' : "/search/?type=Experiment&experiment_sets.experimentset_type=replicate&experiment_sets.@type=ExperimentSetReplicate",
        'expsets' : "/browse/?type=ExperimentSetReplicate&experimentset_type=replicate",
        'files' : "/search/?type=File&experiments.experiment_sets.@type=ExperimentSetReplicate&experiments.experiment_sets.experimentset_type=replicate"
    }

    filtersHrefChunk(){
        if (this.props.classNameID === 'experiments'){
            return Filters.expSetFiltersToURLQuery(Filters.transformExpSetFiltersToExpFilters(this.props.expSetFilters));
        } else if (this.props.classNameID === 'expsets') {
            return Filters.expSetFiltersToURLQuery(this.props.expSetFilters);
        } else if (this.props.classNameID === 'files') {
            return Filters.expSetFiltersToURLQuery(Filters.transformExpSetFiltersToFileFilters(this.props.expSetFilters));
        }
    }

    label(){
        if (!this.props.value) {
            return this.props.shortLabel;
        }

        // Always goto Browse page for now
        var filtersHrefChunk = Filters.expSetFiltersToURLQuery(this.props.expSetFilters); //this.filtersHrefChunk();
        var targetHref = navigate.getBrowseBaseHref();
        targetHref += (filtersHrefChunk ? navigate.determineSeparatorChar(targetHref) + filtersHrefChunk : '');

        if (typeof this.props.href === 'string'){
            // Strip hostname/port from this.props.href and compare pathnames to check if we are already on this page.
            if (navigate.isBrowseHref(this.props.href)) return { this.props.shortLabel };
            if (this.props.href.replace(/(http:|https:)(\/\/)[^\/]+(?=\/)/, '') === targetHref) return { this.props.shortLabel };
        }

        return (
            { this.props.shortLabel }
        );
    }

    render(){
        var { classNameID, longLabel, value, id, isLoadingChartData } = this.props;
        return (

                    { isLoadingChartData ?  : value }

                    { this.label() }

        );
    }

}

<commit_msg>Codacy<commit_after>'use strict';

import React from 'react';
import PropTypes from 'prop-types';
import _ from 'underscore';
import url from 'url';
import queryString from 'query-string';
import * as d3 from 'd3';
import * as vizUtil from './utilities';
import { expFxn, Filters, console, object, isServerSide, layout, analytics, navigate } from '../util';
import { Toggle } from '../inputs';
import * as store from './../../store';
import { ActiveFiltersBar } from './components/ActiveFiltersBar';
import { ChartDataController } from './chart-data-controller';
import ReactTooltip from 'react-tooltip';

/**
 * Bar shown below header on home and browse pages.
 * Shows counts of selected experiment_sets, experiments, and files against those properties' total counts.
 *
 * Possible todo: Remove functions for updating counts, instead wrap in ChartDataController.provider and aggregate, using shouldComponentUpdate
 * More likely todo: Do chart-stuff aggregation on back-end, display context.charts.aggregations.counts.files, ...experiments, ...experiment_sets, etc. here instead.
 *
 * @module {Component} viz/QuickInfoBar
 * @prop {string} href - Current location/href passed down from Redux store. Used for determining whether to display QuickInfoBar or not.
 */

export default class QuickInfoBar extends React.Component {

    static isInvisibleForHref(href){
        // If have href, only show for /browse/, /search/, and / & /home
        var urlParts = url.parse(href);
        if (urlParts.hash && urlParts.hash.indexOf('!impersonate-user') > -1) return true;
        // Doing replace twice should be faster than one time with /g regex flag (3 steps each or 15 steps combined w/ '/g')
        var pathParts = urlParts.pathname.replace(/^\//, "").replace(/\/$/, "").split('/');
        if (pathParts[0] === 'browse') return false;
        if (pathParts[0] === 'search') return true;
        if (pathParts[0] === 'home') return false;
        if (pathParts.length === 1 && pathParts[0] === "") return false;
        return true;
    }

    static getCountsFromProps(props){
        var defaultNullCounts = { 'experiment_sets' : null, 'experiments' : null, 'files' : null };
        var current = (props.barplot_data_filtered && props.barplot_data_filtered.total) || defaultNullCounts,
            total = (props.barplot_data_unfiltered && props.barplot_data_unfiltered.total) || defaultNullCounts;
        return { current, total };
    }

    static defaultProps = {
        'offset' : {},
        'id' : 'stats',
        'className' : null,
        'showCurrent' : true
    }

    /**
     * Sets this.state, containing counts for filtered & total experiments, experiment_sets, and files.
     * Counts are set to null by default, and instance's updateCurrentAndTotalCounts method must be called
     * each time stats are updated from some high-level component.
     *
     * Currently this is done by having refs...updateCurrentAndTotalCounts being accessible
     * through refs.navigation on app component/module, which makes an 'updateStats' instance function available,
     * which is provided to ChartDataController.
     *
     * Additionally holds {boolean|string} 'show' property, describing what is shown in bottom part; and a {boolean} 'mounted' property.
     *
     * @constructor
     */
    constructor(props){
        super(props);
        this.componentWillReceiveProps = this.componentWillReceiveProps.bind(this);
        this.componentDidMount = this.componentDidMount.bind(this);
        this.componentDidUpdate = this.componentDidUpdate.bind(this);
        this.isInvisible = this.isInvisible.bind(this);
        this.anyFiltersSet = this.anyFiltersSet.bind(this);
        this.className = this.className.bind(this);
        this.onIconMouseEnter = _.debounce(this.onIconMouseEnter.bind(this), 500, true);
        this.onBrowseStateToggle = this.onBrowseStateToggle.bind(this);
        this.onPanelAreaMouseLeave = this.onPanelAreaMouseLeave.bind(this);
        this.renderStats = this.renderStats.bind(this);
        this.renderHoverBar = this.renderHoverBar.bind(this);
        this.state = {
            'mounted'               : false,
            'show'                  : false,
            'reallyShow'            : false
        };
    }

    /**
     * Updates state.show if no filters are selected.
     *
     * @private
     * @instance
     * @param {Object} nextProps - Next props.
     * @returns {undefined}
     */
    componentWillReceiveProps(nextProps){
        if (!(nextProps.expSetFilters && _.keys(nextProps.expSetFilters).length > 0) && this.state.show){
            this.setState({ 'show' : false });
        }
    }

    /** @private */
    componentDidMount(){
        this.setState({'mounted' : true});
    }

    componentDidUpdate(pastProps, pastState){
        if (this.anyFiltersSet() !== this.anyFiltersSet(pastProps)) ReactTooltip.rebuild();
    }

    /**
     * Check if QuickInfoBar instance is currently invisible, i.e. according to props.href.
     *
     * @public
     * @instance
     * @returns {boolean} True if counts are null or on a 'href' is not of a page for which searching or summary is applicable.
     */
    isInvisible(props = this.props, state = this.state){
        var { total, current } = QuickInfoBar.getCountsFromProps(props);
        if (
            !state.mounted ||
            props.invisible ||
            total === null ||
            (
                (current.experiment_sets === null && total.experiment_sets === null) &&
                (current.experiments === null     && total.experiments === null) &&
                (current.files === null           && total.files === null)
            )
        ) return true;

        if (typeof props.href === 'string'){
            return QuickInfoBar.isInvisibleForHref(props.href);
        }

        return false;
    }

    anyFiltersSet(props = this.props){
        return (props.expSetFilters && _.keys(props.expSetFilters).length > 0);
    }

    className(){
        var cn = "explanation";
        if (typeof this.props.className === 'string') cn += ' ' + this.props.className;
        if (this.isInvisible()) cn += ' invisible';
        return cn;
    }

    onIconMouseEnter(e){
        var areAnyFiltersSet = this.anyFiltersSet();
        if (this.timeout) clearTimeout(this.timeout);
        if (areAnyFiltersSet) this.setState({ 'show' : 'activeFilters', 'reallyShow' : true });
        analytics.event('QuickInfoBar', 'Hover over Filters Icon', {
            'eventLabel' : ( areAnyFiltersSet ? "Some filters are set" : "No filters set" ),
            'dimension1' : analytics.getStringifiedCurrentFilters(this.props.expSetFilters)
        });
    }

    onPanelAreaMouseLeave(e){
        e.preventDefault();
        this.setState({ 'show' : false }, ()=>{
            this.timeout = setTimeout(this.setState.bind(this), 500, { 'reallyShow' : false });
        });
    }

    renderStats(extraClassName = null){
        var areAnyFiltersSet = this.anyFiltersSet();
        var { total, current } = QuickInfoBar.getCountsFromProps(this.props);

        var stats;
        if (current && (typeof current.experiment_sets === 'number' || typeof current.experiments === 'number' || typeof current.files === 'number')) {
            stats = {
                'experiment_sets'   : { current.experiment_sets } / { total.experiment_sets || 0 },
                'experiments'       : { current.experiments } / {total.experiments || 0},
                'files'             : { current.files } / {total.files || 0}
            };
        } else {
            stats = {
                'experiment_sets'   : total.experiment_sets || 0,
                'experiments'       : total.experiments || 0,
                'files'             : total.files || 0
            };
        }
        var statProps = _.pick(this.props, 'id', 'expSetFilters', 'href', 'isLoadingChartData');
        return (

                <Stat {...statProps} shortLabel="Experiment Sets" longLabel="Experiment Sets" classNameID="expsets" value={stats.experiment_sets} key="expsets" />
                <Stat {...statProps} shortLabel="Experiments" longLabel="Experiments" classNameID="experiments" value={stats.experiments} key="experiments" />
                <Stat {...statProps} shortLabel="Files" longLabel="Files in Experiments" classNameID="files" value={stats.files} key="files" />

        );
    }

    onBrowseStateToggle(){
        navigate.setBrowseBaseStateAndRefresh(this.props.browseBaseState === 'only_4dn' ? 'all' : 'only_4dn', this.props.href, this.props.context);
    }

    renderBrowseStateToggle(){
        var checked = this.props.browseBaseState === 'all';
        return (

                    <Toggle checked={checked} onChange={this.onBrowseStateToggle} />
                    Include External Data

        );
    }

    renderHoverBar(){
        if (this.state.show === 'activeFilters' || (this.state.show === false && this.state.reallyShow)) {
            return (

                        Filtered by

                    <ActiveFiltersBar
                        expSetFilters={this.props.expSetFilters}
                        orderedFieldNames={null}
                        href={this.props.href}
                        showTitle={false}
                        schemas={this.props.schemas}
                        context={this.props.context}
                    />

{ this.setState({ show : 'mosaicCharts' }); },1000)*/}>

            );
        } else return null;
    }

    renderBar(){
        var { show, mounted } = this.state;
        if (!mounted) return null;

        var className = "inner container";
        if (show !== false) className += ' showing';
        if (show === 'activeFilters') className += ' showing-filters';
        if (show === 'mosaicCharts') className += ' showing-charts';

        return (

                    { this.renderStats('col-xs-8') }
                    { this.renderBrowseStateToggle() }

                { this.renderHoverBar() }

        );
    }

    render(){
        return
{ this.renderBar() }
;
    }

}

class Stat extends React.Component {

    static defaultProps = {
        'value' : 0,
        'longLabel' : 'Experiments',
        'classNameID': 'experiments',
        'id' : null
    }

    /**
     * { classNameID : @type }
     */
    static typesPathMap = {
        'experiments' : "/search/?type=Experiment&experiment_sets.experimentset_type=replicate&experiment_sets.@type=ExperimentSetReplicate",
        'expsets' : "/browse/?type=ExperimentSetReplicate&experimentset_type=replicate",
        'files' : "/search/?type=File&experiments.experiment_sets.@type=ExperimentSetReplicate&experiments.experiment_sets.experimentset_type=replicate"
    }

    filtersHrefChunk(){
        if (this.props.classNameID === 'experiments'){
            return Filters.expSetFiltersToURLQuery(Filters.transformExpSetFiltersToExpFilters(this.props.expSetFilters));
        } else if (this.props.classNameID === 'expsets') {
            return Filters.expSetFiltersToURLQuery(this.props.expSetFilters);
        } else if (this.props.classNameID === 'files') {
            return Filters.expSetFiltersToURLQuery(Filters.transformExpSetFiltersToFileFilters(this.props.expSetFilters));
        }
    }

    label(){
        if (!this.props.value) {
            return this.props.shortLabel;
        }

        // Always goto Browse page for now
        var filtersHrefChunk = Filters.expSetFiltersToURLQuery(this.props.expSetFilters); //this.filtersHrefChunk();
        var targetHref = navigate.getBrowseBaseHref();
        targetHref += (filtersHrefChunk ? navigate.determineSeparatorChar(targetHref) + filtersHrefChunk : '');

        if (typeof this.props.href === 'string'){
            // Strip hostname/port from this.props.href and compare pathnames to check if we are already on this page.
            if (navigate.isBrowseHref(this.props.href)) return { this.props.shortLabel };
            if (this.props.href.replace(/(http:|https:)(\/\/)[^\/]+(?=\/)/, '') === targetHref) return { this.props.shortLabel };
        }

        return (
            { this.props.shortLabel }
        );
    }

    render(){
        var { classNameID, longLabel, value, id, isLoadingChartData } = this.props;
        return (

                    { isLoadingChartData ?  : value }

                    { this.label() }

        );
    }

}

<|endoftext|>


<commit_before>// optional:
//import FastIntCompression from "fastintcompression";

import { emptyINode, emptyAttrMap, attrEntries, setAttribute, ivalue, count, push, finalize } from './pvnode';

import { iter } from "./access";

export function str2array(str, ar, idx){
    for (var i=0, strLen=str.length; i<strLen; i++) {
        //ar.push(str.codePointAt(i));
        ar[idx++] = str.codePointAt(i);
    }
    return idx;
}

export function array2str(ar,i){
	var str = "",l = ar.length;
    for (; i<l; i++) {
    	str += String.fromCodePoint(ar[i]);
    }
    return str;
}

export function convert(v){
	var i = parseFloat(v);
	if(!isNaN(i)) return i;
	if(v === "true" || v === "false") return v !== "false";
	return v;
}

export function toNative1(val){
    if(val === 1) return false;
    if(val === 2) return true;
    if(val === 3) return 0;
    if(val === 4) return null;
}

export function toNative(v,i){
    if(v.length == 1) return new Float64Array(new Uint32Array([0,v[i]]))[0];
    return new Float64Array(new Uint32Array([v[i],v[i+1]]))[0];
}

export function fromNative(v,arr){
    var f = new Float64Array(1);
    f[0] = v;
    var i = new Uint32Array(f.buffer);
    if(i[0]) arr.push(i[0]);
    arr.push(i[1]);
}

function docAttrType(k) {
	switch (k) {
		case "DOCTYPE": return 10;
		default: return 7;
	}
}

/**
 * Create a flat buffer from the document tree
 * @param  {VNode} doc The document
 * @return {ArrayBuffer}  A flat buffer
 */
export function toL3(doc){
    var block = 1024 * 1024 * 8;
	var out = new Uint32Array(block),
	    names = {},
	    i = 0,
        j = 0;
	for (let attr of attrEntries(doc)) {
		let name = attr[0], attrname = "@"+name;
		if (!names[attrname]) {
			names[attrname] = ++j;
			out[i++] = 0;
			out[i++] = 15;
			i = str2array(name,out,i);
		}
		out[i++] = docAttrType(attr[0]);
		i = str2array(attr[0],out,i);
		i = str2array(attr[1],out,i);
	}
	iter(doc, function (node) {
		let type = node.type,
		    inode = node.inode,
		    depth = node.depth,
		    name = node.name;
        var nameIndex = 0;
        if (typeof name === "string") {
			if(!names[name]) {
				names[name] = ++j;
				out[i++] = 0;
				out[i++] = 15;
				i = str2array(name,out,i);
			}
			nameIndex = names[name];
		}
        out[i++] = 0;
        out[i++] = type;
        out[i++] = depth;
        if(nameIndex) out[i++] = nameIndex;
		if (type == 1) {
			for (let attr of attrEntries(inode)) {
				let name = attr[0], attrname = "@"+name;
				if (!names[attrname]) {
					names[attrname] = ++j;
					out[i++] = 0;
					out[i++] = 15;
					i = str2array(name,out,i);
				}
				out[i++] = 0;
				out[i++] = 2;
				out[i++] = names[attrname];
				i = str2array(attr[1],out,i);
			}
		} else if (type == 3) {
			i = str2array(node.value,out,i);
        } else if(type == 12){
            i = str2array(node.value+"",out,i);
        }
	});
    // remove first 0
    //out.shift();
	return out.subarray(1,i+1);
}
/*

export function toL3(doc){
   var out = [],
       names = {},
       i = 1;
   for (let attr of doc._attrs.entries()) {
       let name = attr[0], attrname = "@"+name;
       if (!names[attrname]) {
           names[attrname] = i;
           i++;
           out.push(0);
           out.push(15);
           str2array(name,out);
       }
       out.push(docAttrType(attr[0]));
       str2array(attr[0],out);
       str2array(attr[1],out);
   }
   iter(doc, function (node) {
       let type = node.type,
           inode = node.inode,
           depth = inode._depth,
           name = node.name;
       var nameIndex = 0;
       if (typeof name === "string") {
           if(!names[name]) {
               names[name] = i;
               i++;
               out.push(0);
               out.push(15);
               str2array(name,out);
           }
           nameIndex = names[name];
       }
       out.push(0);
       out.push(type);
       out.push(depth);
       if(nameIndex) out.push(nameIndex);
       if (type == 1) {
           for (let attr of inode._attrs.entries()) {
               let name = attr[0], attrname = "@"+name;
               if (!names[attrname]) {
                   names[attrname] = i;
                   i++;
                   out.push(0);
                   out.push(15);
                   str2array(name,out);
               }
               out.push(0);
               out.push(2);
               out.push(names[attrname]);
               str2array(attr[1],out);
           }
       } else if (type == 3) {
           str2array(node.value,out);
       } else if(type == 12){
           str2array(node.value+"",out);
       }
   });
   // remove first 0
   out.shift();
   return out;
}
 */

export function fromL3(l3) {
	var names = {},
	    n = 0,
	    parents = [],
		depth = 0;
	var doc = emptyINode(9, "#document", emptyAttrMap());
	parents[0] = doc;
	const process = function(entry){
		let type = entry[0];
        // TODO have attributes accept any type
        if(type == 2){
            let parent = parents[depth];
            let name = names[entry[1]];
			parent = setAttribute(parent, name, array2str(entry,2));
        } else if(type == 7 || type == 10){
            doc = setAttribute(doc, entry[1], array2str(entry,2));
        } else if(type == 15){
            n++;
            names[n] = array2str(entry,1);
        } else if(type != 17){
            depth = entry[1];
            let parent = parents[depth - 1];
            let parentType = !!parent && parent._type;
            var node, name, valIndex;
    		if(type == 1 || type == 5 || type == 6) {
                name = names[entry[2]];
                if(parents[depth]) {
                    parents[depth] = finalize(parents[depth]);
                }
    			node = emptyINode(type, name, emptyAttrMap());
    			parents[depth] = node;
    		} else if(type == 3){
                if(parentType == 1 || parentType == 9){
                    name = count(parent);
                    valIndex = 2;
                } else {
                    name = names[entry[2]];
                    valIndex = 3;
                }
    			node = ivalue(type,name,array2str(entry,valIndex));
            } else  if(type == 12){
                if(parentType == 1 || parentType == 9){
                    name = count(parent);
                    valIndex = 2;
                } else {
                    name = names[entry[2]];
                    valIndex = 3;
                }
                node = ivalue(type,name,convert(array2str(entry,valIndex)),depth);
            }
            if (parent) parent = push(parent,[name, node]);
        }
	};
	var entry = [];
	for (var i = 0, l = l3.length; i < l; i++) {
		if(l3[i] === 0){
			process(entry);
			entry = [];
		} else {
			entry.push(l3[i]);
		}
	}
    process(entry);
	return finalize(parents[0]);
}
<commit_msg>moved to persist<commit_after>// optional:
//import FastIntCompression from "fastintcompression";

import { emptyINode, emptyAttrMap, attrEntries, setAttribute, ivalue, count, push, finalize } from './persist';

import { iter } from "./access";

export function str2array(str, ar, idx){
    for (var i=0, strLen=str.length; i<strLen; i++) {
        //ar.push(str.codePointAt(i));
        ar[idx++] = str.codePointAt(i);
    }
    return idx;
}

export function array2str(ar,i){
	var str = "",l = ar.length;
    for (; i<l; i++) {
    	str += String.fromCodePoint(ar[i]);
    }
    return str;
}

export function convert(v){
	var i = parseFloat(v);
	if(!isNaN(i)) return i;
	if(v === "true" || v === "false") return v !== "false";
	return v;
}

export function toNative1(val){
    if(val === 1) return false;
    if(val === 2) return true;
    if(val === 3) return 0;
    if(val === 4) return null;
}

export function toNative(v,i){
    if(v.length == 1) return new Float64Array(new Uint32Array([0,v[i]]))[0];
    return new Float64Array(new Uint32Array([v[i],v[i+1]]))[0];
}

export function fromNative(v,arr){
    var f = new Float64Array(1);
    f[0] = v;
    var i = new Uint32Array(f.buffer);
    if(i[0]) arr.push(i[0]);
    arr.push(i[1]);
}

function docAttrType(k) {
	switch (k) {
		case "DOCTYPE": return 10;
		default: return 7;
	}
}

/**
 * Create a flat buffer from the document tree
 * @param  {VNode} doc The document
 * @return {ArrayBuffer}  A flat buffer
 */
export function toL3(doc){
    var block = 1024 * 1024 * 8;
	var out = new Uint32Array(block),
	    names = {},
	    i = 0,
        j = 0;
	for (let attr of attrEntries(doc)) {
		let name = attr[0], attrname = "@"+name;
		if (!names[attrname]) {
			names[attrname] = ++j;
			out[i++] = 0;
			out[i++] = 15;
			i = str2array(name,out,i);
		}
		out[i++] = docAttrType(attr[0]);
		i = str2array(attr[0],out,i);
		i = str2array(attr[1],out,i);
	}
	iter(doc, function (node) {
		let type = node.type,
		    inode = node.inode,
		    depth = node.depth,
		    name = node.name;
        var nameIndex = 0;
        if (typeof name === "string") {
			if(!names[name]) {
				names[name] = ++j;
				out[i++] = 0;
				out[i++] = 15;
				i = str2array(name,out,i);
			}
			nameIndex = names[name];
		}
        out[i++] = 0;
        out[i++] = type;
        out[i++] = depth;
        if(nameIndex) out[i++] = nameIndex;
		if (type == 1) {
			for (let attr of attrEntries(inode)) {
				let name = attr[0], attrname = "@"+name;
				if (!names[attrname]) {
					names[attrname] = ++j;
					out[i++] = 0;
					out[i++] = 15;
					i = str2array(name,out,i);
				}
				out[i++] = 0;
				out[i++] = 2;
				out[i++] = names[attrname];
				i = str2array(attr[1],out,i);
			}
		} else if (type == 3) {
			i = str2array(node.value,out,i);
        } else if(type == 12){
            i = str2array(node.value+"",out,i);
        }
	});
    // remove first 0
    //out.shift();
	return out.subarray(1,i+1);
}
/*

export function toL3(doc){
   var out = [],
       names = {},
       i = 1;
   for (let attr of doc._attrs.entries()) {
       let name = attr[0], attrname = "@"+name;
       if (!names[attrname]) {
           names[attrname] = i;
           i++;
           out.push(0);
           out.push(15);
           str2array(name,out);
       }
       out.push(docAttrType(attr[0]));
       str2array(attr[0],out);
       str2array(attr[1],out);
   }
   iter(doc, function (node) {
       let type = node.type,
           inode = node.inode,
           depth = inode._depth,
           name = node.name;
       var nameIndex = 0;
       if (typeof name === "string") {
           if(!names[name]) {
               names[name] = i;
               i++;
               out.push(0);
               out.push(15);
               str2array(name,out);
           }
           nameIndex = names[name];
       }
       out.push(0);
       out.push(type);
       out.push(depth);
       if(nameIndex) out.push(nameIndex);
       if (type == 1) {
           for (let attr of inode._attrs.entries()) {
               let name = attr[0], attrname = "@"+name;
               if (!names[attrname]) {
                   names[attrname] = i;
                   i++;
                   out.push(0);
                   out.push(15);
                   str2array(name,out);
               }
               out.push(0);
               out.push(2);
               out.push(names[attrname]);
               str2array(attr[1],out);
           }
       } else if (type == 3) {
           str2array(node.value,out);
       } else if(type == 12){
           str2array(node.value+"",out);
       }
   });
   // remove first 0
   out.shift();
   return out;
}
 */

export function fromL3(l3) {
	var names = {},
	    n = 0,
	    parents = [],
		depth = 0;
	var doc = emptyINode(9, "#document", emptyAttrMap());
	parents[0] = doc;
	const process = function(entry){
		let type = entry[0];
        // TODO have attributes accept any type
        if(type == 2){
            let parent = parents[depth];
            let name = names[entry[1]];
			parent = setAttribute(parent, name, array2str(entry,2));
        } else if(type == 7 || type == 10){
            doc = setAttribute(doc, entry[1], array2str(entry,2));
        } else if(type == 15){
            n++;
            names[n] = array2str(entry,1);
        } else if(type != 17){
            depth = entry[1];
            let parent = parents[depth - 1];
            let parentType = !!parent && parent._type;
            var node, name, valIndex;
    		if(type == 1 || type == 5 || type == 6) {
                name = names[entry[2]];
                if(parents[depth]) {
                    parents[depth] = finalize(parents[depth]);
                }
    			node = emptyINode(type, name, emptyAttrMap());
    			parents[depth] = node;
    		} else if(type == 3){
                if(parentType == 1 || parentType == 9){
                    name = count(parent);
                    valIndex = 2;
                } else {
                    name = names[entry[2]];
                    valIndex = 3;
                }
    			node = ivalue(type,name,array2str(entry,valIndex));
            } else  if(type == 12){
                if(parentType == 1 || parentType == 9){
                    name = count(parent);
                    valIndex = 2;
                } else {
                    name = names[entry[2]];
                    valIndex = 3;
                }
                node = ivalue(type,name,convert(array2str(entry,valIndex)),depth);
            }
            if (parent) parent = push(parent,[name, node]);
        }
	};
	var entry = [];
	for (var i = 0, l = l3.length; i < l; i++) {
		if(l3[i] === 0){
			process(entry);
			entry = [];
		} else {
			entry.push(l3[i]);
		}
	}
    process(entry);
	return finalize(parents[0]);
}
<|endoftext|>