<commit_before>/**
 * Validate contact us form
 */
let $contactForm = $('.js_contact_form'),
  formKey = simpleFormService.checkKey('d9878ccc8e22c7253d057015617f82cd'/* production key*/, null)[0],
  /* formKeyCC = simpleFormService.checkKey(null,'0d9da5473940d4380dc3a16fb47a2c55')[1], */
  formKeyCC = simpleFormService.checkKey(null, '6810d8ddb032c4c2a1a77cc7fe467bc3' /* CC production key*/)[1],
  $textAreaDescription = $('#message-detail-text');

let $modalAlert = $('#contact-alert-modal'),
  $modalAlertError = $('#contact-alert-modal-error'),
  $btnAlertOk = $modalAlert.find('#js_contact_btn_alert_ok'),
  $btnAlertError = $modalAlertError.find('#js_contact_btn_alert_ok-error'),
  errorDescriptionID = 'char-count';

$contactForm.submit(function(e) {
  let charCount = $textAreaDescription.val().length;
  function sendRequest(formData, formKey) {
    $.ajax({
      dataType: 'jsonp',
      url: 'https://getsimpleform.com/messages/ajax?form_api_token='+formKey,
      data: formData,
    }).done(function() {
      // callback shows the 'thank you message'
      showMsgSuccess('#contact-alert-modal');
    });
  }

  e.preventDefault();
  $('button', $contactForm).prop('disabled', true);

  if (3000 < charCount) {
    showMsgError('#contact-alert-modal-error', charCount);
    return false;
  }
  let formData = $contactForm.serialize();

  // sendRequest(formData, formKey);
  sendRequest(formData, formKeyCC);

  return false; // to stop the form from submitting
});

function showMsgSuccess($modalAlert) {
  // Show message
  $($modalAlert).modal();
  $contactForm.trigger('reset'); // clear on success
  $('button', $contactForm).prop('disabled', false);
}

function showMsgError(id, charCount) {
  $('#nexus-text-overflow-message').append(' Current count is '+charCount+'');
  $(id).modal();
}

function initListeners() {
  $btnAlertOk.on('click', function() {
    $modalAlert.modal('hide');
  });

  $btnAlertError.on('click', function() {
    $modalAlertError.modal('hide');
    $('#'+errorDescriptionID).remove();
    $('button', $contactForm).attr('disabled', false);
  });
}

initListeners();
<commit_msg>Revert "Merge branch 'fix/contact-us-form' into 'dev'"<commit_after>/**
 * Validate contact us form
 */
let $contactForm = $('.js_contact_form'),
  formKey = simpleFormService.checkKey('d9878ccc8e22c7253d057015617f82cd'/* production key*/, null)[0],
  /* formKeyCC = simpleFormService.checkKey(null,'0d9da5473940d4380dc3a16fb47a2c55')[1], */
  formKeyCC = simpleFormService.checkKey(null, 'f4a6500b8d01c981db58b4b859b78224' /* CC production key*/)[1],
  $textAreaDescription = $('#message-detail-text');

let $modalAlert = $('#contact-alert-modal'),
  $modalAlertError = $('#contact-alert-modal-error'),
  $btnAlertOk = $modalAlert.find('#js_contact_btn_alert_ok'),
  $btnAlertError = $modalAlertError.find('#js_contact_btn_alert_ok-error'),
  errorDescriptionID = 'char-count';

$contactForm.submit(function(e) {
  let charCount = $textAreaDescription.val().length;
  function sendRequest(formData, formKey) {
    $.ajax({
      dataType: 'jsonp',
      url: 'https://getsimpleform.com/messages/ajax?form_api_token='+formKey,
      data: formData,
    }).done(function() {
      // callback shows the 'thank you message'
      showMsgSuccess('#contact-alert-modal');
    });
  }

  e.preventDefault();
  $('button', $contactForm).prop('disabled', true);

  if (3000 < charCount) {
    showMsgError('#contact-alert-modal-error', charCount);
    return false;
  }
  let formData = $contactForm.serialize();

  // sendRequest(formData, formKey);
  sendRequest(formData, formKeyCC);

  return false; // to stop the form from submitting
});

function showMsgSuccess($modalAlert) {
  // Show message
  $($modalAlert).modal();
  $contactForm.trigger('reset'); // clear on success
  $('button', $contactForm).prop('disabled', false);
}

function showMsgError(id, charCount) {
  $('#nexus-text-overflow-message').append(' Current count is '+charCount+'');
  $(id).modal();
}

function initListeners() {
  $btnAlertOk.on('click', function() {
    $modalAlert.modal('hide');
  });

  $btnAlertError.on('click', function() {
    $modalAlertError.modal('hide');
    $('#'+errorDescriptionID).remove();
    $('button', $contactForm).attr('disabled', false);
  });
}

initListeners();
<|endoftext|>


<commit_before>import { _ } from 'meteor/underscore';
import { Meteor } from 'meteor/meteor';
import { check, Match } from 'meteor/check';

import { dbFoundations } from '/db/dbFoundations';
import { dbLog } from '/db/dbLog';
import { dbCompanyArchive } from '/db/dbCompanyArchive';
import { dbRound } from '/db/dbRound';
import { dbSeason } from '/db/dbSeason';
import { checkImageUrl } from '/server/imports/utils/checkImageUrl';
import { limitMethod } from '/server/imports/utils/rateLimit';
import { debug } from '/server/imports/utils/debug';
import { resourceManager } from '/server/imports/threading/resourceManager';

Meteor.methods({
  foundCompany(foundCompanyData) {
    check(this.userId, String);
    check(foundCompanyData, {
      companyName: String,
      tags: [String],
      pictureSmall: new Match.Maybe(String),
      pictureBig: new Match.Maybe(String),
      description: String
    });
    foundCompany(Meteor.user(), foundCompanyData);

    return true;
  }
});
export function foundCompany(user, foundCompanyData) {
  debug.log('foundCompany', { user, foundCompanyData });
  if (user.profile.isInVacation) {
    throw new Meteor.Error(403, '您現在正在渡假中，請好好放鬆！');
  }
  if (user.profile.notPayTax) {
    throw new Meteor.Error(403, '您現在有稅單逾期未繳！');
  }
  if (_.contains(user.profile.ban, 'manager')) {
    throw new Meteor.Error(403, '您現在被金融管理會禁止了擔任經理人的資格！');
  }
  if (_.contains(user.profile.ban, 'deal')) {
    throw new Meteor.Error(403, '您現在被金融管理會禁止了所有投資下單行為！');
  }
  if (user.profile.money < Meteor.settings.public.founderEarnestMoney) {
    throw new Meteor.Error(401, '您的現金不足，不足以支付投資保證金！');
  }
  const userId = user._id;
  if (dbFoundations.find({ manager: userId }).count() > 0) {
    throw new Meteor.Error(403, '您現在已經有一家新創公司正在申請中，無法同時發起第二家新創公司！');
  }
  const lastSeasonData = dbSeason.findOne({}, {
    sort: {
      beginDate: -1
    }
  });
  if (Date.now() >= (lastSeasonData.endDate.getTime() - Meteor.settings.public.foundExpireTime - 600000)) {
    const hours = Math.ceil(Meteor.settings.public.foundExpireTime / 3600000);
    throw new Meteor.Error(403, '商業季度即將結束前' + hours + '小時，禁止新創計劃！');
  }
  const lastRoundData = dbRound.findOne({}, {
    sort: {
      beginDate: -1
    }
  });
  if (Date.now() >= (lastRoundData.endDate.getTime() - Meteor.settings.public.seasonTime)) {
    throw new Meteor.Error(403, '賽季度結束前的最後一個商業季度，禁止新創計劃！');
  }
  const companyName = foundCompanyData.companyName;
  if (dbCompanyArchive.find({ name: companyName }).count() > 0) {
    throw new Meteor.Error(403, '已有相同名稱的公司上市或創立中，無法創立同名公司！');
  }
  if (foundCompanyData.pictureBig) {
    checkImageUrl(foundCompanyData.pictureBig);
  }
  if (foundCompanyData.pictureSmall) {
    checkImageUrl(foundCompanyData.pictureSmall);
  }
  // 先鎖定資源，再重新讀取一次資料進行運算
  resourceManager.throwErrorIsResourceIsLock(['user' + userId]);
  resourceManager.request('foundCompany', ['user' + userId], (release) => {
    const user = Meteor.users.findOne(userId, {
      fields: {
        'profile.money': 1
      }
    });
    if (user.profile.money < Meteor.settings.public.founderEarnestMoney) {
      throw new Meteor.Error(401, '您的現金不足，不足以支付投資保證金！');
    }
    if (dbFoundations.find({ manager: userId }).count() > 0) {
      throw new Meteor.Error(403, '您現在已經有一家新創公司正在籌備中，無法同時發起第二家新創公司！');
    }
    // 存放進archive中並取得_id
    foundCompanyData._id = dbCompanyArchive.insert({
      status: 'foundation',
      name: foundCompanyData.companyName,
      tags: foundCompanyData.tags,
      pictureSmall: foundCompanyData.pictureSmall,
      pictureBig: foundCompanyData.pictureBig,
      description: foundCompanyData.description
    });
    foundCompanyData.manager = userId;
    const createdAt = new Date();
    foundCompanyData.createdAt = createdAt;
    dbLog.insert({
      logType: '創立公司',
      userId: [userId],
      companyId: foundCompanyData._id,
      data: { companyName },
      createdAt: createdAt
    });
    dbLog.insert({
      logType: '參與投資',
      userId: [userId],
      companyId: foundCompanyData._id,
      data: {
        companyName,
        fund: Meteor.settings.public.founderEarnestMoney
      },
      createdAt: new Date(createdAt.getTime() + 1)
    });
    Meteor.users.update(userId, {
      $inc: {
        'profile.money': -1 * Meteor.settings.public.founderEarnestMoney
      }
    });
    foundCompanyData.invest = [
      {
        userId: userId,
        amount: Meteor.settings.public.founderEarnestMoney
      }
    ];
    dbFoundations.insert(foundCompanyData);
    release();
  });
}
// 二十秒鐘最多一次
limitMethod('foundCompany', 1, 20000);
<commit_msg>整理並加註部分程式碼<commit_after>import { _ } from 'meteor/underscore';
import { Meteor } from 'meteor/meteor';
import { check, Match } from 'meteor/check';

