<commit_before>// @flow
import BigNumber from 'bignumber.js';
import { intervalRates } from '../config';
import createLogger from '../../utils/logger';
import ActionTypes from './actionTypes';
import history from '../wallet/history';
import { dispatchRpcError } from '../wallet/screen/screenActions';

export function switchChain({ chain, chainId }) {
  return (dispatch, getState) => {
    dispatch({
      type: ActionTypes.SWITCH_CHAIN,
      chain,
      chainId,
    });
  };
}

export function loadHeight(watch) {
  return (dispatch, getState, api) => {
    return api.geth.eth.getBlockNumber().then((result) => {
      dispatch({
        type: ActionTypes.BLOCK,
        height: result,
      });
    }).catch(dispatchRpcError(dispatch));
  };
}

export function loadPeerCount() {
  return (dispatch, getState, api) => {
    return api.geth.net.peerCount().then((result) => {
      dispatch({
        type: ActionTypes.PEER_COUNT,
        peerCount: result,
      });
    }).catch(dispatchRpcError(dispatch));
  };
}

export function loadAddressesTransactions(addresses) {
  return (dispatch, getState, api) => {
    const addressTransactionPromises = addresses.map((address) => {
      return api.geth.eth.getAddressTransactions(address, 0, 0, 'tf', 'sc', -1, -1, false);
    }).toJS();

    Promise.all(addressTransactionPromises).then((transactionsByAccount) => {
      const results = transactionsByAccount.reduce((m, r) => m.concat(r), []);
      const uniqueTransactions = Array.from(new Set(results));
      if (results.length === 0) { return; }

      const trackedTxs = getState().wallet.history.get('trackedTransactions');
      const untrackedResults = uniqueTransactions.filter((txHash) => {
        const isAlreadyTracked = !trackedTxs.find((tx) => txHash === tx.get('hash'));
        return isAlreadyTracked;
      });

      if (untrackedResults.length === 0) { return; }

      return api.geth.ext.getTransactions(untrackedResults).then((txes) => {
        return dispatch(history.actions.trackTxs(txes.map((tx) => tx.result)));
      });
    }).catch(dispatchRpcError(dispatch));
  };
}

export function loadSyncing() {
  return (dispatch, getState, api) => {
    return api.geth.eth.getSyncing().then((result) => {
      if (typeof result === 'object') {
        return dispatch({
          type: ActionTypes.SYNCING,
          syncing: true,
          status: result,
        });
      }

      dispatch({
        type: ActionTypes.SYNCING,
        syncing: false,
      });
    }).catch(dispatchRpcError(dispatch));
  };
}

export function getGasPrice() {
  return (dispatch, getState, api) => {
    return api.geth.eth.gasPrice().then((result) => {
      dispatch({
        type: ActionTypes.GAS_PRICE,
        value: result,
      });
    }).catch(dispatchRpcError(dispatch));
  };
}

export function estimateGas(from: string, to: string, gas: string, gasPrice: string, value: string, data: string) {
  return (dispatch, getState, api) => {
    return api.geth.eth.estimateGas({
      from,
      to,
      gas,
      gasPrice,
      value,
      data,
    });
  };
}
<commit_msg>problem: tries to call local-only methods on a remote rpc<commit_after>// @flow
import BigNumber from 'bignumber.js';
import { intervalRates } from '../config';
import createLogger from '../../utils/logger';
import ActionTypes from './actionTypes';
import history from '../wallet/history';
import { dispatchRpcError } from '../wallet/screen/screenActions';

export function switchChain({ chain, chainId }) {
  return (dispatch, getState) => {
    dispatch({
      type: ActionTypes.SWITCH_CHAIN,
      chain,
      chainId,
    });
  };
}

export function loadHeight(watch) {
  return (dispatch, getState, api) => {
    return api.geth.eth.getBlockNumber().then((result) => {
      dispatch({
        type: ActionTypes.BLOCK,
        height: result,
      });
    }).catch(dispatchRpcError(dispatch));
  };
}

export function loadPeerCount() {
  return (dispatch, getState, api) => {
    return api.geth.net.peerCount().then((result) => {
      dispatch({
        type: ActionTypes.PEER_COUNT,
        peerCount: result,
      });
    }).catch(dispatchRpcError(dispatch));
  };
}

export function loadAddressesTransactions(addresses) {
  return (dispatch, getState, api) => {
    if (getState().launcher.getIn(["geth", "type"]) === 'remote') {
      return;
    }
    const addressTransactionPromises = addresses.map((address) => {
      return api.geth.eth.getAddressTransactions(address, 0, 0, 'tf', 'sc', -1, -1, false);
    }).toJS();

    Promise.all(addressTransactionPromises).then((transactionsByAccount) => {
      const results = transactionsByAccount.reduce((m, r) => m.concat(r), []);
      const uniqueTransactions = Array.from(new Set(results));
      if (results.length === 0) { return; }

      const trackedTxs = getState().wallet.history.get('trackedTransactions');
      const untrackedResults = uniqueTransactions.filter((txHash) => {
        const isAlreadyTracked = !trackedTxs.find((tx) => txHash === tx.get('hash'));
        return isAlreadyTracked;
      });

      if (untrackedResults.length === 0) { return; }

      return api.geth.ext.getTransactions(untrackedResults).then((txes) => {
        return dispatch(history.actions.trackTxs(txes.map((tx) => tx.result)));
      });
    }).catch(dispatchRpcError(dispatch));
  };
}

export function loadSyncing() {
  return (dispatch, getState, api) => {
    return api.geth.eth.getSyncing().then((result) => {
      if (typeof result === 'object') {
        return dispatch({
          type: ActionTypes.SYNCING,
          syncing: true,
          status: result,
        });
      }

      dispatch({
        type: ActionTypes.SYNCING,
        syncing: false,
      });
    }).catch(dispatchRpcError(dispatch));
  };
}

export function getGasPrice() {
  return (dispatch, getState, api) => {
    return api.geth.eth.gasPrice().then((result) => {
      dispatch({
        type: ActionTypes.GAS_PRICE,
        value: result,
      });
    }).catch(dispatchRpcError(dispatch));
  };
}

export function estimateGas(from: string, to: string, gas: string, gasPrice: string, value: string, data: string) {
  return (dispatch, getState, api) => {
    return api.geth.eth.estimateGas({
      from,
      to,
      gas,
      gasPrice,
      value,
      data,
    });
  };
}
<|endoftext|>


<commit_before>'use strict';

var jf = require('../../'),
    expect    = require('chai').expect,
    fs = require('fs');

const testPath_1 = './' + Math.random() + '.json';
const testPath_2 = './' + Math.random() + '.json'

var testValue = { msg: Math.random().toString() };

describe('Copy functions ', function () {
  it('should create copied file', function (done) {

    jf.filed( testPath_1 )
    .io(
      function( obj, filePath) {
        return testValue;
      }
    ).copy(
      function(obj, filePath){
        return testPath_2;
      }
    ).exec();

    setTimeout(
      function(){
        jf.filed( testPath_2 )
        .io( function( o ) {
          expect( o ).to.eql( testValue );
          done();
        }).exec();
      },
      1000);
  });
});
<commit_msg>add test case to testCopy.js<commit_after>'use strict';

var jf = require('../../'),
    expect    = require('chai').expect,
    fs = require('fs');

const testPath_1 = './' + Math.random() + '.json';
const testPath_2 = './' + Math.random() + '.json';

var testValue = { msg: Math.random().toString() };

describe('Copy functions ', function () {
  it('should create copied file', function (done) {

    jf.filed( testPath_1 )
    .io(
      function( obj, filePath) {
        return testValue;
      }
    ).copy(
      function(obj, filePath){
        return testPath_2;
      }
    ).exec();

    setTimeout(
      function(){
        jf.filed( testPath_2 )
        .io( function( o ) {
          expect( o ).to.eql( testValue );
          done();
        }).exec();
      },
      1000);
  });

});

const testPath_3 = './' + Math.random() + '.json';
const testPath_4 = './' + Math.random() + '.json';

describe('Copy functions ', function () {
  it('should create multiple copied file', function (done) {

    jf.filed( testPath_1 )
    .copy(
      function(obj, filePath){
        return [ testPath_3, testPath_4 ];
      }
    ).exec();

    setTimeout(
      function(){
        jf.filed( testPath_3 )
        .pass( function( o ) {
          expect( o ).to.eql( testValue );

          jf.filed( testPath_4 )
          .pass( function( o ) {
            expect( o ).to.eql( testValue );
            done();

          }).exec();

        }).exec();
      },
      1000);
  });

});
<|endoftext|>


<commit_before>const fs = require('fs');
const pluralize = require('pluralize');
const { rootDir, capitalize } = require('../../util/all.js');
const ItemCollection = require('./ItemCollection.js');
const itemTypes = {
  item: require('./Item.js'),
  recipe: require('./Recipe.js'),
  currency: require('./Currency.js')
};

const items = new ItemCollection(require(`${rootDir}/assets/items.json`).map(item => {
  return [item.id, new itemTypes[item.type](item)];
}));

const baseCurrency = findBaseCurrency();

class ItemHandler {
  constructor() {
    throw new Error('this class may not be instantiated.');
  }

  static findAmountAndName(string, overwriteAmount) {
    const words = string.split(' ');
    let amount = words.find(word => /(^-?\d+$)|(^an?$)/.test(word));

    if (typeof overwriteAmount === 'number') {
      amount = overwriteAmount;
    } else {
      amount = parseInt(amount) || 1;
    }

    return { name: words.join(' ').toLowerCase(), amount };
  }

  static resolveGroup(string, count) {
    if (!string) return null;
    let { name, amount } = ItemHandler.findAmountAndName(string, count);
    let recipe;

    if (name.toLowerCase().includes('recipe')) {
      name = ItemHandler.formatRecipeName(name);
      recipe = true;
    }

    const formatted = pluralize(name, 1);
    const regexp = new RegExp(`^${recipe ? `recipe: ${formatted}` : formatted}`, 'i');
    const item = items.find(i => regexp.test(i.id));
    if (!item) return null;

    const obj = Object.assign({}, item);

    return new itemTypes[obj.type](obj).groupOf(amount);
  }

  static resolveCollection(string) {
    if (!string) return null;
    return new ItemCollection(string.split(/[+,]|and/)
      .map(word => ItemHandler.resolveGroup(word.trim()))
      .filter(item => item)
      .map(item => [item.id, item])
    );
  }

  static convertToCurrency(amount) {
    const result = [];

    for (const currency of items.sortedCurrencies()) {
      const count = ~~(amount / currency.value);
      amount -= currency.value * count;
      result.push(currency.groupOf(count));
    }

    return new ItemCollection(result
      .filter(curr => curr.amount)
      .map(curr => [curr.id, curr])
    );
  }

  static formatName(name, amount) {
    return pluralize(name, amount).split(' ').map(word => capitalize(word)).join(' ');
  }

  static formatRecipeName(name) {
    const words = name.split(' ');
    const recipeWord = words.find(word => /recipe/.test(word));
    if (recipeWord) words.splice(words.indexOf(recipeWord), 1);
    return words.join(' ').toLowerCase();
  }

