<commit_before>import { pt, rect } from "lively.graphics";
import { arr, string } from "lively.lang";

export default class FontMetric {

  static default() {
    if (!this._fontMetric)
      throw new Error("FontMetric has not yet been initialized!")
    return this._fontMetric;
  }

  static initDefault(domEnv) {
    if (!this._fontMetric) {
      if (!domEnv && typeof document === "undefined")
        throw new Error("Cannot initialize FontMetric without document");
      if (!domEnv) domEnv = {document}
      this._fontMetric = this.forDOMEnv(domEnv);
    }
    return this._fontMetric;
  }

  static removeDefault() {
    if (this._fontMetric) {
      this._fontMetric.uninstall();
      this._fontMetric = null;
    }
  }

  static forDOMEnv({document}) {
    var fontMetric = new FontMetric();
    fontMetric.install(document, document.body);
    return fontMetric;
  }

  constructor() {
    this.charMap = [];
    this.element = this.cachedBounds
                 = this.cachedBoundsFontFamily
                 = this.cachedBoundsFontSize
                 = null;
    this.cachedBoundsStr = "";
  }

  install(doc, parentEl) {
    this.element = doc.createElement("div");
    this.element.name = "fontMetric";
    this.setMeasureNodeStyles(this.element.style, true);
    parentEl.appendChild(this.element);
  }

  uninstall() {
    if (!this.element) return
    if (this.element.parentNode) this.element.parentNode.removeChild(this.element);
    this.element = null;
  }

  setMeasureNodeStyles(style, isRoot) {
    style.width = style.height = "auto";
    style.left = style.top = "0px";
    style.visibility = "hidden";
    style.position = "absolute";
    style.whiteSpace = "pre";
    style.font = "inherit";
    style.overflow = isRoot ? "hidden" : "visible";
  }

  measure(fontFamily, fontSize, char) {
    var rect = null;
    this.element.innerHTML = char;
    this.element.style.fontFamily = fontFamily;
    this.element.style.fontSize = fontSize + "px";
    try {
      rect = this.element.getBoundingClientRect();
    } catch(e) {
      rect = {width: 0, height:0};
    };
    return {
      height: rect.height,
      width: rect.width
    }
  }

  charBoundsFor(fontFamily, fontSize, fontKerning, str) {
    let nCols = str.length,
        bounds = new Array(nCols),
        { cachedBounds, cachedBoundsFontFamily, cachedBoundsFontSize, cachedBoundsStr } = this,
        nCacheCols = cachedBoundsStr.length,
        useCache = cachedBounds &&
                   cachedBoundsFontFamily === fontFamily &&
                   cachedBoundsFontSize === fontSize,
        w_width = this.sizeFor(fontFamily, fontSize, 'w').width,
        i_width = this.sizeFor(fontFamily, fontSize, 'i').width,
        fontIsProportional = (w_width !== i_width);
    for (let col = 0, x = 0; col < nCols; col++) {
      let width, height, char = str[col];
      if (fontIsProportional && fontKerning) {
        useCache = useCache && char === cachedBoundsStr[col];
        if (useCache) {
          ({ width, height } = cachedBounds[col]);
        } else {
          let prefix = str.substr(0, col+1),
              { width: prefixWidth, height: prefixHeight } = this.measure(fontFamily, fontSize, prefix);
          width = prefixWidth - x;
          height = prefixHeight;
        }
      } else {
        ({ width, height } = this.sizeFor(fontFamily, fontSize, char));
      }
      bounds[col] = { x, y: 0, width, height };
      x += width;
    }
    if (fontKerning) {
      this.cachedBounds = bounds;
      this.cachedBoundsStr = str;
      this.cachedBoundsFontFamily = fontFamily;
      this.cachedBoundsFontSize = fontSize;
    }
    return bounds;
  }

  sizeFor(fontFamily, fontSize, char) {
    if (char.length > 1) return this.measure(fontFamily, fontSize, char);

    if (!this.charMap[fontFamily]) {
      this.charMap[fontFamily] = [];
    }
    if (!this.charMap[fontFamily][fontSize]) {
      this.charMap[fontFamily][fontSize] = [];
    }
    if (!this.charMap[fontFamily][fontSize][char])
      this.charMap[fontFamily][fontSize][char] = this.measure(fontFamily, fontSize, char);
    return this.charMap[fontFamily][fontSize][char];
  }

  asciiSizes(fontFamily, fontSize) {
    var result = {};
    for (var i = 32; i <= 126; i++) {
      var char = String.fromCharCode(i);
      result[char] = this.sizeFor(fontFamily, fontSize, char)
    }
    return result;
  }

  defaultLineHeight(fontFamily, fontSize) {
    return this.sizeFor(fontFamily, fontSize, " ").height;
  }
}
<commit_msg>clean up fontMetric.cachedBoundsFor<commit_after>import { pt, rect } from "lively.graphics";
import { arr, string } from "lively.lang";

export default class FontMetric {

  static default() {
    if (!this._fontMetric)
      throw new Error("FontMetric has not yet been initialized!")
    return this._fontMetric;
  }

  static initDefault(domEnv) {
    if (!this._fontMetric) {
      if (!domEnv && typeof document === "undefined")
        throw new Error("Cannot initialize FontMetric without document");
      if (!domEnv) domEnv = {document}
      this._fontMetric = this.forDOMEnv(domEnv);
    }
    return this._fontMetric;
  }

  static removeDefault() {
    if (this._fontMetric) {
      this._fontMetric.uninstall();
      this._fontMetric = null;
    }
  }

  static forDOMEnv({document}) {
    var fontMetric = new FontMetric();
    fontMetric.install(document, document.body);
    return fontMetric;
  }

  constructor() {
    this.charMap = [];
    this.element = null;
    this.cachedBoundsInfo = {};
  }

  install(doc, parentEl) {
    this.element = doc.createElement("div");
    this.element.name = "fontMetric";
    this.setMeasureNodeStyles(this.element.style, true);
    parentEl.appendChild(this.element);
  }

  uninstall() {
    if (!this.element) return
    if (this.element.parentNode) this.element.parentNode.removeChild(this.element);
    this.element = null;
  }

  setMeasureNodeStyles(style, isRoot) {
    style.width = style.height = "auto";
    style.left = style.top = "0px";
    style.visibility = "hidden";
    style.position = "absolute";
    style.whiteSpace = "pre";
    style.font = "inherit";
    style.overflow = isRoot ? "hidden" : "visible";
  }

  measure(fontFamily, fontSize, char) {
    var rect = null;
    this.element.innerHTML = char;
    this.element.style.fontFamily = fontFamily;
    this.element.style.fontSize = fontSize + "px";
    try {
      rect = this.element.getBoundingClientRect();
    } catch(e) {
      rect = {width: 0, height:0};
    };
    return {
      height: rect.height,
      width: rect.width
    }
  }

  charBoundsFor(fontFamily, fontSize, fontKerning, str) {
    let nCols = str.length,
        bounds = new Array(nCols),
        { cachedBoundsInfo: { bounds: cachedBounds, str: cachedStr, fontFamily: cachedFontFamily, fontSize: cachedFontSize } } = this,
        useCache = cachedBounds && cachedFontFamily === fontFamily && cachedFontSize === fontSize,
        fontIsProportional = this.isProportional(fontFamily),
        adjustSpacing = fontIsProportional && fontKerning;
    for (let col = 0, x = 0; col < nCols; col++) {
      let width, height, char = str[col];
      if (adjustSpacing) {
        useCache = useCache && char === cachedStr[col];
        if (useCache)
          ({ width, height } = cachedBounds[col]);
        else {
          let prefix = str.substr(0, col+1);
          ({ width, height } = this.measure(fontFamily, fontSize, prefix));
          width -= x;
        }
      } else {
        ({ width, height } = this.sizeFor(fontFamily, fontSize, char));
      }
      bounds[col] = { x, y: 0, width, height };
      x += width;
    }
    if (adjustSpacing) this.cachedBoundsInfo = { bounds, str, fontFamily, fontSize };
    return bounds;
  }

  isProportional(fontFamily) {
    let w_width = this.sizeFor(fontFamily, 12, 'w').width,
        i_width = this.sizeFor(fontFamily, 12, 'i').width;
    return w_width !== i_width;
  }

  sizeFor(fontFamily, fontSize, char) {
    if (char.length > 1) return this.measure(fontFamily, fontSize, char);

    if (!this.charMap[fontFamily]) {
      this.charMap[fontFamily] = [];
    }
    if (!this.charMap[fontFamily][fontSize]) {
      this.charMap[fontFamily][fontSize] = [];
    }
    if (!this.charMap[fontFamily][fontSize][char])
      this.charMap[fontFamily][fontSize][char] = this.measure(fontFamily, fontSize, char);
    return this.charMap[fontFamily][fontSize][char];
  }

  asciiSizes(fontFamily, fontSize) {
    var result = {};
    for (var i = 32; i <= 126; i++) {
      var char = String.fromCharCode(i);
      result[char] = this.sizeFor(fontFamily, fontSize, char)
    }
    return result;
  }

  defaultLineHeight(fontFamily, fontSize) {
    return this.sizeFor(fontFamily, fontSize, " ").height;
  }
}
<|endoftext|>