import { dbFoundations } from '/db/dbFoundations';
import { dbLog } from '/db/dbLog';
import { dbCompanyArchive } from '/db/dbCompanyArchive';
import { dbRound } from '/db/dbRound';
import { dbSeason } from '/db/dbSeason';
import { checkImageUrl } from '/server/imports/utils/checkImageUrl';
import { limitMethod } from '/server/imports/utils/rateLimit';
import { debug } from '/server/imports/utils/debug';
import { resourceManager } from '/server/imports/threading/resourceManager';

Meteor.methods({
  foundCompany(foundCompanyData) {
    check(this.userId, String);
    check(foundCompanyData, {
      companyName: String,
      tags: [String],
      pictureSmall: new Match.Maybe(String),
      pictureBig: new Match.Maybe(String),
      description: String
    });
    foundCompany(Meteor.user(), foundCompanyData);

    return true;
  }
});
export function foundCompany(user, foundCompanyData) {
  const { foundExpireTime, founderEarnestMoney, seasonTime } = Meteor.settings.public;

  debug.log('foundCompany', { user, foundCompanyData });
  if (user.profile.isInVacation) {
    throw new Meteor.Error(403, '您現在正在渡假中，請好好放鬆！');
  }
  if (user.profile.notPayTax) {
    throw new Meteor.Error(403, '您現在有稅單逾期未繳！');
  }
  if (_.contains(user.profile.ban, 'manager')) {
    throw new Meteor.Error(403, '您現在被金融管理會禁止了擔任經理人的資格！');
  }
  if (_.contains(user.profile.ban, 'deal')) {
    throw new Meteor.Error(403, '您現在被金融管理會禁止了所有投資下單行為！');
  }
  if (user.profile.money < founderEarnestMoney) {
    throw new Meteor.Error(401, '您的現金不足，不足以支付投資保證金！');
  }
  const userId = user._id;
  if (dbFoundations.find({ manager: userId }).count() > 0) {
    throw new Meteor.Error(403, '您現在已經有一家新創公司正在申請中，無法同時發起第二家新創公司！');
  }
  const lastSeasonData = dbSeason.findOne({}, {
    sort: {
      beginDate: -1
    }
  });
  // 防止換季動作與新創集資期間重疊，並預留足夠時間（10分鐘）以確保換季前最後一批新創處理完成
  if (Date.now() >= (lastSeasonData.endDate.getTime() - foundExpireTime - 600000)) {
    const hours = Math.ceil(foundExpireTime / 3600000);
    throw new Meteor.Error(403, '商業季度即將結束前' + hours + '小時，禁止新創計劃！');
  }
  const lastRoundData = dbRound.findOne({}, {
    sort: {
      beginDate: -1
    }
  });
  if (Date.now() >= (lastRoundData.endDate.getTime() - seasonTime)) {
    throw new Meteor.Error(403, '賽季度結束前的最後一個商業季度，禁止新創計劃！');
  }
  const companyName = foundCompanyData.companyName;
  if (dbCompanyArchive.find({ name: companyName }).count() > 0) {
    throw new Meteor.Error(403, '已有相同名稱的公司上市或創立中，無法創立同名公司！');
  }
  if (foundCompanyData.pictureBig) {
    checkImageUrl(foundCompanyData.pictureBig);
  }
  if (foundCompanyData.pictureSmall) {
    checkImageUrl(foundCompanyData.pictureSmall);
  }
  // 先鎖定資源，再重新讀取一次資料進行運算
  resourceManager.throwErrorIsResourceIsLock(['user' + userId]);
  resourceManager.request('foundCompany', ['user' + userId], (release) => {
    const user = Meteor.users.findOne(userId, {
      fields: {
        'profile.money': 1
      }
    });
    if (user.profile.money < founderEarnestMoney) {
      throw new Meteor.Error(401, '您的現金不足，不足以支付投資保證金！');
    }
    if (dbFoundations.find({ manager: userId }).count() > 0) {
      throw new Meteor.Error(403, '您現在已經有一家新創公司正在籌備中，無法同時發起第二家新創公司！');
    }
    // 存放進archive中並取得_id
    foundCompanyData._id = dbCompanyArchive.insert({
      status: 'foundation',
      name: foundCompanyData.companyName,
      tags: foundCompanyData.tags,
      pictureSmall: foundCompanyData.pictureSmall,
      pictureBig: foundCompanyData.pictureBig,
      description: foundCompanyData.description
    });
    foundCompanyData.manager = userId;
    const createdAt = new Date();
    foundCompanyData.createdAt = createdAt;
    dbLog.insert({
      logType: '創立公司',
      userId: [userId],
      companyId: foundCompanyData._id,
      data: { companyName },
      createdAt: createdAt
    });
    dbLog.insert({
      logType: '參與投資',
      userId: [userId],
      companyId: foundCompanyData._id,
      data: {
        companyName,
        fund: Meteor.settings.public.founderEarnestMoney
      },
      createdAt: new Date(createdAt.getTime() + 1)
    });
    Meteor.users.update(userId, {
      $inc: {
        'profile.money': -1 * founderEarnestMoney
      }
    });
    foundCompanyData.invest = [
      {
        userId: userId,
        amount: founderEarnestMoney
      }
    ];
    dbFoundations.insert(foundCompanyData);
    release();
  });
}
// 二十秒鐘最多一次
limitMethod('foundCompany', 1, 20000);
<|endoftext|>


<commit_before>var vows    = require('vows')
  , assert  = require('assert')
  , http    = require('http')
  , Client  = require('../lib/client')
  , hexUtil = require('./util/hexToBuffer')