  static create(options) {
    if (options.type === 'recipe') {
      options.id = `recipe: ${ItemHandler.formatRecipeName(options.id)}`;
    }

    if (items.has(options.id)) return;
    const item = new itemTypes[options.type](options);
    items.set(item.id, item);
    return writeItems();
  }

  static update(options) {
    if (!items.has(options.id)) return ItemHandler.create(options);
    const item = new itemTypes[options.type](options);
    items.set(item.id, item);
    return writeItems();
  }

  static destroy(id) {
    if (!items.has(id)) return;
    items.delete(id);
    return writeItems();
  }

  static baseCurrency() { return new itemTypes[baseCurrency.type](baseCurrency); }
  static all(filter) { return items.filter(filter); }
  static get SHOP() { return items.filter(item => item.shop); }
}

function findBaseCurrency() {
  const currencies = Array.from(items.filter(item => item.type === 'currency').values());
  const values = currencies.map(currency => currency.value);
  return currencies[values.indexOf(Math.min(...values))];
}

function writeItems() {
  return fs.writeFileSync(`${rootDir}/assets/items.json`, JSON.stringify(items.array().map(i => i.toJSON()), null, 2), 'utf8');
}

module.exports = ItemHandler;
<commit_msg>Fix another derp<commit_after>const fs = require('fs');
const pluralize = require('pluralize');
const { rootDir, capitalize } = require('../../util/all.js');
const ItemCollection = require('./ItemCollection.js');
const itemTypes = {
  item: require('./Item.js'),
  recipe: require('./Recipe.js'),
  currency: require('./Currency.js')
};

const items = new ItemCollection(require(`${rootDir}/assets/items.json`).map(item => {
  return [item.id, new itemTypes[item.type](item)];
}));

const baseCurrency = findBaseCurrency();

class ItemHandler {
  constructor() {
    throw new Error('this class may not be instantiated.');
  }

  static findAmountAndName(string, overwriteAmount) {
    const words = string.split(' ');
    let amount = words.find(word => /(^-?\d+$)|(^an?$)/.test(word));
    if (amount) words.splice(words.indexOf(amount), 1);

    if (typeof overwriteAmount === 'number') {
      amount = overwriteAmount;
    } else {
      amount = parseInt(amount) || 1;
    }

    return { name: words.join(' ').toLowerCase(), amount };
  }

  static resolveGroup(string, count) {
    if (!string) return null;
    let { name, amount } = ItemHandler.findAmountAndName(string, count);
    let recipe;

    if (name.toLowerCase().includes('recipe')) {
      name = ItemHandler.formatRecipeName(name);
      recipe = true;
    }

    const formatted = pluralize(name, 1);
    const regexp = new RegExp(`^${recipe ? `recipe: ${formatted}` : formatted}`, 'i');
    const item = items.find(i => regexp.test(i.id));
    if (!item) return null;

    const obj = Object.assign({}, item);

    return new itemTypes[obj.type](obj).groupOf(amount);
  }

  static resolveCollection(string) {
    if (!string) return null;
    return new ItemCollection(string.split(/[+,]|and/)
      .map(word => ItemHandler.resolveGroup(word.trim()))
      .filter(item => item)
      .map(item => [item.id, item])
    );
  }

  static convertToCurrency(amount) {
    const result = [];

    for (const currency of items.sortedCurrencies()) {
      const count = ~~(amount / currency.value);
      amount -= currency.value * count;
      result.push(currency.groupOf(count));
    }

    return new ItemCollection(result
      .filter(curr => curr.amount)
      .map(curr => [curr.id, curr])
    );
  }

  static formatName(name, amount) {
    return pluralize(name, amount).split(' ').map(word => capitalize(word)).join(' ');
  }

  static formatRecipeName(name) {
    const words = name.split(' ');
    const recipeWord = words.find(word => /recipe/.test(word));
    if (recipeWord) words.splice(words.indexOf(recipeWord), 1);
    return words.join(' ').toLowerCase();
  }

  static create(options) {
    if (options.type === 'recipe') {
      options.id = `recipe: ${ItemHandler.formatRecipeName(options.id)}`;
    }

    if (items.has(options.id)) return;
    const item = new itemTypes[options.type](options);
    items.set(item.id, item);
    return writeItems();
  }

  static update(options) {
    if (!items.has(options.id)) return ItemHandler.create(options);
    const item = new itemTypes[options.type](options);
    items.set(item.id, item);
    return writeItems();
  }

  static destroy(id) {
    if (!items.has(id)) return;
    items.delete(id);
    return writeItems();
  }

  static baseCurrency() { return new itemTypes[baseCurrency.type](baseCurrency); }
  static all(filter) { return items.filter(filter); }
  static get SHOP() { return items.filter(item => item.shop); }
}

function findBaseCurrency() {
  const currencies = Array.from(items.filter(item => item.type === 'currency').values());
  const values = currencies.map(currency => currency.value);
  return currencies[values.indexOf(Math.min(...values))];
}

function writeItems() {
  return fs.writeFileSync(`${rootDir}/assets/items.json`, JSON.stringify(items.array().map(i => i.toJSON()), null, 2), 'utf8');
}

module.exports = ItemHandler;
<|endoftext|>


<commit_before>angular.module('$strap.directives')