<commit_before>//index.js
//获取应用实例
var app = getApp()
Page({
  data: {
    motto: 'Senparc.Weixin SDK Demo',
    userInfo: {}
  },
  //事件处理函数
  bindViewTap: function() {
    wx.navigateTo({
      url: '../logs/logs'
    })
  },

  bindWebsocketTap: function(){
    wx.navigateTo({
      url: '../websocket/websocket'
    })
  },

  //处理wx.request请求
  doRequest:function(){
    var that = this;
    wx.request({
      url: 'https://sdk.weixin.senparc.com/WxOpen/RequestData',
      data: { nickName : that.data.userInfo.nickName},
      method: 'POST', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
      // header: {}, // 设置请求的 header
      success: function(res){
        // success
        var json = res.data;
        //模组对话框
        wx.showModal({
          title: '收到消息',
          content: json.msg,
          showCancel:false,
          success: function(res) {
            if (res.confirm) {
              console.log('用户点击确定')
            }
          }
        });
      },
      fail: function() {
        // fail
      },
      complete: function() {
        // complete
      }
    })
  },
  //测试模板消息提交form
  formTemplateMessageSubmit:function(e)
  {
       var submitData = JSON.stringify({
          sessionId:wx.getStorageSync("sessionId"),
          formId:e.detail.formId
        });

        wx.request({
          url: 'https://sdk.weixin.senparc.com/WxOpen/TemplateTest',
          data: submitData,
          method: 'POST',
          success: function(res){
            // success
            var json = res.data;
            console.log(res.data);
            //模组对话框
            wx.showModal({
              title: '已尝试发送模板消息',
              content: json.msg,
              showCancel:false
            });
          }
        })
  },
  getPhoneNumber: function (e) {
    console.log(e.detail.errMsg)
    console.log(e.detail.iv)
    console.log(e.detail.encryptedData);

    //传输到后台解密
    wx.request({
      url: 'https://sdk.weixin.senparc.com/WxOpen/DecryptPhoneNumber',
      data: {
        sessionId: wx.getStorageSync('sessionId'),
        iv: e.detail.iv,
        encryptedData:e.detail.encryptedData
        },
      method: 'POST',
      success: function (res) {
        // success
        var json = res.data;
        console.log(res.data);
        //模组对话框
        var phoneNumberData = json.phoneNumber;
        var msg = '手机号：' + phoneNumberData.phoneNumber+
          '\r\n手机号（不带区号）：' + phoneNumberData.purePhoneNumber+
          '\r\n区号（国别号）' + phoneNumberData.countryCode+
          '\r\n水印信息：' + JSON.stringify(phoneNumberData.watermark);

        wx.showModal({
          title: '收到解密后的手机号信息',
          content: msg,
          showCancel: false
        });
      }
    })

  } ,

  onLoad: function () {
    console.log('onLoad')
    var that = this
    //调用应用实例的方法获取全局数据
    app.getUserInfo(function(userInfo){
      //更新数据
      that.setData({
        userInfo:userInfo
      })
      //console.log(userInfo);
    })

    var interval = setInterval(function() {
        that.setData({time:new Date().toLocaleTimeString()});
    },1000);
  }
})
<commit_msg>修改小程序Demo<commit_after>//index.js
//获取应用实例
var app = getApp()
Page({
  data: {
    motto: 'Senparc.Weixin SDK Demo',
    userInfo: {}
  },
  //事件处理函数
  bindViewTap: function() {
    wx.navigateTo({
      url: '../logs/logs'
    })
  },

  bindWebsocketTap: function(){
    wx.navigateTo({
      url: '../websocket/websocket'
    })
  },

  //处理wx.request请求
  doRequest:function(){
    var that = this;
    wx.request({
      url: 'https://sdk.weixin.senparc.com/WxOpen/RequestData',
      data: { nickName : that.data.userInfo.nickName},
      method: 'POST', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
      // header: {}, // 设置请求的 header
      success: function(res){
        // success
        var json = res.data;
        //模组对话框
        wx.showModal({
          title: '收到消息',
          content: json.msg,
          showCancel:false,
          success: function(res) {
            if (res.confirm) {
              console.log('用户点击确定')
            }
          }
        });
      },
      fail: function() {
        // fail
      },
      complete: function() {
        // complete
      }
    })
  },
  //测试模板消息提交form
  formTemplateMessageSubmit:function(e)
  {
       var submitData = JSON.stringify({
          sessionId:wx.getStorageSync("sessionId"),
          formId:e.detail.formId
        });

        wx.request({
          url: 'https://sdk.weixin.senparc.com/WxOpen/TemplateTest',
          data: submitData,
          method: 'POST',
          success: function(res){
            // success
            var json = res.data;
            console.log(res.data);
            //模组对话框
            wx.showModal({
              title: '已尝试发送模板消息',
              content: json.msg,
              showCancel:false
            });
          }
        })
  },
  getPhoneNumber: function (e) {
    console.log(e.detail.errMsg)
    console.log(e.detail.iv)
    console.log(e.detail.encryptedData);

    //传输到后台解密
    wx.request({
      url: 'https://sdk.weixin.senparc.com/WxOpen/DecryptPhoneNumber',
      data: {
        sessionId: wx.getStorageSync('sessionId'),
        iv: e.detail.iv,
        encryptedData:e.detail.encryptedData
        },
      method: 'POST',
      success: function (res) {
        // success
        var json = res.data;
        console.log(res.data);

        if(!json.success){

          wx.showModal({
            title: '解密过程发生异常',
            content: json.msg,
            showCancel: false
          });
          return;
        }

        //模组对话框
        var phoneNumberData = json.phoneNumber;
        var msg = '手机号：' + phoneNumberData.phoneNumber+
          '\r\n手机号（不带区号）：' + phoneNumberData.purePhoneNumber+
          '\r\n区号（国别号）' + phoneNumberData.countryCode+
          '\r\n水印信息：' + JSON.stringify(phoneNumberData.watermark);

        wx.showModal({
          title: '收到解密后的手机号信息',
          content: msg,
          showCancel: false
        });
      }
    })

  } ,

  onLoad: function () {
    console.log('onLoad')
    var that = this
    //调用应用实例的方法获取全局数据
    app.getUserInfo(function(userInfo){
      //更新数据
      that.setData({
        userInfo:userInfo
      })
      //console.log(userInfo);
    })

    var interval = setInterval(function() {
        that.setData({time:new Date().toLocaleTimeString()});
    },1000);
  }
})
<|endoftext|>


<commit_before> // Dependencies
 //import /s/jquery183.all.js

 // being tested
 //import /s/jquery.tagify.js

 // unit test helpers
 //import /s/qunit/qunit.js
 //import /s/test/testutil.js
 //import /s/support/sinon-1.1.1.js
 //import /s/support/sinon-qunit-1.0.0.js

/*global QUnit, URL, sinon, testutil*/

(function () {

	var tests = {};
	var val = 'ggoforth@decipherinc.com seth@decipherinc.com dj@decipherinc.com carlos@decipherinc.com';
	var className = 'emails';
	var tagifyOpts = {
		removeCb: sinon.stub(),
		addCb: sinon.stub(),
		placeholder: 'Enter email and press ENTER to add recipient',
		inputValidation: /.+@.+\..+/,
		validationMessage: 'Please enter a proper email address',
		delimiter: ' ',
		buttonText: 'add email',
		showButton: false
	};

	tests.tagify = function () {
		QUnit.module('$.fn', {
			setup: function () {
				var $input = $('<input />', {'class': className, type: 'text'});
				$input.val(val);

				$('#qunit-fixture').append($input);
			},
			teardown: function () {}
		});

		QUnit.test('fixture creation', function () {
			QUnit.ok($('.' + className).length, 'There should be a fixture created with a class of .' + className);
		});

		QUnit.test('tagify', function () {
			var $input = $('.' + className);
			var $fixture = $('#qunit-fixture');
			var emailToAdd = 'amrit@decipherinc.com';
			var $tagifyInput;
			var newInputVal;

			QUnit.raises(function () {
				$input.tagify('foo');
			}, /foo/, 'Calling tagify with a string argument that has no api should raise an error.');

			$input.tagify(tagifyOpts);

			//assert we have a tagify-instance stored on the node
			QUnit.ok($input.data('tagify-instance'), 'We have the tagify-instance on the node.');

			$tagifyInput = $fixture.find('.tagify-input');

			//assert the inital setup works properly
			QUnit.equal($tagifyInput.length, 1, 'An input should be created that will handle adding new tags.');
			QUnit.ok(! $input.is(':visible'), 'The original input is hidden.');

			//assert there is a proper amount of tags created
			QUnit.equal($fixture.find('.tagify-tag').length, val.split(' ').length, '4 tagify-tags should be created.');
			QUnit.equal($input.val(), val, 'The starting value of the original input should remain unchanged.');
			QUnit.equal($tagifyInput.attr('placeholder'), tagifyOpts.placeholder, 'The proper placeholder is used for the tagify input.');

			//test adding a new tag
			$tagifyInput.val($tagifyInput.val() + ' ' + emailToAdd);
			$tagifyInput.blur();

			newInputVal = $input.val();

			QUnit.ok(tagifyOpts.addCb.calledOnce, 'Should call the specified add callback.');
			QUnit.equal(newInputVal, val + ' ' + emailToAdd, 'The new value of the input should reflect the thing we just added.');
			QUnit.equal($fixture.find('.tagify-tag').length, $input.val().split(' ').length, '5 tagify-tags should be visible.');

			//test removing a tag
			$fixture.find('.tagify-remove').eq(0).click();

			newInputVal = $input.val();

			QUnit.equal($fixture.find('.tagify-tag').length, 4, '4 tags shold now be visible.');
			QUnit.equal($.inArray('ggoforth@decipherinc.com', newInputVal.split(' ')), -1, 'The proper thing has been removed from the original input.');
			QUnit.ok(tagifyOpts.removeCb.calledOnce, 'Should call the specified remove callback.');

			//remove everything and start again by simulating a pasted string
			$fixture.find('.tagify-remove').click();
			QUnit.equal(tagifyOpts.removeCb.callCount, 5, 'Should call the remove call back once for each tag that is removed.');
			QUnit.equal($fixture.find('.tagify-tag').length, 0, 'All tags should be removed from view.');
			QUnit.equal($fixture.find('.emails').val(), '', 'The original input should be empty now that everything has been removed');

			$tagifyInput.val(val);
			$tagifyInput.blur();

			QUnit.equal(tagifyOpts.addCb.callCount, 2, 'The add callback is called the proper amount of times.');
			QUnit.equal($fixture.find('.tagify-tag').length, val.split(' ').length, 'Pasting a space delimited string should properly parse the input when adding.');

			//test reset method
			$input.tagify('reset');

			QUnit.equal($fixture.find('.tagify-tag').length, 0, 'There should be no tags after a reset');
			QUnit.equal($tagifyInput.val(), '', 'The tagify input should be reset');
			QUnit.equal($input.val(), '', 'The original Tagify input should be reset');
		});
	};

    testutil.executeAll(tests);

})();<commit_msg>updates to unit tests<commit_after>
 // Dependencies
 //import /s/jquery183.all.js

 // being tested
 //import /s/jquery.tagify.js

 // unit test helpers
 //import /s/qunit/qunit.js
 //import /s/test/testutil.js
 //import /s/support/sinon-1.1.1.js
 //import /s/support/sinon-qunit-1.0.0.js

/*global QUnit, URL, sinon, testutil*/