vows.describe('Client').addBatch({
  //////////////////////////////////////////////////////////////////////
  // Test Constructor functionality
  //////////////////////////////////////////////////////////////////////
  'A constructor' : {
    // Test standard Client initialization
    'with URI options only' : {
      topic: function () {
        var client = new Client({ host: 'localhost', port: 9999, path: '/'}, false)
        return client.options
      }
    , 'contains the standard headers' : function (topic) {
        var headers = {
          'User-Agent': 'NodeJS XML-RPC Client'
        , 'Content-Type': 'text/xml'
        , 'Accept': 'text/xml'
        , 'Accept-Charset': 'UTF8'
        , 'Connection': 'Keep-Alive'
        }
        assert.deepEqual(topic, { host: 'localhost', port: 9999, path: '/', method: 'POST', headers: headers })
      }
    }
    // Test passing string URI for options
  , 'with a string URI for options' : {
      topic: function () {
        var client = new Client('http://localhost:9999', false)
        return client.options
      }
    , 'parses the string URI into URI fields' : function (topic) {
        assert.strictEqual(topic.host, 'localhost')
        assert.strictEqual(topic.path, '/')
        assert.equal(topic.port, 9999)
      }
    }
    // Test passing custom headers to the Client
  , 'with options containing header params' : {
      topic: function () {
        var client = new Client({ host: 'localhost', port: 9999, path: '/', headers: { 'User-Agent': 'Testaroo', 'Authorization': 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==' }}, false)
        return client.options
      }
    , 'does not overwrite the custom headers' : function (topic) {
        var headers = {
          'User-Agent': 'Testaroo'
        , 'Authorization': 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=='
        , 'Content-Type': 'text/xml'
        , 'Accept': 'text/xml'
        , 'Accept-Charset' : 'UTF8'
        , 'Connection': 'Keep-Alive'
        }
        assert.deepEqual(topic, { host: 'localhost', port: 9999, path: '/', method: 'POST', headers: headers })
      }
    }
    // Test passing HTTP Basic authentication credentials
  , 'with basic auth passed' : {
      topic: function () {
        var client = new Client({ basic_auth: { user: 'john', pass: '12345' } }, false)
        return client.options.headers
      }
    , 'correctly encodes and sets the \'Authorization\' header' : function (topic) {
        assert.isNotNull(topic.Authorization)
        assert.equal(topic.Authorization, "Basic am9objoxMjM0NQ==")
      }
    }
  }
  //////////////////////////////////////////////////////////////////////
  // Test method call functionality
  //////////////////////////////////////////////////////////////////////
, 'A method call' : {
    // Test invalid internal URI to send method call to
    'with an invalid internal URI' : {
      topic: function () {
        var client = new Client({ host: 'localhost', port: 9999, path: '/'}, false)
        client.methodCall('getArray', null, this.callback)
      }
    , 'contains the error' : function (error, value) {
        assert.isObject(error)
      }
    }
  , 'with a string URI for options' : {
      topic: function () {
        var that = this
        // Basic http server that sends a chunked XML response
        http.createServer(function (request, response) {
            response.writeHead(200, {'Content-Type': 'text/xml'})
            var data = '<?xml version="2.0" encoding="UTF-8"?>'
              + '<methodResponse>'
              + '<params>'
              + '<param><value><string>more.listMethods</string></value></param>'
              + '</params>'
              + '</methodResponse>'
            response.write(data)
            response.end()
        }).listen(9090, 'localhost')
        // Waits briefly to give the server time to start up and start listening
        setTimeout(function () {
          var client = new Client('http://localhost:9090', false)
          client.methodCall('listMethods', null, that.callback)
        }, 500)
      }
    , 'contains the string' : function (error, value) {
        assert.isNull(error)
        assert.deepEqual(value, 'more.listMethods')
      }
    }
  , 'with no host specified' : {
      topic: function () {
        var that = this
        // Basic http server that sends a chunked XML response
        http.createServer(function (request, response) {
            response.writeHead(200, {'Content-Type': 'text/xml'})
            var data = '<?xml version="2.0" encoding="UTF-8"?>'
              + '<methodResponse>'
              + '<params>'
              + '<param><value><string>system.listMethods</string></value></param>'
              + '</params>'
              + '</methodResponse>'
            response.write(data)
            response.end()
        }).listen(9091, 'localhost')
        // Waits briefly to give the server time to start up and start listening
        setTimeout(function () {
          var client = new Client({ port: 9091, path: '/'}, false)
          client.methodCall('listMethods', null, that.callback)
        }, 500)
      }
    , 'contains the string' : function (error, value) {
        assert.isNull(error)
        assert.deepEqual(value, 'system.listMethods')
      }
    }
  , 'with a chunked response' : {
      topic: function () {
        var that = this
        // Basic http server that sends a chunked XML response
        http.createServer(function (request, response) {
          response.writeHead(200, {'Content-Type': 'text/xml'})
          var chunk1 = '<?xml version="2.0" encoding="UTF-8"?>'
            + '<methodResponse>'
            + '<params>'
            + '<param><value><array><data>'
            + '<value><string>system.listMethods</string></value>'
            + '<value><string>system.methodSignature</string></value>'
          var chunk2 = '<value><string>xmlrpc_dialect</string></value>'
            + '</data></array></value></param>'
            + '</params>'
            + '</methodResponse>'
          response.write(chunk1)
          response.write(chunk2)
          response.end()
        }).listen(9092, 'localhost')
        // Waits briefly to give the server time to start up and start listening
        setTimeout(function () {
          var client = new Client({ host: 'localhost', port: 9092, path: '/'}, false)
          client.methodCall('listMethods', null, that.callback)
        }, 500)
      }
    , 'contains the array' : function (error, value) {
        assert.isNull(error)
        assert.deepEqual(value, ['system.listMethods', 'system.methodSignature', 'xmlrpc_dialect'])
      }
    }
  , 'with a utf-8 encoding' : {
      topic: function () {
        var that = this
        http.createServer(function (request, response) {
            response.writeHead(200, {'Content-Type': 'text/xml'})
            var data = '<?xml version="2.0" encoding="UTF-8"?>'
              + '<methodResponse>'
              + '<params>'
              + '<param><value><string>here is mr. Snowman: ☃</string></value></param>'
              + '</params>'
              + '</methodResponse>'
            response.write(data)
            response.end()
        }).listen(9093, 'localhost')
        // Waits briefly to give the server time to start up and start listening
        setTimeout(function () {
          var client = new Client('http://localhost:9093', false)
          client.methodCall('listMethods', null, that.callback)
        }, 500)
      }
    , 'contains the correct string' : function (error, value) {
        assert.isNull(error)
        assert.deepEqual(value, 'here is mr. Snowman: ☃')
      }
    }
  , 'with a ISO-8859-1 encoding' : {
      topic: function () {
        var that = this
        http.createServer(function (request, response) {
          response.writeHead(200, {'Content-Type': 'text/xml'})
          // To prevent including a npm package that needs to compile (iconv):
          // The following iso 8859-1 text below in hex
          //   <?xml version="1.0" encoding="ISO-8859-1"?>
          //   <methodResponse>
          //   <params>
          //   <param><value><string>äè12</string></value></param>
          //   </params>
          //   </methodResponse>
          var hex = '3c3f786d6c2076657273696f6e3d22312e302220656e636'
            + 'f64696e673d2249534f2d383835392d31223f3e3c6d6574686f64'
            + '526573706f6e73653e3c706172616d733e3c706172616d3e3c766'
            + '16c75653e3c737472696e673ee4e831323c2f737472696e673e3c'
            + '2f76616c75653e3c2f706172616d3e3c2f706172616d733e3c2f6'
            + 'd6574686f64526573706f6e73653e'
          var hexData = null
          try {
            // Hex encoding is only supported in Node v0.6+
            hexData = new Buffer(hex, 'hex')
          }
          catch (e) {
            hexData = hexUtil.hexToBuffer(hex)
          }
          response.write(hexData)
          response.end()
        }).listen(9094, 'localhost')
        // Waits briefly to give the server time to start up and start listening
        setTimeout(function () {
          var client = new Client({ host: 'localhost', port: 9094, path: '/', responseEncoding : 'binary'}, false)
          client.methodCall('listMethods', null, that.callback)
        }, 500)
      }
    , 'contains the correct string' : function (error, value) {
        assert.isNull(error)
        assert.deepEqual(value, 'äè12')
      }
    }
  , 'with a multi-byte character in request' : {
      topic: function () {
        var that = this
          , requestBody = ""
        http.createServer(function (request, response) {
          request.setEncoding('utf8')
          request.on('data', function (chunk) {
            requestBody += chunk
          })
          request.on('end', function () {
            response.writeHead(200, {'Content-Type': 'text/xml'})
            var data = '<?xml version="2.0" encoding="UTF-8"?>'
              + '<methodResponse>'
              + '<params>'
              + '<param><value><string>ok</string></value></param>'
              + '</params>'
              + '</methodResponse>'
            response.write(data)
            response.end()
          })
        }).listen(9095, 'localhost')
        // Waits briefly to give the server time to start up and start listening
        setTimeout(function () {
          var client = new Client({ host: 'localhost', port: 9095, path: '/'}, false)
          client.methodCall('multiByte', ['ö'], function (error) {
            that.callback(error, requestBody)
          })
        }, 500)
      }
    , 'contains full request' : function (error, value) {
        var data = '<?xml version="1.0"?>' +
          '<methodCall>' +
          '<methodName>multiByte</methodName>' +
          '<params><param><value><string>ö</string></value></param></params>' +
          '</methodCall>'
        assert.isNull(error)
        assert.deepEqual(value, data)
      }
    }
  }
}).export(module)
<commit_msg>Uses callbacks when server is ready for test.<commit_after>var vows    = require('vows')
  , assert  = require('assert')
  , http    = require('http')
  , Client  = require('../lib/client')
  , hexUtil = require('./util/hexToBuffer')

vows.describe('Client').addBatch({
  //////////////////////////////////////////////////////////////////////
  // Test Constructor functionality
  //////////////////////////////////////////////////////////////////////
  'A constructor' : {
    // Test standard Client initialization
    'with URI options only' : {
      topic: function () {
        var client = new Client({ host: 'localhost', port: 9999, path: '/'}, false)
        return client.options
      }
    , 'contains the standard headers' : function (topic) {
        var headers = {
          'User-Agent': 'NodeJS XML-RPC Client'
        , 'Content-Type': 'text/xml'
        , 'Accept': 'text/xml'
        , 'Accept-Charset': 'UTF8'
        , 'Connection': 'Keep-Alive'
        }
        assert.deepEqual(topic, { host: 'localhost', port: 9999, path: '/', method: 'POST', headers: headers })
      }
    }
    // Test passing string URI for options
  , 'with a string URI for options' : {
      topic: function () {
        var client = new Client('http://localhost:9999', false)
        return client.options
      }
    , 'parses the string URI into URI fields' : function (topic) {
        assert.strictEqual(topic.host, 'localhost')
        assert.strictEqual(topic.path, '/')
        assert.equal(topic.port, 9999)
      }
    }
    // Test passing custom headers to the Client
  , 'with options containing header params' : {
      topic: function () {
        var client = new Client({ host: 'localhost', port: 9999, path: '/', headers: { 'User-Agent': 'Testaroo', 'Authorization': 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==' }}, false)
        return client.options
      }
    , 'does not overwrite the custom headers' : function (topic) {
        var headers = {
          'User-Agent': 'Testaroo'
        , 'Authorization': 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=='
        , 'Content-Type': 'text/xml'
        , 'Accept': 'text/xml'
        , 'Accept-Charset' : 'UTF8'
        , 'Connection': 'Keep-Alive'
        }
        assert.deepEqual(topic, { host: 'localhost', port: 9999, path: '/', method: 'POST', headers: headers })
      }
    }
    // Test passing HTTP Basic authentication credentials
  , 'with basic auth passed' : {
      topic: function () {
        var client = new Client({ basic_auth: { user: 'john', pass: '12345' } }, false)
        return client.options.headers
      }
    , 'correctly encodes and sets the \'Authorization\' header' : function (topic) {
        assert.isNotNull(topic.Authorization)
        assert.equal(topic.Authorization, "Basic am9objoxMjM0NQ==")
      }
    }
  }
  //////////////////////////////////////////////////////////////////////
  // Test method call functionality
  //////////////////////////////////////////////////////////////////////
, 'A method call' : {
    // Test invalid internal URI to send method call to
    'with an invalid internal URI' : {
      topic: function () {
        var client = new Client({ host: 'localhost', port: 9999, path: '/'}, false)
        client.methodCall('getArray', null, this.callback)
      }
    , 'contains the error' : function (error, value) {
        assert.isObject(error)
      }
    }
  , 'with a string URI for options' : {
      topic: function () {
        var that = this
        // Basic http server that sends a chunked XML response
        http.createServer(function (request, response) {
            response.writeHead(200, {'Content-Type': 'text/xml'})
            var data = '<?xml version="2.0" encoding="UTF-8"?>'
              + '<methodResponse>'
              + '<params>'
              + '<param><value><string>more.listMethods</string></value></param>'
              + '</params>'
              + '</methodResponse>'
            response.write(data)
            response.end()
        }).listen(9090, 'localhost', function() {
          var client = new Client('http://localhost:9090', false)
          client.methodCall('listMethods', null, that.callback)
        })
      }
    , 'contains the string' : function (error, value) {
        assert.isNull(error)
        assert.deepEqual(value, 'more.listMethods')
      }
    }
  , 'with no host specified' : {
      topic: function () {
        var that = this
        // Basic http server that sends a chunked XML response
        http.createServer(function (request, response) {
            response.writeHead(200, {'Content-Type': 'text/xml'})
            var data = '<?xml version="2.0" encoding="UTF-8"?>'
              + '<methodResponse>'
              + '<params>'
              + '<param><value><string>system.listMethods</string></value></param>'
              + '</params>'
              + '</methodResponse>'
            response.write(data)
            response.end()
        }).listen(9091, 'localhost', function() {
          var client = new Client({ port: 9091, path: '/'}, false)
          client.methodCall('listMethods', null, that.callback)
        })
      }
    , 'contains the string' : function (error, value) {
        assert.isNull(error)
        assert.deepEqual(value, 'system.listMethods')
      }
    }
  , 'with a chunked response' : {
      topic: function () {
        var that = this
        // Basic http server that sends a chunked XML response
        http.createServer(function (request, response) {
          response.writeHead(200, {'Content-Type': 'text/xml'})
          var chunk1 = '<?xml version="2.0" encoding="UTF-8"?>'
            + '<methodResponse>'
            + '<params>'
            + '<param><value><array><data>'
            + '<value><string>system.listMethods</string></value>'
            + '<value><string>system.methodSignature</string></value>'
          var chunk2 = '<value><string>xmlrpc_dialect</string></value>'
            + '</data></array></value></param>'
            + '</params>'
            + '</methodResponse>'
          response.write(chunk1)
          response.write(chunk2)
          response.end()
        }).listen(9092, 'localhost', function() {
          var client = new Client({ host: 'localhost', port: 9092, path: '/'}, false)
          client.methodCall('listMethods', null, that.callback)
        })
      }
    , 'contains the array' : function (error, value) {
        assert.isNull(error)
        assert.deepEqual(value, ['system.listMethods', 'system.methodSignature', 'xmlrpc_dialect'])
      }
    }
  , 'with a utf-8 encoding' : {
      topic: function () {
        var that = this
        http.createServer(function (request, response) {
            response.writeHead(200, {'Content-Type': 'text/xml'})
            var data = '<?xml version="2.0" encoding="UTF-8"?>'
              + '<methodResponse>'
              + '<params>'
              + '<param><value><string>here is mr. Snowman: ☃</string></value></param>'
              + '</params>'
              + '</methodResponse>'
            response.write(data)
            response.end()
        }).listen(9093, 'localhost', function() {
          var client = new Client('http://localhost:9093', false)
          client.methodCall('listMethods', null, that.callback)
        })
      }
    , 'contains the correct string' : function (error, value) {
        assert.isNull(error)
        assert.deepEqual(value, 'here is mr. Snowman: ☃')
      }
    }
  , 'with a ISO-8859-1 encoding' : {
      topic: function () {
        var that = this
        http.createServer(function (request, response) {
          response.writeHead(200, {'Content-Type': 'text/xml'})
          // To prevent including a npm package that needs to compile (iconv):
          // The following iso 8859-1 text below in hex
          //   <?xml version="1.0" encoding="ISO-8859-1"?>
          //   <methodResponse>
          //   <params>
          //   <param><value><string>äè12</string></value></param>
          //   </params>
          //   </methodResponse>
          var hex = '3c3f786d6c2076657273696f6e3d22312e302220656e636'
            + 'f64696e673d2249534f2d383835392d31223f3e3c6d6574686f64'
            + '526573706f6e73653e3c706172616d733e3c706172616d3e3c766'
            + '16c75653e3c737472696e673ee4e831323c2f737472696e673e3c'
            + '2f76616c75653e3c2f706172616d3e3c2f706172616d733e3c2f6'
            + 'd6574686f64526573706f6e73653e'
          var hexData = null
          try {
            // Hex encoding is only supported in Node v0.6+
            hexData = new Buffer(hex, 'hex')
          }
          catch (e) {
            hexData = hexUtil.hexToBuffer(hex)
          }
          response.write(hexData)
          response.end()
        }).listen(9094, 'localhost', function() {
          var client = new Client({ host: 'localhost', port: 9094, path: '/', responseEncoding : 'binary'}, false)
          client.methodCall('listMethods', null, that.callback)
        })
      }
    , 'contains the correct string' : function (error, value) {
        assert.isNull(error)
        assert.deepEqual(value, 'äè12')
      }
    }
  , 'with a multi-byte character in request' : {
      topic: function () {
        var that = this
          , requestBody = ""
        http.createServer(function (request, response) {
          request.setEncoding('utf8')
          request.on('data', function (chunk) {
            requestBody += chunk
          })
          request.on('end', function () {
            response.writeHead(200, {'Content-Type': 'text/xml'})
            var data = '<?xml version="2.0" encoding="UTF-8"?>'
              + '<methodResponse>'
              + '<params>'
              + '<param><value><string>ok</string></value></param>'
              + '</params>'
              + '</methodResponse>'
            response.write(data)
            response.end()
          })
        }).listen(9095, 'localhost', function() {
          var client = new Client({ host: 'localhost', port: 9095, path: '/'}, false)
          client.methodCall('multiByte', ['ö'], function (error) {
            that.callback(error, requestBody)
          })
        })
      }
    , 'contains full request' : function (error, value) {
        var data = '<?xml version="1.0"?>' +
          '<methodCall>' +
          '<methodName>multiByte</methodName>' +
          '<params><param><value><string>ö</string></value></param></params>' +
          '</methodCall>'
        assert.isNull(error)
        assert.deepEqual(value, data)
      }
    }
  }
}).export(module)
<|endoftext|>


<commit_before>'use strict';

const sinon = require('sinon');
const proxyquire = require('proxyquire');
const expect = require('chai').expect;
const Engine = require('..').Engine;
const Config = require('..').Config;
const Storage = require('storj-service-storage-models');
const Mailer = require('storj-service-mailer');
const middleware = require('storj-service-middleware');
const log = require('../lib/logger');
const Server = require('..').Server;

describe('Engine', function() {

  describe('@constructor', function() {

    it('should create instance without the new keyword', function() {
      expect(Engine(Config('__tmptest'))).to.be.instanceOf(Engine);
    });

    it('should keep reference to config', function() {
      var config = Config('__tmptest');
      var engine = new Engine(config);
      expect(engine._config).to.equal(config);
    });

  });

  describe('#_countPendingResponses', function() {
    it('will return pending count', function() {
    });
  });

  describe('#_logHealthInfo', function() {
    const sandbox = sinon.sandbox.create();
    afterEach(() => sandbox.restore());

    var config = Config('__tmptest');
    var engine = new Engine(config);

    it('will handle error', function() {
    });

    it('will log health information', function() {
      sandbox.stub(log, 'info');
      engine.server = {
        server: {
          listening: true,
          getConnections: sandbox.stub().callsArgWith(0, null, 12)
        }
      };
      engine.storage = {
        connection: {
          readyState: 1
        }
      };
      engine._countPendingResponses = sinon.stub().returns(10);
      engine._logHealthInfo();
      expect(log.info.callCount).to.equal(1);
      expect(log.info.args[0][0]).to.equal('%j');

      const report = log.info.args[0][1].bridge_health_report;
      expect(report.pid);
      expect(report.cpuUsage);
      expect(report.memory);
      expect(report.heapStatistics);
      expect(report.heapSpaceStatistics);
      expect(report.uptime);
      expect(report.listening).to.equal(true);
      expect(report.connections).to.equal(12);
      expect(report.pendingResponses).to.equal(10);
      expect(report.databaseState).to.equal(1);
    });

  });

  describe('#getSpecification', function() {

    var config = Config('__tmptest');
    var engine = new Engine(config);

    it('should return the swagger specification', function() {
      var spec = engine.getSpecification();
      expect(typeof spec).to.equal('object');
    });

    it('should return the cached swagger specification', function() {
      expect(engine._apispec).to.equal(engine.getSpecification());
    });

  });

  describe('#start', function() {

    it('should setup storage, mailer, server', function(done) {
      var config = Config('__tmptest');
      var engine = new Engine(config);
      engine._logHealthInfo = sinon.stub();
      engine.start(function(err) {
        expect(err).to.equal(undefined);
        expect(engine.storage).to.be.instanceOf(Storage);
        expect(engine.mailer).to.be.instanceOf(Mailer);
        expect(engine.server).to.be.instanceOf(Server);
        expect(engine._healthInterval);
        engine.server.server.close(function() {
          done();
        });
      });
    });

  });

  describe('#_configureApp', function() {
    const sandbox = sinon.sandbox.create();
    afterEach(() => sandbox.restore());

    it('it should use middleware error handler', function(done) {
      const use = sandbox.stub();
      const express = sandbox.stub().returns({
        use: use,
        get: sandbox.stub()
      });
      const TestEngine = proxyquire('../lib/engine', {
        express: express
      });
      const errorhandler = function(err, req, res, next) {
        next();
      };
      sandbox.stub(middleware, 'errorhandler').returns(errorhandler);
      sandbox.stub(Server, 'Routes').returns([]);
      var config = Config('__tmptest');
      var engine = new TestEngine(config);
      engine._configureApp();
      expect(middleware.errorhandler.callCount).to.equal(1);
      expect(use.args[2][0]).to.equal(errorhandler);
      done();
    });

  });

  describe('#_handleRootGET', function() {

    it('should respond with the api specification', function(done) {
      var config = Config('__tmptest');
      var engine = new Engine(config);
      engine._handleRootGET({}, {
        send: function(content) {
          expect(content).to.equal(engine.getSpecification());
          done();
        }
      });
    });

  });

  describe('#_trackResponseStatus', function() {

    it('should store reference to response', function(done) {
      var engine = new Engine(Config('__tmptest'));
      var resp = {};
      engine._trackResponseStatus({}, resp, function() {
        var key = Object.keys(engine._pendingResponses)[0];
        expect(engine._pendingResponses[key]).to.equal(resp);
        done();
      });
    });

  });

  describe('#_keepPendingResponsesClean', function() {

    it('should delete responses that are finished', function(done) {
      var engine = new Engine(Config('__tmptest'));
      engine._pendingResponses = {
        one: { finished: false },
        two: { finished: true }
      };
      var clock = sinon.useFakeTimers();
      engine._keepPendingResponsesClean();
      clock.tick(Engine.RESPONSE_CLEAN_INTERVAL);
      expect(engine._pendingResponses.two).to.equal(undefined);
      expect(engine._pendingResponses.one).to.not.equal(undefined);
      clock.restore();
      done();
    });

  });

});
<commit_msg>More tests for health report<commit_after>'use strict';

const sinon = require('sinon');
const proxyquire = require('proxyquire');
const expect = require('chai').expect;
const Engine = require('..').Engine;
const Config = require('..').Config;
const Storage = require('storj-service-storage-models');
const Mailer = require('storj-service-mailer');
const middleware = require('storj-service-middleware');
const log = require('../lib/logger');
const Server = require('..').Server;

describe('Engine', function() {

  describe('@constructor', function() {

    it('should create instance without the new keyword', function() {
      expect(Engine(Config('__tmptest'))).to.be.instanceOf(Engine);
    });

    it('should keep reference to config', function() {
      var config = Config('__tmptest');
      var engine = new Engine(config);
      expect(engine._config).to.equal(config);
    });

  });

  describe('#_countPendingResponses', function() {
    const sandbox = sinon.sandbox.create();
    afterEach(() => sandbox.restore());

    it('will return pending count', function() {
      var config = Config('__tmptest');
      var engine = new Engine(config);

      engine._pendingResponses = {
        'one': {
          finished: false
        },
        'two': {
          finished: true
        }
      };

      const count = engine._countPendingResponses();
      expect(count).to.equal(1);
      expect(Object.keys(engine._pendingResponses).length).to.equal(1);
    });
  });

  describe('#_logHealthInfo', function() {
    const sandbox = sinon.sandbox.create();
    afterEach(() => sandbox.restore());

    it('will handle error', function() {
      var config = Config('__tmptest');
      var engine = new Engine(config);

      sandbox.stub(log, 'info');
      engine.server = {
        server: {
          listening: true,
          getConnections: sandbox.stub().callsArgWith(0, new Error('test'))
        }
      };
      engine.storage = {
        connection: {
          readyState: 1
        }
      };
      engine._countPendingResponses = sinon.stub().returns(10);
      engine._logHealthInfo();
      expect(log.info.callCount).to.equal(1);
      expect(log.info.args[0][0]).to.equal('%j');

      const report = log.info.args[0][1].bridge_health_report;
      expect(report.error).to.equal('test');
      expect(report.connections).to.equal(undefined);

      expect(report.pid);
      expect(report.cpuUsage);
      expect(report.memory);
      expect(report.heapStatistics);
      expect(report.heapSpaceStatistics);
      expect(report.uptime);
      expect(report.listening).to.equal(true);
      expect(report.pendingResponses).to.equal(10);
      expect(report.databaseState).to.equal(1);
    });

    it('will log health information', function() {
      var config = Config('__tmptest');
      var engine = new Engine(config);

      sandbox.stub(log, 'info');
      engine.server = {
        server: {
          listening: true,
          getConnections: sandbox.stub().callsArgWith(0, null, 12)
        }
      };
      engine.storage = {
        connection: {
          readyState: 1
        }
      };
      engine._countPendingResponses = sinon.stub().returns(10);
      engine._logHealthInfo();
      expect(log.info.callCount).to.equal(1);
      expect(log.info.args[0][0]).to.equal('%j');

      const report = log.info.args[0][1].bridge_health_report;
      expect(report.pid);
      expect(report.cpuUsage);
      expect(report.memory);
      expect(report.heapStatistics);
      expect(report.heapSpaceStatistics);
      expect(report.uptime);
      expect(report.listening).to.equal(true);
      expect(report.connections).to.equal(12);
      expect(report.pendingResponses).to.equal(10);
      expect(report.databaseState).to.equal(1);
    });

  });

  describe('#getSpecification', function() {

    var config = Config('__tmptest');
    var engine = new Engine(config);

    it('should return the swagger specification', function() {
      var spec = engine.getSpecification();
      expect(typeof spec).to.equal('object');
    });

    it('should return the cached swagger specification', function() {
      expect(engine._apispec).to.equal(engine.getSpecification());
    });

  });

  describe('#start', function() {

    it('should setup storage, mailer, server', function(done) {
      var config = Config('__tmptest');
      var engine = new Engine(config);
      engine._logHealthInfo = sinon.stub();
      engine.start(function(err) {
        expect(err).to.equal(undefined);
        expect(engine.storage).to.be.instanceOf(Storage);
        expect(engine.mailer).to.be.instanceOf(Mailer);
        expect(engine.server).to.be.instanceOf(Server);
        expect(engine._healthInterval);
        engine.server.server.close(function() {
          done();
        });
      });
    });

  });

  describe('#_configureApp', function() {
    const sandbox = sinon.sandbox.create();
    afterEach(() => sandbox.restore());

    it('it should use middleware error handler', function(done) {
      const use = sandbox.stub();
      const express = sandbox.stub().returns({
        use: use,
        get: sandbox.stub()
      });
      const TestEngine = proxyquire('../lib/engine', {
        express: express
      });
      const errorhandler = function(err, req, res, next) {
        next();
      };
      sandbox.stub(middleware, 'errorhandler').returns(errorhandler);
      sandbox.stub(Server, 'Routes').returns([]);
      var config = Config('__tmptest');
      var engine = new TestEngine(config);
      engine._configureApp();
      expect(middleware.errorhandler.callCount).to.equal(1);
      expect(use.args[2][0]).to.equal(errorhandler);
      done();
    });

  });

  describe('#_handleRootGET', function() {

    it('should respond with the api specification', function(done) {
      var config = Config('__tmptest');
      var engine = new Engine(config);
      engine._handleRootGET({}, {
        send: function(content) {
          expect(content).to.equal(engine.getSpecification());
          done();
        }
      });
    });

  });

  describe('#_trackResponseStatus', function() {

    it('should store reference to response', function(done) {
      var engine = new Engine(Config('__tmptest'));
      var resp = {};
      engine._trackResponseStatus({}, resp, function() {
        var key = Object.keys(engine._pendingResponses)[0];
        expect(engine._pendingResponses[key]).to.equal(resp);
        done();
      });
    });

  });

  describe('#_keepPendingResponsesClean', function() {

    it('should delete responses that are finished', function(done) {
      var engine = new Engine(Config('__tmptest'));
      engine._pendingResponses = {
        one: { finished: false },
        two: { finished: true }
      };
      var clock = sinon.useFakeTimers();
      engine._keepPendingResponsesClean();
      clock.tick(Engine.RESPONSE_CLEAN_INTERVAL);
      expect(engine._pendingResponses.two).to.equal(undefined);
      expect(engine._pendingResponses.one).to.not.equal(undefined);
      clock.restore();
      done();
    });

  });

});
<|endoftext|>


<commit_before>// Apply new password entered by user.

'use strict';

var _ = require('lodash');

module.exports = function (N, apiPath) {
  N.validate(apiPath, {
    secret_key:   { type: 'string', required: true }
  , new_password: { type: 'string', required: true }
  });

  N.wire.on(apiPath, function (env, callback) {
    if (!N.models.users.User.validatePassword(env.params.new_password)) {
      callback(N.io.CLIENT_ERROR);
      return;
    }

    N.models.users.TokenResetPassword.findOne({
      secret_key: env.params.secret_key
    }, function (err, token) {
      if (err) {
        callback(err);
        return;
      }

      if (!token || token.isExpired()) {
        callback({
          code:    N.io.NOT_FOUND
        , message: env.t('expired_token')
        });
        return;
      }

      N.models.users.AuthLink.findById(token.authlink_id, function (err, authlink) {
        if (err) {
          callback(err);
          return;
        }

        var provider = _.find(authlink.providers, function (provider) {
          return provider._id.equals(token.authprovider_id);
        });

        if (!provider) {
          callback({
            code:    N.io.NOT_FOUND
          , message: env.t('broken_token')
          });
          return;
        }

        provider.setPass(env.params.new_password);

        // Remove current and all other password reset tokens for this provider.
        N.models.users.TokenResetPassword.remove({
          authprovider_id: provider._id
        }, function (err) {
          if (err) {
            callback(err);
            return;
          }

          // Save new password.
          authlink.save(callback);
        });
      });
    });
  });
};
<commit_msg>Add missed "not found" check in reset_password/apply.js<commit_after>// Apply new password entered by user.

'use strict';

var _ = require('lodash');

module.exports = function (N, apiPath) {
  N.validate(apiPath, {
    secret_key:   { type: 'string', required: true }
  , new_password: { type: 'string', required: true }
  });

  N.wire.on(apiPath, function (env, callback) {
    if (!N.models.users.User.validatePassword(env.params.new_password)) {
      callback(N.io.CLIENT_ERROR);
      return;
    }

    N.models.users.TokenResetPassword.findOne({
      secret_key: env.params.secret_key
    }, function (err, token) {
      if (err) {
        callback(err);
        return;
      }

      if (!token || token.isExpired()) {
        callback({
          code:    N.io.NOT_FOUND
        , message: env.t('expired_token')
        });
        return;
      }

      N.models.users.AuthLink.findById(token.authlink_id, function (err, authlink) {
        if (err) {
          callback(err);
          return;
        }

        if (!authlink) {
          callback({
            code:    N.io.NOT_FOUND
          , message: env.t('broken_token')
          });
          return;
        }

        var provider = _.find(authlink.providers, function (provider) {
          return provider._id.equals(token.authprovider_id);
        });

        if (!provider) {
          callback({
            code:    N.io.NOT_FOUND
          , message: env.t('broken_token')
          });
          return;
        }

        provider.setPass(env.params.new_password);

        // Remove current and all other password reset tokens for this provider.
        N.models.users.TokenResetPassword.remove({
          authprovider_id: provider._id
        }, function (err) {
          if (err) {
            callback(err);
            return;
          }

          // Save new password.
          authlink.save(callback);
        });
      });
    });
  });
};
<|endoftext|>


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

  properties: [
    { class: 'Float', name: 'w', value: 80 },
    { class: 'Float', name: 'x' },
    { class: 'Float', name: 'y' },
    { class: 'String', name: 'rotate' },
    { name: 'heightFactor', value: 0.55 },
    { name: 'lean', value: 0 },
    { name: 'lvl', value: 1 },
    { name: 'maxlvl', value: 11 }
  ],

  methods: [
    function initE() {
      this.SUPER();

      this.setNodeName('g').
          attrs({transform: 'translate(' + this.x + ' ' + this.y + ') ' + this.rotate}).
          start('rect').
            attrs({width: this.w, height: this.w, x: 0, y: 0}).
            style({fill: 'hsl(' + this.lvl/this.maxlvl*180 + ',70%,70%)'}).
          end();

      if ( this.lvl < this.maxlvl ) {
        var lean      = this.lean, w = this.w;
        var trigH     = this.heightFactor * w;
        var nextRight = Math.sqrt(trigH**2 + (w * (.5+lean))**2);
        var nextLeft  = Math.sqrt(trigH**2 + (w * (.5-lean))**2);
        var A         = Math.atan(trigH / ((.5-lean) * w));
        var B         = Math.atan(trigH / ((.5+lean) * w));

        this.add(
            nextLeft > 1 && this.cls_.create({
              x: 0,
              y: -nextLeft,
              w: nextLeft,
              rotate: 'rotate(' + this.radToDeg(-A) + ' 0 ' + nextLeft + ')',
              lvl: this.lvl+1,
              maxlvl: this.maxlvl,
              heightFactor: this.heightFactor,
              lean: this.lean
            }),
            nextRight > 1 && this.cls_.create({
              x: Math.cos(A)*nextLeft,
              y: -nextRight - Math.sin(A)*nextLeft,
              w: nextRight,
              rotate: 'rotate(' + this.radToDeg(B) + ' 0 ' + nextRight + ')',
              lvl: this.lvl+1,
              maxlvl: this.maxlvl,
              heightFactor: this.heightFactor,
              lean: this.lean
            }));
      }
    },

    function radToDeg(r) { return 180*r/Math.PI; }
  ]
});

foam.CLASS({
  name: 'PyTreeController',
  extends: 'foam.u2.Element',

  requires: [ 'PyTree' ],

  properties: [
    { name: 'heightFactor', value: 0.55 },
    { name: 'lean', value: 0 }
  ],

  methods: [
    function initE() {
      this.SUPER();

      this.setNodeName('svg').
        attrs({width: 1600, height: 800}).
        on('mousemove', this.onMouseMove).
        add(this.slot(function(heightFactor, lean) {
          return this.PyTree.create({x: 800, y: 500, heightFactor: heightFactor, lean: lean});
        }));
    }
  ],

  listeners: [
    {
      name: 'onMouseMove',
//      isFramed: true,
      code: function(e) {
        var x = e.clientX, y = e.clientY;
        this.heightFactor = y / this.getAttribute('height') * 0.8;
        this.lean         = x / this.getAttribute('width') - 0.5;
      }
    }
  ]
});

//var tree = PyTree.create();
//foam.__context__.E('svg').style({padding: 500}).add(tree).write();

var treeCtrl = PyTreeController.create();
treeCtrl.write();
<commit_msg>Indentation.<commit_after>/**
 * @license
 * Copyright 2017 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
foam.CLASS({
  name: 'PyTree',
  extends: 'foam.u2.Element',

  properties: [
    { class: 'Float', name: 'w', value: 80 },
    { class: 'Float', name: 'x' },
    { class: 'Float', name: 'y' },
    { class: 'String', name: 'rotate' },
    { name: 'heightFactor', value: 0.55 },
    { name: 'lean', value: 0 },
    { name: 'lvl', value: 1 },
    { name: 'maxlvl', value: 11 }
  ],

  methods: [
    function initE() {
      this.SUPER();

      this.setNodeName('g').
          attrs({transform: 'translate(' + this.x + ' ' + this.y + ') ' + this.rotate}).
          start('rect').
            attrs({width: this.w, height: this.w, x: 0, y: 0}).
            style({fill: 'hsl(' + this.lvl/this.maxlvl*180 + ',70%,70%)'}).
          end();

      if ( this.lvl < this.maxlvl ) {
        var lean      = this.lean, w = this.w;
        var trigH     = this.heightFactor * w;
        var nextRight = Math.sqrt(trigH**2 + (w * (.5+lean))**2);
        var nextLeft  = Math.sqrt(trigH**2 + (w * (.5-lean))**2);
        var A         = Math.atan(trigH / ((.5-lean) * w));
        var B         = Math.atan(trigH / ((.5+lean) * w));

        this.add(
          nextLeft > 1 && this.cls_.create({
            x: 0,
            y: -nextLeft,
            w: nextLeft,
            rotate: 'rotate(' + this.radToDeg(-A) + ' 0 ' + nextLeft + ')',
            lvl: this.lvl+1,
            maxlvl: this.maxlvl,
            heightFactor: this.heightFactor,
            lean: this.lean
          }),
          nextRight > 1 && this.cls_.create({
            x: Math.cos(A)*nextLeft,
            y: -nextRight - Math.sin(A)*nextLeft,
            w: nextRight,
            rotate: 'rotate(' + this.radToDeg(B) + ' 0 ' + nextRight + ')',
            lvl: this.lvl+1,
            maxlvl: this.maxlvl,
            heightFactor: this.heightFactor,
            lean: this.lean
          }));
      }
    },

    function radToDeg(r) { return 180*r/Math.PI; }
  ]
});

foam.CLASS({
  name: 'PyTreeController',
  extends: 'foam.u2.Element',

  requires: [ 'PyTree' ],

  properties: [
    { name: 'heightFactor', value: 0.55 },
    { name: 'lean',         value: 0 }
  ],

  methods: [
    function initE() {
      this.SUPER();

      this.setNodeName('svg').
        attrs({width: 1600, height: 800}).
        on('mousemove', this.onMouseMove).
        add(this.slot(function(heightFactor, lean) {
          return this.PyTree.create({x: 800, y: 500, heightFactor: heightFactor, lean: lean});
        }));
    }
  ],

  listeners: [
    {
      name: 'onMouseMove',
//      isFramed: true,
      code: function(e) {
        var x = e.clientX, y = e.clientY;
        this.heightFactor = y / this.getAttribute('height') * 0.8;
        this.lean         = x / this.getAttribute('width') - 0.5;
      }
    }
  ]
});

//var tree = PyTree.create();
//foam.__context__.E('svg').style({padding: 500}).add(tree).write();

var treeCtrl = PyTreeController.create();
treeCtrl.write();
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import {Link} from 'react-router';
import InfoBox from './InfoBox';
import Footer from './Footer';
import Right from './Right';

class MembersDetail extends Component {

  createMarkup(html) {
    return {
      __html: html,
    };
  }

  render() {
    const { address, displayName, image, intro, bio, since } = this.props;

    return (

            {/* breadcrumbs */}

                <Link to="/">
                  Home
                </Link>

                <Link to="/members">
                  Members
                </Link>

{displayName}

{/* /breadcrumbs */}

        {/* /PAGE HEADER */}
        {/* */}

            {/* LEFT */}

              <InfoBox address={address} image={image} displayName={displayName} since={since} intro={this.createMarkup(intro)}/>

              {/* SIDE NAV */}

 PROFILE

 PROJECTS

 COMMENTS

 HISTORY

 SETTINGS

                  DROPDOWN EXAMPLE

{/* NOTE: "collapse in" to be open on page load */}

 SUMBENU 1

                      New
                       SUMBENU 2

 SUMBENU 3

 SUMBENU 4

              {/* /SIDE NAV */}
              {/* info */}

{/* .box-light OR .box-light */}

12

PROJECTS

34

TASKS

32

UPLOADS

                {/* /info */}

About {displayName}

Lorem ipsum dolor sit amet diam nonummy nibh dolore.

 www.stepofweb.com

 stepofweb

 @stepofweb

            {/* RIGHT */}

              {/* FLIP BOX */}

{displayName} – Profile

              <Right displayName={displayName} />

        {/* / */}
        {/* FOOTER */}

        {/* /FOOTER */}

    );
  }
}