.factory('$modal', function($rootScope, $compile, $http, $timeout, $q, $templateCache) {
  'use strict';

  var ModalFactory = function ModalFactory(options) {

    function Modal(options) {
      if(!options) options = {};

      var scope = options.scope ? options.scope.$new() : $rootScope.$new(),
          templateUrl = options.template;

      //@todo support {title, content} object

      return $q.when($templateCache.get(templateUrl) || $http.get(templateUrl, {cache: true}).then(function(res) { return res.data; }))
      .then(function onSuccess(template) {

        // Build modal object
        var id = templateUrl.replace('.html', '').replace(/[\/|\.|:]/g, '-') + '-' + scope.$id;
        var $modal = $('

').attr('id', id).addClass('fade').html(template);
        if(options.modalClass) $modal.addClass(options.modalClass);

        $('body').append($modal);

        // Compile modal content
        $timeout(function() {
          $compile($modal)(scope);
        });

        // Provide scope display functions
        scope.$modal = function(name) {
          $modal.modal(name);
        };
        angular.forEach(['show', 'hide'], function(name) {
          scope[name] = function() {
            $modal.modal(name);
          };
        });
        scope.dismiss = scope.hide;

        // Emit modal events
        angular.forEach(['show', 'shown', 'hide', 'hidden'], function(name) {
          $modal.on(name, function(ev) {
            scope.$emit('modal-' + name, ev);
          });
        });

        // Support autofocus attribute
        $modal.on('shown', function(ev) {
          $('input[autofocus]', $modal).first().trigger('focus');
        });
        // Auto-remove $modal created via service
        $modal.on('hidden', function(ev) {
          if(!options.persist) scope.$destroy();
        });

        // Garbage collection
        scope.$on('$destroy', function() {
          $modal.remove();
        });

        if(options.show) {
          $modal.modal('show');
        }

        return $modal;

      });

    }

    return new Modal(options);

  };

  return ModalFactory;

})

.directive('bsModal', function($q, $modal) {
  'use strict';

  return {
    restrict: 'A',
    scope: true,
    link: function postLink(scope, iElement, iAttrs, controller) {

      var options = {
        template: scope.$eval(iAttrs.bsModal),
        persist: true,
        scope: scope,
        modalClass: iAttrs.modalClass || '',
        backdrop: iAttrs.backdrop*1 || true,
        keyboard: iAttrs.keyboard*1 || true,
      };

      $q.when($modal(options)).then(function onSuccess(modal) {
        iElement.attr('data-target', '#' + modal.attr('id')).attr('data-toggle', 'modal');
      });

    }
  };
});
<commit_msg>fix(modal): revert forced custom scope<commit_after>angular.module('$strap.directives')

.factory('$modal', function($rootScope, $compile, $http, $timeout, $q, $templateCache) {
  'use strict';

  var ModalFactory = function ModalFactory(options) {

    function Modal(options) {
      if(!options) options = {};

      var scope = options.scope ? options.scope : $rootScope.$new(),
          templateUrl = options.template;

      //@todo support {title, content} object

      return $q.when($templateCache.get(templateUrl) || $http.get(templateUrl, {cache: true}).then(function(res) { return res.data; }))
      .then(function onSuccess(template) {

        // Build modal object
        var id = templateUrl.replace('.html', '').replace(/[\/|\.|:]/g, '-') + '-' + scope.$id;
        var $modal = $('

').attr('id', id).addClass('fade').html(template);
        if(options.modalClass) $modal.addClass(options.modalClass);

        $('body').append($modal);

        // Compile modal content
        $timeout(function() {
          $compile($modal)(scope);
        });

        // Provide scope display functions
        scope.$modal = function(name) {
          $modal.modal(name);
        };
        angular.forEach(['show', 'hide'], function(name) {
          scope[name] = function() {
            $modal.modal(name);
          };
        });
        scope.dismiss = scope.hide;

        // Emit modal events
        angular.forEach(['show', 'shown', 'hide', 'hidden'], function(name) {
          $modal.on(name, function(ev) {
            scope.$emit('modal-' + name, ev);
          });
        });

        // Support autofocus attribute
        $modal.on('shown', function(ev) {
          $('input[autofocus]', $modal).first().trigger('focus');
        });
        // Auto-remove $modal created via service
        $modal.on('hidden', function(ev) {
          if(!options.persist) scope.$destroy();
        });

        // Garbage collection
        scope.$on('$destroy', function() {
          $modal.remove();
        });

        if(options.show) {
          $modal.modal('show');
        }

        return $modal;

      });

    }

    return new Modal(options);

  };

  return ModalFactory;

})

.directive('bsModal', function($q, $modal) {
  'use strict';

  return {
    restrict: 'A',
    scope: true,
    link: function postLink(scope, iElement, iAttrs, controller) {

      var options = {
        template: scope.$eval(iAttrs.bsModal),
        persist: true,
        scope: scope,
        modalClass: iAttrs.modalClass || '',
        backdrop: iAttrs.backdrop*1 || true,
        keyboard: iAttrs.keyboard*1 || true,
      };

      $q.when($modal(options)).then(function onSuccess(modal) {
        iElement.attr('data-target', '#' + modal.attr('id')).attr('data-toggle', 'modal');
      });

    }
  };
});
<|endoftext|>


<commit_before>Children = new Mongo.Collection('children');
MathsGame = new Mongo.Collection('mathsGame');
ColoursGame = new Mongo.Collection('coloursgame');

Meteor.methods({

// -------------------------------------------- Add Child to DB

  addChild: function(name, age) {

    if (!Meteor.userId()) {
      throw new Meteor.Error("not authorised");
    }

    Children.insert({

      name: name,
      age: age,
      parent_id: Meteor.userId(),
      createdAt: new Date()

    });

  },

// -------------------------------------------- Remove Child from DB

  deleteChild: function(childId) {
    Children.remove(childId);
  },
<<<<<<< HEAD
=======

// -------------------------------------------- Add Colours Score to DB

  addColoursScore: function(childId, correctScores, incorrectScores, answersArray) {

    if (!Meteor.userId()) {
      throw new Meteor.Error("not authorised");
    }

    var gameScore = {

      child_id: childId,
      results: answersArray,
      total_correct: correctScores,
      total_incorrect: incorrectScores,
      score: Math.floor(correctScores/(correctScores + incorrectScores)*100),
      createdAt: new Date()

    };

    ColoursGame.insert(gameScore);

  },

// -------------------------------------------- Create Colour Game Question

  createColourQuestion: function(colours) {

    var nextRandomColour = colours[Math.floor(Math.random()*colours.length)];

// -------------------------------------------- Update Random Colour in current Session

    Session.set('randomColour', nextRandomColour);

  }
>>>>>>> updated colour button route to avoid IR bug. Generate random colour question based on four coloured divs. Store correct/wrong answers in Session temp variable. Generate a new question after every correct answer.

  addMathsScore: function(childId, answersArray, correctScores, incorrectScores) {

    if (!Meteor.userId()) {
      throw new Meteor.Error("not authorised");
    }

    MathsGame.insert({

      child_id: childId,
      results: answersArray,
      total_correct: correctScores,
      total_incorrect: incorrectScores,
      score: Math.floor(correctScores/(correctScores + incorrectScores)*100),
      createdAt: new Date()
    });

  }

});<commit_msg>fix syntax bug<commit_after>Children = new Mongo.Collection('children');
MathsGame = new Mongo.Collection('mathsGame');
ColoursGame = new Mongo.Collection('coloursgame');

Meteor.methods({

// -------------------------------------------- Add Child to DB

  addChild: function(name, age) {

    if (!Meteor.userId()) {
      throw new Meteor.Error("not authorised");
    }

    Children.insert({

      name: name,
      age: age,
      parent_id: Meteor.userId(),
      createdAt: new Date()

    });

  },

// -------------------------------------------- Remove Child from DB

  deleteChild: function(childId) {
    Children.remove(childId);
  },

// -------------------------------------------- Add Colours Score to DB

  addColoursScore: function(childId, correctScores, incorrectScores, answersArray) {

    if (!Meteor.userId()) {
      throw new Meteor.Error("not authorised");
    }

    var gameScore = {

      child_id: childId,
      results: answersArray,
      total_correct: correctScores,
      total_incorrect: incorrectScores,
      score: Math.floor(correctScores/(correctScores + incorrectScores)*100)

    };

    ColoursGame.insert(gameScore);

  },

// -------------------------------------------- Create Colour Game Question

  createColourQuestion: function(colours) {

    var nextRandomColour = colours[Math.floor(Math.random()*colours.length)];

// -------------------------------------------- Update Random Colour in current Session

    Session.set('randomColour', nextRandomColour);

  },

  addMathsScore: function(childId, answersArray, correctScores, incorrectScores) {

    if (!Meteor.userId()) {
      throw new Meteor.Error("not authorised");
    }

    MathsGame.insert({

      child_id: childId,
      results: answersArray,
      total_correct: correctScores,
      total_incorrect: incorrectScores,
      score: Math.floor(correctScores/(correctScores + incorrectScores)*100),
      createdAt: new Date()
    });

  }

});<|endoftext|>


<commit_before>var Session = require('../lib/session');
var SessionStore = require('../server/session_store');

function savedTo(store, transform) {
    if (typeof store === 'string') store = new SessionStore(store);
    return function(session, done) {
        transform(session, function(err, session) {
            if (err) return done(err);
            store.save(session, done);
        });
    };
}

var async = require('async');

function doTransform(src, dst, transform, done) {
    transform = savedTo(dst, transform);
    src.keys(function(err, keys) {
        if (err) return done(err);
        async.each(keys, function(key, keyDone) {
            src.load(key, function(err, session) {
                if (err) return keyDone(err);
                transform(session, keyDone);
            });
        }, done);
    });
}

var path = require('path');
var config = require('../server/config');

var argv = require('minimist')(process.argv.slice(2), {
    alias: {
        i: 'input',
        o: 'output'
    },
    default: {
        input: path.join(config.var, 'sessions')
    }
});
var input = new SessionStore(argv.input);
var output = argv.output ? argv.output : input;
var transforms = argv._.map(function(transform) {
    return require(path.join(process.cwd(), transform));
});

doTransform(input, output, function(session, done) {
    session = new Session(session.getData());
    for (var n=transforms.length, i=0; i<n; i++) {
        var r = transforms[i](session);
        if (r) session = r;
    }
    done(null, session);
}, allDone);

function allDone(err) {
    if (err) return console.error(err);
}
<commit_msg>scripts/transform: subsume doTransform<commit_after>var Session = require('../lib/session');
var SessionStore = require('../server/session_store');

function savedTo(store, transform) {
    if (typeof store === 'string') store = new SessionStore(store);
    return function(session, done) {
        transform(session, function(err, session) {
            if (err) return done(err);
            store.save(session, done);
        });
    };
}

var async = require('async');
var path = require('path');
var config = require('../server/config');

var argv = require('minimist')(process.argv.slice(2), {
    alias: {
        i: 'input',
        o: 'output'
    },
    default: {
        input: path.join(config.var, 'sessions')
    }
});
var input = new SessionStore(argv.input);
var output = argv.output ? argv.output : input;
var transforms = argv._.map(function(transform) {
    return require(path.join(process.cwd(), transform));
});

var transform = savedTo(output, function transform(session, done) {
    session = new Session(session.getData());
    for (var n=transforms.length, i=0; i<n; i++) {
        var r = transforms[i](session);
        if (r) session = r;
    }
    done(null, session);
});

input.keys(function(err, keys) {
    if (err) return allDone(err);
    async.each(keys, function(key, keyDone) {
        input.load(key, function(err, session) {
            if (err) return keyDone(err);
            transform(session, keyDone);
        });
    }, allDone);
});

function allDone(err) {
    if (err) return console.error(err);
}
<|endoftext|>


<commit_before>var fs = require( 'fs' );
var path = require( 'path' );
var crypto = require( 'crypto' );
var url = require( 'url' );
var Emitter = require( 'events' ).EventEmitter;

var UglifyJS = require( 'uglify-js' );
var CleanCSS = require( 'clean-css' );
var jschardet = require( 'jschardet' );
var iconvLite = require( 'iconv-lite' );
var Iconv = require( 'iconv' ).Iconv;
var mkdirp = require( 'mkdirp' );

var appUtil = require( './util' );

var emitter = new Emitter();

var defaultConfig = {
    author : 'f2e'
};

var defaultSetting = {
    stampFormat : 'yyyy-MM-dd hh:mm:ss'
};

var compressor = {

    init : function ( config, setting ) {
        this.config = appUtil.applyIf( config || {}, defaultConfig );
        this.setting = appUtil.applyIf( setting || {}, defaultSetting );

        this.localSetting = this.setting.compressor || {};

        if ( this.config.root == '.' || this.config.root == './' ) {
            this.config.root = '';
        }

        this.minFileNames = [];

        this.isExecModify = false;
    },

    compress : function ( fileNames ) {

        fileNames = fileNames.map( function ( filename ) {
            return path.resolve( this.config.root, filename );
        }.bind( this ) );

        fileNames = appUtil.unique( fileNames );

        this.miniNormalJSFileNames = [];

        var fileName = '';
        for ( var i = 0, len = fileNames.length; i < len; i++ ) {

            fileName = fileNames[ i ];

            var minFileName = this.compressOne( fileName);

            if ( this.minFileNames.indexOf( minFileName ) == -1 ) {
                this.minFileNames.push( minFileName );
            }
        }

        if ( this.miniNormalJSFileNames.length && !this.isExecModify ) {

            this.modifyMapFile();

        } else {

            this.minFileNames.sort( function ( f1, f2 ) {

                var ext1 = path.extname( f1 ).toLowerCase();
                var ext2 = path.extname( f2 ).toLowerCase();

                if ( ( ext1 == '.js' && ext2 != '.js' )
                    || ( ext1 == '.css' && ext2 != '.js' && ext2 != '.css' ) ) {
                    return -1;
                }

                if ( ( ext1 == '.js' && ext2 == '.js' )
                    || ( ext1 == '.css' && ext2 == '.css' )
                    || ( ext1 != '.js' && ext1 != '.css' && ext2!= '.js' && ext2 != '.css' ) ) {
                        return 0;
                }

                return 1;
            } );

            this.log();

            this.emit( 'done' );
        }
    },

    compressOne : function ( fileName ) {

        fileName = path.resolve( this.config.root, fileName );

        var minFileName = '';

        if ( appUtil.isScript( fileName ) ) {

            minFileName = this.compressJS( fileName );

        } else if ( appUtil.isCss( fileName ) ) {

            minFileName = this.compressCSS( fileName );

        } else {
            minFileName = this.compressOther( fileName );
        }
        return minFileName;
    },

    compressJS : function ( fileName ) {

        //获得utf-8 buffer
        var buffer = fs.readFileSync( fileName );
        var encoding = ( jschardet.detect( buffer ).encoding || '' ).toLowerCase();
        if ( encoding !== 'utf-8' ) {
            var iconv = new Iconv( 'GBK', 'UTF-8');
            buffer = iconv.convert( buffer );
        }

        //获得文件内容并压缩文件
        var content = iconvLite.decode( buffer, 'utf8' );
        var minContent = UglifyJS.minify( content, {
            fromString: true,
            output: {
                ascii_only : true,
                max_line_len : null
            }
        } ).code;

        //获得sha1签名
        var shasum = crypto.createHash( 'sha1' );
        var signature = shasum.update( buffer ).digest( 'hex' ).slice( 0, 6 );

        //banner
        var author = this.config.author;
        var timestamp = appUtil.dateFormat( new Date(), this.setting.stampFormat );
        var banner = '\/* @author ' + author + ' ' + timestamp + ' ' + signature + ' *\/';

        //最终文件
        minContent = banner + '\n' + minContent;

        var relativeFileName = fileName.replace( this.config.root, '' ).replace( /^\//, '' );

        if ( !this.localSetting.excludes || !appUtil.isExclude( relativeFileName, this.localSetting.excludes ) ) {

            relativeFileName = path.join( path.dirname( relativeFileName), path.basename( relativeFileName, '.js' ) + '_' + signature + '.js' );

            this.miniNormalJSFileNames.push( relativeFileName );
        }

        var buildFileName = path.resolve( this.config.build_dir, relativeFileName );

        appUtil.writeFile( buildFileName, minContent );

        return relativeFileName;
    },

    compressCSS : function ( fileName ) {

        var content = appUtil.readFile( fileName )
        var minContent = new CleanCSS().minify( content );

        //banner
        var author = this.config.author;
        var timestamp = appUtil.dateFormat( new Date(), this.setting.stampFormat );
        var banner = '\/* @author ' + author + ' ' + timestamp + ' *\/';

        //最终文件
        minContent = banner + '\n' + minContent;

        var relativeFileName = fileName.replace( this.config.root, '' ).replace( /^\//, '' );
        var buildFileName = path.resolve( this.config.build_dir, relativeFileName );

        appUtil.writeFile( buildFileName, minContent );

        return relativeFileName;
    },

    //其他文件只做拷贝
    compressOther : function ( fileName ) {

        var relativeFileName = fileName.replace( this.config.root, '' ).replace( /^\//, '' );
        var buildFileName = path.resolve( this.config.build_dir, relativeFileName );

        mkdirp.sync( path.dirname( buildFileName ) );
        fs.createReadStream( fileName ).pipe( fs.createWriteStream( buildFileName ) );

        return relativeFileName;
    },

    modifyMapFile : function () {
        var walk = function ( dir, done ) {
            var results = [];
            fs.readdir( dir, function ( err, list ) {
                if ( err ) {
                    return done( err );
                }
                var i = 0;
                ( function next() {
                    var file = list[ i++ ];
                    if ( !file ) {
                        return done( null, results );
                    }
                    file = dir + '/' + file;
                    fs.stat( file, function( err, stat ) {
                        if ( stat && stat.isDirectory() ) {
                            walk( file, function ( err, res ) {
                                results = results.concat( res );
                                next();
                            } );
                        } else {
                            results.push( file );
                            next();
                        }
                    } );
                } )();
            });
        };

        this.isExecModify = true;

        walk( path.resolve( this.config.root, 'js' ), function ( placeholder, results ) {
            this._modifyMapFile( results );
        }.bind( this ) );
    },

    _modifyMapFile : function ( fileNames ) {

        var minNormalFileNames = this.miniNormalJSFileNames.map( function ( fileName ) {
            return fileName.replace( /^js\//, '' );
        } );

        var regs = minNormalFileNames.map( function ( fileName ) {

            if ( fileName.split( '_' ).length > 2 ) {
                fileName = fileName.split( '_' ).slice( 0, -1 ).join( '_' );
                fileName = fileName.replace( '/', '\\\/' ) + '((_\\w+)|(_\\d+))?\\.js';
            } else {
                fileName = fileName.replace('/', '\\\/').replace(/_\w+\.js/, '((_\\w+)|(\\d+))?\\.js');
            }
            return new RegExp( fileName );
        } );

        var includePattern = this.setting.mapFiles;

        mapFileNames = fileNames.filter( function ( fileName ) {
            return appUtil.isMapFile( fileName, includePattern );
        } );

        var modifiedMapFileNames = [];

        mapFileNames.forEach( function ( mapFileName ) {

            var content = appUtil.readFile( mapFileName );

            var isModyfied = false;

            minNormalFileNames.forEach( function ( minFileName, index ) {
                var reg = regs[ index ];
                if ( reg && reg.test( content ) ) {
                    isModyfied = true;
                    content = content.replace( reg, minFileName );
                }
            } );

            if ( isModyfied ) {
                modifiedMapFileNames.push( mapFileName );
                appUtil.writeFile( mapFileName, content );
            }

        }.bind( this ) );

        this.compress( modifiedMapFileNames );
    },

    log : function () {

        var jsReg = /^js\//;
        var cssReg = /^css\//;
        var imgReg = /^img\//;

        var urls = this.minFileNames.map( function ( fileName ) {

            if ( jsReg.test( fileName ) ) {
                return url.resolve( 'http://js.tv.itc.cn', fileName.replace( jsReg, '' ) );
            }

            if ( cssReg.test( fileName ) ) {
                return url.resolve( 'http://css.tv.itc.cn', fileName.replace( cssReg, '' ) );
            }

            if ( imgReg.test( fileName ) ) {
                return url.resolve( 'http://css.tv.itc.cn', fileName.replace( imgReg, '' ) );
            }
        } );

        var content = this.minFileNames.join( '\n' );
        var urlContent = urls.join( '\n' );

        console.info( 'compress:' );
        console.info( content + '\n\n' + urlContent );

        appUtil.appendFile( this.config.logFile, content + '\n\n' + urlContent );

        var pListFile = this.config.pListFile;

        if ( !pListFile ) {
            pListFile = path.resolve( path.dirname( this.config.listFile ), 'plist.txt' );
        }

        console.log( '\n生成上传文件清单：' + pListFile + '\n' );
        appUtil.writeFile( pListFile, content );

    },

    on : function ( topic, handler ) {
        emitter.on( topic, handler );
    },

    emit : function ( topic ) {
        emitter.emit( topic );
    }
};

module.exports = compressor;
<commit_msg>compressor log<commit_after>var fs = require( 'fs' );
var path = require( 'path' );
var crypto = require( 'crypto' );
var url = require( 'url' );
var Emitter = require( 'events' ).EventEmitter;

var UglifyJS = require( 'uglify-js' );
var CleanCSS = require( 'clean-css' );
var jschardet = require( 'jschardet' );
var iconvLite = require( 'iconv-lite' );
var Iconv = require( 'iconv' ).Iconv;
var mkdirp = require( 'mkdirp' );

var appUtil = require( './util' );

var emitter = new Emitter();

var defaultConfig = {
    author : 'f2e'
};

var defaultSetting = {
    stampFormat : 'yyyy-MM-dd hh:mm:ss'
};

var compressor = {

    init : function ( config, setting ) {
        this.config = appUtil.applyIf( config || {}, defaultConfig );
        this.setting = appUtil.applyIf( setting || {}, defaultSetting );

        this.localSetting = this.setting.compressor || {};

        if ( this.config.root == '.' || this.config.root == './' ) {
            this.config.root = '';
        }

        this.minFileNames = [];

        this.isExecModify = false;
    },

    compress : function ( fileNames ) {

        fileNames = fileNames.map( function ( filename ) {
            return path.resolve( this.config.root, filename );
        }.bind( this ) );

        fileNames = appUtil.unique( fileNames );

        this.miniNormalJSFileNames = [];

        var fileName = '';
        for ( var i = 0, len = fileNames.length; i < len; i++ ) {

            fileName = fileNames[ i ];

            var minFileName = this.compressOne( fileName);

            if ( this.minFileNames.indexOf( minFileName ) == -1 ) {
                this.minFileNames.push( minFileName );
            }
        }

        if ( this.miniNormalJSFileNames.length && !this.isExecModify ) {

            this.modifyMapFile();

        } else {

            this.minFileNames.sort( function ( f1, f2 ) {

                var ext1 = path.extname( f1 ).toLowerCase();
                var ext2 = path.extname( f2 ).toLowerCase();

                if ( ( ext1 == '.js' && ext2 != '.js' )
                    || ( ext1 == '.css' && ext2 != '.js' && ext2 != '.css' ) ) {
                    return -1;
                }

                if ( ( ext1 == '.js' && ext2 == '.js' )
                    || ( ext1 == '.css' && ext2 == '.css' )
                    || ( ext1 != '.js' && ext1 != '.css' && ext2!= '.js' && ext2 != '.css' ) ) {
                        return 0;
                }

                return 1;
            } );

            this.log();

            this.emit( 'done' );
        }
    },

    compressOne : function ( fileName ) {

        fileName = path.resolve( this.config.root, fileName );

        var minFileName = '';

        if ( appUtil.isScript( fileName ) ) {

            minFileName = this.compressJS( fileName );

        } else if ( appUtil.isCss( fileName ) ) {

            minFileName = this.compressCSS( fileName );

        } else {
            minFileName = this.compressOther( fileName );
        }
        return minFileName;
    },

    compressJS : function ( fileName ) {

        //获得utf-8 buffer
        var buffer = fs.readFileSync( fileName );
        var encoding = ( jschardet.detect( buffer ).encoding || '' ).toLowerCase();
        if ( encoding !== 'utf-8' ) {
            var iconv = new Iconv( 'GBK', 'UTF-8');
            buffer = iconv.convert( buffer );
        }

        //获得文件内容并压缩文件
        var content = iconvLite.decode( buffer, 'utf8' );
        var minContent = UglifyJS.minify( content, {
            fromString: true,
            output: {
                ascii_only : true,
                max_line_len : null
            }
        } ).code;

        //获得sha1签名
        var shasum = crypto.createHash( 'sha1' );
        var signature = shasum.update( buffer ).digest( 'hex' ).slice( 0, 6 );

        //banner
        var author = this.config.author;
        var timestamp = appUtil.dateFormat( new Date(), this.setting.stampFormat );
        var banner = '\/* @author ' + author + ' ' + timestamp + ' ' + signature + ' *\/';

        //最终文件
        minContent = banner + '\n' + minContent;

        var relativeFileName = fileName.replace( this.config.root, '' ).replace( /^\//, '' );

        if ( !this.localSetting.excludes || !appUtil.isExclude( relativeFileName, this.localSetting.excludes ) ) {

            relativeFileName = path.join( path.dirname( relativeFileName), path.basename( relativeFileName, '.js' ) + '_' + signature + '.js' );

            this.miniNormalJSFileNames.push( relativeFileName );
        }

        var buildFileName = path.resolve( this.config.build_dir, relativeFileName );

        appUtil.writeFile( buildFileName, minContent );

        return relativeFileName;
    },

    compressCSS : function ( fileName ) {

        var content = appUtil.readFile( fileName )
        var minContent = new CleanCSS().minify( content );

        //banner
        var author = this.config.author;
        var timestamp = appUtil.dateFormat( new Date(), this.setting.stampFormat );
        var banner = '\/* @author ' + author + ' ' + timestamp + ' *\/';

        //最终文件
        minContent = banner + '\n' + minContent;

        var relativeFileName = fileName.replace( this.config.root, '' ).replace( /^\//, '' );
        var buildFileName = path.resolve( this.config.build_dir, relativeFileName );

        appUtil.writeFile( buildFileName, minContent );

        return relativeFileName;
    },

    //其他文件只做拷贝
    compressOther : function ( fileName ) {

        var relativeFileName = fileName.replace( this.config.root, '' ).replace( /^\//, '' );
        var buildFileName = path.resolve( this.config.build_dir, relativeFileName );

        mkdirp.sync( path.dirname( buildFileName ) );
        fs.createReadStream( fileName ).pipe( fs.createWriteStream( buildFileName ) );

        return relativeFileName;
    },

    modifyMapFile : function () {
        var walk = function ( dir, done ) {
            var results = [];
            fs.readdir( dir, function ( err, list ) {
                if ( err ) {
                    return done( err );
                }
                var i = 0;
                ( function next() {
                    var file = list[ i++ ];
                    if ( !file ) {
                        return done( null, results );
                    }
                    file = dir + '/' + file;
                    fs.stat( file, function( err, stat ) {
                        if ( stat && stat.isDirectory() ) {
                            walk( file, function ( err, res ) {
                                results = results.concat( res );
                                next();
                            } );
                        } else {
                            results.push( file );
                            next();
                        }
                    } );
                } )();
            });
        };

        this.isExecModify = true;

        walk( path.resolve( this.config.root, 'js' ), function ( placeholder, results ) {
            this._modifyMapFile( results );
        }.bind( this ) );
    },

    _modifyMapFile : function ( fileNames ) {

        var minNormalFileNames = this.miniNormalJSFileNames.map( function ( fileName ) {
            return fileName.replace( /^js\//, '' );
        } );

        var regs = minNormalFileNames.map( function ( fileName ) {

            if ( fileName.split( '_' ).length > 2 ) {
                fileName = fileName.split( '_' ).slice( 0, -1 ).join( '_' );
                fileName = fileName.replace( '/', '\\\/' ) + '((_\\w+)|(_\\d+))?\\.js';
            } else {
                fileName = fileName.replace('/', '\\\/').replace(/_\w+\.js/, '((_\\w+)|(\\d+))?\\.js');
            }
            return new RegExp( fileName );
        } );

        var includePattern = this.setting.mapFiles;

        mapFileNames = fileNames.filter( function ( fileName ) {
            return appUtil.isMapFile( fileName, includePattern );
        } );

        var modifiedMapFileNames = [];

        mapFileNames.forEach( function ( mapFileName ) {

            var content = appUtil.readFile( mapFileName );

            var isModyfied = false;

            minNormalFileNames.forEach( function ( minFileName, index ) {
                var reg = regs[ index ];
                if ( reg && reg.test( content ) ) {
                    isModyfied = true;
                    content = content.replace( reg, minFileName );
                }
            } );

            if ( isModyfied ) {
                modifiedMapFileNames.push( mapFileName );
                appUtil.writeFile( mapFileName, content );
            }

        }.bind( this ) );

        this.compress( modifiedMapFileNames );
    },

    log : function () {

        var jsReg = /^js\//;
        var cssReg = /^css\//;
        var imgReg = /^img\//;

        var urls = this.minFileNames.map( function ( fileName ) {

            if ( jsReg.test( fileName ) ) {
                return url.resolve( 'http://js.tv.itc.cn', fileName.replace( jsReg, '' ) );
            }

            if ( cssReg.test( fileName ) ) {
                return url.resolve( 'http://css.tv.itc.cn', fileName.replace( cssReg, '' ) );
            }

            if ( imgReg.test( fileName ) ) {
                return url.resolve( 'http://css.tv.itc.cn', fileName.replace( imgReg, '' ) );
            }
        } );

        var content = this.minFileNames.join( '\n' );
        var urlContent = urls.join( '\n' );

        console.info( 'compress:' );
        console.info( content + '\n\n' + urlContent );

        appUtil.writeFile( this.config.logFile, content + '\n\n' + urlContent );

        var pListFile = this.config.pListFile;

        if ( !pListFile ) {
            pListFile = path.resolve( path.dirname( this.config.listFile ), 'plist.txt' );
        }

        console.log( '\n生成上传文件清单：' + pListFile + '\n' );
        appUtil.writeFile( pListFile, content );

    },

    on : function ( topic, handler ) {
        emitter.on( topic, handler );
    },

    emit : function ( topic ) {
        emitter.emit( topic );
    }
};

module.exports = compressor;
<|endoftext|>


<commit_before>/**
 * Node.js wrapper for Atlassian's Confluence API.
 * See https://developer.atlassian.com/confdev/confluence-rest-api
 *
 * Copyright (c) 2015, John Duane
 * Released under the MIT License
 */

var request = require('superagent');

/**
 * Construct Confluence.
 *
 * @constructor
 * @this {Confluence}
 * @param {Object} config
 * @param {string} config.username
 * @param {string} config.password
 * @param {string} config.baseUrl
 * @param {number} config.version - Optional
 *
 */
function Confluence(config) {
    if (!(this instanceof Confluence)) return new Confluence(config);

    if (!config) {
        throw new Error("Confluence module expects a config object.");
    }
    else if (!config.username || ! config.password) {
        throw new Error("Confluence module expects a config object with both a username and password.");
    }
    else if (!config.baseUrl) {
        throw new Error("Confluence module expects a config object with a baseUrl.");
    }

    this.config = config;

    this.config.apiPath = '/rest/api';
    this.config.extension = ''; // no extension by default

    if (this.config.version && this.config.version === 4) {
        this.config.apiPath = '/rest/prototype/latest';
        this.config.extension = '.json';
    }
}

function processCallback(cb, err, res) {
    if (err || !res || !res.body) {
        cb(err, res);
    }
    else {
        cb(err, res.body);
    }
}

/**
 * Get space information.
 *
 * @param {string} space
 * @param {Function} callback
 */
Confluence.prototype.getSpace = function(space, callback){

    request
        .get(this.config.baseUrl + this.config.apiPath + "/space" + this.config.extension + "?spaceKey=" + space)
        .auth(this.config.username, this.config.password)
        .end(function(err, res){
            processCallback(callback, err, res);
        });

};

/**
 * Get space home page.
 *
 * @param {string} space
 * @param {Function} callback
 */
Confluence.prototype.getSpaceHomePage = function(space, callback){
    var config = this.config;

    request
        .get(config.baseUrl + config.apiPath + "/space" + config.extension + "?spaceKey=" + space)
        .auth(config.username, config.password)
        .end(function(err, res){
            if (err) {
                callback(err);
            }
            else {
                try {
                    request
                        .get(config.baseUrl + res.body.results[0]._expandable.homepage)
                        .auth(config.username, config.password)
                        .end(function(err, res){
                            processCallback(callback, err, res);
                        });
                }
                catch (e) {
                    callback("Can't find space home page. " + e.message, res);
                }
            }
        });

};

/**
 * Get stored content for a specific space and page title.
 *
 * @param {string} id
 * @param {Function} callback
 */
Confluence.prototype.getContentById = function(id, callback){

    request
        .get(this.config.baseUrl + this.config.apiPath + "/content/" + id + this.config.extension + "?expand=body.storage,version")
        .auth(this.config.username, this.config.password)
        .end(function(err, res){
            processCallback(callback, err, res);
        });
};

/**
 * Get stored content for a specific page id with optional custom expanders.
 *
 * @param {object} options for the custom content request
 * @param {Function} callback
 */
Confluence.prototype.getCustomContentById = function(options, callback) {
    var expanders = options.expanders || ['body.storage', 'version'];

    request
        .get(this.config.baseUrl + this.config.apiPath + "/content/" + options.id + this.config.extension + "?expand=" + expanders.join())
        .auth(this.config.username, this.config.password)
        .end(function(err, res){
            processCallback(callback, err, res);
        });
};

/**
 * Get stored content for a specific space and page title.
 *
 * @param {string} space
 * @param {string} title
 * @param {Function} callback
 */
Confluence.prototype.getContentByPageTitle = function(space, title, callback){
    var query =
        "?spaceKey=" + space +
        "&title=" + title +
        "&expand=body.storage,version";

    request
        .get(this.config.baseUrl + this.config.apiPath + "/content" + this.config.extension + query)
        .auth(this.config.username, this.config.password)
        .end(function(err, res){
            processCallback(callback, err, res);
        });

};

/**
 * Post content to a new page.
 *
 * @param {string} space
 * @param {string} title
 * @param {string} content
 * @param {number} parentId - A null value will cause the page to be added under the space's home page
 * @param {Function} callback
 */
Confluence.prototype.postContent = function(space, title, content, parentId, callback){
    var config = this.config;
    var page = {
        "type": "page",
        "title": title,
        "space": {
            "key": space
        },
        "ancestors": [{
            "type": "page"
        }],
        "body": {
            "storage": {
                "value": content,
                "representation": "storage"
            }
        }
    };

    function createPage() {
        request
            .post(config.baseUrl + config.apiPath + "/content" + config.extension)
            .auth(config.username, config.password)
            .type('json')
            .send(page)
            .end(function(err, res){
                processCallback(callback, err, res);
            });
    }

    if (!parentId) {
        this.getSpaceHomePage(space, function(err, res) {
            if (err) callback(err);
            else if (!res || !res.id) {
                callback("Can't find space home page.");
            }
            else {
                page.ancestors[0].id = res.id;
                createPage();
            }
        });
    }
    else {
        page.ancestors[0].id = parentId;
        createPage();
    }

};

/**
 * Put/update stored content for a page.
 *
 * @param {string} space
 * @param {string} id
 * @param {number} version
 * @param {string} title
 * @param {string} content
 * @param {Function} callback
 */
Confluence.prototype.putContent = function(space, id, version, title, content, callback){
    var page = {
        "id": id,
        "type": "page",
        "title": title,
        "space": {
            "key": space
        },
        "version": {
            "number": version,
            "minorEdit": false
        },
        "body": {
            "storage": {
                "value": content,
                "representation": "storage"
            }
        }
    };

    request
        .put(this.config.baseUrl + this.config.apiPath + "/content/" + id + this.config.extension + "?expand=body.storage,version")
        .auth(this.config.username, this.config.password)
        .type('json')
        .send(page)
        .end(function(err, res){
            processCallback(callback, err, res);
        });

};

/**
 * Delete a page.
 *
 * @param {string} id
 * @param {Function} callback
 */
Confluence.prototype.deleteContent = function(id, callback){

    request
        .del(this.config.baseUrl + this.config.apiPath + "/content/" + id + this.config.extension)
        .auth(this.config.username, this.config.password)
        .end(function(err, res){
            callback(err, res);
        });

};

/**
 * Get attachments
 *
 * @param {string} space
 * @param {string} id
 * @param {Function} callback
 */
Confluence.prototype.getAttachments = function(space, id , callback ){
    var query =
        "?spaceKey=" + space +
        "&expand=version,container";

    request
        .get(this.config.baseUrl + this.config.apiPath + "/content/" + id + "/child/attachment" + query )
        .auth(this.config.username, this.config.password)
        .end(function(err, res){
            processCallback(callback, err, res);
        });
};

/**
 * This allows you to post attachments to the pages you create.
 *
 * @param {string} space
 * @param {string} id
 * @param {string} filepath - absolute path of the file you are sending
 * @param {Function} callback
 */
Confluence.prototype.createAttachment = function(space, id, filepath, callback ){
//https://docs.atlassian.com/atlassian-confluence/REST/latest/#content/{id}/child/attachment-getAttachments

    request
        .post(this.config.baseUrl + this.config.apiPath + "/content/" + id + "/child/attachment")
        .auth(this.config.username, this.config.password)
        .set("X-Atlassian-Token", "nocheck")
        .attach("file", filepath )
        .end(function(err, res){
            processCallback(callback, err, res);
        });
};

/**
 *  This allows you to update posted attachments data
 *
 * @param {string} space
 * @param {string} id
 * @param {string} attachmentId
 * @param {string} filepath
 * @param {Function} callback
 */
Confluence.prototype.updateAttachmentData = function(space, id, attachmentId, filepath, callback ){

    request
        .post(this.config.baseUrl + this.config.apiPath + "/content/" + id + "/child/attachment/" + attachmentId + "/data")
        .auth(this.config.username, this.config.password)
        .set("X-Atlassian-Token", "nocheck")
        .attach("file", filepath )
        .end(function(err, res){
            processCallback(callback, err, res);
        });
};

module.exports = Confluence;<commit_msg>Added functions to manage contant labels<commit_after>/**
 * Node.js wrapper for Atlassian's Confluence API.
 * See https://developer.atlassian.com/confdev/confluence-rest-api
 *
 * Copyright (c) 2015, John Duane
 * Released under the MIT License
 */

var request = require('superagent');

/**
 * Construct Confluence.
 *
 * @constructor
 * @this {Confluence}
 * @param {Object} config
 * @param {string} config.username
 * @param {string} config.password
 * @param {string} config.baseUrl
 * @param {number} config.version - Optional
 *
 */
function Confluence(config) {
    if (!(this instanceof Confluence)) return new Confluence(config);

    if (!config) {
        throw new Error("Confluence module expects a config object.");
    }
    else if (!config.username || ! config.password) {
        throw new Error("Confluence module expects a config object with both a username and password.");
    }
    else if (!config.baseUrl) {
        throw new Error("Confluence module expects a config object with a baseUrl.");
    }

    this.config = config;

    this.config.apiPath = '/rest/api';
    this.config.extension = ''; // no extension by default

    if (this.config.version && this.config.version === 4) {
        this.config.apiPath = '/rest/prototype/latest';
        this.config.extension = '.json';
    }
}

function processCallback(cb, err, res) {
    if (err || !res || !res.body) {
        cb(err, res);
    }
    else {
        cb(err, res.body);
    }
}

/**
 * Get space information.
 *
 * @param {string} space
 * @param {Function} callback
 */
Confluence.prototype.getSpace = function(space, callback){

    request
        .get(this.config.baseUrl + this.config.apiPath + "/space" + this.config.extension + "?spaceKey=" + space)
        .auth(this.config.username, this.config.password)
        .end(function(err, res){
            processCallback(callback, err, res);
        });

};

/**
 * Get space home page.
 *
 * @param {string} space
 * @param {Function} callback
 */
Confluence.prototype.getSpaceHomePage = function(space, callback){
    var config = this.config;

    request
        .get(config.baseUrl + config.apiPath + "/space" + config.extension + "?spaceKey=" + space)
        .auth(config.username, config.password)
        .end(function(err, res){
            if (err) {
                callback(err);
            }
            else {
                try {
                    request
                        .get(config.baseUrl + res.body.results[0]._expandable.homepage)
                        .auth(config.username, config.password)
                        .end(function(err, res){
                            processCallback(callback, err, res);
                        });
                }
                catch (e) {
                    callback("Can't find space home page. " + e.message, res);
                }
            }
        });

};

/**
 * Get stored content for a specific space and page title.
 *
 * @param {string} id
 * @param {Function} callback
 */
Confluence.prototype.getContentById = function(id, callback){

    request
        .get(this.config.baseUrl + this.config.apiPath + "/content/" + id + this.config.extension + "?expand=body.storage,version")
        .auth(this.config.username, this.config.password)
        .end(function(err, res){
            processCallback(callback, err, res);
        });
};

/**
 * Get stored content for a specific page id with optional custom expanders.
 *
 * @param {object} options for the custom content request
 * @param {Function} callback
 */
Confluence.prototype.getCustomContentById = function(options, callback) {
    var expanders = options.expanders || ['body.storage', 'version'];

    request
        .get(this.config.baseUrl + this.config.apiPath + "/content/" + options.id + this.config.extension + "?expand=" + expanders.join())
        .auth(this.config.username, this.config.password)
        .end(function(err, res){
            processCallback(callback, err, res);
        });
};

/**
 * Get stored content for a specific space and page title.
 *
 * @param {string} space
 * @param {string} title
 * @param {Function} callback
 */
Confluence.prototype.getContentByPageTitle = function(space, title, callback){
    var query =
        "?spaceKey=" + space +
        "&title=" + title +
        "&expand=body.storage,version";

    request
        .get(this.config.baseUrl + this.config.apiPath + "/content" + this.config.extension + query)
        .auth(this.config.username, this.config.password)
        .end(function(err, res){
            processCallback(callback, err, res);
        });

};

/**
 * Post content to a new page.
 *
 * @param {string} space
 * @param {string} title
 * @param {string} content
 * @param {number} parentId - A null value will cause the page to be added under the space's home page
 * @param {Function} callback
 */
Confluence.prototype.postContent = function(space, title, content, parentId, callback){
    var config = this.config;
    var page = {
        "type": "page",
        "title": title,
        "space": {
            "key": space
        },
        "ancestors": [{
            "type": "page"
        }],
        "body": {
            "storage": {
                "value": content,
                "representation": "storage"
            }
        }
    };

    function createPage() {
        request
            .post(config.baseUrl + config.apiPath + "/content" + config.extension)
            .auth(config.username, config.password)
            .type('json')
            .send(page)
            .end(function(err, res){
                processCallback(callback, err, res);
            });
    }

    if (!parentId) {
        this.getSpaceHomePage(space, function(err, res) {
            if (err) callback(err);
            else if (!res || !res.id) {
                callback("Can't find space home page.");
            }
            else {
                page.ancestors[0].id = res.id;
                createPage();
            }
        });
    }
    else {
        page.ancestors[0].id = parentId;
        createPage();
    }

};

/**
 * Put/update stored content for a page.
 *
 * @param {string} space
 * @param {string} id
 * @param {number} version
 * @param {string} title
 * @param {string} content
 * @param {Function} callback
 */
Confluence.prototype.putContent = function(space, id, version, title, content, callback){
    var page = {
        "id": id,
        "type": "page",
        "title": title,
        "space": {
            "key": space
        },
        "version": {
            "number": version,
            "minorEdit": false
        },
        "body": {
            "storage": {
                "value": content,
                "representation": "storage"
            }
        }
    };

    request
        .put(this.config.baseUrl + this.config.apiPath + "/content/" + id + this.config.extension + "?expand=body.storage,version")
        .auth(this.config.username, this.config.password)
        .type('json')
        .send(page)
        .end(function(err, res){
            processCallback(callback, err, res);
        });

};

/**
 * Delete a page.
 *
 * @param {string} id
 * @param {Function} callback
 */
Confluence.prototype.deleteContent = function(id, callback){

    request
        .del(this.config.baseUrl + this.config.apiPath + "/content/" + id + this.config.extension)
        .auth(this.config.username, this.config.password)
        .end(function(err, res){
            callback(err, res);
        });

};

/**
 * Get attachments
 *
 * @param {string} space
 * @param {string} id
 * @param {Function} callback
 */
Confluence.prototype.getAttachments = function(space, id , callback ){
    var query =
        "?spaceKey=" + space +
        "&expand=version,container";

    request
        .get(this.config.baseUrl + this.config.apiPath + "/content/" + id + "/child/attachment" + query )
        .auth(this.config.username, this.config.password)
        .end(function(err, res){
            processCallback(callback, err, res);
        });
};

/**
 * This allows you to post attachments to the pages you create.
 *
 * @param {string} space
 * @param {string} id
 * @param {string} filepath - absolute path of the file you are sending
 * @param {Function} callback
 */
Confluence.prototype.createAttachment = function(space, id, filepath, callback ){
//https://docs.atlassian.com/atlassian-confluence/REST/latest/#content/{id}/child/attachment-getAttachments

    request
        .post(this.config.baseUrl + this.config.apiPath + "/content/" + id + "/child/attachment")
        .auth(this.config.username, this.config.password)
        .set("X-Atlassian-Token", "nocheck")
        .attach("file", filepath )
        .end(function(err, res){
            processCallback(callback, err, res);
        });
};

/**
 *  This allows you to update posted attachments data
 *
 * @param {string} space
 * @param {string} id
 * @param {string} attachmentId
 * @param {string} filepath
 * @param {Function} callback
 */
Confluence.prototype.updateAttachmentData = function(space, id, attachmentId, filepath, callback ){

    request
        .post(this.config.baseUrl + this.config.apiPath + "/content/" + id + "/child/attachment/" + attachmentId + "/data")
        .auth(this.config.username, this.config.password)
        .set("X-Atlassian-Token", "nocheck")
        .attach("file", filepath )
        .end(function(err, res){
            processCallback(callback, err, res);
        });
};

/**
 * Get labels from content
 *
 * @param {string} id
 * @param {Function} callback
 */
Confluence.prototype.getContentLabels = function(id , callback ){

    request
        .get(this.config.baseUrl + this.config.apiPath + "/content/" + id + "/label" )
        .auth(this.config.username, this.config.password)
        .end(function(err, res){
            processCallback(callback, err, res);
        });
};

/**
 * Add content labels to a existing page.
 *
 * @param {string} id
 * @param {array} labels
 * @param {Function} callback
 */
Confluence.prototype.addContentLabels = function(id, labels, callback){

    request
        .post(this.config.baseUrl + this.config.apiPath + "/content/" + id + "/label")
        .auth(this.config.username, this.config.password)
        .type('json')
        .send(labels)
        .end(function(err, res){
            processCallback(callback, err, res);
        });

};

/**
 * Delete a label from a page.
 *
 * @param {string} id
 * @param {string} label
 * @param {Function} callback
 */
Confluence.prototype.deleteContentLabel = function(id, label, callback){

    request
        .del(this.config.baseUrl + this.config.apiPath + "/content/" + id + "/label?name=" + label)
        .auth(this.config.username, this.config.password)
        .end(function(err, res){
            callback(err, res);
        });

};

module.exports = Confluence;<|endoftext|>


<commit_before>"use strict";

var EventEmitter = require('events').EventEmitter
  , spawn = require('child_process').spawn
  , Utils = require('./utils');

exports.IssueLog = IssueLog;         // connection issue handling
exports.Available = ping;            // connection availablity

function ping (host, callback) {
  var pong = spawn('ping', [host]);

  pong.stdout.on('data', function stdoutdata (data) {
    callback(false, data.toString().split('\n')[0].substr(14));
    pong.kill();
  });

  pong.stderr.on('data', function stderrdata (data) {
    callback(new Error(data.toString().split('\n')[0].substr(14)), false);
    pong.kill();
  });
}

function IssueLog (args) {
  this.config = args;
  this.messages = [];
  this.failed = false;

  this.totalRetries = 0;
  this.retry = 0;
  this.totalReconnectsAttempted = 0;
  this.totalReconnectsSuccess = 0;

  Utils.merge(this, args);
  EventEmitter.call(this);
}

var issues = IssueLog.prototype = new EventEmitter;

issues.log = function log (message) {
  var issue = this;

  this.failed = true;
  this.messages.push(message || 'No message specified');

  if (this.retries) {
    setTimeout(issue.attemptRetry.bind(issue), this.retry);
    return this.emit('issue', this.details);
  }

  if (this.remove) return this.emit('remove', this.details);

  setTimeout(issue.attemptReconnect.bind(issue), this.reconnect);
};

Object.defineProperty(issues, 'details', {
  get: function getDetails () {
    var res = {};

    res.server = this.server;
    res.tokens = this.tokens;
    res.messages = this.messages;

    if (this.retries) {
      res.retries = this.retries;
      res.totalRetries = this.totalRetries;
    } else {
      res.totalReconnectsAttempted = this.totalReconnectsAttempted;
      res.totalReconnectsSuccess = this.totalReconnectsSuccess;
      res.totalReconnectsFailed = this.totalReconnectsAttempted - this.totalReconnectsSuccess;
      res.totalDownTime = (res.totalReconnectsFailed * this.reconnect) + (this.totalRetries * this.retry);
    }

    return res;
  }
});

issues.attemptRetry = function attemptRetry () {
  this.totalRetries++;
  this.retries--;
  this.failed = false;
};

issues.attemptReconnect = function attemptReconnect () {
  var issue = this;
  this.totalReconnectsAttempted++;
  this.emit('reconnecting', this.details);

  // Ping the server
  ping(this.tokens[1], function pingpong (err) {
    // still no access to the server
    if (err) {
      this.messages.push(err.message || 'No message specified');
      return setTimeout(issue.attemptReconnect.bind(issue), issue.reconnect);
    }

    issue.emit('reconnected', issue.details);

    issue.totalReconnectsSuccess++;
    issue.messages.length = 0;
    issue.failed = false;

    // we connected again, so we are going through the whole cycle again
    Utils.merge(issue, JSON.parse(JSON.stringify(issue.config)));
  });
};
<commit_msg>add lock around registration of server retry<commit_after>"use strict";

var EventEmitter = require('events').EventEmitter
  , spawn = require('child_process').spawn
  , Utils = require('./utils');

exports.IssueLog = IssueLog;         // connection issue handling
exports.Available = ping;            // connection availablity

function ping (host, callback) {
  var pong = spawn('ping', [host]);

  pong.stdout.on('data', function stdoutdata (data) {
    callback(false, data.toString().split('\n')[0].substr(14));
    pong.kill();
  });

  pong.stderr.on('data', function stderrdata (data) {
    callback(new Error(data.toString().split('\n')[0].substr(14)), false);
    pong.kill();
  });
}

function IssueLog (args) {
  this.config = args;
  this.messages = [];
  this.failed = false;
  this.locked = false;

  this.totalRetries = 0;
  this.retry = 0;
  this.totalReconnectsAttempted = 0;
  this.totalReconnectsSuccess = 0;

  Utils.merge(this, args);
  EventEmitter.call(this);
}

var issues = IssueLog.prototype = new EventEmitter;

issues.log = function log (message) {
  var issue = this;

  this.failed = true;
  this.messages.push(message || 'No message specified');
  if (this.retries && !this.locked) {
    this.locked = true;
    setTimeout(issue.attemptRetry.bind(issue), this.retry);
    return this.emit('issue', this.details);
  }

  if (this.remove) return this.emit('remove', this.details);

  setTimeout(issue.attemptReconnect.bind(issue), this.reconnect);
};

Object.defineProperty(issues, 'details', {
  get: function getDetails () {
    var res = {};

    res.server = this.server;
    res.tokens = this.tokens;
    res.messages = this.messages;

    if (this.retries) {
      res.retries = this.retries;
      res.totalRetries = this.totalRetries;
    } else {
      res.totalReconnectsAttempted = this.totalReconnectsAttempted;
      res.totalReconnectsSuccess = this.totalReconnectsSuccess;
      res.totalReconnectsFailed = this.totalReconnectsAttempted - this.totalReconnectsSuccess;
      res.totalDownTime = (res.totalReconnectsFailed * this.reconnect) + (this.totalRetries * this.retry);
    }

    return res;
  }
});

issues.attemptRetry = function attemptRetry () {
  this.totalRetries++;
  this.retries--;
  this.failed = false;
  this.locked = false;
};

issues.attemptReconnect = function attemptReconnect () {
  var issue = this;
  this.totalReconnectsAttempted++;
  this.emit('reconnecting', this.details);

  // Ping the server
  ping(this.tokens[1], function pingpong (err) {
    // still no access to the server
    if (err) {
      this.messages.push(err.message || 'No message specified');
      return setTimeout(issue.attemptReconnect.bind(issue), issue.reconnect);
    }

    issue.emit('reconnected', issue.details);

    issue.totalReconnectsSuccess++;
    issue.messages.length = 0;
    issue.failed = false;

    // we connected again, so we are going through the whole cycle again
    Utils.merge(issue, JSON.parse(JSON.stringify(issue.config)));
  });
};
<|endoftext|>


<commit_before>function ViewModel() {
    var self = this;
    var dropzones = {
        "uk-sibson": [52.560706, -0.395692],
        "uk-chatteris": [52.48866, 0.086044],
        "ru-puschino": [54.790046, 37.642547],
        "ru-kolomna": [55.091914, 38.917231],
        "ru-vatulino": [55.663505, 36.142181],
        "other-dubai": [25.090282, 55.135681],
        "other-red-square": [55.754216, 37.620083],
        "other-statue-of-liberty": [40.690531, -74.04575],
        "custom": null
    };

    self.debug = {
        on: ko.observable(true)
    };

    self.display = {
        language: ko.observable("en"),
        unitSystem: ko.observable("metric"),

        steadyPoint: ko.observable(false),
        reachset: ko.observable(false),
        controlset: ko.observable(false),

        pattern: ko.observable("hide"),

        fullscreen: ko.observable(false),

        maxAltitude: ko.computed(function() {
            return Math.max(altitudeProgressbarMax, self.pattern.openingAltitude());
        }, this, { deferEvaluation: true })
    };

    self.wind = {
        // We use the azimuth of the wind speed vector here, not the navigational wind direction (i.e. where wind is blowing, not where _from_)
        direction: ko.observable(Math.random() * Math.PI * 2),
        speed: ko.observable(5 + Math.random() * 2 - 1)
    };

    self.pattern = {
        selectedLandingDirection: ko.observable(0),
        intoWind: ko.observable(true),
        openingAltitude: ko.observable(700),

        show: ko.computed(function() {
            return self.display.pattern() !== "hide";
        }, this, { deferEvaluation: true }),
        lhs: ko.computed(function() {
            return self.pattern.show() ?
                (self.display.pattern() === "lhs"):
                undefined;
        }, this, { deferEvaluation: true }),

        landingDirection: ko.computed(function() {
            return self.pattern.intoWind() ? normalizeAngle(self.wind.direction() + Math.PI) : self.pattern.selectedLandingDirection();
        }, this, { deferEvaluation: true }),

        points: ko.computed(function() {
            if (!self.pattern.show()) {
                return [];
            }
            return computeLandingPattern(self.location.coords(), self.wind, self.pattern);
        }, this, { deferEvaluation: true })
    };

    self.simulation = {
        started: ko.observable(false),
        speed: ko.observable(1.0),

        oldSpeed: 1.0, // to support togglePause
        togglePause: function() {
            if (self.simulation.speed() != 0) {
                self.simulation.oldSpeed = self.simulation.speed();
                self.simulation.speed(0);
            } else {
                self.simulation.speed(self.simulation.oldSpeed);
            }
        },

        flying: ko.computed(function() {
            return self.simulation.started() && self.canopy.altitude() > eps;
        }, this, { deferEvaluation: true }),

        start: function(loc) {
            self.canopy.location(loc);
            self.canopy.altitude(self.pattern.openingAltitude());
            self.canopy.heading(self.wind.direction() + Math.PI); // Into the wind
            self.canopy.mode(0.6);

            self.simulation.started(true);
        },

        stop: function() {
            self.canopy.altitude(0);
        }
    };

    self.canopy = {
        location: ko.observable(),
        altitude: ko.observable(),
        heading: ko.observable(),
        mode: ko.observable(),

        speedH: ko.computed(function() {
            return getCanopyHorizontalSpeed(self.canopy.mode());
        }, this, { deferEvaluation: true }),

        speedV: ko.computed(function() {
            return getCanopyVerticalSpeed(self.canopy.mode());
        }, this, { deferEvaluation: true }),

        icon: ko.computed(function() {
            return createCanopyMarkerIcon(self.canopy.heading());
        }, this, { deferEvaluation: true }),

        modeChange: function(amount) {
            var minMode = 0.1; // We don't allow flying in the stall
            self.canopy.mode(clamp(self.canopy.mode() + amount, minMode, 1));
        },

        steeringInput: function(amount) {
            self.canopy.heading(normalizeAngle(self.canopy.heading() + amount));
        },

        descend: function(time) {
            self.canopy.altitude(self.canopy.altitude() - time * self.canopy.speedV());
            self.canopy.location(moveInWind(self.canopy.location(), self.wind.speed(), self.wind.direction(), self.canopy.speedH(), self.canopy.heading(), time));
        }
    };

    self.location = {
        _id: ko.observable(),
        coords: ko.observable(),

        custom: {
            coords: ko.observable(),
            name: ko.observable(),
            available: ko.computed(function() {
                return !!self.location.custom.coords();
            }, this, { deferEvaluation: true }),

            // This is used for persistence
            coordsJS: ko.computed({
                read: function() {
                    if (self.location.custom.coords()) {
                        return [
                            self.location.custom.coords().lat(),
                            self.location.custom.coords().lng()
                        ];
                    } else {
                        return null;
                    }
                },
                write: function(val) {
                    if (val) {
                        self.location.custom.coords(createLatLng(val));
                    } else {
                        self.location.custom.coords(null);
                    }
                },
                deferEvaluation: true
            })
        },
        id: ko.computed({
            write: function(id) {
                if (!(id in dropzones)) {
                    return;
                }

                self.location.coords(id === "custom" ? self.location.custom.coords() : createLatLng(dropzones[id]));
                self.location._id(id);
            },
            read: function() { return self.location._id(); },
            deferEvaluation: true
        }),

        name: ko.computed(function() {
            return $("#dz-" + self.location.id() + "> a").html();
        }, this, { deferEvaluation: true }),
        finderText: ko.computed(function() {
            return (self.location.id() == 'custom' ? self.location.custom.name() : '')
        }, this, { deferEvaluation: true })
    };

    self.location.id("uk-sibson");

    self.reachSetAltitude = ko.computed(function() {
        return self.simulation.flying() ? self.canopy.altitude() : self.pattern.openingAltitude();
    });

    self.analytics = {
        steadyPoint: ko.computed(function() {
            if (!self.simulation.flying()) {
                return undefined;
            }
            var timeToLanding = this.altitude() / this.speedV();
            return moveInWind(this.location(), self.wind.speed(), self.wind.direction(), this.speedH(), this.heading(), timeToLanding);
        }, self.canopy, { deferEvaluation: true }),

        reachSet: ko.computed(function() {
            if (!(self.display.reachset() && self.simulation.flying())) {
                return undefined;
            }
            return computeReachSet(self.canopy.location(), self.canopy.altitude(), true);
        }, this, { deferEvaluation: true }),
        controlSet: ko.computed(function() {
            if (!self.display.controlset()) {
                return undefined;
            }
            return computeReachSet(self.location.coords(), self.reachSetAltitude(), false);
        }, this, { deferEvaluation: true })
    };

    self.misc = {
        tutorFinished: ko.observable(false)
    };

    self.persistence = {
        // List of observables to save and load
        _list: [
            self.display.language,
            self.display.unitSystem,
            self.display.steadyPoint,
            self.display.reachset,
            self.display.controlset,
            self.display.pattern,

            self.location.custom.coordsJS,
            self.location.custom.name,
            self.location.id,

            self.pattern.openingAltitude,

            self.misc.tutorFinished
        ],
        // If _list is only appended to after the release, we don't need to
        // change _version. If _list is modified incompatibly, or we need to reset user
        // saved settings for other reasons, bump _version!
        _version: 1,

        saveOnExit: ko.observable(true),

        save: function() {
            if (!localStorage) {
                return;
            }

            var saveData = self.persistence._list.map(function(observable) {
                return observable();
            });

            localStorage.persistence = JSON.stringify(saveData);
            localStorage.version = self.persistence._version;
        },

        load: function() {
            if (!localStorage || localStorage.version != self.persistence._version) {
                return;
            }

            var saveData = JSON.parse(localStorage.persistence);
            for (var i = 0; i < saveData.length; i++ ) {
                self.persistence._list[i](saveData[i]);
            }
        },

        reset: function() {
            if (localStorage) {
                localStorage.removeItem("persistence");
                localStorage.removeItem("version");
            }
            self.persistence.saveOnExit(false);
        }
    };
}

var viewModel = new ViewModel();
ko.applyBindings(viewModel);
<commit_msg>Fix searching for a DZ from custom location<commit_after>function ViewModel() {
    var self = this;
    var dropzones = {
        "uk-sibson": [52.560706, -0.395692],
        "uk-chatteris": [52.48866, 0.086044],
        "ru-puschino": [54.790046, 37.642547],
        "ru-kolomna": [55.091914, 38.917231],
        "ru-vatulino": [55.663505, 36.142181],
        "other-dubai": [25.090282, 55.135681],
        "other-red-square": [55.754216, 37.620083],
        "other-statue-of-liberty": [40.690531, -74.04575],
        "custom": null
    };

    self.debug = {
        on: ko.observable(true)
    };

    self.display = {
        language: ko.observable("en"),
        unitSystem: ko.observable("metric"),

        steadyPoint: ko.observable(false),
        reachset: ko.observable(false),
        controlset: ko.observable(false),

        pattern: ko.observable("hide"),

        fullscreen: ko.observable(false),

        maxAltitude: ko.computed(function() {
            return Math.max(altitudeProgressbarMax, self.pattern.openingAltitude());
        }, this, { deferEvaluation: true })
    };

    self.wind = {
        // We use the azimuth of the wind speed vector here, not the navigational wind direction (i.e. where wind is blowing, not where _from_)
        direction: ko.observable(Math.random() * Math.PI * 2),
        speed: ko.observable(5 + Math.random() * 2 - 1)
    };

    self.pattern = {
        selectedLandingDirection: ko.observable(0),
        intoWind: ko.observable(true),
        openingAltitude: ko.observable(700),

        show: ko.computed(function() {
            return self.display.pattern() !== "hide";
        }, this, { deferEvaluation: true }),
        lhs: ko.computed(function() {
            return self.pattern.show() ?
                (self.display.pattern() === "lhs"):
                undefined;
        }, this, { deferEvaluation: true }),

        landingDirection: ko.computed(function() {
            return self.pattern.intoWind() ? normalizeAngle(self.wind.direction() + Math.PI) : self.pattern.selectedLandingDirection();
        }, this, { deferEvaluation: true }),

        points: ko.computed(function() {
            if (!self.pattern.show()) {
                return [];
            }
            return computeLandingPattern(self.location.coords(), self.wind, self.pattern);
        }, this, { deferEvaluation: true })
    };

    self.simulation = {
        started: ko.observable(false),
        speed: ko.observable(1.0),

        oldSpeed: 1.0, // to support togglePause
        togglePause: function() {
            if (self.simulation.speed() != 0) {
                self.simulation.oldSpeed = self.simulation.speed();
                self.simulation.speed(0);
            } else {
                self.simulation.speed(self.simulation.oldSpeed);
            }
        },

        flying: ko.computed(function() {
            return self.simulation.started() && self.canopy.altitude() > eps;
        }, this, { deferEvaluation: true }),

        start: function(loc) {
            self.canopy.location(loc);
            self.canopy.altitude(self.pattern.openingAltitude());
            self.canopy.heading(self.wind.direction() + Math.PI); // Into the wind
            self.canopy.mode(0.6);

            self.simulation.started(true);
        },

        stop: function() {
            self.canopy.altitude(0);
        }
    };

    self.canopy = {
        location: ko.observable(),
        altitude: ko.observable(),
        heading: ko.observable(),
        mode: ko.observable(),

        speedH: ko.computed(function() {
            return getCanopyHorizontalSpeed(self.canopy.mode());
        }, this, { deferEvaluation: true }),

        speedV: ko.computed(function() {
            return getCanopyVerticalSpeed(self.canopy.mode());
        }, this, { deferEvaluation: true }),

        icon: ko.computed(function() {
            return createCanopyMarkerIcon(self.canopy.heading());
        }, this, { deferEvaluation: true }),

        modeChange: function(amount) {
            var minMode = 0.1; // We don't allow flying in the stall
            self.canopy.mode(clamp(self.canopy.mode() + amount, minMode, 1));
        },

        steeringInput: function(amount) {
            self.canopy.heading(normalizeAngle(self.canopy.heading() + amount));
        },

        descend: function(time) {
            self.canopy.altitude(self.canopy.altitude() - time * self.canopy.speedV());
            self.canopy.location(moveInWind(self.canopy.location(), self.wind.speed(), self.wind.direction(), self.canopy.speedH(), self.canopy.heading(), time));
        }
    };

    self.location = {
        _id: ko.observable().extend({ notify: 'always' }),
        coords: ko.observable(),

        custom: {
            coords: ko.observable(),
            name: ko.observable(),
            available: ko.computed(function() {
                return !!self.location.custom.coords();
            }, this, { deferEvaluation: true }),

            // This is used for persistence
            coordsJS: ko.computed({
                read: function() {
                    if (self.location.custom.coords()) {
                        return [
                            self.location.custom.coords().lat(),
                            self.location.custom.coords().lng()
                        ];
                    } else {
                        return null;
                    }
                },
                write: function(val) {
                    if (val) {
                        self.location.custom.coords(createLatLng(val));
                    } else {
                        self.location.custom.coords(null);
                    }
                },
                deferEvaluation: true
            })
        },
        id: ko.computed({
            write: function(id) {
                if (!(id in dropzones)) {
                    return;
                }

                self.location.coords(id === "custom" ? self.location.custom.coords() : createLatLng(dropzones[id]));
                self.location._id(id);
            },
            read: function() { return self.location._id(); },
            deferEvaluation: true
        }).extend({ notify: 'always' }),

        name: ko.computed(function() {
            return $("#dz-" + self.location.id() + "> a").html();
        }, this, { deferEvaluation: true }),
        finderText: ko.computed(function() {
            return (self.location.id() == 'custom' ? self.location.custom.name() : '')
        }, this, { deferEvaluation: true })
    };

    self.location.id("uk-sibson");

    self.reachSetAltitude = ko.computed(function() {
        return self.simulation.flying() ? self.canopy.altitude() : self.pattern.openingAltitude();
    });

    self.analytics = {
        steadyPoint: ko.computed(function() {
            if (!self.simulation.flying()) {
                return undefined;
            }
            var timeToLanding = this.altitude() / this.speedV();
            return moveInWind(this.location(), self.wind.speed(), self.wind.direction(), this.speedH(), this.heading(), timeToLanding);
        }, self.canopy, { deferEvaluation: true }),

        reachSet: ko.computed(function() {
            if (!(self.display.reachset() && self.simulation.flying())) {
                return undefined;
            }
            return computeReachSet(self.canopy.location(), self.canopy.altitude(), true);
        }, this, { deferEvaluation: true }),
        controlSet: ko.computed(function() {
            if (!self.display.controlset()) {
                return undefined;
            }
            return computeReachSet(self.location.coords(), self.reachSetAltitude(), false);
        }, this, { deferEvaluation: true })
    };

    self.misc = {
        tutorFinished: ko.observable(false)
    };

    self.persistence = {
        // List of observables to save and load
        _list: [
            self.display.language,
            self.display.unitSystem,
            self.display.steadyPoint,
            self.display.reachset,
            self.display.controlset,
            self.display.pattern,

            self.location.custom.coordsJS,
            self.location.custom.name,
            self.location.id,

            self.pattern.openingAltitude,

            self.misc.tutorFinished
        ],
        // If _list is only appended to after the release, we don't need to
        // change _version. If _list is modified incompatibly, or we need to reset user
        // saved settings for other reasons, bump _version!
        _version: 1,

        saveOnExit: ko.observable(true),

        save: function() {
            if (!localStorage) {
                return;
            }

            var saveData = self.persistence._list.map(function(observable) {
                return observable();
            });

            localStorage.persistence = JSON.stringify(saveData);
            localStorage.version = self.persistence._version;
        },

        load: function() {
            if (!localStorage || localStorage.version != self.persistence._version) {
                return;
            }

            var saveData = JSON.parse(localStorage.persistence);
            for (var i = 0; i < saveData.length; i++ ) {
                self.persistence._list[i](saveData[i]);
            }
        },

        reset: function() {
            if (localStorage) {
                localStorage.removeItem("persistence");
                localStorage.removeItem("version");
            }
            self.persistence.saveOnExit(false);
        }
    };
}

var viewModel = new ViewModel();
ko.applyBindings(viewModel);
<|endoftext|>


<commit_before>var mv = require('mv'),
    fs = require('fs'),
    path = require('path');

var isWin = /^win/.test(process.platform);

if (isWin) {
    var target = path.resolve(__dirname + '../' + '../node_modules/youtube-dl/lib/youtube-dl.js');

    fs.unlink(target, function (err) {
        'use strict';
        if (err !== null) { return console.log(err.stack); }
        mv(path.resolve(__dirname + '../' + '../.temp/youtube-dl.js'), target, function error(err) {
            if (err) { console.log(err); }
            console.log('win py3.x fix');
        });
    });
}<commit_msg>info added<commit_after>/*
 * mongo-edu
 *
 * Copyright (c) 2014 Przemyslaw Pluta
 * Licensed under the MIT license.
 * https://github.com/przemyslawpluta/mongo-edu/blob/master/LICENSE
 */

var mv = require('mv'),
    fs = require('fs'),
    path = require('path');

var isWin = /^win/.test(process.platform);

if (isWin) {
    var target = path.resolve(__dirname + '../' + '../node_modules/youtube-dl/lib/youtube-dl.js');

    fs.unlink(target, function (err) {
        'use strict';
        if (err !== null) { return console.log(err.stack); }
        mv(path.resolve(__dirname + '../' + '../.temp/youtube-dl.js'), target, function error(err) {
            if (err) { console.log(err); }
            console.log('win py3.x fix');
        });
    });
}<|endoftext|>