(function () {

	var tests = {};
	var val = 'ggoforth@decipherinc.com seth@decipherinc.com dj@decipherinc.com carlos@decipherinc.com';
	var className = 'emails';
	var tagifyOpts = {
		removeCb: sinon.stub(),
		addCb: sinon.stub(),
		invalidCb: sinon.stub().callsArg(2),
		placeholder: 'Enter email and press ENTER to add recipient',
		inputValidation: /.+@.+\..+/,
		disallowInvalid: true,
		validationMessage: 'Please enter a proper email address',
		delimiter: ' ',
		buttonText: 'add email',
		showButton: false
	};

	tests.tagify = function () {
		QUnit.module('$.fn', {
			setup: function () {
				var $input = $('<input />', {'class': className, type: 'text'});
				$input.val(val);

				$('#qunit-fixture').append($input);
			},
			teardown: function () {}
		});

		QUnit.test('fixture creation', function () {
			QUnit.ok($('.' + className).length, 'There should be a fixture created with a class of .' + className);
		});

		QUnit.test('tagify', function () {
			var $input = $('.' + className);
			var $fixture = $('#qunit-fixture');
			var emailToAdd = 'amrit@decipherinc.com';
			var $tagifyInput;
			var newInputVal;

			QUnit.raises(function () {
				$input.tagify('foo');
			}, /foo/, 'Calling tagify with a string argument that has no api should raise an error.');

			$input.tagify(tagifyOpts);

			var inst = $input.data('tagify-instance');
			sinon.spy(inst, 'forceAdd');

			//assert we have a tagify-instance stored on the node
			QUnit.ok($input.data('tagify-instance'), 'We have the tagify-instance on the node.');

			$tagifyInput = $fixture.find('.tagify-input');

			//assert the inital setup works properly
			QUnit.equal($tagifyInput.length, 1, 'An input should be created that will handle adding new tags.');
			QUnit.ok(! $input.is(':visible'), 'The original input is hidden.');

			//assert there is a proper amount of tags created
			QUnit.equal($fixture.find('.tagify-tag').length, val.split(' ').length, '4 tagify-tags should be created.');
			QUnit.equal($input.val(), val, 'The starting value of the original input should remain unchanged.');
			QUnit.equal($tagifyInput.attr('placeholder'), tagifyOpts.placeholder, 'The proper placeholder is used for the tagify input.');

			//test adding an invalid tag
			$tagifyInput.val('foo');
			$tagifyInput.blur();
			QUnit.ok(tagifyOpts.invalidCb.called, 'the invalid callback is called.');
			QUnit.ok(inst.forceAdd.called, 'the force function is properly called when envoked from an invalidCb.');

			//test adding a new tag
			$tagifyInput.val($tagifyInput.val() + ' ' + emailToAdd);
			$tagifyInput.blur();
			newInputVal = $input.val();

			QUnit.ok(tagifyOpts.addCb.calledOnce, 'Should call the specified add callback.');
			QUnit.equal(newInputVal, val + ' ' + emailToAdd, 'The new value of the input should reflect the thing we just added.');
			QUnit.equal($fixture.find('.tagify-tag').length, $input.val().split(' ').length, '5 tagify-tags should be visible.');

			//test removing a tag
			$fixture.find('.tagify-remove').eq(0).click();
			newInputVal = $input.val();

			QUnit.equal($fixture.find('.tagify-tag').length, 4, '4 tags shold now be visible.');
			QUnit.equal($.inArray('ggoforth@decipherinc.com', newInputVal.split(' ')), -1, 'The proper thing has been removed from the original input.');
			QUnit.ok(tagifyOpts.removeCb.calledOnce, 'Should call the specified remove callback.');

			//remove everything and start again by simulating a pasted string
			$fixture.find('.tagify-remove').click();
			QUnit.equal(tagifyOpts.removeCb.callCount, 5, 'Should call the remove call back once for each tag that is removed.');
			QUnit.equal($fixture.find('.tagify-tag').length, 0, 'All tags should be removed from view.');
			QUnit.equal($fixture.find('.emails').val(), '', 'The original input should be empty now that everything has been removed');

			$tagifyInput.val(val);
			$tagifyInput.blur();

			QUnit.equal(tagifyOpts.addCb.callCount, 2, 'The add callback is called the proper amount of times.');
			QUnit.equal($fixture.find('.tagify-tag').length, val.split(' ').length, 'Pasting a space delimited string should properly parse the input when adding.');

			//test reset method
			$input.tagify('reset');

			QUnit.equal($fixture.find('.tagify-tag').length, 0, 'There should be no tags after a reset');
			QUnit.equal($tagifyInput.val(), '', 'The tagify input should be reset');
			QUnit.equal($input.val(), '', 'The original Tagify input should be reset');

			inst.forceAdd.restore();
		});
	};

    testutil.executeAll(tests);

})();<|endoftext|>