MembersDetail.propTypes = {
  address: PropTypes.object,
  bio: PropTypes.string,
  displayName: PropTypes.string.isRequired,
  image: PropTypes.shape({
    uri: PropTypes.string.isRequired,
    height: PropTypes.number,
    width: PropTypes.number,
  }),
  intro: PropTypes.string,
  since: PropTypes.string,
  slug: PropTypes.string.isRequired,
  statement: PropTypes.string,
  usState: PropTypes.string,
};

export default MembersDetail;
<commit_msg>Show links on member detail page<commit_after>import React, { Component, PropTypes } from 'react';
import {Link} from 'react-router';
import InfoBox from './InfoBox';
import Footer from './Footer';
import Right from './Right';

class MembersDetail extends Component {

  createMarkup(html) {
    return {
      __html: html,
    };
  }

  render() {
    const { address, displayName, image, intro, links,
            bio, since, statement, twitter } = this.props;

    return (

            {/* breadcrumbs */}

                <Link to="/">
                  Home
                </Link>

                <Link to="/members">
                  Members
                </Link>

{displayName}

{/* /breadcrumbs */}

        {/* /PAGE HEADER */}
        {/* */}

            {/* LEFT */}

              <InfoBox address={address} image={image} displayName={displayName} since={since} intro={this.createMarkup(intro)}/>

              {/* SIDE NAV */}

 PROFILE

 PROJECTS

 COMMENTS

 HISTORY

 SETTINGS

                  DROPDOWN EXAMPLE

{/* NOTE: "collapse in" to be open on page load */}

 SUMBENU 1

                      New
                       SUMBENU 2

 SUMBENU 3

 SUMBENU 4

              {/* /SIDE NAV */}
              {/* info */}

{/* .box-light OR .box-light */}

12

PROJECTS

34

TASKS

32

UPLOADS

                {/* /info */}

About {displayName}

Lorem ipsum dolor sit amet diam nonummy nibh dolore.

                    {
                      links.map((link) => {
                        return (

                              {link.title}

                        );
                      })
                    }

 stepofweb

 @stepofweb

            {/* RIGHT */}

              {/* FLIP BOX */}

{displayName} – Profile

              <Right displayName={displayName} />

        {/* / */}
        {/* FOOTER */}

        {/* /FOOTER */}

    );
  }
}

MembersDetail.propTypes = {
  address: PropTypes.object,
  bio: PropTypes.string,
  displayName: PropTypes.string.isRequired,
  image: PropTypes.shape({
    uri: PropTypes.string.isRequired,
    height: PropTypes.number,
    width: PropTypes.number,
  }),
  intro: PropTypes.string,
  since: PropTypes.string,
  slug: PropTypes.string.isRequired,
  statement: PropTypes.string,
  usState: PropTypes.string,
};

export default MembersDetail;
<|endoftext|>


<commit_before>
function clamp(num, min = 0, max = 100) {
  return Math.min(Math.max(num, min), max);
}

function fraction(num, min = 0, max = 100) {
  return ((num - min) / (max - min));
}

export function getClampedProgress(progress, min, max) {
  return fraction(clamp(progress, min, max), min, max) * 100;
}
<commit_msg>Round clamped value in Progress component (#482)<commit_after>
function clamp(num, min = 0, max = 100) {
  return Math.min(Math.max(num, min), max);
}

function fraction(num, min = 0, max = 100) {
  return ((num - min) / (max - min));
}

export function getClampedProgress(progress, min, max) {
  return Math.round(fraction(clamp(progress, min, max), min, max) * 100);
}
<|endoftext|>


<commit_before>/** @jsx h */
import { h, Component } from 'preact';
import shuffle from 'just-shuffle';

import './style.scss';

import viewer from '../../viewer';
import audio from '../../audio';

import AudioTimeline from '../AudioTimeline';
import LineTitle from '../LineTitle';

import { worldToScreen } from '../../utils/three';

export default class TutorialTimeline extends Component {
  constructor() {
    super();
    this.performUpdate = this.performUpdate.bind(this);
    this.tick = this.tick.bind(this);
    this.getTime = this.getTime.bind(this);
  }

  componentWillMount() {
    const getHeadPosition = (index) => {
      const { room } = this.context;
      if (!room) return;
      const count = room.frame.count;
      if (!count) return;
      return (
        room &&
        room.getHeadPosition(
          index !== undefined
            ? (index + Math.floor(audio.totalProgress * 0.5)) % count
            : count - 1
        )
      );
    };
    let time = 0;
    const randomIndex = () => Math.floor(Math.random() * 100);
    const compliments = shuffle([
      'Nice moves.',
      'Killer steps.',
      'Sh.. Sh.. Shake it!',
      'So elegant.',
      'Remarkeable.',
      'You monster, you!',
      'Cut that rug up!',
      'Exactly!',
      'Yes!',
      'You the best!',
      'Yes. Yes. Yes!',
      'Get your freak on.',
      'Loved this bit.',
      'E-l-e-c-t-r-i-f-y-i-n-g!',
      'Put that foot down.',
      'Get down with it.',
      'Cha! Cha! Dontcha!',
      'Improvisational.',
      'Pop it. Lock it.',
      'Classic.',
      'Such finesse.',
      'Such concentration!',
      'So nimble.',
      'Gene, is that you?',
      'Crank that.',
    ]);
    const keyframes = this.props.fromRecording
      ? [
        {
          duration: 2,
          text: '',
        },
        {
          duration: 1,
          text: '...',
        },
        {
          duration: 1,
          text: 'Gosh...',
        },
        {
          duration: 2,
          text: 'We have no words!',
        },
        {
          duration: 4,
          text: 'That was amazing.',
        },
        {
          duration: 4,
          text: 'You must be worn out.',
        },
        {
          duration: 6,
          text: 'Thanks so much for your contribution.',
        },
        {
          duration: 4,
          text: 'Let’s take a moment to admire your moves:',
        },
        {
          duration: 3,
          text: '',
        },
      ]
    : [
      {
        duration: 2,
        text: '',
      },
      {
        duration: 2,
        text: '…',
      },
      {
        duration: 6,
        text: 'Here’s your friend in Dance Tonite.',
      },
      {
        duration: 1,
        text: 'Pretty,',
      },
      {
        duration: 1,
        text: 'Pretty, pretty.',
      },
      {
        duration: 1,
        text: 'Pretty, pretty, good,',
      },
      {
        duration: 4,
        text: 'Pretty, pretty, good, right?',
      },
      {
        duration: 4,
        text: 'Be sure to watch them in the full experience.',
      },
      {
        duration: 3,
        text: 'But first…',
      },
      {
        duration: 4,
        text: 'Let’s take a moment to admire their moves:',
      },
      {
        duration: 3,
        text: '',
      },
    ];

    for (let i = 0, l = compliments.length; i < l; i++) {
      const text = compliments.pop();
      keyframes.push({
        duration: Math.max(2, text.length * 0.15),
        text,
        getPosition: getHeadPosition.bind(this, randomIndex()),
      });
      keyframes.push({
        duration: 2 + Math.random() * 8,
        text: '',
      });
    }

    this.keyframes = keyframes.map(keyframe => {
      keyframe.time = time;
      time += keyframe.duration;
      return keyframe;
    });
    viewer.on('tick', this.tick);
  }

  componentWillUnmount() {
    viewer.off('tick', this.tick);
  }

  getTime() {
    return audio.totalTime;
  }

  tick() {
    if (this.getLineTarget) {
      const target = this.getLineTarget();
      if (!target) return;
      this.setState(worldToScreen(viewer.camera, target));
    } else {
      this.setState({
        x: null,
        y: null,
      });
    }
  }

  performUpdate({ text, getPosition, layers }) {
    // just !text would return true on empty string, so:
    if (text !== undefined) {
      this.setState({ text });
    }
    this.getLineTarget = getPosition;
    if (layers !== undefined) {
      this.props.onUpdateLayers(layers);
    }
  }

  render({ children, visible = true }, state) {
    return (
      <LineTitle
        {...state}
        visible={visible}
      >
        <AudioTimeline
          keyframes={this.keyframes}
          getTime={this.getTime}
          callback={this.performUpdate}
        />
      </LineTitle>
    );
  }
}
<commit_msg>work on compliments – closes #476<commit_after>/** @jsx h */
import { h, Component } from 'preact';
import shuffle from 'just-shuffle';

import './style.scss';

import viewer from '../../viewer';
import audio from '../../audio';

import AudioTimeline from '../AudioTimeline';
import LineTitle from '../LineTitle';

import { worldToScreen } from '../../utils/three';

export default class TutorialTimeline extends Component {
  constructor() {
    super();
    this.performUpdate = this.performUpdate.bind(this);
    this.tick = this.tick.bind(this);
    this.getTime = this.getTime.bind(this);
  }

  componentWillMount() {
    const getHeadPosition = (index) => {
      const { room } = this.context;
      if (!room) return;
      const count = room.frame.count;
      if (!count) return;
      return (
        room &&
        room.getHeadPosition(
          index !== undefined
            ? (index + Math.floor(audio.totalProgress * 0.5)) % count
            : count - 1
        )
      );
    };
    let time = 0;
    const randomIndex = () => Math.floor(Math.random() * 100);
    const compliments = shuffle([
      'Nice moves.',
      'Killer steps.',
      'Sh.. Sh.. Shake it!',
      'So elegant.',
      'Remarkeable.',
      'You monster, you!',
      'Cut that rug up!',
      'Exactly!',
      'Yes!',
      'You the best!',
      'Yes. Yes. Yes!',
      'Get your freak on.',
      'Loved this bit.',
      'E-l-e-c-t-r-i-f-y-i-n-g!',
      'Put that foot down.',
      'Get down with it.',
      'Cha! Cha! Dontcha!',
      'Improvisational.',
      'Pop it. Lock it.',
      'Classic.',
      'Such finesse.',
      'Such concentration!',
      'So nimble.',
      'Gene, is that you?',
      'Crank that.',
    ]);
    const keyframes = this.props.fromRecording
      ? [
        {
          duration: 2,
          text: '',
        },
        {
          duration: 1,
          text: '...',
        },
        {
          duration: 1,
          text: 'Gosh...',
        },
        {
          duration: 2,
          text: 'We have no words!',
        },
        {
          duration: 4,
          text: 'That was amazing.',
        },
        {
          duration: 4,
          text: 'You must be worn out.',
        },
        {
          duration: 6,
          text: 'Thanks so much for your contribution.',
        },
        {
          duration: 4,
          text: 'Let’s take a moment to admire your moves:',
        },
        {
          duration: 3,
          text: '',
        },
      ]
    : [
      {
        duration: 2,
        text: '',
      },
      {
        duration: 2,
        text: '…',
      },
      {
        duration: 6,
        text: 'Here’s your friend in Dance Tonite.',
      },
      {
        duration: 0.5,
        text: 'Pretty,',
      },
      {
        duration: 0.5,
        text: 'Pretty, pretty.',
      },
      {
        duration: 0.5,
        text: 'Pretty, pretty, good,',
      },
      {
        duration: 4,
        text: 'Pretty, pretty, good, right?',
      },
      {
        duration: 4,
        text: 'Be sure to watch them in the full experience.',
      },
      {
        duration: 3,
        text: 'But first…',
      },
      {
        duration: 4,
        text: 'Let’s take a moment to admire their moves:',
      },
    ];

    for (let i = 0, l = compliments.length; i < l; i++) {
      const text = compliments.pop();
      keyframes.push({
        duration: 4 + Math.random() * 6,
        text: '',
      });
      keyframes.push({
        duration: Math.max(2, text.length * 0.15),
        text,
        getPosition: getHeadPosition.bind(this, randomIndex()),
      });
    }

    this.keyframes = keyframes.map(keyframe => {
      keyframe.time = time;
      time += keyframe.duration;
      return keyframe;
    });
    viewer.on('tick', this.tick);
  }

  componentWillUnmount() {
    viewer.off('tick', this.tick);
  }

  getTime() {
    return audio.totalTime;
  }

  tick() {
    if (this.getLineTarget) {
      const target = this.getLineTarget();
      if (!target) return;
      this.setState(worldToScreen(viewer.camera, target));
    } else {
      this.setState({
        x: null,
        y: null,
      });
    }
  }

  performUpdate({ text, getPosition, layers }) {
    // just !text would return true on empty string, so:
    if (text !== undefined) {
      this.setState({ text });
    }
    this.getLineTarget = getPosition;
    if (layers !== undefined) {
      this.props.onUpdateLayers(layers);
    }
  }

  render({ children, visible = true }, state) {
    return (
      <LineTitle
        {...state}
        visible={visible}
      >
        <AudioTimeline
          keyframes={this.keyframes}
          getTime={this.getTime}
          callback={this.performUpdate}
        />
      </LineTitle>
    );
  }
}
<|endoftext|>


<commit_before>import React from 'react';

export default class KatasNavigation extends React.Component {

  render() {
    if (!this.props.katas) {
      return null;
    }
    const selectedKataId = null;
    const katas = this.props.katas.items;
    return (

ES6 Katas

          {katas.map(kata => <KataLink kata={kata} selected={selectedKataId === kata.id} />)}

    );
  }

}

class KataLink extends React.Component {

  render() {
    const {kata, selected} = this.props;
    const {id, path, groupName, name} = kata;
    const url = `${window.location.pathname}?${('' + (0 + new Date() )).substr(-5)}#?kata=es6/language/${path}`;
    const className = selected ? 'selected' : '';
    return (
      <a href={url} title={`${groupName}: ${name}`} className={className}>{id}
    );
  }

}
<commit_msg>Use a better unique strings.<commit_after>import React from 'react';

export default class KatasNavigation extends React.Component {

  render() {
    if (!this.props.katas) {
      return null;
    }
    const selectedKataId = null;
    const katas = this.props.katas.items;
    return (

ES6 Katas

          {katas.map(kata => <KataLink kata={kata} selected={selectedKataId === kata.id} />)}

    );
  }

}

class KataLink extends React.Component {

  render() {
    const {kata, selected} = this.props;
    const {id, path, groupName, name} = kata;
    const uniqueString = new Date().getMilliseconds();
    const url = `${window.location.pathname}?${uniqueString}#?kata=es6/language/${path}`;
    const className = selected ? 'selected' : '';
    return (
      <a href={url} title={`${groupName}: ${name}`} className={className}>{id}
    );
  }

}
<|endoftext|>


<commit_before>// Global variables only exist for the life of the page, so they get reset
// each time the page is unloaded.
const activeTabs = {};
const injected = {};

function load(tabId) {
  chrome.tabs.executeScript(tabId, { file: 'src/bg/injecthtml.js' }, (response) => {
    injected[tabId] = response;
    chrome.browserAction.setIcon({ tabId, path: 'icons/play.png' });
    chrome.browserAction.setTitle({ tabId, title: 'Collapse brackets' });
    chrome.tabs.insertCSS(tabId, { file: 'css/toggle.css' });
    chrome.tabs.executeScript(tabId, { file: 'src/bg/toggle_collapse.js' });
  });
}

function preload() {
  chrome.permissions.contains({
    permissions: ['tabs'],
    origins: ['http://*/', 'https://*/'],
  }, (result) => {
    if (result) {
      chrome.storage.sync.get(null, (options) => {
        if (options.autoActivate) {
          chrome.tabs.query({ active: true }, tabs => load(tabs[0].id));
        }
      });
    }
    // else {
    //   alert('Permission has been denied.');
    // }
  });
}

function playPause(tabId, action) {
  console.log(chrome.tabs);
  let message = action === 'play' ? 'Pause collapsing' : 'Collapse brackets';
  let collapse = action === 'play' ? true : false;

  activeTabs[tabId] = collapse;
  chrome.browserAction.setIcon({ tabId, path: `icons/${action}.png` });
  chrome.browserAction.setTitle({ tabId, title: message });
  chrome.tabs.sendMessage(tabId, { collapse: collapse });
}

// Called when the user clicks on the browser action.
chrome.browserAction.onClicked.addListener((tab) => {
  const tabId = tab.id;
  if (!injected[tabId]) {
    load(tabId);
  } else if (!activeTabs[tabId]) {
    playPause(tabId, 'play');
  } else if (activeTabs[tabId]) {
    playPause(tabId, 'pause');
  }
});

// preload script if user granted tabs permission from options page
document.addEventListener('DOMContentLoaded', preload);
<commit_msg>Optimize and follow eslint in playPause()<commit_after>// Global variables only exist for the life of the page, so they get reset
// each time the page is unloaded.
const activeTabs = {};
const injected = {};

function load(tabId) {
  chrome.tabs.executeScript(tabId, { file: 'src/bg/injecthtml.js' }, (response) => {
    injected[tabId] = response;
    chrome.browserAction.setIcon({ tabId, path: 'icons/play.png' });
    chrome.browserAction.setTitle({ tabId, title: 'Collapse brackets' });
    chrome.tabs.insertCSS(tabId, { file: 'css/toggle.css' });
    chrome.tabs.executeScript(tabId, { file: 'src/bg/toggle_collapse.js' });
  });
}

function preload() {
  chrome.permissions.contains({
    permissions: ['tabs'],
    origins: ['http://*/', 'https://*/'],
  }, (result) => {
    if (result) {
      chrome.storage.sync.get(null, (options) => {
        if (options.autoActivate) {
          chrome.tabs.query({ active: true }, tabs => load(tabs[0].id));
        }
      });
    }
    // else {
    //   alert('Permission has been denied.');
    // }
  });
}

function playPause(tabId, action) {
  const state = action === 'play' ?
    { message: 'Pause collapsing', collapse: true } : { message: 'Collapse brackets', collapse: false };

  activeTabs[tabId] = state.collapse;
  chrome.browserAction.setIcon({ tabId, path: `icons/${action}.png` });
  chrome.browserAction.setTitle({ tabId, title: state.message });
  chrome.tabs.sendMessage(tabId, { collapse: state.collapse });
}

// Called when the user clicks on the browser action.
chrome.browserAction.onClicked.addListener((tab) => {
  const tabId = tab.id;
  if (!injected[tabId]) {
    load(tabId);
  } else if (!activeTabs[tabId]) {
    playPause(tabId, 'play');
  } else if (activeTabs[tabId]) {
    playPause(tabId, 'pause');
  }
});

// preload script if user granted tabs permission from options page
document.addEventListener('DOMContentLoaded', preload);

<|endoftext|>


<commit_before>import should from 'turris-test-helpers';

import findPrimes from '../src/helpers/find-primes.js';

describe('Find primes', function() {
	it('Returns an array of numbers equal in length to the parameter passed in', function() {
		findPrimes(5).length.should.equal(5);
	});
	it('Returns the 1st 10 primes correctly', function() {
		const tenPrimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29];
		findPrimes(10).should.eql(tenPrimes);

	});
});
<commit_msg>Modify find-primes test to check for 168 primes<commit_after>import should from 'turris-test-helpers';