<commit_before>/**
 * Copyright (c) 2014, 2015 Tim Kuijsten
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

'use strict';

var bcryptNodejs = require('bcrypt-nodejs');
var twinBcrypt = require('twin-bcrypt');
var bcryptjs = require('bcryptjs');
var bcrypt = require('bcrypt');
var async = require('async');

var maxDuration = Number(process.argv[2]) || 500;
console.log('test duration per number of rounds, up to ' + maxDuration + 'ms');

var start, duration, salt, hash, rounds;

var tests = [];

tests.push(idle, testBcryptNodejs)
tests.push(idle, testTwinBcrypt)
tests.push(idle, testBcryptjs)
if (!process.browser) tests.push(idle, testBcrypt)

async.series(tests);

/////////////////////////////////////////////////////////////////////
// bcrypt-nodejs
function testBcryptNodejs(callback){

  rounds = 3;

  console.log('\nbcrypt-nodejs (pure js, no deps)');
  console.log('rounds', ' ms');

  do {
    rounds++;
    salt = bcryptNodejs.genSaltSync(rounds);
    start = new Date();
    hash = bcryptNodejs.hashSync('somepass', salt);
    duration = new Date() - start.getTime();
    console.log(('   ' + rounds).slice(-3), ('     ' + duration).slice(-6));
  } while (duration < maxDuration);

  callback()
}
/////////////////////////////////////////////////////////////////////
// twin-bcrypt
function testTwinBcrypt(callback){

  rounds = 3;

  console.log('\ntwin-bcrypt (pure js, no deps, asm.js)');
  console.log('rounds', ' ms');

  do {
    rounds++;
    salt = twinBcrypt.genSalt(rounds);
    start = new Date();
    hash = twinBcrypt.hashSync('somepass', salt);
    duration = new Date() - start.getTime();
    console.log(('   ' + rounds).slice(-3), ('     ' + duration).slice(-6));
  } while (duration < maxDuration);

  callback()
}
/////////////////////////////////////////////////////////////////////
// bcryptjs
function testBcryptjs(callback){

  rounds = 3;

  console.log('\nbcryptjs (pure js, no deps)');
  console.log('rounds', ' ms');

  do {
    rounds++;
    salt = bcryptjs.genSaltSync(rounds);
    start = new Date();
    hash = bcryptjs.hashSync('somepass', salt);
    duration = new Date() - start.getTime();
    console.log(('   ' + rounds).slice(-3), ('     ' + duration).slice(-6));
  } while (duration < maxDuration);

  callback()
}
/////////////////////////////////////////////////////////////////////
// bcrypt
function testBcrypt(callback){

  rounds = 3;

  console.log('\nbcrypt (c++, has deps)');
  console.log('rounds', ' ms');

  do {
    rounds++;
    salt = bcrypt.genSaltSync(rounds);
    start = new Date();
    hash = bcrypt.hashSync('somepass', salt);
    duration = new Date() - start.getTime();
    console.log(('   ' + rounds).slice(-3), ('     ' + duration).slice(-6));
  } while (duration < maxDuration);

  callback()
}

function idle(callback) {
  setTimeout(callback, 200)
}
<commit_msg>jshint<commit_after>/**
 * Copyright (c) 2014, 2015 Tim Kuijsten
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

'use strict';

var bcryptNodejs = require('bcrypt-nodejs');
var twinBcrypt = require('twin-bcrypt');
var bcryptjs = require('bcryptjs');
var bcrypt = require('bcrypt');
var async = require('async');

var maxDuration = Number(process.argv[2]) || 500;
console.log('test duration per number of rounds, up to ' + maxDuration + 'ms');

var start, duration, salt, hash, rounds;

var tests = [];

function idle(cb) {
  setTimeout(cb, 200);
}

/////////////////////////////////////////////////////////////////////
// bcrypt-nodejs
function testBcryptNodejs(cb){

  rounds = 3;

  console.log('\nbcrypt-nodejs (pure js, no deps)');
  console.log('rounds', ' ms');

  do {
    rounds++;
    salt = bcryptNodejs.genSaltSync(rounds);
    start = new Date();
    hash = bcryptNodejs.hashSync('somepass', salt);
    duration = new Date() - start.getTime();
    console.log(('   ' + rounds).slice(-3), ('     ' + duration).slice(-6));
  } while (duration < maxDuration);

  cb();
}
/////////////////////////////////////////////////////////////////////
// twin-bcrypt
function testTwinBcrypt(cb){

  rounds = 3;

  console.log('\ntwin-bcrypt (pure js, no deps, asm.js)');
  console.log('rounds', ' ms');

  do {
    rounds++;
    salt = twinBcrypt.genSalt(rounds);
    start = new Date();
    hash = twinBcrypt.hashSync('somepass', salt);
    duration = new Date() - start.getTime();
    console.log(('   ' + rounds).slice(-3), ('     ' + duration).slice(-6));
  } while (duration < maxDuration);

  cb();
}
/////////////////////////////////////////////////////////////////////
// bcryptjs
function testBcryptjs(cb){

  rounds = 3;

  console.log('\nbcryptjs (pure js, no deps)');
  console.log('rounds', ' ms');

  do {
    rounds++;
    salt = bcryptjs.genSaltSync(rounds);
    start = new Date();
    hash = bcryptjs.hashSync('somepass', salt);
    duration = new Date() - start.getTime();
    console.log(('   ' + rounds).slice(-3), ('     ' + duration).slice(-6));
  } while (duration < maxDuration);

  cb();
}
/////////////////////////////////////////////////////////////////////
// bcrypt
function testBcrypt(cb){

  rounds = 3;

  console.log('\nbcrypt (c++, has deps)');
  console.log('rounds', ' ms');

  do {
    rounds++;
    salt = bcrypt.genSaltSync(rounds);
    start = new Date();
    hash = bcrypt.hashSync('somepass', salt);
    duration = new Date() - start.getTime();
    console.log(('   ' + rounds).slice(-3), ('     ' + duration).slice(-6));
  } while (duration < maxDuration);

  cb();
}

tests.push(idle, testBcryptNodejs);
tests.push(idle, testTwinBcrypt);
tests.push(idle, testBcryptjs);
if (!process.browser) { tests.push(idle, testBcrypt); }

async.series(tests);
<|endoftext|>


<commit_before>var fs = require("fs");
var g = require("../src/gitlet");
var testUtil = require("./test-util");

describe("checkout", function() {
  beforeEach(testUtil.initTestDataDir);
  beforeEach(testUtil.pinDate);
  afterEach(testUtil.unpinDate);

  it("should throw if not in repo", function() {
    expect(function() { g.checkout(); })
      .toThrow("fatal: Not a gitlet repository (or any of the parent directories): .gitlet");
  });

  it("should throw if pass ref that does not resolve to a hash", function() {
    g.init();
    expect(function() { g.checkout("woo"); })
      .toThrow("error: pathspec woo did not match any file(s) known to gitlet.");
  });

  it("should throw if passed ref points to blob", function() {
    testUtil.createStandardFileStructure();
    g.init();
    g.add("1a/filea");
    g.commit({ m: "first" });
    expect(function() { g.checkout("5ceba65") })
      .toThrow("fatal: reference is not a tree: 5ceba65")
  });

  it("should throw if passed ref points to tree", function() {
    testUtil.createStandardFileStructure();
    g.init();
    g.add("1a/filea");
    g.commit({ m: "first" });
    expect(function() { g.checkout("17653b6d") })
      .toThrow("fatal: reference is not a tree: 17653b6d")
  });

  it("should throw if file has unstaged changes w/o common orig content with c/o", function() {
    testUtil.createStandardFileStructure();
    g.init();

    g.add("1a/filea");
    g.commit({ m: "first" });

    g.branch("other");

    fs.writeFileSync("1a/filea", "fileachange1");
    g.add("1a/filea");
    g.commit({ m: "second" });

    fs.writeFileSync("1a/filea", "fileachange2");

    expect(function() { g.checkout("other"); })
      .toThrow("error: Aborting. Your local changes to these files would be overwritten:\n" +
	             "1a/filea\n");
  });

  it("should throw if file has staged changes w/o common orig content with c/o", function() {
    testUtil.createStandardFileStructure();
    g.init();

    g.add("1a/filea");
    g.commit({ m: "first" });

    g.branch("other");

    fs.writeFileSync("1a/filea", "fileachange1");
    g.add("1a/filea");
    g.commit({ m: "second" });

    fs.writeFileSync("1a/filea", "fileachange2");
    g.add("1a/filea");

    expect(function() { g.checkout("other"); })
      .toThrow("error: Aborting. Your local changes to these files would be overwritten:\n" +
	             "1a/filea\n");
  });

  it("should list all files that would be overwritten when throwing", function() {
    testUtil.createStandardFileStructure();
    g.init();

    g.add("1a/filea");
    g.add("1b/fileb");
    g.add("1b/2b/filec");
    g.commit({ m: "first" });

    g.branch("other");

    fs.writeFileSync("1a/filea", "fileachange1");
    fs.writeFileSync("1b/fileb", "fileachange1");
    fs.writeFileSync("1b/2b/filec", "fileachange1");
    g.add("1a/filea");
    g.add("1b/fileb");
    g.add("1b/2b/filec");
    g.commit({ m: "second" });

    fs.writeFileSync("1a/filea", "fileachange2");
    fs.writeFileSync("1b/fileb", "fileachange2");
    fs.writeFileSync("1b/2b/filec", "fileachange2");

    expect(function() { g.checkout("other"); })
      .toThrow("error: Aborting. Your local changes to these files would be overwritten:\n" +
	             "1a/filea\n1b/fileb\n1b/2b/filec\n");
  });

  it("should not throw if file has changes w/ common orig content w/ c/o branch", function() {
    testUtil.createStandardFileStructure();
    g.init();

    g.add("1a/filea");
    g.commit({ m: "first" });

    g.branch("other");
    fs.writeFileSync("1a/filea", "fileachange2");

    g.checkout("other"); // does not throw
  });

  it("should keep uncommitted changes compatible w checked out branch", function() {
    testUtil.createStandardFileStructure();
    g.init();

    g.add("1a/filea");
    g.commit({ m: "first" });

    g.branch("other");
    fs.writeFileSync("1a/filea", "fileachange2");

    g.checkout("other");
    testUtil.expectFile("1a/filea", "fileachange2");
  });

  describe("successful checkout", function() {
    it("should remove committed files in previous working copy", function() {
      testUtil.createStandardFileStructure();
      g.init();

      g.add("1a/filea");
      g.commit({ m: "first" });
      g.branch("other");

      g.add("1b/fileb");
      g.commit({ m: "second" });

      g.checkout("other");
      expect(fs.existsSync("1b/fileb")).toEqual(false);
    });

    it("should add committed files in checked out ref", function() {
      testUtil.createStandardFileStructure();
      g.init();

      g.add("1a/filea");
      g.commit({ m: "first" });
      g.branch("other");

      g.add("1b/fileb");
      g.commit({ m: "second" });

      g.checkout("other");
      expect(fs.existsSync("1b/fileb")).toEqual(false); // sanity check

      g.checkout("master");
      expect(fs.existsSync("1b/fileb")).toEqual(true); // sanity check
    });

    it("should remove empty folders after checkout", function() {
      testUtil.createStandardFileStructure();
      g.init();

      g.add("1a/filea");
      g.commit({ m: "first" });
      g.branch("other");

      g.add("1b/2b/3b/4b/filed");
      g.commit({ m: "second" });

      g.checkout("other");
      expect(fs.existsSync("1b/2b/3b")).toEqual(false);
    });

    it("should not remove folders that have unindexed files", function() {
      testUtil.createStandardFileStructure();
      g.init();

      g.add("1a/filea");
      g.commit({ m: "first" });
      g.branch("other");

      g.add("1b/2b/3b/4b/filed");
      g.commit({ m: "second" });

      g.checkout("other");
      expect(fs.existsSync("1b/fileb")).toEqual(true);
    });

    it("should point head at checked out branch", function() {
      testUtil.createStandardFileStructure();
      g.init();

      g.add("1a/filea");
      g.commit({ m: "first" });
      g.branch("other");

      g.add("1b/fileb");
      g.commit({ m: "second" });

      g.checkout("other");
      testUtil.expectFile(".gitlet/HEAD", "ref: refs/heads/other");
    });

    it("should warn in detached head state if checkout commit", function() {
      testUtil.createStandardFileStructure();
      g.init();
      g.add("1a/filea");
      g.commit({ m: "first" });
      expect(g.checkout("21cb63f6"))
        .toEqual("Note: checking out 21cb63f6\nYou are in 'detached HEAD' state.");
    });
  });

  it("should allow a commit hash to be passed", function() {
    testUtil.createStandardFileStructure();
    g.init();

    g.add("1a/filea");
    g.commit({ m: "first" });
    g.add("1b/fileb");
    g.commit({ m: "second" });
    g.checkout("21cb63f6");
    testUtil.expectFile(".gitlet/HEAD", "21cb63f6");
  });

  it("should be able to exit detached head state", function() {
    testUtil.createStandardFileStructure();
    g.init();
    g.add("1a/filea");
    g.commit({ m: "first" });
    g.branch("other");
    g.add("1b/fileb");
    g.commit({ m: "second" });
    g.checkout("21cb63f6");
    g.checkout("other");
    testUtil.expectFile(".gitlet/HEAD", "ref: refs/heads/other");
  });

  describe("repeated checkout of same thing", function() {
    it("should be idempodent adds, dels, mods for branches", function() {
      testUtil.createStandardFileStructure();
      g.init();

      g.add("1a/filea");
      g.commit({ m: "first" });
      g.branch("other");

      fs.writeFileSync("1a/filea", "somethingelse");
      g.add("1a/filea");
      g.add("1b/fileb");
      g.commit({ m: "second" });

      g.checkout("other");
      g.checkout("other");
      testUtil.expectFile(".gitlet/HEAD", "ref: refs/heads/other");
      testUtil.expectFile("1a/filea", "filea");
      expect(fs.existsSync("1b/fileb")).toEqual(false);

      g.checkout("master");
      g.checkout("master");
      testUtil.expectFile(".gitlet/HEAD", "ref: refs/heads/master");
      testUtil.expectFile("1a/filea", "somethingelse");
      expect(fs.existsSync("1b/fileb")).toEqual(true);
    });

    it("should be idempodent adds, dels, mods for detached heads", function() {
      testUtil.createStandardFileStructure();
      g.init();
      g.add("1a/filea");
      g.commit({ m: "first" });
      fs.writeFileSync("1a/filea", "somethingelse");
      g.add("1a/filea");
      g.add("1b/fileb");
      g.commit({ m: "second" });

      g.checkout("21cb63f6");
      g.checkout("21cb63f6");
      testUtil.expectFile(".gitlet/HEAD", "21cb63f6");
      testUtil.expectFile("1a/filea", "filea");
      expect(fs.existsSync("1b/fileb")).toEqual(false);

      g.checkout("5c4868ac");
      g.checkout("5c4868ac");
      testUtil.expectFile(".gitlet/HEAD", "5c4868ac");
      testUtil.expectFile("1a/filea", "somethingelse");
      expect(fs.existsSync("1b/fileb")).toEqual(true);
    });
  });
});
<commit_msg>Test index gets written on checkout<commit_after>var fs = require("fs");
var g = require("../src/gitlet");
var testUtil = require("./test-util");

describe("checkout", function() {
  beforeEach(testUtil.initTestDataDir);
  beforeEach(testUtil.pinDate);
  afterEach(testUtil.unpinDate);

  it("should throw if not in repo", function() {
    expect(function() { g.checkout(); })
      .toThrow("fatal: Not a gitlet repository (or any of the parent directories): .gitlet");
  });

  it("should throw if pass ref that does not resolve to a hash", function() {
    g.init();
    expect(function() { g.checkout("woo"); })
      .toThrow("error: pathspec woo did not match any file(s) known to gitlet.");
  });

  it("should throw if passed ref points to blob", function() {
    testUtil.createStandardFileStructure();
    g.init();
    g.add("1a/filea");
    g.commit({ m: "first" });
    expect(function() { g.checkout("5ceba65") })
      .toThrow("fatal: reference is not a tree: 5ceba65")
  });

  it("should throw if passed ref points to tree", function() {
    testUtil.createStandardFileStructure();
    g.init();
    g.add("1a/filea");
    g.commit({ m: "first" });
    expect(function() { g.checkout("17653b6d") })
      .toThrow("fatal: reference is not a tree: 17653b6d")
  });

  it("should throw if file has unstaged changes w/o common orig content with c/o", function() {
    testUtil.createStandardFileStructure();
    g.init();

    g.add("1a/filea");
    g.commit({ m: "first" });

    g.branch("other");

    fs.writeFileSync("1a/filea", "fileachange1");
    g.add("1a/filea");
    g.commit({ m: "second" });

    fs.writeFileSync("1a/filea", "fileachange2");

    expect(function() { g.checkout("other"); })
      .toThrow("error: Aborting. Your local changes to these files would be overwritten:\n" +
	             "1a/filea\n");
  });

  it("should throw if file has staged changes w/o common orig content with c/o", function() {
    testUtil.createStandardFileStructure();
    g.init();

    g.add("1a/filea");
    g.commit({ m: "first" });

    g.branch("other");

    fs.writeFileSync("1a/filea", "fileachange1");
    g.add("1a/filea");
    g.commit({ m: "second" });

    fs.writeFileSync("1a/filea", "fileachange2");
    g.add("1a/filea");

    expect(function() { g.checkout("other"); })
      .toThrow("error: Aborting. Your local changes to these files would be overwritten:\n" +
	             "1a/filea\n");
  });

  it("should list all files that would be overwritten when throwing", function() {
    testUtil.createStandardFileStructure();
    g.init();

    g.add("1a/filea");
    g.add("1b/fileb");
    g.add("1b/2b/filec");
    g.commit({ m: "first" });

    g.branch("other");

    fs.writeFileSync("1a/filea", "fileachange1");
    fs.writeFileSync("1b/fileb", "fileachange1");
    fs.writeFileSync("1b/2b/filec", "fileachange1");
    g.add("1a/filea");
    g.add("1b/fileb");
    g.add("1b/2b/filec");
    g.commit({ m: "second" });

    fs.writeFileSync("1a/filea", "fileachange2");
    fs.writeFileSync("1b/fileb", "fileachange2");
    fs.writeFileSync("1b/2b/filec", "fileachange2");

    expect(function() { g.checkout("other"); })
      .toThrow("error: Aborting. Your local changes to these files would be overwritten:\n" +
	             "1a/filea\n1b/fileb\n1b/2b/filec\n");
  });

  it("should not throw if file has changes w/ common orig content w/ c/o branch", function() {
    testUtil.createStandardFileStructure();
    g.init();

    g.add("1a/filea");
    g.commit({ m: "first" });

    g.branch("other");
    fs.writeFileSync("1a/filea", "fileachange2");

    g.checkout("other"); // does not throw
  });

  it("should keep uncommitted changes compatible w checked out branch", function() {
    testUtil.createStandardFileStructure();
    g.init();

    g.add("1a/filea");
    g.commit({ m: "first" });

    g.branch("other");
    fs.writeFileSync("1a/filea", "fileachange2");

    g.checkout("other");
    testUtil.expectFile("1a/filea", "fileachange2");
  });

  describe("successful checkout", function() {
    it("should remove committed files in previous working copy", function() {
      testUtil.createStandardFileStructure();
      g.init();

      g.add("1a/filea");
      g.commit({ m: "first" });
      g.branch("other");

      g.add("1b/fileb");
      g.commit({ m: "second" });

      g.checkout("other");
      expect(fs.existsSync("1b/fileb")).toEqual(false);
    });

    it("should add committed files in checked out ref", function() {
      testUtil.createStandardFileStructure();
      g.init();

      g.add("1a/filea");
      g.commit({ m: "first" });
      g.branch("other");

      g.add("1b/fileb");
      g.commit({ m: "second" });

      g.checkout("other");
      expect(fs.existsSync("1b/fileb")).toEqual(false); // sanity check

      g.checkout("master");
      expect(fs.existsSync("1b/fileb")).toEqual(true); // sanity check
    });

    it("should remove empty folders after checkout", function() {
      testUtil.createStandardFileStructure();
      g.init();

      g.add("1a/filea");
      g.commit({ m: "first" });
      g.branch("other");

      g.add("1b/2b/3b/4b/filed");
      g.commit({ m: "second" });

      g.checkout("other");
      expect(fs.existsSync("1b/2b/3b")).toEqual(false);
    });

    it("should not remove folders that have unindexed files", function() {
      testUtil.createStandardFileStructure();
      g.init();

      g.add("1a/filea");
      g.commit({ m: "first" });
      g.branch("other");

      g.add("1b/2b/3b/4b/filed");
      g.commit({ m: "second" });

      g.checkout("other");
      expect(fs.existsSync("1b/fileb")).toEqual(true);
    });

    it("should point head at checked out branch", function() {
      testUtil.createStandardFileStructure();
      g.init();

      g.add("1a/filea");
      g.commit({ m: "first" });
      g.branch("other");

      g.add("1b/fileb");
      g.commit({ m: "second" });

      g.checkout("other");
      testUtil.expectFile(".gitlet/HEAD", "ref: refs/heads/other");
    });

    it("should warn in detached head state if checkout commit", function() {
      testUtil.createStandardFileStructure();
      g.init();
      g.add("1a/filea");
      g.commit({ m: "first" });
      expect(g.checkout("21cb63f6"))
        .toEqual("Note: checking out 21cb63f6\nYou are in 'detached HEAD' state.");
    });

    describe('index writing', function() {
      it("should remove files from index that are not in checked out branch", function() {
        testUtil.createStandardFileStructure();
        g.init();

        g.add("1a/filea");
        g.commit({ m: "first" });
        g.branch("other");

        g.add("1b/fileb");
        g.commit({ m: "second" });

        g.checkout("other");
        testUtil.expectFile(".gitlet/index", "1a/filea 5ceba65\n");
      });

      it("should add files to index that are now in checked out branch", function() {
        testUtil.createStandardFileStructure();
        g.init();

        g.add("1a/filea");
        g.commit({ m: "first" });
        g.branch("other");

        g.add("1b/fileb");
        g.commit({ m: "second" });

        g.checkout("other");
        testUtil.expectFile(".gitlet/index", "1a/filea 5ceba65\n");
        g.checkout("master");
        testUtil.expectFile(".gitlet/index", "1a/filea 5ceba65\n1b/fileb 5ceba66\n");
      });
    });
  });

  it("should allow a commit hash to be passed", function() {
    testUtil.createStandardFileStructure();
    g.init();

    g.add("1a/filea");
    g.commit({ m: "first" });
    g.add("1b/fileb");
    g.commit({ m: "second" });
    g.checkout("21cb63f6");
    testUtil.expectFile(".gitlet/HEAD", "21cb63f6");
  });

  it("should be able to exit detached head state", function() {
    testUtil.createStandardFileStructure();
    g.init();
    g.add("1a/filea");
    g.commit({ m: "first" });
    g.branch("other");
    g.add("1b/fileb");
    g.commit({ m: "second" });
    g.checkout("21cb63f6");
    g.checkout("other");
    testUtil.expectFile(".gitlet/HEAD", "ref: refs/heads/other");
  });

  describe("repeated checkout of same thing", function() {
    it("should be idempodent adds, dels, mods for branches", function() {
      testUtil.createStandardFileStructure();
      g.init();

      g.add("1a/filea");
      g.commit({ m: "first" });
      g.branch("other");

      fs.writeFileSync("1a/filea", "somethingelse");
      g.add("1a/filea");
      g.add("1b/fileb");
      g.commit({ m: "second" });

      g.checkout("other");
      g.checkout("other");
      testUtil.expectFile(".gitlet/HEAD", "ref: refs/heads/other");
      testUtil.expectFile("1a/filea", "filea");
      expect(fs.existsSync("1b/fileb")).toEqual(false);

      g.checkout("master");
      g.checkout("master");
      testUtil.expectFile(".gitlet/HEAD", "ref: refs/heads/master");
      testUtil.expectFile("1a/filea", "somethingelse");
      expect(fs.existsSync("1b/fileb")).toEqual(true);
    });

    it("should be idempodent adds, dels, mods for detached heads", function() {
      testUtil.createStandardFileStructure();
      g.init();
      g.add("1a/filea");
      g.commit({ m: "first" });
      fs.writeFileSync("1a/filea", "somethingelse");
      g.add("1a/filea");
      g.add("1b/fileb");
      g.commit({ m: "second" });

      g.checkout("21cb63f6");
      g.checkout("21cb63f6");
      testUtil.expectFile(".gitlet/HEAD", "21cb63f6");
      testUtil.expectFile("1a/filea", "filea");
      expect(fs.existsSync("1b/fileb")).toEqual(false);

      g.checkout("5c4868ac");
      g.checkout("5c4868ac");
      testUtil.expectFile(".gitlet/HEAD", "5c4868ac");
      testUtil.expectFile("1a/filea", "somethingelse");
      expect(fs.existsSync("1b/fileb")).toEqual(true);
    });
  });
});
<|endoftext|>


<commit_before>const assert = require('assert');
const http = require('http');
const path = require('path');
const ws = require('ws');
const remote = require('electron').remote;

const BrowserWindow = remote.require('electron').BrowserWindow;
const session = remote.require('electron').session;

describe('chromium feature', function() {
  var fixtures = path.resolve(__dirname, 'fixtures');
  var listener = null;

  afterEach(function() {
    if (listener != null) {
      window.removeEventListener('message', listener);
    }
    listener = null;
  });

  xdescribe('heap snapshot', function() {
    it('does not crash', function() {
      process.atomBinding('v8_util').takeHeapSnapshot();
    });
  });

  describe('sending request of http protocol urls', function() {
    it('does not crash', function(done) {
      this.timeout(5000);

      var server = http.createServer(function(req, res) {
        res.end();
        server.close();
        done();
      });
      server.listen(0, '127.0.0.1', function() {
        var port = server.address().port;
        $.get("http://127.0.0.1:" + port);
      });
    });
  });

  describe('document.hidden', function() {
    var url = "file://" + fixtures + "/pages/document-hidden.html";
    var w = null;

    afterEach(function() {
      w != null ? w.destroy() : void 0;
    });

    it('is set correctly when window is not shown', function(done) {
      w = new BrowserWindow({
        show: false
      });
      w.webContents.on('ipc-message', function(event, args) {
        assert.deepEqual(args, ['hidden', true]);
        done();
      });
      w.loadURL(url);
    });

    it('is set correctly when window is inactive', function(done) {
      w = new BrowserWindow({
        show: false
      });
      w.webContents.on('ipc-message', function(event, args) {
        assert.deepEqual(args, ['hidden', false]);
        done();
      });
      w.showInactive();
      w.loadURL(url);
    });
  });

  xdescribe('navigator.webkitGetUserMedia', function() {
    it('calls its callbacks', function(done) {
      this.timeout(5000);

      navigator.webkitGetUserMedia({
        audio: true,
        video: false
      }, function() {
        done();
      }, function() {
        done();
      });
    });
  });

  describe('navigator.mediaDevices', function() {
    if (process.env.TRAVIS === 'true') {
      return;
    }

    it('can return labels of enumerated devices', function(done) {
      navigator.mediaDevices.enumerateDevices().then((devices) => {
        const labels = devices.map((device) => device.label);
        const labelFound = labels.some((label) => !!label);
        if (labelFound)
          done();
        else
          done('No device labels found: ' + JSON.stringify(labels));
      }).catch(done);
    });
  });

  describe('navigator.language', function() {
    it('should not be empty', function() {
      assert.notEqual(navigator.language, '');
    });
  });

  describe('navigator.serviceWorker', function() {
    var url = "file://" + fixtures + "/pages/service-worker/index.html";
    var w = null;

    afterEach(function() {
      w != null ? w.destroy() : void 0;
    });

    it('should register for file scheme', function(done) {
      w = new BrowserWindow({
        show: false
      });
      w.webContents.on('ipc-message', function(event, args) {
        if (args[0] === 'reload') {
          w.webContents.reload();
        } else if (args[0] === 'error') {
          done('unexpected error : ' + args[1]);
        } else if (args[0] === 'response') {
          assert.equal(args[1], 'Hello from serviceWorker!');
          session.defaultSession.clearStorageData({
            storages: ['serviceworkers']
          }, function() {
            done();
          });
        }
      });
      w.loadURL(url);
    });
  });

  describe('window.open', function() {
    this.timeout(20000);

    it('returns a BrowserWindowProxy object', function() {
      var b = window.open('about:blank', '', 'show=no');
      assert.equal(b.closed, false);
      assert.equal(b.constructor.name, 'BrowserWindowProxy');
      b.close();
    });

    it('accepts "node-integration" as feature', function(done) {
      var b;
      listener = function(event) {
        assert.equal(event.data, 'undefined');
        b.close();
        done();
      };
      window.addEventListener('message', listener);
      b = window.open("file://" + fixtures + "/pages/window-opener-node.html", '', 'nodeIntegration=no,show=no');
    });

    it('inherit options of parent window', function(done) {
      var b;
      listener = function(event) {
        var height, ref1, width;
        ref1 = remote.getCurrentWindow().getSize(), width = ref1[0], height = ref1[1];
        assert.equal(event.data, "size: " + width + " " + height);
        b.close();
        done();
      };
      window.addEventListener('message', listener);
      b = window.open("file://" + fixtures + "/pages/window-open-size.html", '', 'show=no');
    });

    it('does not override child options', function(done) {
      var b, size;
      size = {
        width: 350,
        height: 450
      };
      listener = function(event) {
        assert.equal(event.data, "size: " + size.width + " " + size.height);
        b.close();
        done();
      };
      window.addEventListener('message', listener);
      b = window.open("file://" + fixtures + "/pages/window-open-size.html", '', "show=no,width=" + size.width + ",height=" + size.height);
    });
  });

  describe('window.opener', function() {
    this.timeout(10000);

    var url = "file://" + fixtures + "/pages/window-opener.html";
    var w = null;

    afterEach(function() {
      w != null ? w.destroy() : void 0;
    });

    it('is null for main window', function(done) {
      w = new BrowserWindow({
        show: false
      });
      w.webContents.on('ipc-message', function(event, args) {
        assert.deepEqual(args, ['opener', null]);
        done();
      });
      w.loadURL(url);
    });

    it('is not null for window opened by window.open', function(done) {
      var b;
      listener = function(event) {
        assert.equal(event.data, 'object');
        b.close();
        done();
      };
      window.addEventListener('message', listener);
      b = window.open(url, '', 'show=no');
    });
  });

  describe('window.postMessage', function() {
    it('sets the source and origin correctly', function(done) {
      var b, sourceId;
      sourceId = remote.getCurrentWindow().id;
      listener = function(event) {
        window.removeEventListener('message', listener);
        b.close();
        var message = JSON.parse(event.data);
        assert.equal(message.data, 'testing');
        assert.equal(message.origin, 'file://');
        assert.equal(message.sourceEqualsOpener, true);
        assert.equal(message.sourceId, sourceId);
        assert.equal(event.origin, 'file://');
        done();
      };
      window.addEventListener('message', listener);
      b = window.open("file://" + fixtures + "/pages/window-open-postMessage.html", '', 'show=no');
      BrowserWindow.fromId(b.guestId).webContents.once('did-finish-load', function() {
        b.postMessage('testing', '*');
      });
    });
  });

  describe('window.opener.postMessage', function() {
    it('sets source and origin correctly', function(done) {
      var b;
      listener = function(event) {
        window.removeEventListener('message', listener);
        b.close();
        assert.equal(event.source, b);
        assert.equal(event.origin, 'file://');
        done();
      };
      window.addEventListener('message', listener);
      b = window.open("file://" + fixtures + "/pages/window-opener-postMessage.html", '', 'show=no');
    });
  });

  describe('creating a Uint8Array under browser side', function() {
    it('does not crash', function() {
      var RUint8Array = remote.getGlobal('Uint8Array');
      new RUint8Array;
    });
  });

  describe('webgl', function() {
    it('can be get as context in canvas', function() {
      if (process.platform === 'linux') {
        return;
      }
      var webgl = document.createElement('canvas').getContext('webgl');
      assert.notEqual(webgl, null);
    });
  });

  describe('web workers', function() {
    it('Worker can work', function(done) {
      var worker = new Worker('../fixtures/workers/worker.js');
      var message = 'ping';
      worker.onmessage = function(event) {
        assert.equal(event.data, message);
        worker.terminate();
        done();
      };
      worker.postMessage(message);
    });

    it('SharedWorker can work', function(done) {
      var worker = new SharedWorker('../fixtures/workers/shared_worker.js');
      var message = 'ping';
      worker.port.onmessage = function(event) {
        assert.equal(event.data, message);
        done();
      };
      worker.port.postMessage(message);
    });
  });

  describe('iframe', function() {
    var iframe = null;

    beforeEach(function() {
      iframe = document.createElement('iframe');
    });

    afterEach(function() {
      document.body.removeChild(iframe);
    });

    it('does not have node integration', function(done) {
      iframe.src = "file://" + fixtures + "/pages/set-global.html";
      document.body.appendChild(iframe);
      iframe.onload = function() {
        assert.equal(iframe.contentWindow.test, 'undefined undefined undefined');
        done();
      };
    });
  });

  describe('storage', function() {
    it('requesting persitent quota works', function(done) {
      navigator.webkitPersistentStorage.requestQuota(1024 * 1024, function(grantedBytes) {
        assert.equal(grantedBytes, 1048576);
        done();
      });
    });
  });

  describe('websockets', function() {
    var wss = null;
    var server = null;
    var WebSocketServer = ws.Server;

    afterEach(function() {
      wss.close();
      server.close();
    });

    it('has user agent', function(done) {
      server = http.createServer();
      server.listen(0, '127.0.0.1', function() {
        var port = server.address().port;
        wss = new WebSocketServer({
          server: server
        });
        wss.on('error', done);
        wss.on('connection', function(ws) {
          if (ws.upgradeReq.headers['user-agent']) {
            done();
          } else {
            done('user agent is empty');
          }
        });
        new WebSocket("ws://127.0.0.1:" + port);
      });
    });
  });

  describe('Promise', function() {
    it('resolves correctly in Node.js calls', function(done) {
      document.registerElement('x-element', {
        prototype: Object.create(HTMLElement.prototype, {
          createdCallback: {
            value: function() {}
          }
        })
      });
      setImmediate(function() {
        var called = false;
        Promise.resolve().then(function() {
          done(called ? void 0 : new Error('wrong sequence'));
        });
        document.createElement('x-element');
        called = true;
      });
    });

    it('resolves correctly in Electron calls', function(done) {
      document.registerElement('y-element', {
        prototype: Object.create(HTMLElement.prototype, {
          createdCallback: {
            value: function() {}
          }
        })
      });
      remote.getGlobal('setImmediate')(function() {
        var called = false;
        Promise.resolve().then(function() {
          done(called ? void 0 : new Error('wrong sequence'));
        });
        document.createElement('y-element');
        called = true;
      });
    });
  });
});
<commit_msg>Don't run mediaDevices spec on Linux CI<commit_after>const assert = require('assert');
const http = require('http');
const path = require('path');
const ws = require('ws');
const remote = require('electron').remote;

const BrowserWindow = remote.require('electron').BrowserWindow;
const session = remote.require('electron').session;

const isCI = remote.getGlobal('isCi');

describe('chromium feature', function() {
  var fixtures = path.resolve(__dirname, 'fixtures');
  var listener = null;

  afterEach(function() {
    if (listener != null) {
      window.removeEventListener('message', listener);
    }
    listener = null;
  });

  xdescribe('heap snapshot', function() {
    it('does not crash', function() {
      process.atomBinding('v8_util').takeHeapSnapshot();
    });
  });

  describe('sending request of http protocol urls', function() {
    it('does not crash', function(done) {
      this.timeout(5000);

      var server = http.createServer(function(req, res) {
        res.end();
        server.close();
        done();
      });
      server.listen(0, '127.0.0.1', function() {
        var port = server.address().port;
        $.get("http://127.0.0.1:" + port);
      });
    });
  });

  describe('document.hidden', function() {
    var url = "file://" + fixtures + "/pages/document-hidden.html";
    var w = null;

    afterEach(function() {
      w != null ? w.destroy() : void 0;
    });

    it('is set correctly when window is not shown', function(done) {
      w = new BrowserWindow({
        show: false
      });
      w.webContents.on('ipc-message', function(event, args) {
        assert.deepEqual(args, ['hidden', true]);
        done();
      });
      w.loadURL(url);
    });

    it('is set correctly when window is inactive', function(done) {
      w = new BrowserWindow({
        show: false
      });
      w.webContents.on('ipc-message', function(event, args) {
        assert.deepEqual(args, ['hidden', false]);
        done();
      });
      w.showInactive();
      w.loadURL(url);
    });
  });

  xdescribe('navigator.webkitGetUserMedia', function() {
    it('calls its callbacks', function(done) {
      this.timeout(5000);

      navigator.webkitGetUserMedia({
        audio: true,
        video: false
      }, function() {
        done();
      }, function() {
        done();
      });
    });
  });

  describe('navigator.mediaDevices', function() {
    if (process.env.TRAVIS === 'true') {
      return;
    }
    if (isCI && process.platform === 'linux') {
      return;
    }

    it('can return labels of enumerated devices', function(done) {
      navigator.mediaDevices.enumerateDevices().then((devices) => {
        const labels = devices.map((device) => device.label);
        const labelFound = labels.some((label) => !!label);
        if (labelFound)
          done();
        else
          done('No device labels found: ' + JSON.stringify(labels));
      }).catch(done);
    });
  });

  describe('navigator.language', function() {
    it('should not be empty', function() {
      assert.notEqual(navigator.language, '');
    });
  });

  describe('navigator.serviceWorker', function() {
    var url = "file://" + fixtures + "/pages/service-worker/index.html";
    var w = null;

    afterEach(function() {
      w != null ? w.destroy() : void 0;
    });

    it('should register for file scheme', function(done) {
      w = new BrowserWindow({
        show: false
      });
      w.webContents.on('ipc-message', function(event, args) {
        if (args[0] === 'reload') {
          w.webContents.reload();
        } else if (args[0] === 'error') {
          done('unexpected error : ' + args[1]);
        } else if (args[0] === 'response') {
          assert.equal(args[1], 'Hello from serviceWorker!');
          session.defaultSession.clearStorageData({
            storages: ['serviceworkers']
          }, function() {
            done();
          });
        }
      });
      w.loadURL(url);
    });
  });

  describe('window.open', function() {
    this.timeout(20000);

    it('returns a BrowserWindowProxy object', function() {
      var b = window.open('about:blank', '', 'show=no');
      assert.equal(b.closed, false);
      assert.equal(b.constructor.name, 'BrowserWindowProxy');
      b.close();
    });

    it('accepts "node-integration" as feature', function(done) {
      var b;
      listener = function(event) {
        assert.equal(event.data, 'undefined');
        b.close();
        done();
      };
      window.addEventListener('message', listener);
      b = window.open("file://" + fixtures + "/pages/window-opener-node.html", '', 'nodeIntegration=no,show=no');
    });

    it('inherit options of parent window', function(done) {
      var b;
      listener = function(event) {
        var height, ref1, width;
        ref1 = remote.getCurrentWindow().getSize(), width = ref1[0], height = ref1[1];
        assert.equal(event.data, "size: " + width + " " + height);
        b.close();
        done();
      };
      window.addEventListener('message', listener);
      b = window.open("file://" + fixtures + "/pages/window-open-size.html", '', 'show=no');
    });

    it('does not override child options', function(done) {
      var b, size;
      size = {
        width: 350,
        height: 450
      };
      listener = function(event) {
        assert.equal(event.data, "size: " + size.width + " " + size.height);
        b.close();
        done();
      };
      window.addEventListener('message', listener);
      b = window.open("file://" + fixtures + "/pages/window-open-size.html", '', "show=no,width=" + size.width + ",height=" + size.height);
    });
  });

  describe('window.opener', function() {
    this.timeout(10000);

    var url = "file://" + fixtures + "/pages/window-opener.html";
    var w = null;

    afterEach(function() {
      w != null ? w.destroy() : void 0;
    });

    it('is null for main window', function(done) {
      w = new BrowserWindow({
        show: false
      });
      w.webContents.on('ipc-message', function(event, args) {
        assert.deepEqual(args, ['opener', null]);
        done();
      });
      w.loadURL(url);
    });

    it('is not null for window opened by window.open', function(done) {
      var b;
      listener = function(event) {
        assert.equal(event.data, 'object');
        b.close();
        done();
      };
      window.addEventListener('message', listener);
      b = window.open(url, '', 'show=no');
    });
  });

  describe('window.postMessage', function() {
    it('sets the source and origin correctly', function(done) {
      var b, sourceId;
      sourceId = remote.getCurrentWindow().id;
      listener = function(event) {
        window.removeEventListener('message', listener);
        b.close();
        var message = JSON.parse(event.data);
        assert.equal(message.data, 'testing');
        assert.equal(message.origin, 'file://');
        assert.equal(message.sourceEqualsOpener, true);
        assert.equal(message.sourceId, sourceId);
        assert.equal(event.origin, 'file://');
        done();
      };
      window.addEventListener('message', listener);
      b = window.open("file://" + fixtures + "/pages/window-open-postMessage.html", '', 'show=no');
      BrowserWindow.fromId(b.guestId).webContents.once('did-finish-load', function() {
        b.postMessage('testing', '*');
      });
    });
  });

  describe('window.opener.postMessage', function() {
    it('sets source and origin correctly', function(done) {
      var b;
      listener = function(event) {
        window.removeEventListener('message', listener);
        b.close();
        assert.equal(event.source, b);
        assert.equal(event.origin, 'file://');
        done();
      };
      window.addEventListener('message', listener);
      b = window.open("file://" + fixtures + "/pages/window-opener-postMessage.html", '', 'show=no');
    });
  });

  describe('creating a Uint8Array under browser side', function() {
    it('does not crash', function() {
      var RUint8Array = remote.getGlobal('Uint8Array');
      new RUint8Array;
    });
  });

  describe('webgl', function() {
    it('can be get as context in canvas', function() {
      if (process.platform === 'linux') {
        return;
      }
      var webgl = document.createElement('canvas').getContext('webgl');
      assert.notEqual(webgl, null);
    });
  });

  describe('web workers', function() {
    it('Worker can work', function(done) {
      var worker = new Worker('../fixtures/workers/worker.js');
      var message = 'ping';
      worker.onmessage = function(event) {
        assert.equal(event.data, message);
        worker.terminate();
        done();
      };
      worker.postMessage(message);
    });

    it('SharedWorker can work', function(done) {
      var worker = new SharedWorker('../fixtures/workers/shared_worker.js');
      var message = 'ping';
      worker.port.onmessage = function(event) {
        assert.equal(event.data, message);
        done();
      };
      worker.port.postMessage(message);
    });
  });

  describe('iframe', function() {
    var iframe = null;

    beforeEach(function() {
      iframe = document.createElement('iframe');
    });

    afterEach(function() {
      document.body.removeChild(iframe);
    });

    it('does not have node integration', function(done) {
      iframe.src = "file://" + fixtures + "/pages/set-global.html";
      document.body.appendChild(iframe);
      iframe.onload = function() {
        assert.equal(iframe.contentWindow.test, 'undefined undefined undefined');
        done();
      };
    });
  });

  describe('storage', function() {
    it('requesting persitent quota works', function(done) {
      navigator.webkitPersistentStorage.requestQuota(1024 * 1024, function(grantedBytes) {
        assert.equal(grantedBytes, 1048576);
        done();
      });
    });
  });

  describe('websockets', function() {
    var wss = null;
    var server = null;
    var WebSocketServer = ws.Server;

    afterEach(function() {
      wss.close();
      server.close();
    });

    it('has user agent', function(done) {
      server = http.createServer();
      server.listen(0, '127.0.0.1', function() {
        var port = server.address().port;
        wss = new WebSocketServer({
          server: server
        });
        wss.on('error', done);
        wss.on('connection', function(ws) {
          if (ws.upgradeReq.headers['user-agent']) {
            done();
          } else {
            done('user agent is empty');
          }
        });
        new WebSocket("ws://127.0.0.1:" + port);
      });
    });
  });

  describe('Promise', function() {
    it('resolves correctly in Node.js calls', function(done) {
      document.registerElement('x-element', {
        prototype: Object.create(HTMLElement.prototype, {
          createdCallback: {
            value: function() {}
          }
        })
      });
      setImmediate(function() {
        var called = false;
        Promise.resolve().then(function() {
          done(called ? void 0 : new Error('wrong sequence'));
        });
        document.createElement('x-element');
        called = true;
      });
    });

    it('resolves correctly in Electron calls', function(done) {
      document.registerElement('y-element', {
        prototype: Object.create(HTMLElement.prototype, {
          createdCallback: {
            value: function() {}
          }
        })
      });
      remote.getGlobal('setImmediate')(function() {
        var called = false;
        Promise.resolve().then(function() {
          done(called ? void 0 : new Error('wrong sequence'));
        });
        document.createElement('y-element');
        called = true;
      });
    });
  });
});
<|endoftext|>


<commit_before>var context = typeof AudioContext === 'undefined' ? new webkitAudioContext() : new AudioContext()
  , soundBank = {}, beats = {}
  , tempo = QUERY.tempo || 120
  , signature = QUERY.signature || 4
  , beatDur = 60/tempo, barDur = signature * beatDur
  , clock = new WAAClock(context, {tickTime: 0.05, lookAheadTime: 0.1})

// The following code highlights the current beat in the UI by calling the function `uiNextBeat` periodically.  //
// Using `WAAClock.setTimeout` we create an event that will be executed at t=0, then repeated every `beatDur`   //
// (so at t=0, t=1*beatDur, t=2*beatDur, ...).                                                                  //
// We also set a very big tolerance, because we don't want an event to be dropped just because it is late.      //
var event = clock.callbackAtTime(uiNextBeat, 0)
  .repeat(beatDur)
  .tolerance(100)

// This function activates the beat `beatInd` of `track`.                                                       //
// First we calculate the time of the next `beatInd`, and we schedule the node to start playing then, using     //
// `AudioNode.start2`.                                                                                //
// Because `AudioNode.start` can be called only once, we cannot use `repeat`, and we have to redo the whole     //
// thing : create a new node, schedule it with `start2`, loop, ..., once the event has been dealt with.         //
// This is achieved by adding listeners to 'executed' and 'expired' on the event, and rescheduling things for   //
// the next bar.                                                                                //
// For the `start` event, we need a small tolerance (10 ms here), because if the beat is activated right when   //
// it should be played, we will simply hear the beat late. So instead the beat is dropped and rescheduled for   //
// next bar, this keeping the pulse intact.                                                                     //
var startBeat = function(track, beatInd) {
  var scheduleBeat = function(time) {
    var bufferNode = soundBank[track]()
      , redo = function() { scheduleBeat(event.time + barDur) }
      , event = bufferNode.start2(time).tolerance(0.01)
    event.on('executed', redo)
    event.on('expired', redo)
    beats[track][beatInd] = event
  }
  scheduleBeat(nextBeatTime(beatInd))
}

// This function deactivates the beat `beatInd` of `track`
var stopBeat = function(track, beatInd) {
  var event = beats[track][beatInd]
  event.clear()                           // If the beat is deactivated, we simply clear the upcoming event.
  event.removeAllListeners()
}

// ---------- Just some helpers ---------- //
// This helper calculates the absolute time of the upcoming `beatInd`.
var nextBeatTime = function(beatInd) {
  var currentTime = context.currentTime
    , currentBar = Math.floor(currentTime / barDur)
    , currentBeat = Math.round(currentTime % barDur)
  if (currentBeat < beatInd) return currentBar * barDur + beatInd * beatDur
  else return (currentBar + 1) * barDur + beatInd * beatDur
}

// This helper loads sound buffers
var loadTrack = function(track) {
  var request = new XMLHttpRequest()
  request.open('GET', 'sounds/' + track + '.wav', true)
  request.responseType = 'arraybuffer'
  request.onload = function() {
    context.decodeAudioData(request.response, function(buffer) {
      var createNode = function() {
        var node = context.createBufferSource()
        node.buffer = buffer
        node.connect(context.destination)
        return node
      }
      soundBank[track] = createNode
    })
  }
  request.send()
}
<commit_msg>Remove verbose comments<commit_after>var context = typeof AudioContext === 'undefined' ? new webkitAudioContext() : new AudioContext()
  , soundBank = {}, beats = {}
  , tempo = QUERY.tempo || 120
  , signature = QUERY.signature || 4
  , beatDur = 60/tempo, barDur = signature * beatDur
  , clock = new WAAClock(context, {tickTime: 0.05, lookAheadTime: 0.1})

// The following code highlights the current beat in the UI by calling the function `uiNextBeat` periodically.
var event = clock.callbackAtTime(uiNextBeat, 0)
  .repeat(beatDur)
  .tolerance(100)

// This function activates the beat `beatInd` of `track`.
var startBeat = function(track, beatInd) {
  var scheduleBeat = function(time) {
    var bufferNode = soundBank[track]()
      , redo = function() { scheduleBeat(event.time + barDur) }
      , event = bufferNode.start2(time).tolerance(0.01)
    event.on('executed', redo)
    event.on('expired', redo)
    beats[track][beatInd] = event
  }
  scheduleBeat(nextBeatTime(beatInd))
}

// This function deactivates the beat `beatInd` of `track`.
var stopBeat = function(track, beatInd) {
  var event = beats[track][beatInd]
  event.clear()
  event.removeAllListeners()
}

// ---------- Just some helpers ---------- //
// This helper calculates the absolute time of the upcoming `beatInd`.
var nextBeatTime = function(beatInd) {
  var currentTime = context.currentTime
    , currentBar = Math.floor(currentTime / barDur)
    , currentBeat = Math.round(currentTime % barDur)
  if (currentBeat < beatInd) return currentBar * barDur + beatInd * beatDur
  else return (currentBar + 1) * barDur + beatInd * beatDur
}

// This helper loads sound buffers
var loadTrack = function(track) {
  var request = new XMLHttpRequest()
  request.open('GET', 'sounds/' + track + '.wav', true)
  request.responseType = 'arraybuffer'
  request.onload = function() {
    context.decodeAudioData(request.response, function(buffer) {
      var createNode = function() {
        var node = context.createBufferSource()
        node.buffer = buffer
        node.connect(context.destination)
        return node
      }
      soundBank[track] = createNode
    })
  }
  request.send()
}
<|endoftext|>


<commit_before>var privet2lastfm = {
    init: function () {
        // The event can be DOMContentLoaded, pageshow, pagehide, load or unload.
        if (gBrowser) gBrowser.addEventListener('DOMContentLoaded', this.onPageLoad, false);
    },
    onPageLoad: function (aEvent) {
        var d = aEvent.originalTarget; // doc is document that triggered the event
        var w = d.defaultView; // win is the window for the doc
        // test desired conditions and do something
        // if (d.nodeName == "#document") return; // only documents
        // if (w != w.top) return; //only top window.
        // if (w.frameElement) return; // skip iframes/frames

        if (d.location.href.match('privet.ru')) {
            var style = d.createElement("link");
            style.type = 'text/css';
            style.rel = 'stylesheet';
            style.href = 'chrome://privet2lastfm/skin/ascii-player.css';
            d.head.appendChild(style);

            var A = ASCIIPlayer(d);
            var flashPlayers = Array.prototype.slice.call(d.getElementsByTagName('embed'),0);
            var len = flashPlayers.length,
                i;

            console.log(flashPlayers.length);
            for (i = 0; i < len; i += 1) {
                var flashPlayer = flashPlayers[i];
                var flashVars = flashPlayer.getAttribute('flashvars');
                var fileURL = getFileURL(flashVars);
//                console.log(fileURL);
//                if (fileURL !== -1) {
//                    flashPlayer.setAttribute('data-url', fileURL);
//                    var a = new A(flashPlayer, {
//                        title: '',
//                        format: ''
//                    });
//                    var a = d.createElement('a');
//                    a.href = fileURL;
//                    a.innerHTML = fileURL;
//                    flashPlayer.insertBefore(a);

//                }
            }
        }
    }
}
window.addEventListener('load', function load(event) {
    window.removeEventListener('load', load, false); //remove listener, no longer needed
    privet2lastfm.init();
}, false);

function getFileURL(flashVars) {
    flashVars = flashVars.split('&');
    var len = flashVars.length,
        j;
    for (j = 0; j < len; j += 1) {
        var flashVarPair = flashVars[j].split('=');
        if (flashVarPair[0] === 'file') return flashVarPair[1];
    }
    return -1;
}

// content dictionarytip	jar:chrome/dictionarytip.jar!/content/dictionarytip/ contentaccessible=yes<commit_msg>Fix player replacer<commit_after>var privet2lastfm = {
    init: function () {
        // The event can be DOMContentLoaded, pageshow, pagehide, load or unload.
        if (gBrowser) gBrowser.addEventListener('DOMContentLoaded', this.onPageLoad, false);
    },
    onPageLoad: function (aEvent) {
        var d = aEvent.originalTarget; // doc is document that triggered the event
        var w = d.defaultView; // win is the window for the doc
        // test desired conditions and do something
        // if (d.nodeName == "#document") return; // only documents
        // if (w != w.top) return; //only top window.
        // if (w.frameElement) return; // skip iframes/frames

        if (d.location.href.match('privet.ru')) {
            var style = d.createElement("link");
            style.type = 'text/css';
            style.rel = 'stylesheet';
            style.href = 'chrome://privet2lastfm/skin/ascii-player.css';
            d.head.appendChild(style);

            var A = ASCIIPlayer(d);
            var flashPlayers = Array.prototype.slice.call(d.getElementsByTagName('embed'),0);
            var len = flashPlayers.length,
                i;

            console.log(flashPlayers.length);
            for (i = 0; i < len; i += 1) {
                var flashPlayer = flashPlayers[i];
                var flashVars = flashPlayer.getAttribute('flashvars');
                var fileURL = getFileURL(flashVars);
                console.log(fileURL);
                if (fileURL !== -1) {
                    flashPlayer.setAttribute('data-url', fileURL);
                    var a = new A(flashPlayer, {
                        title: '',
                        format: ''
                    });
                }
            }
        }
    }
}
window.addEventListener('load', function load(event) {
    window.removeEventListener('load', load, false); //remove listener, no longer needed
    privet2lastfm.init();
}, false);

function getFileURL(flashVars) {
    flashVars = flashVars.split('&');
    var len = flashVars.length,
        j;
    for (j = 0; j < len; j += 1) {
        var flashVarPair = flashVars[j].split('=');
        if (flashVarPair[0] === 'file') return flashVarPair[1];
    }
    return -1;
}

// content dictionarytip	jar:chrome/dictionarytip.jar!/content/dictionarytip/ contentaccessible=yes<|endoftext|>


<commit_before>/*
 * @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
 *
 * @author John Molakvoæ <skjnldsv@protonmail.com>
 *
 * @license GNU AGPL version 3 or any later version
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 */
(function() {
	'use strict';

	/**
	 * @class OCA.Search
	 *
	 * The Search class manages a search
	 *
	 * This is a simple method. Register a new search with your function as references.
	 * The events will forward the search or reset directly
	 *
	 * @param {function} searchCallback the function to run on a query search
	 * @param {function} resetCallback the function to run when the user reset the form
	 */
	var Search = function(searchCallback, resetCallback) {
		this.initialize(searchCallback, resetCallback);
	};

	/**
	 * @memberof OC
	 */
	Search.prototype = {
		/**
		 * Initialize the search box
		 *
		 * @param {function} searchCallback the function to run on a query search
		 * @param {function} resetCallback the function to run when the user reset the form
		 */
		initialize: function(searchCallback, resetCallback) {

			var self = this;

			if (typeof searchCallback !== 'function') {
				throw 'searchCallback must be a function';
			}
			if (typeof resetCallback !== 'function') {
				throw 'resetCallback must be a function';
			}

			this.searchCallback = searchCallback;
			this.resetCallback = resetCallback;
			console.debug('New search handler registered');

			/**
			 * Search
			 */
			this.search = function(event) {
				event.preventDefault();
				var query = document.getElementById('searchbox').value;
				self.searchCallback(query);
			};

			/**
			 * Reset form
			 */
			this.reset = function(event) {
				event.preventDefault();
				document.getElementById('searchbox').value = '';
				self.resetCallback();
			};

			// Show search
			document.getElementById('searchbox').style.display = 'block';

			// Register input event
			document
				.getElementById('searchbox')
				.addEventListener('input', _.debounce(this.search, 500), true);
			document
				.querySelector('form.searchbox')
				.addEventListener('submit', _.debounce(this.search, 500), true);

			// Register reset
			document
				.querySelector('form.searchbox')
				.addEventListener('reset', _.debounce(this.reset, 500), true);

			// Register esc key shortcut reset if focused
			document.addEventListener('keyup', function(event) {
				if (event.defaultPrevented) {
					return;
				}

				var key = event.key || event.keyCode;
				if (
					document.getElementById('searchbox') === document.activeElement &&
					document.getElementById('searchbox').value === ''
				) {
					if (key === 'Escape' || key === 'Esc' || key === 27) {
						_.debounce(self.reset, 500);
					}
				}
			});

			// Register ctrl+F key shortcut to focus
			document.addEventListener('keydown', function(event) {
				if (event.defaultPrevented) {
					return;
				}

				var key = event.key || event.keyCode;
				if (document.getElementById('searchbox') !== document.activeElement) {
					if (
						(event.ctrlKey || event.metaKey) && // CTRL or mac CMD
						!event.shiftKey &&					// Not SHIFT
						(key === 'f' || key === 70)			// F
					) {
						event.preventDefault();
						document.getElementById('searchbox').focus();
						document.getElementById('searchbox').select();
					}
				}
			});
		}
	};

	OCA.Search = Search;
})();
<commit_msg>Prevent search form submit<commit_after>/*
 * @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
 *
 * @author John Molakvoæ <skjnldsv@protonmail.com>
 *
 * @license GNU AGPL version 3 or any later version
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 */
(function() {
	'use strict';

	/**
	 * @class OCA.Search
	 *
	 * The Search class manages a search
	 *
	 * This is a simple method. Register a new search with your function as references.
	 * The events will forward the search or reset directly
	 *
	 * @param {function} searchCallback the function to run on a query search
	 * @param {function} resetCallback the function to run when the user reset the form
	 */
	var Search = function(searchCallback, resetCallback) {
		this.initialize(searchCallback, resetCallback);
	};

	/**
	 * @memberof OC
	 */
	Search.prototype = {
		/**
		 * Initialize the search box
		 *
		 * @param {function} searchCallback the function to run on a query search
		 * @param {function} resetCallback the function to run when the user reset the form
		 */
		initialize: function(searchCallback, resetCallback) {

			var self = this;

			if (typeof searchCallback !== 'function') {
				throw 'searchCallback must be a function';
			}
			if (typeof resetCallback !== 'function') {
				throw 'resetCallback must be a function';
			}

			this.searchCallback = searchCallback;
			this.resetCallback = resetCallback;
			console.debug('New search handler registered');

			/**
			 * Search
			 */
			this.search = function(event) {
				event.preventDefault();
				var query = document.getElementById('searchbox').value;
				self.searchCallback(query);
			};

			/**
			 * Reset form
			 */
			this.reset = function(event) {
				event.preventDefault();
				document.getElementById('searchbox').value = '';
				self.resetCallback();
			};

			// Show search
			document.getElementById('searchbox').style.display = 'block';

			// Register input event
			document
				.getElementById('searchbox')
				.addEventListener('input', _.debounce(self.search, 500), true);
			document
				.querySelector('form.searchbox')
				.addEventListener('submit', function(event) {
					// Avoid form submit
					event.preventDefault();
					_.debounce(self.search, 500);
				}, true);

			// Register reset
			document
				.querySelector('form.searchbox')
				.addEventListener('reset', _.debounce(self.reset, 500), true);

			// Register esc key shortcut reset if focused
			document.addEventListener('keyup', function(event) {
				if (event.defaultPrevented) {
					return;
				}

				var key = event.key || event.keyCode;
				if (
					document.getElementById('searchbox') === document.activeElement &&
					document.getElementById('searchbox').value === ''
				) {
					if (key === 'Escape' || key === 'Esc' || key === 27) {
						_.debounce(self.reset, 500);
					}
				}
			});

			// Register ctrl+F key shortcut to focus
			document.addEventListener('keydown', function(event) {
				if (event.defaultPrevented) {
					return;
				}

				var key = event.key || event.keyCode;
				if (document.getElementById('searchbox') !== document.activeElement) {
					if (
						(event.ctrlKey || event.metaKey) && // CTRL or mac CMD
						!event.shiftKey &&					// Not SHIFT
						(key === 'f' || key === 70)			// F
					) {
						event.preventDefault();
						document.getElementById('searchbox').focus();
						document.getElementById('searchbox').select();
					}
				}
			});
		}
	};

	OCA.Search = Search;
})();
<|endoftext|>