import findPrimes from '../src/helpers/find-primes.js';

describe('Find primes', function() {
	it('Returns an array of numbers equal in length to the parameter passed in', function() {
		findPrimes(5).length.should.equal(5);
	});
	it('Returns the first 168 primes correctly', function() {
		const primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997];
		findPrimes(168).should.eql(primes);

	});
});
<|endoftext|>


<commit_before>/**
 * Created by dhc on 2015/9/27.
 */

"use strict";

var pngtolcd = require('png-to-lcd');
var Framebuffer = require('framebuffer');
var mmap = require('mmap-io');

var fb = new Framebuffer('/dev/fb0');
console.log(fb.toString());

pngtolcd(__dirname + '/../resource/logo.png', function (err, buffer) {
    if (err) console.log(err);
    else {
        fb.fbp.write(buffer);
    }
});<commit_msg>update<commit_after>/**
 * Created by dhc on 2015/9/27.
 */

"use strict";

var pngtolcd = require('png-to-lcd');
var Framebuffer = require('framebuffer');

var fb = new Framebuffer('/dev/fb0');
console.log(fb.toString());

pngtolcd(__dirname + '/../resource/logo.png', function (err, buffer) {
    if (err) console.log(err);
    else {
        fb.fbp.write(buffer);
    }
});<|endoftext|>