<commit_before>import React from 'react';
import { findDOMNode } from 'react-dom';
import moment from 'moment';
import ReactTestUtils from 'react/lib/ReactTestUtils';

import MonthDropdown from '../src/Calendar/MonthDropdown';

describe('MonthDropdown', () => {

  it('Should output year and month ', () => {

    const date = moment();
    const size = (date.year() - 1950) + 6;
    const instance = ReactTestUtils.renderIntoDocument(
      <MonthDropdown date={date} />
    );

    const instanceDOM = findDOMNode(instance);
    assert.equal(instanceDOM.querySelectorAll('.month-dropdown-year-title').length, size);
    assert.equal(instanceDOM.querySelectorAll('.month-dropdown-month-cell').length, size * 12);
  });

  it('Should call `onClick` callback ', (done) => {

    const date = moment();
    const doneOp = () => {
      done();
    };

    const instance = ReactTestUtils.renderIntoDocument(
      <MonthDropdown date={date} onClick={doneOp} />
    );

    const instanceDOM = findDOMNode(instance);
    ReactTestUtils.Simulate.click(instanceDOM.querySelector('.month-dropdown-month-cell'));
  });

  it('Should have a custom className', () => {
    const instance = ReactTestUtils.renderIntoDocument(
      <MonthDropdown className="custom" />
    );
    assert.ok(findDOMNode(instance).className.match(/\bcustom\b/));
  });

  it('Should have a custom style', () => {
    const fontSize = '12px';
    const instance = ReactTestUtils.renderIntoDocument(
      <MonthDropdown style={{ fontSize }} />
    );
    assert.equal(findDOMNode(instance).style.fontSize, fontSize);
  });

});
<commit_msg>Update test case<commit_after>import React from 'react';
import { findDOMNode } from 'react-dom';
import moment from 'moment';
import ReactTestUtils from 'react/lib/ReactTestUtils';

import MonthDropdown from '../src/Calendar/MonthDropdown';

describe('MonthDropdown', () => {

  it('Should output year and month ', () => {

    const date = moment();
    const size = (date.year() - 1950) + 6;
    const instance = ReactTestUtils.renderIntoDocument(
      <MonthDropdown date={date} />
    );

    const instanceDOM = findDOMNode(instance);
    assert.equal(instanceDOM.querySelectorAll('.month-dropdown-year-title').length, size);
  });

  it('Should call `onClick` callback ', (done) => {

    const date = moment();
    const doneOp = () => {
      done();
    };

    const instance = ReactTestUtils.renderIntoDocument(
      <MonthDropdown date={date} onClick={doneOp} />
    );

    const instanceDOM = findDOMNode(instance);
    ReactTestUtils.Simulate.click(instanceDOM.querySelector('.month-dropdown-month-cell'));
  });

  it('Should have a custom className', () => {
    const instance = ReactTestUtils.renderIntoDocument(
      <MonthDropdown className="custom" />
    );
    assert.ok(findDOMNode(instance).className.match(/\bcustom\b/));
  });

  it('Should have a custom style', () => {
    const fontSize = '12px';
    const instance = ReactTestUtils.renderIntoDocument(
      <MonthDropdown style={{ fontSize }} />
    );
    assert.equal(findDOMNode(instance).style.fontSize, fontSize);
  });

});
<|endoftext|>