<commit_before>module.exports = function(grunt) {
  grunt.registerTask('default', 'Test app, transpile code and run development environment', function() {
    /**
     grunt.task.run([
     'eslint:src',
     'test:phantom:false',
     'dist',
     'sass',
     'dev'
     ]);
     **/
    grunt.task.run([
      'init',
      // Check
      'check:demo',
      'check:main',
      'check:test',
      // Build
      'build:demo',
      'build:main',
      'build:test',
      // Test
      'test:specs'
    ]);
  });
};
<commit_msg>Removed uncommented tasks<commit_after>module.exports = function(grunt) {
  grunt.registerTask('default', 'Test app, transpile code and run development environment', function() {
    grunt.task.run([
      'init',
      // Check
      'check:demo',
      'check:main',
      'check:test',
      // Build
      'build:demo',
      'build:main',
      'build:test',
      // Test
      'test:specs'
    ]);
  });
};
<|endoftext|>


<commit_before>import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { currentURL, click } from '@ember/test-helpers';
import window, { setupWindowMock } from 'ember-window-mock';
import { percySnapshot } from 'ember-percy';
import Response from 'ember-cli-mirage/response';

import setupMirage from '../helpers/setup-mirage';
import { visit } from '../helpers/visit-ignoring-abort';

module('Acceptance | /me/pending-invites', function (hooks) {
  setupApplicationTest(hooks);
  setupWindowMock(hooks);
  setupMirage(hooks);

  function prepare(context) {
    window.localStorage.setItem('isLoggedIn', '1');

    context.server.get('/api/v1/me', {
      user: {
        id: 42,
        login: 'johnnydee',
        email_verified: true,
        email_verification_sent: true,
        name: 'John Doe',
        email: 'john@doe.com',
        avatar: 'https://avatars2.githubusercontent.com/u/1234567?v=4',
        url: 'https://github.com/johnnydee',
      },
      owned_crates: [],
    });

    context.server.get('/api/v1/me/crate_owner_invitations', {
      crate_owner_invitations: [
        {
          invited_by_username: 'janed',
          crate_name: 'nanomsg',
          crate_id: 42,
          created_at: '2016-12-24T12:34:56Z',
        },
        {
          invited_by_username: 'wycats',
          crate_name: 'ember-rs',
          crate_id: 1,
          created_at: '2020-12-31T12:34:56Z',
        },
      ],
    });
  }

  test('redirects to / when not logged in', async function (assert) {
    await visit('/me/pending-invites');
    assert.equal(currentURL(), '/');
    assert.dom('[data-test-flash-message]').hasText('Please log in to proceed');
  });

  test('list all pending crate owner invites', async function (assert) {
    prepare(this);

    await visit('/me/pending-invites');
    assert.equal(currentURL(), '/me/pending-invites');
    assert.dom('[data-test-invite]').exists({ count: 2 });
    assert.dom('[data-test-invite="nanomsg"]').exists();
    assert.dom('[data-test-invite="nanomsg"] [data-test-date]').hasText('a year ago');
    assert.dom('[data-test-invite="nanomsg"] [data-test-accept-button]').exists();
    assert.dom('[data-test-invite="nanomsg"] [data-test-decline-button]').exists();
    assert.dom('[data-test-invite="ember-rs"]').exists();
    assert.dom('[data-test-invite="ember-rs"] [data-test-crate-link]').hasText('ember-rs');
    assert.dom('[data-test-invite="ember-rs"] [data-test-crate-link]').hasAttribute('href', '/crates/ember-rs');
    assert.dom('[data-test-invite="ember-rs"] [data-test-inviter-link]').hasText('wycats');
    assert.dom('[data-test-invite="ember-rs"] [data-test-inviter-link]').hasAttribute('href', '/users/wycats');
    assert.dom('[data-test-invite="ember-rs"] [data-test-date]').hasText('in 3 years');
    assert.dom('[data-test-invite="ember-rs"] [data-test-accept-button]').exists();
    assert.dom('[data-test-invite="ember-rs"] [data-test-decline-button]').exists();
    assert.dom('[data-test-error-message]').doesNotExist();
    assert.dom('[data-test-accepted-message]').doesNotExist();
    assert.dom('[data-test-declined-message]').doesNotExist();
  });

  test('shows empty list message', async function (assert) {
    prepare(this);

    this.server.get('/api/v1/me/crate_owner_invitations', { crate_owner_invitations: [] });

    await visit('/me/pending-invites');
    assert.equal(currentURL(), '/me/pending-invites');
    assert.dom('[data-test-invite]').doesNotExist();
    assert.dom('[data-test-empty-state]').exists();
  });

  test('invites can be declined', async function (assert) {
    assert.expect(9);

    prepare(this);

    this.server.put('/api/v1/me/crate_owner_invitations/:crate', (schema, request) => {
      assert.deepEqual(request.params, { crate: '42' });

      let body = JSON.parse(request.requestBody);
      assert.strictEqual(body.crate_owner_invite.accepted, false);
      assert.strictEqual(body.crate_owner_invite.crate_id, 42);

      return { crate_owner_invitation: { crate_id: 42, accepted: false } };
    });

    await visit('/me/pending-invites');
    assert.equal(currentURL(), '/me/pending-invites');

    await click('[data-test-invite="nanomsg"] [data-test-decline-button]');
    assert.dom('[data-test-error-message]').doesNotExist();
    assert.dom('[data-test-accepted-message]').doesNotExist();
    assert
      .dom('[data-test-invite="nanomsg"][data-test-declined-message]')
      .hasText('Declined. You have not been added as an owner of crate nanomsg.');
    assert.dom('[data-test-invite="nanomsg"] [data-test-crate-link]').doesNotExist();
    assert.dom('[data-test-invite="nanomsg"] [data-test-inviter-link]').doesNotExist();
  });

  test('error message is shown if decline request fails', async function (assert) {
    prepare(this);

    this.server.put('/api/v1/me/crate_owner_invitations/:crate', () => new Response(500));

    await visit('/me/pending-invites');
    assert.equal(currentURL(), '/me/pending-invites');

    await click('[data-test-invite="nanomsg"] [data-test-decline-button]');
    assert.dom('[data-test-error-message]').containsText('Error in declining invite');
    assert.dom('[data-test-accepted-message]').doesNotExist();
    assert.dom('[data-test-declined-message]').doesNotExist();
  });

  test('invites can be accepted', async function (assert) {
    assert.expect(9);

    prepare(this);

    this.server.put('/api/v1/me/crate_owner_invitations/:crate', (schema, request) => {
      assert.deepEqual(request.params, { crate: '42' });

      let body = JSON.parse(request.requestBody);
      assert.strictEqual(body.crate_owner_invite.accepted, true);
      assert.strictEqual(body.crate_owner_invite.crate_id, 42);

      return { crate_owner_invitation: { crate_id: 42, accepted: true } };
    });

    await visit('/me/pending-invites');
    assert.equal(currentURL(), '/me/pending-invites');

    await click('[data-test-invite="nanomsg"] [data-test-accept-button]');
    assert.dom('[data-test-error-message]').doesNotExist();
    assert.dom('[data-test-declined-message]').doesNotExist();
    assert
      .dom('[data-test-invite="nanomsg"][data-test-accepted-message]')
      .hasText("Success! You've been added as an owner of crate nanomsg.");
    assert.dom('[data-test-invite="nanomsg"] [data-test-crate-link]').doesNotExist();
    assert.dom('[data-test-invite="nanomsg"] [data-test-inviter-link]').doesNotExist();

    percySnapshot(assert);
  });

  test('error message is shown if accept request fails', async function (assert) {
    prepare(this);

    this.server.put('/api/v1/me/crate_owner_invitations/:crate', () => new Response(500));

    await visit('/me/pending-invites');
    assert.equal(currentURL(), '/me/pending-invites');

    await click('[data-test-invite="nanomsg"] [data-test-accept-button]');
    assert.dom('[data-test-error-message]').containsText('Error in accepting invite');
    assert.dom('[data-test-accepted-message]').doesNotExist();
    assert.dom('[data-test-declined-message]').doesNotExist();
  });
});
<commit_msg>tests/invites: Use generic `GET /api/v1/me` route handler<commit_after>import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { currentURL, click } from '@ember/test-helpers';
import window, { setupWindowMock } from 'ember-window-mock';
import { percySnapshot } from 'ember-percy';
import Response from 'ember-cli-mirage/response';

import setupMirage from '../helpers/setup-mirage';
import { visit } from '../helpers/visit-ignoring-abort';

module('Acceptance | /me/pending-invites', function (hooks) {
  setupApplicationTest(hooks);
  setupWindowMock(hooks);
  setupMirage(hooks);

  function prepare(context) {
    let user = context.server.create('user');
    context.server.create('mirage-session', { user });
    window.localStorage.setItem('isLoggedIn', '1');

    context.server.get('/api/v1/me/crate_owner_invitations', {
      crate_owner_invitations: [
        {
          invited_by_username: 'janed',
          crate_name: 'nanomsg',
          crate_id: 42,
          created_at: '2016-12-24T12:34:56Z',
        },
        {
          invited_by_username: 'wycats',
          crate_name: 'ember-rs',
          crate_id: 1,
          created_at: '2020-12-31T12:34:56Z',
        },
      ],
    });
  }

  test('redirects to / when not logged in', async function (assert) {
    await visit('/me/pending-invites');
    assert.equal(currentURL(), '/');
    assert.dom('[data-test-flash-message]').hasText('Please log in to proceed');
  });

  test('list all pending crate owner invites', async function (assert) {
    prepare(this);

    await visit('/me/pending-invites');
    assert.equal(currentURL(), '/me/pending-invites');
    assert.dom('[data-test-invite]').exists({ count: 2 });
    assert.dom('[data-test-invite="nanomsg"]').exists();
    assert.dom('[data-test-invite="nanomsg"] [data-test-date]').hasText('a year ago');
    assert.dom('[data-test-invite="nanomsg"] [data-test-accept-button]').exists();
    assert.dom('[data-test-invite="nanomsg"] [data-test-decline-button]').exists();
    assert.dom('[data-test-invite="ember-rs"]').exists();
    assert.dom('[data-test-invite="ember-rs"] [data-test-crate-link]').hasText('ember-rs');
    assert.dom('[data-test-invite="ember-rs"] [data-test-crate-link]').hasAttribute('href', '/crates/ember-rs');
    assert.dom('[data-test-invite="ember-rs"] [data-test-inviter-link]').hasText('wycats');
    assert.dom('[data-test-invite="ember-rs"] [data-test-inviter-link]').hasAttribute('href', '/users/wycats');
    assert.dom('[data-test-invite="ember-rs"] [data-test-date]').hasText('in 3 years');
    assert.dom('[data-test-invite="ember-rs"] [data-test-accept-button]').exists();
    assert.dom('[data-test-invite="ember-rs"] [data-test-decline-button]').exists();
    assert.dom('[data-test-error-message]').doesNotExist();
    assert.dom('[data-test-accepted-message]').doesNotExist();
    assert.dom('[data-test-declined-message]').doesNotExist();
  });

  test('shows empty list message', async function (assert) {
    prepare(this);

    this.server.get('/api/v1/me/crate_owner_invitations', { crate_owner_invitations: [] });

    await visit('/me/pending-invites');
    assert.equal(currentURL(), '/me/pending-invites');
    assert.dom('[data-test-invite]').doesNotExist();
    assert.dom('[data-test-empty-state]').exists();
  });

  test('invites can be declined', async function (assert) {
    assert.expect(9);

    prepare(this);

    this.server.put('/api/v1/me/crate_owner_invitations/:crate', (schema, request) => {
      assert.deepEqual(request.params, { crate: '42' });

      let body = JSON.parse(request.requestBody);
      assert.strictEqual(body.crate_owner_invite.accepted, false);
      assert.strictEqual(body.crate_owner_invite.crate_id, 42);

      return { crate_owner_invitation: { crate_id: 42, accepted: false } };
    });

    await visit('/me/pending-invites');
    assert.equal(currentURL(), '/me/pending-invites');

    await click('[data-test-invite="nanomsg"] [data-test-decline-button]');
    assert.dom('[data-test-error-message]').doesNotExist();
    assert.dom('[data-test-accepted-message]').doesNotExist();
    assert
      .dom('[data-test-invite="nanomsg"][data-test-declined-message]')
      .hasText('Declined. You have not been added as an owner of crate nanomsg.');
    assert.dom('[data-test-invite="nanomsg"] [data-test-crate-link]').doesNotExist();
    assert.dom('[data-test-invite="nanomsg"] [data-test-inviter-link]').doesNotExist();
  });

  test('error message is shown if decline request fails', async function (assert) {
    prepare(this);

    this.server.put('/api/v1/me/crate_owner_invitations/:crate', () => new Response(500));

    await visit('/me/pending-invites');
    assert.equal(currentURL(), '/me/pending-invites');

    await click('[data-test-invite="nanomsg"] [data-test-decline-button]');
    assert.dom('[data-test-error-message]').containsText('Error in declining invite');
    assert.dom('[data-test-accepted-message]').doesNotExist();
    assert.dom('[data-test-declined-message]').doesNotExist();
  });

  test('invites can be accepted', async function (assert) {
    assert.expect(9);

    prepare(this);

    this.server.put('/api/v1/me/crate_owner_invitations/:crate', (schema, request) => {
      assert.deepEqual(request.params, { crate: '42' });

      let body = JSON.parse(request.requestBody);
      assert.strictEqual(body.crate_owner_invite.accepted, true);
      assert.strictEqual(body.crate_owner_invite.crate_id, 42);

      return { crate_owner_invitation: { crate_id: 42, accepted: true } };
    });

    await visit('/me/pending-invites');
    assert.equal(currentURL(), '/me/pending-invites');

    await click('[data-test-invite="nanomsg"] [data-test-accept-button]');
    assert.dom('[data-test-error-message]').doesNotExist();
    assert.dom('[data-test-declined-message]').doesNotExist();
    assert
      .dom('[data-test-invite="nanomsg"][data-test-accepted-message]')
      .hasText("Success! You've been added as an owner of crate nanomsg.");
    assert.dom('[data-test-invite="nanomsg"] [data-test-crate-link]').doesNotExist();
    assert.dom('[data-test-invite="nanomsg"] [data-test-inviter-link]').doesNotExist();

    percySnapshot(assert);
  });

  test('error message is shown if accept request fails', async function (assert) {
    prepare(this);

    this.server.put('/api/v1/me/crate_owner_invitations/:crate', () => new Response(500));

    await visit('/me/pending-invites');
    assert.equal(currentURL(), '/me/pending-invites');

    await click('[data-test-invite="nanomsg"] [data-test-accept-button]');
    assert.dom('[data-test-error-message]').containsText('Error in accepting invite');
    assert.dom('[data-test-accepted-message]').doesNotExist();
    assert.dom('[data-test-declined-message]').doesNotExist();
  });
});
<|endoftext|>


<commit_before>'use strict';

import * as _ from 'lodash'
import * as React from 'react'
import * as humanize from 'humanize-plus'

import add from '../helpers/add'
import randomChar from '../helpers/randomChar'

let goodGraduationMessage = 'It looks like you\'ll make it! Just follow the plan, and go over my output with your advisor a few times.'
let badGraduationMessage = 'You haven\'t planned everything out yet. Ask your advisor if you need help fitting everything in.'

var StudentSummary = React.createClass({
	render() {
		var student = this.props.student
		var studies = student.studies
		var name = student.name || randomChar()
		var has = _.mapValues(_.groupBy(studies, 'type'), _.size)

		let objects = {
			degree: _.filter(studies, {type: 'degree'}),
			major: _.filter(studies, {type: 'major'}),
			concentration: _.filter(studies, {type: 'concentration'}),
			emphasis: _.filter(studies, {type: 'emphasis'}),
		}

		let titles = {
			degree: humanize.oxford(_.pluck(objects.degree, 'title')),
			major: humanize.oxford(_.pluck(objects.major, 'title')),
			concentration: humanize.oxford(_.pluck(objects.concentration, 'title')),
			emphasis: humanize.oxford(_.pluck(objects.emphasis, 'title')),
		}

		let words = {
			degree: humanize.pluralize(_.size(objects.degree), 'degree'),
			major: humanize.pluralize(_.size(objects.major), 'major'),
			concentration: humanize.pluralize(_.size(objects.concentration), 'concentration'),
			emphasis: humanize.pluralize(_.size(objects.emphasis), 'emphasis', 'emphases'),
		}

		// var canGraduate = checkElegibilityForGraduation(this.props)
		var canGraduate = false

		let phrases = {
			degree: React.DOM.span({className: 'area-of-study-list'}, titles.degree),
			major: React.DOM.span({className: 'area-of-study-list'}, titles.major),
			concentration: React.DOM.span({className: 'area-of-study-list'}, titles.concentration),
			emphasis: React.DOM.span({className: 'area-of-study-list'}, titles.emphasis),
		}

		var emphasisEmphasizer = has.emphasis > 0 && has.emphasis < 2 ? 'an ' : ''

		return React.DOM.article({id: 'student-summary', className: canGraduate ? 'can-graduate' : 'cannot-graduate'},
			React.DOM.div({key: 'letter', id: 'student-letter'}, name[0]),
			React.DOM.p({key: 'hi'}, 'Hi, ', name, '!'),
			React.DOM.p({key: 'overview'},
				'You are planning on ', _.size(objects.degree === 1) ? 'a ' : '', phrases.degree,
				' ', words.degree, ', with ', words.major, ' in ', phrases.major,
				has.concentration > 0 ? [', and ', words.concentration, ' in ', phrases.concentration] : '',
				has.emphasis > 0 ? [', not to mention ', emphasisEmphasizer, words.emphasis, ' in ', phrases.emphasis] : '',
				'.'),
			React.DOM.p({key: 'message', className: 'graduation-message'},
				canGraduate ? goodGraduationMessage : badGraduationMessage)
		)
	}
})

export default StudentSummary
<commit_msg>Give the children of StudentSummary each `key`s<commit_after>'use strict';

import * as _ from 'lodash'
import * as React from 'react'
import * as humanize from 'humanize-plus'

import add from '../helpers/add'
import randomChar from '../helpers/randomChar'

let goodGraduationMessage = 'It looks like you\'ll make it! Just follow the plan, and go over my output with your advisor a few times.'
let badGraduationMessage = 'You haven\'t planned everything out yet. Ask your advisor if you need help fitting everything in.'

var StudentSummary = React.createClass({
	render() {
		var student = this.props.student
		var studies = student.studies
		var name = student.name || randomChar()
		var has = _.mapValues(_.groupBy(studies, 'type'), _.size)

		let objects = {
			degree: _.filter(studies, {type: 'degree'}),
			major: _.filter(studies, {type: 'major'}),
			concentration: _.filter(studies, {type: 'concentration'}),
			emphasis: _.filter(studies, {type: 'emphasis'}),
		}

		let titles = {
			degree: humanize.oxford(_.pluck(objects.degree, 'title')),
			major: humanize.oxford(_.pluck(objects.major, 'title')),
			concentration: humanize.oxford(_.pluck(objects.concentration, 'title')),
			emphasis: humanize.oxford(_.pluck(objects.emphasis, 'title')),
		}

		let words = {
			degree: humanize.pluralize(_.size(objects.degree), 'degree'),
			major: humanize.pluralize(_.size(objects.major), 'major'),
			concentration: humanize.pluralize(_.size(objects.concentration), 'concentration'),
			emphasis: humanize.pluralize(_.size(objects.emphasis), 'emphasis', 'emphases'),
		}

		// var canGraduate = checkElegibilityForGraduation(this.props)
		var canGraduate = false

		let phrases = {
			degree: React.DOM.span({className: 'area-of-study-list', key:'degree'}, titles.degree),
			major: React.DOM.span({className: 'area-of-study-list', key:'major'}, titles.major),
			concentration: React.DOM.span({className: 'area-of-study-list', key:'concentration'}, titles.concentration),
			emphasis: React.DOM.span({className: 'area-of-study-list', key:'emphasis'}, titles.emphasis),
		}

		var emphasisEmphasizer = has.emphasis > 0 && has.emphasis < 2 ? 'an ' : ''

		return React.DOM.article({id: 'student-summary', className: canGraduate ? 'can-graduate' : 'cannot-graduate'},
			React.DOM.div({key: 'letter', id: 'student-letter'}, name[0]),
			React.DOM.p({key: 'hi'}, 'Hi, ', name, '!'),
			React.DOM.p({key: 'overview'},
				'You are planning on ', _.size(objects.degree === 1) ? 'a ' : '', phrases.degree,
				' ', words.degree, ', with ', words.major, ' in ', phrases.major,
				has.concentration > 0 ? [', and ', words.concentration, ' in ', phrases.concentration] : '',
				has.emphasis > 0 ? [', not to mention ', emphasisEmphasizer, words.emphasis, ' in ', phrases.emphasis] : '',
				'.'),
			React.DOM.p({key: 'message', className: 'graduation-message'},
				canGraduate ? goodGraduationMessage : badGraduationMessage)
		)
	}
})

export default StudentSummary
<|endoftext|>


<commit_before>var keys = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B'];
var customKeys;
var temp;
var i = 0;

function shuffle(array) {
    var currentIndex = array.length,
        temporaryValue, randomIndex;

    // While there remain elements to shuffle...
    while (0 !== currentIndex) {

        // Pick a remaining element...
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex -= 1;

        // And swap it with the current element.
        temporaryValue = array[currentIndex];
        array[currentIndex] = array[randomIndex];
        array[randomIndex] = temporaryValue;
    }

    return array;
}

var bar = new ProgressBar.Circle("#container", {
    strokeWidth: 3,
    text: {
        value: keys[0]
    },
    from: { color: '#ffffff', a: 0 },
    to: { color: '#CC6600', a: 1 },
    // Set default step function for all animate calls
    step: function(state, circle) {
        circle.path.setAttribute('stroke', state.color);
    }
});

var set;
var isPlaying = false;

function play(keysArr) {
    if (isPlaying) return;
    isPlaying = true;
    temp = $('#temp').val() * 1000;
    metronomePlay(0, temp);
    set = setInterval(function() {
        bar.set(0);
        bar.setText(keysArr[i]);
        bar.animate(1.0, {
            duration: temp
        }, function() {

        });
        i++;
        if (i === keysArr.length) {
            i = 0;
        }
    }, temp);
}

var metronome;
var sound = new Howl({
    src: ['./MetroBar1.wav']
});

function metronomePlay(timeSign, bpm) {
    metronome = setInterval(() => {
        sound.play();
    }, bpm);
}

function stop() {
    bar.setText(keys[0]);
    isPlaying = false;
    clearInterval(set);
    clearInterval(metronome);
    i = 0;
}

function pause() {
    isPlaying = false;
    clearInterval(set);
    clearInterval(metronome);
}

$('#start').on('click', function() {
    console.log('play');
    play(keys || customKeys);
});

$('#reset').on('click', function() {
    console.log('stop');
    stop();
});

$('#pause').on('click', function() {
    console.log('pause');
    pause();
});

$('#shuffle').on('click', function() {
    shuffle(keys);
    console.log(keys)
});<commit_msg>metronom 4th edit<commit_after>var keys = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B'];
var customKeys;
var temp;
var i = 0;

function shuffle(array) {
    var currentIndex = array.length,
        temporaryValue, randomIndex;

    // While there remain elements to shuffle...
    while (0 !== currentIndex) {

        // Pick a remaining element...
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex -= 1;

        // And swap it with the current element.
        temporaryValue = array[currentIndex];
        array[currentIndex] = array[randomIndex];
        array[randomIndex] = temporaryValue;
    }

    return array;
}

var bar = new ProgressBar.Circle("#container", {
    strokeWidth: 3,
    text: {
        value: keys[0]
    },
    from: { color: '#ffffff', a: 0 },
    to: { color: '#CC6600', a: 1 },
    // Set default step function for all animate calls
    step: function(state, circle) {
        circle.path.setAttribute('stroke', state.color);
    }
});

var set;
var isPlaying = false;

function play(keysArr) {
    if (isPlaying) return;
    isPlaying = true;
    temp = $('#temp').val() * 1000;
    metronomePlay(0, temp);
    set = setInterval(function() {
        bar.set(0);
        bar.setText(keysArr[i]);
        bar.animate(1.0, {
            duration: temp
        }, function() {

        });
        i++;
        if (i === keysArr.length) {
            i = 0;
        }
    }, temp);
}

var metronome;
var sound = new Howl({
    src: ['./MetroBar1.wav']
});

function metronomePlay(timeSign, bpm) {
    metronome = setInterval(() => {
        sound.play();
    }, bpm);
}

function stop() {
    bar.setText(keys[0]);
    isPlaying = false;
    clearInterval(set);
    clearInterval(metronome);
    i = 0;
}

function pause() {
    isPlaying = false;
    clearInterval(set);
    clearInterval(metronome);
}

$('#start').on('click', function() {
    console.log('play');
    pause();
    play(keys || customKeys);
});

$('#reset').on('click', function() {
    console.log('stop');
    stop();
});

$('#pause').on('click', function() {
    console.log('pause');
    pause();
});

$('#shuffle').on('click', function() {
    shuffle(keys);
    console.log(keys)
});<|endoftext|>


<commit_before>const CACHE_NAME = 'sgomes-v7';
const TIMEOUT = 4;

// Cached files
const SITE_ASSETS = [
  '/favicon.ico',
  '/assets/images/avatar.jpg',
  '/assets/images/email.svg',
  '/assets/images/feed.svg',
  '/assets/images/github.svg',
  '/assets/images/logo.svg',
  '/assets/images/twitter.svg',
  '/assets/images/touch/16x16.png',
  '/assets/images/touch/32x32.png',
  '/assets/images/touch/144x144.png',
  '/assets/images/touch/152x152.png',
  '/assets/images/touch/192x192.png',
  '/assets/fonts/oMMgfZMQthOryQo9n22dcuvvDin1pK8aKteLpeZ5c0A.woff2',
  '/assets/fonts/RxZJdnzeo3R5zSexge8UUZBw1xU1rKptJj_0jans920.woff2',
  '/assets/fonts/d-6IYplOFocCacKzxwXSOJBw1xU1rKptJj_0jans920.woff2',
  '/assets/fonts/vPcynSL0qHq_6dX7lKVByXYhjbSpvc47ee6xR_80Hnw.woff2',
  '/assets/fonts/OLffGBTaF0XFOW1gnuHF0Ygp9Q8gbYrhqGlRav_IXfk.woff2',
  '/assets/fonts/hMqPNLsu_dywMa4C_DEpY4gp9Q8gbYrhqGlRav_IXfk.woff2',
  '/manifest.json'
];

// Install essential URLs.
self.addEventListener('install', event => {
  event.waitUntil(
      caches.open(CACHE_NAME).then(cache => cache.addAll(SITE_ASSETS)));
});

// Delete old caches.
self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.filter(cacheName => cacheName !== CACHE_NAME)
            .map(cacheName => caches.delete(cacheName))
      );
    })
  );
});

// Fetch data from cache.
self.addEventListener('fetch', event => {
  const requestUrl = new URL(event.request.url);
  // Routing for local URLs
  if (requestUrl.origin == location.origin) {
    if (SITE_ASSETS.find(url => requestUrl.pathname === url)) {
      // Installed asset. Cache only, with network fallback.
      cacheWithNetworkFallback(event);
    } else if (requestUrl.pathname === '/' || requestUrl.pathname === '/index.html') {
      // Home. Try network first, with timeout. If it times out, go to cache.
      networkWithTimeoutAndUpdate(event);
    } else if (/\.html$/.test(requestUrl.pathname)) {
      // Article. Try network first, with timeout. If it times out, go to cache.
      networkWithTimeoutAndUpdate(event, true);
    } else {
      // Cache, then update.
      cacheThenUpdate(event);
    }
  }
});

// Auxiliary methods.

// Use first promise to resolve, reject if they all do.
function promiseAny(promises) {
  return new Promise((resolve, reject) => {
    // make sure promises are all promises
    promises = promises.map(p => Promise.resolve(p));
    // resolve this promise as soon as one resolves
    promises.forEach(p => p.then(resolve));
    // reject if all promises reject
    promises.reduce((a, b) => a.catch(() => b))
      .catch(() => reject(Error("All failed")));
  });
};

// Network with timeout loading strategy, and update logic.
// Attempts to load from the network, with a timeout.
// If the timeout happens, it loads from cache immediately, or waits for
// network if the resource isn't in the cache.
// In parallel, it caches the new network response (if successful).
function networkWithTimeoutAndUpdate(event) {
  const cached = fromCache(event.request);
  const network = fetch(event.request);
  const networkClone = network.then(response => response.clone());

  event.respondWith(promiseAny([
    networkClone.catch(() => cached),
    wait(TIMEOUT).then(() => cached)
  ]));
  event.waitUntil(network.then(resp => update(event.request, resp)));
}

function cacheWithNetworkFallback(event) {
  event.respondWith(fromCache(event.request).catch(() => fetch(event.request)));
}

function cacheThenUpdate(event) {
  const network = fetch(event.request);
  const networkClone = network.then(response => response.clone());

  event.respondWith(fromCache(event.request).catch(() => networkClone));
  event.waitUntil(network.then(resp => update(event.request, resp)));
}

function fromCache(request) {
  return caches.open(CACHE_NAME).then(cache => {
    return cache.match(request).then(matching => {
      return matching || Promise.reject('no-match');
    });
  });
}

function wait(timeout) {
  return new Promise(resolve => setTimeout(resolve, timeout));
}

function update(request, response) {
  return caches.open(CACHE_NAME).then(cache => cache.put(request, response));
}
<commit_msg>Service worker fixes<commit_after>const CACHE_NAME = 'sgomes-v8';
const TIMEOUT = 400;

// Cached files
const SITE_ASSETS = [
  '/favicon.ico',
  '/assets/images/avatar.jpg',
  '/assets/images/email.svg',
  '/assets/images/feed.svg',
  '/assets/images/github.svg',
  '/assets/images/logo.svg',
  '/assets/images/twitter.svg',
  '/assets/images/touch/16x16.png',
  '/assets/images/touch/32x32.png',
  '/assets/images/touch/144x144.png',
  '/assets/images/touch/152x152.png',
  '/assets/images/touch/192x192.png',
  '/assets/fonts/oMMgfZMQthOryQo9n22dcuvvDin1pK8aKteLpeZ5c0A.woff2',
  '/assets/fonts/RxZJdnzeo3R5zSexge8UUZBw1xU1rKptJj_0jans920.woff2',
  '/assets/fonts/d-6IYplOFocCacKzxwXSOJBw1xU1rKptJj_0jans920.woff2',
  '/assets/fonts/vPcynSL0qHq_6dX7lKVByXYhjbSpvc47ee6xR_80Hnw.woff2',
  '/assets/fonts/OLffGBTaF0XFOW1gnuHF0Ygp9Q8gbYrhqGlRav_IXfk.woff2',
  '/assets/fonts/hMqPNLsu_dywMa4C_DEpY4gp9Q8gbYrhqGlRav_IXfk.woff2',
  '/manifest.json'
];

// Install essential URLs.
self.addEventListener('install', event => {
  event.waitUntil(
      caches.open(CACHE_NAME).then(cache => cache.addAll(SITE_ASSETS)));
});

// Delete old caches.
self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.filter(cacheName => cacheName !== CACHE_NAME)
            .map(cacheName => caches.delete(cacheName))
      );
    })
  );
});

// Fetch data from cache.
self.addEventListener('fetch', event => {
  const requestUrl = new URL(event.request.url);
  // Routing for local URLs
  if (requestUrl.origin == location.origin) {
    if (SITE_ASSETS.find(url => requestUrl.pathname === url)) {
      // Installed asset. Cache only, with network fallback.
      cacheWithNetworkFallback(event);
    } else if (requestUrl.pathname === '/' || requestUrl.pathname === '/index.html') {
      // Home. Try network first, with timeout. If it times out, go to cache.
      networkWithTimeoutAndUpdate(event);
    } else if (/\.html$/.test(requestUrl.pathname) || /\/posts\/.*\/$/.test(requestUrl.pathname)) {
      // Article. Try network first, with timeout. If it times out, go to cache.
      networkWithTimeoutAndUpdate(event, true);
    } else {
      // Cache, then update.
      cacheThenUpdate(event);
    }
  }
});

// Auxiliary methods.

// Use first promise to resolve, reject if they all do.
function promiseAny(promises) {
  return new Promise((resolve, reject) => {
    // make sure promises are all promises
    promises = promises.map(p => Promise.resolve(p));
    // resolve this promise as soon as one resolves
    promises.forEach(p => p.then(resolve));
    // reject if all promises reject
    promises.reduce((a, b) => a.catch(() => b))
      .catch(() => reject(Error("All failed")));
  });
};

// Network with timeout loading strategy, and update logic.
// Attempts to load from the network, with a timeout.
// If the timeout happens, it loads from cache immediately, or waits for
// network if the resource isn't in the cache.
// In parallel, it caches the new network response (if successful).
function networkWithTimeoutAndUpdate(event) {
  const cached = fromCache(event.request);
  const network = fetch(event.request);
  const networkClone = network.then(response => response.clone());

  event.respondWith(promiseAny([
    networkClone.catch(() => cached),
    wait(TIMEOUT).then(() => cached)
  ]));
  event.waitUntil(network.then(resp => update(event.request, resp)));
}

function cacheWithNetworkFallback(event) {
  event.respondWith(fromCache(event.request).catch(() => fetch(event.request)));
}

function cacheThenUpdate(event) {
  const network = fetch(event.request);
  const networkClone = network.then(response => response.clone());

  event.respondWith(fromCache(event.request).catch(() => networkClone));
  event.waitUntil(network.then(resp => update(event.request, resp)));
}

function fromCache(request) {
  return caches.open(CACHE_NAME).then(cache => {
    return cache.match(request).then(matching => {
      return matching || Promise.reject('no-match');
    });
  });
}

function wait(timeout) {
  return new Promise(resolve => setTimeout(resolve, timeout));
}

function update(request, response) {
  return caches.open(CACHE_NAME).then(cache => cache.put(request, response));
}
<|endoftext|>


<commit_before>function send_vote(self, vote){
    var uvote = parseInt(vote);
    var row = $(self).closest("tr");
    var dist = parseFloat(row.find("td#dist").text());
    var text = row.find("td#text").text();
    var img_url = row.find("td>img#img_url").attr("src");

    var query_text = $("table>tbody>tr>td#query_text").text();
    var query_img = $("table>tbody>tr>td>img#query_img").attr("src").replace("data:image/png;base64,", "");
    var query_img_src = query_img ? query_img : "";

    var data = {
        dist: dist,
        text: text,
        img_url: img_url,
        query_text: query_text,
        query_img: query_img_src,
        vote: uvote
    };

    $.ajax({
        url: "/vote",
        type: "POST",
        data: data,
        success: function(msg){
            var td = $(self).closest("td");
            td.find("button").remove();
            (uvote == 1) ? td.attr("bgcolor", "#5cb85c") : td.attr("bgcolor", "#c9302c");

        },
        error: function(xhr, textStatus, errorThrown){
            alert("Что-то пошло не так :(");
        }
    });
}<commit_msg>hotfix<commit_after>function send_vote(self, vote){
    var uvote = parseInt(vote);
    var row = $(self).closest("tr");
    var dist = parseFloat(row.find("td#dist").text());
    var text = row.find("td#text").text();
    var img_url = row.find("td>img#img_url").attr("src");

    var query_text = $("table>tbody>tr>td#query_text").text();
    var query_img = $("table>tbody>tr>td>img#query_img").attr("src");
    var query_img_src = query_img ? query_img.replace("data:image/png;base64,", "") : "";

    var data = {
        dist: dist,
        text: text,
        img_url: img_url,
        query_text: query_text,
        query_img: query_img_src,
        vote: uvote
    };

    $.ajax({
        url: "/vote",
        type: "POST",
        data: data,
        success: function(msg){
            var td = $(self).closest("td");
            td.find("button").remove();
            (uvote == 1) ? td.attr("bgcolor", "#5cb85c") : td.attr("bgcolor", "#c9302c");

        },
        error: function(xhr, textStatus, errorThrown){
            alert("Что-то пошло не так :(");
        }
    });
}<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
// Copyright (c) 2008-2011 by Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
"use strict";

/** @scope modules */

/**
 * @instance browser
 */
var Browser = Module("browser", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
    init: function init() {
        this.cleanupProgressListener = util.overlayObject(window.XULBrowserWindow,
                                                          this.progressListener);
        util.addObserver(this);
    },

    destroy: function () {
        this.cleanupProgressListener();
        this.observe.unregister();
    },

    observers: {
        "chrome-document-global-created": function (win, uri) { this.observe(win, "content-document-global-created", uri); },
        "content-document-global-created": function (win, uri) {
            let top = util.topWindow(win);

            if (uri == "null")
                uri = null;

            if (top == window && (win.location.href || uri))
                this._triggerLoadAutocmd("PageLoadPre", win.document, win.location.href || uri);
        }
    },

    _triggerLoadAutocmd: function _triggerLoadAutocmd(name, doc, uri) {
        if (!(uri || doc.location))
            return;

        uri = isObject(uri) ? uri : util.newURI(uri || doc.location.href);
        let args = {
            url: { toString: function () uri.spec, valueOf: function () uri },
            title: doc.title
        };

        if (!dactyl.has("tabs"))
            update(args, { doc: doc, win: doc.defaultView });
        else {
            args.tab = tabs.getContentIndex(doc) + 1;
            args.doc = {
                valueOf: function () doc,
                toString: function () "tabs.getTab(" + (args.tab - 1) + ").linkedBrowser.contentDocument"
            };
            args.win = {
                valueOf: function () doc.defaultView,
                toString: function () "tabs.getTab(" + (args.tab - 1) + ").linkedBrowser.contentWindow"
            };
        }

        autocommands.trigger(name, args);
    },

    events: {
        DOMContentLoaded: function onDOMContentLoaded(event) {
            let doc = event.originalTarget;
            if (doc instanceof HTMLDocument)
                this._triggerLoadAutocmd("DOMLoad", doc);
        },

        // TODO: see what can be moved to onDOMContentLoaded()
        // event listener which is is called on each page load, even if the
        // page is loaded in a background tab
        load: function onLoad(event) {
            let doc = event.originalTarget;
            if (doc instanceof Document)
                dactyl.initDocument(doc);

            if (doc instanceof HTMLDocument) {
                if (doc.defaultView.frameElement) {
                    // document is part of a frameset

                    // hacky way to get rid of "Transferring data from ..." on sites with frames
                    // when you click on a link inside a frameset, because asyncUpdateUI
                    // is not triggered there (Gecko bug?)
                    this.timeout(function () { statusline.updateStatus(); }, 10);
                }
                else {
                    // code which should happen for all (also background) newly loaded tabs goes here:
                    if (doc != config.browser.contentDocument)
                        dactyl.echomsg({ domains: [util.getHost(doc.location)], message: _("buffer.backgroundLoaded", (doc.title || doc.location.href)) }, 3);

                    this._triggerLoadAutocmd("PageLoad", doc);
                }
            }
        }
    },

    /**
     * @property {Object} The document loading progress listener.
     */
    progressListener: {
        // XXX: function may later be needed to detect a canceled synchronous openURL()
        onStateChange: util.wrapCallback(function onStateChange(webProgress, request, flags, status) {
            onStateChange.superapply(this, arguments);
            // STATE_IS_DOCUMENT | STATE_IS_WINDOW is important, because we also
            // receive statechange events for loading images and other parts of the web page
            if (flags & (Ci.nsIWebProgressListener.STATE_IS_DOCUMENT | Ci.nsIWebProgressListener.STATE_IS_WINDOW)) {
                dactyl.applyTriggerObserver("browser.stateChange", arguments);
                // This fires when the load event is initiated
                // only thrown for the current tab, not when another tab changes
                if (flags & Ci.nsIWebProgressListener.STATE_START) {
                    while (document.commandDispatcher.focusedWindow == webProgress.DOMWindow
                           && modes.have(modes.INPUT))
                        modes.pop();

                }
                else if (flags & Ci.nsIWebProgressListener.STATE_STOP) {
                    // Workaround for bugs 591425 and 606877, dactyl bug #81
                    config.browser.mCurrentBrowser.collapsed = false;
                    if (!dactyl.focusedElement || dactyl.focusedElement === document.documentElement)
                        dactyl.focusContent();
                }
            }
        }),
        onSecurityChange: util.wrapCallback(function onSecurityChange(webProgress, request, state) {
            onSecurityChange.superapply(this, arguments);
            dactyl.applyTriggerObserver("browser.securityChange", arguments);
        }),
        onStatusChange: util.wrapCallback(function onStatusChange(webProgress, request, status, message) {
            onStatusChange.superapply(this, arguments);
            dactyl.applyTriggerObserver("browser.statusChange", arguments);
        }),
        onProgressChange: util.wrapCallback(function onProgressChange(webProgress, request, curSelfProgress, maxSelfProgress, curTotalProgress, maxTotalProgress) {
            onProgressChange.superapply(this, arguments);
            dactyl.applyTriggerObserver("browser.progressChange", arguments);
        }),
        // happens when the users switches tabs
        onLocationChange: util.wrapCallback(function onLocationChange(webProgress, request, uri) {
            onLocationChange.superapply(this, arguments);

            dactyl.applyTriggerObserver("browser.locationChange", arguments);

            let win = webProgress.DOMWindow;
            if (win && uri) {
                let oldURI = win.document.dactylURI;
                if (win.document.dactylLoadIdx === webProgress.loadedTransIndex
                    || !oldURI || uri.spec.replace(/#.*/, "") !== oldURI.replace(/#.*/, ""))
                    for (let frame in values(buffer.allFrames(win)))
                        frame.document.dactylFocusAllowed = false;
                win.document.dactylURI = uri.spec;
                win.document.dactylLoadIdx = webProgress.loadedTransIndex;
            }

            // Workaround for bugs 591425 and 606877, dactyl bug #81
            let collapse = uri && uri.scheme === "dactyl" && webProgress.isLoadingDocument;
            if (collapse)
                dactyl.focus(document.documentElement);
            config.browser.mCurrentBrowser.collapsed = collapse;

            util.timeout(function () {
                browser._triggerLoadAutocmd("LocationChange",
                                            (win || content).document,
                                            uri);
            });
        }),
        // called at the very end of a page load
        asyncUpdateUI: util.wrapCallback(function asyncUpdateUI() {
            asyncUpdateUI.superapply(this, arguments);
            util.timeout(function () { statusline.updateStatus(); }, 100);
        }),
        setOverLink: util.wrapCallback(function setOverLink(link, b) {
            setOverLink.superapply(this, arguments);
            dactyl.triggerObserver("browser.overLink", link);
        }),
    }
}, {
}, {
    events: function initEvents(dactyl, modules, window) {
        events.listen(config.browser, browser, "events", true);
    },
    commands: function initCommands(dactyl, modules, window) {
        commands.add(["o[pen]"],
            "Open one or more URLs in the current tab",
            function (args) { dactyl.open(args[0] || "about:blank"); },
            {
                completer: function (context) completion.url(context),
                domains: function (args) array.compact(dactyl.parseURLs(args[0] || "").map(
                    function (url) util.getHost(url))),
                literal: 0,
                privateData: true
            });

        commands.add(["redr[aw]"],
            "Redraw the screen",
            function () {
                window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils)
                      .redraw();
                statusline.updateStatus();
                commandline.clear();
            },
            { argCount: "0" });
    },
    mappings: function initMappings(dactyl, modules, window) {
        // opening websites
        mappings.add([modes.NORMAL],
            ["o"], "Open one or more URLs",
            function () { CommandExMode().open("open "); });

        function decode(uri) statusline.losslessDecodeURI(uri)
                                       .replace(/%20(?!(?:%20)*$)/g, " ")
                                       .replace(RegExp(options["urlseparator"], "g"), encodeURIComponent);

        mappings.add([modes.NORMAL], ["O"],
            "Open one or more URLs, based on current location",
            function () { CommandExMode().open("open " + decode(buffer.uri.spec)); });

        mappings.add([modes.NORMAL], ["t"],
            "Open one or more URLs in a new tab",
            function () { CommandExMode().open("tabopen "); });

        mappings.add([modes.NORMAL], ["T"],
            "Open one or more URLs in a new tab, based on current location",
            function () { CommandExMode().open("tabopen " + decode(buffer.uri.spec)); });

        mappings.add([modes.NORMAL], ["w"],
            "Open one or more URLs in a new window",
            function () { CommandExMode().open("winopen "); });

        mappings.add([modes.NORMAL], ["W"],
            "Open one or more URLs in a new window, based on current location",
            function () { CommandExMode().open("winopen " + decode(buffer.uri.spec)); });

        mappings.add([modes.NORMAL], ["<open-home-directory>", "~"],
            "Open home directory",
            function () { dactyl.open("~"); });

        mappings.add([modes.NORMAL], ["<open-homepage>", "gh"],
            "Open homepage",
            function () { BrowserHome(); });

        mappings.add([modes.NORMAL], ["<tab-open-homepage>", "gH"],
            "Open homepage in a new tab",
            function () {
                let homepages = gHomeButton.getHomePage();
                dactyl.open(homepages, { from: "homepage", where: dactyl.NEW_TAB });
            });

        mappings.add([modes.MAIN], ["<redraw-screen>", "<C-l>"],
            "Redraw the screen",
            function () { ex.redraw(); });
    }
});

// vim: set fdm=marker sw=4 ts=4 et:
<commit_msg>Fix sticky network status.<commit_after>// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
// Copyright (c) 2008-2011 by Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
"use strict";

/** @scope modules */

/**
 * @instance browser
 */
var Browser = Module("browser", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
    init: function init() {
        this.cleanupProgressListener = util.overlayObject(window.XULBrowserWindow,
                                                          this.progressListener);
        util.addObserver(this);
    },

    destroy: function () {
        this.cleanupProgressListener();
        this.observe.unregister();
    },

    observers: {
        "chrome-document-global-created": function (win, uri) { this.observe(win, "content-document-global-created", uri); },
        "content-document-global-created": function (win, uri) {
            let top = util.topWindow(win);

            if (uri == "null")
                uri = null;

            if (top == window && (win.location.href || uri))
                this._triggerLoadAutocmd("PageLoadPre", win.document, win.location.href || uri);
        }
    },

    _triggerLoadAutocmd: function _triggerLoadAutocmd(name, doc, uri) {
        if (!(uri || doc.location))
            return;

        uri = isObject(uri) ? uri : util.newURI(uri || doc.location.href);
        let args = {
            url: { toString: function () uri.spec, valueOf: function () uri },
            title: doc.title
        };

        if (!dactyl.has("tabs"))
            update(args, { doc: doc, win: doc.defaultView });
        else {
            args.tab = tabs.getContentIndex(doc) + 1;
            args.doc = {
                valueOf: function () doc,
                toString: function () "tabs.getTab(" + (args.tab - 1) + ").linkedBrowser.contentDocument"
            };
            args.win = {
                valueOf: function () doc.defaultView,
                toString: function () "tabs.getTab(" + (args.tab - 1) + ").linkedBrowser.contentWindow"
            };
        }

        autocommands.trigger(name, args);
    },

    events: {
        DOMContentLoaded: function onDOMContentLoaded(event) {
            let doc = event.originalTarget;
            if (doc instanceof HTMLDocument)
                this._triggerLoadAutocmd("DOMLoad", doc);
        },

        // TODO: see what can be moved to onDOMContentLoaded()
        // event listener which is is called on each page load, even if the
        // page is loaded in a background tab
        load: function onLoad(event) {
            let doc = event.originalTarget;
            if (doc instanceof Document)
                dactyl.initDocument(doc);

            if (doc instanceof HTMLDocument) {
                if (doc.defaultView.frameElement) {
                    // document is part of a frameset

                    // hacky way to get rid of "Transferring data from ..." on sites with frames
                    // when you click on a link inside a frameset, because asyncUpdateUI
                    // is not triggered there (Gecko bug?)
                    this.timeout(function () { statusline.updateStatus(); }, 10);
                }
                else {
                    // code which should happen for all (also background) newly loaded tabs goes here:
                    if (doc != config.browser.contentDocument)
                        dactyl.echomsg({ domains: [util.getHost(doc.location)], message: _("buffer.backgroundLoaded", (doc.title || doc.location.href)) }, 3);

                    this._triggerLoadAutocmd("PageLoad", doc);
                }
            }
        }
    },

    /**
     * @property {Object} The document loading progress listener.
     */
    progressListener: {
        // XXX: function may later be needed to detect a canceled synchronous openURL()
        onStateChange: util.wrapCallback(function onStateChange(webProgress, request, flags, status) {
            const L = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;

            if (request)
                dactyl.applyTriggerObserver("browser.stateChange", arguments);

            if (flags & (L.STATE_IS_DOCUMENT | L.STATE_IS_WINDOW)) {
                // This fires when the load event is initiated
                // only thrown for the current tab, not when another tab changes
                if (flags & L.STATE_START) {
                    while (document.commandDispatcher.focusedWindow == webProgress.DOMWindow
                           && modes.have(modes.INPUT))
                        modes.pop();

                }
                else if (flags & L.STATE_STOP) {
                    // Workaround for bugs 591425 and 606877, dactyl bug #81
                    config.browser.mCurrentBrowser.collapsed = false;
                    if (!dactyl.focusedElement || dactyl.focusedElement === document.documentElement)
                        dactyl.focusContent();
                }
            }

            onStateChange.superapply(this, arguments);
        }),
        onSecurityChange: util.wrapCallback(function onSecurityChange(webProgress, request, state) {
            onSecurityChange.superapply(this, arguments);
            dactyl.applyTriggerObserver("browser.securityChange", arguments);
        }),
        onStatusChange: util.wrapCallback(function onStatusChange(webProgress, request, status, message) {
            onStatusChange.superapply(this, arguments);
            dactyl.applyTriggerObserver("browser.statusChange", arguments);
        }),
        onProgressChange: util.wrapCallback(function onProgressChange(webProgress, request, curSelfProgress, maxSelfProgress, curTotalProgress, maxTotalProgress) {
            onProgressChange.superapply(this, arguments);
            dactyl.applyTriggerObserver("browser.progressChange", arguments);
        }),
        // happens when the users switches tabs
        onLocationChange: util.wrapCallback(function onLocationChange(webProgress, request, uri) {
            onLocationChange.superapply(this, arguments);

            dactyl.applyTriggerObserver("browser.locationChange", arguments);

            let win = webProgress.DOMWindow;
            if (win && uri) {
                let oldURI = win.document.dactylURI;
                if (win.document.dactylLoadIdx === webProgress.loadedTransIndex
                    || !oldURI || uri.spec.replace(/#.*/, "") !== oldURI.replace(/#.*/, ""))
                    for (let frame in values(buffer.allFrames(win)))
                        frame.document.dactylFocusAllowed = false;
                win.document.dactylURI = uri.spec;
                win.document.dactylLoadIdx = webProgress.loadedTransIndex;
            }

            // Workaround for bugs 591425 and 606877, dactyl bug #81
            let collapse = uri && uri.scheme === "dactyl" && webProgress.isLoadingDocument;
            if (collapse)
                dactyl.focus(document.documentElement);
            config.browser.mCurrentBrowser.collapsed = collapse;

            util.timeout(function () {
                browser._triggerLoadAutocmd("LocationChange",
                                            (win || content).document,
                                            uri);
            });
        }),
        // called at the very end of a page load
        asyncUpdateUI: util.wrapCallback(function asyncUpdateUI() {
            asyncUpdateUI.superapply(this, arguments);
            util.timeout(function () { statusline.updateStatus(); }, 100);
        }),
        setOverLink: util.wrapCallback(function setOverLink(link, b) {
            setOverLink.superapply(this, arguments);
            dactyl.triggerObserver("browser.overLink", link);
        }),
    }
}, {
}, {
    events: function initEvents(dactyl, modules, window) {
        events.listen(config.browser, browser, "events", true);
    },
    commands: function initCommands(dactyl, modules, window) {
        commands.add(["o[pen]"],
            "Open one or more URLs in the current tab",
            function (args) { dactyl.open(args[0] || "about:blank"); },
            {
                completer: function (context) completion.url(context),
                domains: function (args) array.compact(dactyl.parseURLs(args[0] || "").map(
                    function (url) util.getHost(url))),
                literal: 0,
                privateData: true
            });

        commands.add(["redr[aw]"],
            "Redraw the screen",
            function () {
                window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils)
                      .redraw();
                statusline.updateStatus();
                commandline.clear();
            },
            { argCount: "0" });
    },
    mappings: function initMappings(dactyl, modules, window) {
        // opening websites
        mappings.add([modes.NORMAL],
            ["o"], "Open one or more URLs",
            function () { CommandExMode().open("open "); });

        function decode(uri) statusline.losslessDecodeURI(uri)
                                       .replace(/%20(?!(?:%20)*$)/g, " ")
                                       .replace(RegExp(options["urlseparator"], "g"), encodeURIComponent);

        mappings.add([modes.NORMAL], ["O"],
            "Open one or more URLs, based on current location",
            function () { CommandExMode().open("open " + decode(buffer.uri.spec)); });

        mappings.add([modes.NORMAL], ["t"],
            "Open one or more URLs in a new tab",
            function () { CommandExMode().open("tabopen "); });

        mappings.add([modes.NORMAL], ["T"],
            "Open one or more URLs in a new tab, based on current location",
            function () { CommandExMode().open("tabopen " + decode(buffer.uri.spec)); });

        mappings.add([modes.NORMAL], ["w"],
            "Open one or more URLs in a new window",
            function () { CommandExMode().open("winopen "); });

        mappings.add([modes.NORMAL], ["W"],
            "Open one or more URLs in a new window, based on current location",
            function () { CommandExMode().open("winopen " + decode(buffer.uri.spec)); });

        mappings.add([modes.NORMAL], ["<open-home-directory>", "~"],
            "Open home directory",
            function () { dactyl.open("~"); });

        mappings.add([modes.NORMAL], ["<open-homepage>", "gh"],
            "Open homepage",
            function () { BrowserHome(); });

        mappings.add([modes.NORMAL], ["<tab-open-homepage>", "gH"],
            "Open homepage in a new tab",
            function () {
                let homepages = gHomeButton.getHomePage();
                dactyl.open(homepages, { from: "homepage", where: dactyl.NEW_TAB });
            });

        mappings.add([modes.MAIN], ["<redraw-screen>", "<C-l>"],
            "Redraw the screen",
            function () { ex.redraw(); });
    }
});

// vim: set fdm=marker sw=4 ts=4 et:
<|endoftext|>


<commit_before>const path = require('path');
const j79 = require('j79-utils');

const fsx = require('./fsx');
const logger = require('./logger');
const confMgmt = require('./conf-mgmt');
const confConsts = require('../common/conf-constants');
const uiConsts = require('../common/ui-constants');
const di = require('../common/data-interchange-constants');
const utils = require('./utils');

let TREE_ITEMS = [];

function sortFilesFunc(a, b) {
	if (a.label.toUpperCase() > b.label.toUpperCase()) {
		return 1;
	}
	if (a.label.toUpperCase() < b.label.toUpperCase()) {
		return -1;
	}
	return 0;
}

function assembleStorageFilePath(relativePath) {
	if (!utils.isFilePathValid(relativePath)) {
		logger.log.error('The [%s] path is unacceptable', relativePath);
		return Promise.reject('Unacceptable path');
	}

	const fullPath = path.join(confMgmt.getNexlStorageDir(), relativePath || '');

	if (!utils.isFilePathValid(fullPath)) {
		logger.log.error('The [%s] path is unacceptable', fullPath);
		return Promise.reject('Unacceptable path');
	}

	return Promise.resolve(fullPath);
}

function assembleStorageDirPath(relativePath) {
	if (!utils.isDirPathValid(relativePath)) {
		logger.log.error('The [%s] path is unacceptable', relativePath);
		return Promise.reject('Unacceptable path');
	}

	const fullPath = path.join(confMgmt.getNexlStorageDir(), relativePath || '');

	if (!utils.isDirPathValid(fullPath)) {
		logger.log.error('The [%s] path is unacceptable', fullPath);
		return Promise.reject('Unacceptable path');
	}

	return Promise.resolve(fullPath);
}

function loadFileFromStorage(relativePath) {
	return assembleStorageFilePath(relativePath).then(
		(fullPath) => {
			return fsx.exists(fullPath).then(
				(isExists) => {
					if (!isExists) {
						logger.log.error('The [%s] JavaScript file doesn\'t exist', fullPath);
						return Promise.reject('JavaScript file doesn\'t exist !');
					}

					const encoding = confMgmt.getNexlSettingsCached()[confConsts.SETTINGS.STORAGE_FILES_ENCODING];
					return fsx.readFile(fullPath, {encoding: encoding});
				});
		}
	);
}

function saveFileToStorageInnerInner(fullPath, content) {
	const data = {};

	const encoding = confMgmt.getNexlSettingsCached()[confConsts.SETTINGS.STORAGE_FILES_ENCODING];

	return fsx.writeFile(fullPath, content, {encoding: encoding})
		.then(_ => fsx.stat(fullPath))
		.then(stat => Promise.resolve(data[di.FILE_LOAD_TIME] = stat.mtime.getTime()))
		.then(cacheStorageFiles)
		.then(_ => data);
}

function saveFileToStorageInner(fullPath, content, fileLoadTime) {
	if (fileLoadTime === undefined) {
		return saveFileToStorageInnerInner(fullPath, content);
	}

	// comparing fileLoadTime to last file modification time
	return fsx.stat(fullPath)
		.then(stat => {
			if (fileLoadTime >= stat.mtime.getTime()) {
				// file was modified on server before the fileLoadTime, just saving...
				return saveFileToStorageInnerInner(fullPath, content);
			}

			// file on the server was modified after it was opened by client
			// sending back newer file content
			const encoding = confMgmt.getNexlSettingsCached()[confConsts.SETTINGS.STORAGE_FILES_ENCODING];
			return fsx.readFile(fullPath, {encoding: encoding})
				.then(newerFileContent => {
					const data = {};
					data[di.FILE_BODY] = newerFileContent;
					data[di.FILE_LOAD_TIME] = stat.mtime.getTime();
					return data;
				});
		});
}

function saveFileToStorage(relativePath, content, fileLoadTime) {
	return assembleStorageFilePath(relativePath)
		.then(fullPath => {
			return saveFileToStorageInner(fullPath, content, fileLoadTime);
		});
}

function mkdir(relativePath) {
	return assembleStorageFilePath(relativePath).then(
		(fullPath) => {
			return fsx.exists(fullPath).then((isExists) => {
				if (isExists) {
					logger.log.error('The [%s] directory or file already exists', fullPath);
					return Promise.reject('Directory or file already exists');
				}

				return fsx.mkdir(fullPath);
			});
		})
		.then(cacheStorageFiles);
}

function deleteItem(relativePath) {
	return assembleStorageFilePath(relativePath)
		.then(fsx.deleteItem)
		.then(cacheStorageFiles);
}

function rename(oldRelativePath, newRelativePath) {
	return assembleStorageFilePath(newRelativePath).then(
		(newFullPath) => {
			return fsx.exists(newFullPath).then(
				(isExists) => {
					if (isExists) {
						logger.log.error('Cannot rename a [%s] to [%s] because the [%s] already exists', oldRelativePath, newRelativePath, newRelativePath);
						return Promise.reject('Item with the same name already exists');
					}

					return assembleStorageFilePath(oldRelativePath).then(
						(oldFullPath) => {
							return fsx.rename(oldFullPath, newFullPath);
						}
					);

				}
			);
		}
	)
		.then(cacheStorageFiles);
}

function moveInner(sourceStuff, destStuff) {
	return fsx.exists(sourceStuff).then(
		(isSrcExists) => {
			if (!isSrcExists) {
				logger.log.error('Failed to move a [%s] source item to [%s] destination item. Reason : source item doesn\'t exist', sourceStuff, destStuff);
				return Promise.reject('Source item doesn\'t exist');
			}

			const destItem = path.join(destStuff, path.basename(sourceStuff));

			return fsx.exists(destItem).then(
				(isDestExists) => {
					if (isDestExists) {
						logger.log.error('Failed to move a [%s] source item to [%s] destination item. Reason : destination item already exists', sourceStuff, destItem);
						return Promise.reject('Destination item already exist');
					}

					// moving...
					return fsx.move(sourceStuff, destItem);
				}
			);
		}
	);
}

function move(source, dest) {
	const data = {};
	return assembleStorageFilePath(source)
		.then(sourceFullPath => Promise.resolve(data.sourceFullPath = sourceFullPath))
		.then(_ => assembleStorageDirPath(dest))
		.then(destFullPath => Promise.resolve(data.destFullPath = destFullPath))
		.then(_ => moveInner(data.sourceFullPath, data.destFullPath))
		.then(cacheStorageFiles);
}

function listDirItems(fullPath) {
	const dirItems = [];
	const fileItems = [];

	return fsx.readdir(fullPath)
		.then(items => {
			const promises = [];

			items.forEach(item => {
				const itemFullPath = path.join(fullPath, item);
				const promise = fsx.stat(itemFullPath)
					.then(itemStat => {
						if (itemStat.isDirectory()) {
							dirItems.push(item);
						}

						if (itemStat.isFile()) {
							fileItems.push(item);
						}
					});

				promises.push(promise);
			});

			return Promise.all(promises)
				.then(items => {
					return Promise.resolve({
						dirs: dirItems,
						files: fileItems
					});
				});
		});
}

function makeDirItem(item, relativePath, subDirItems) {
	return {
		label: item,
		items: subDirItems,
		icon: uiConsts.DIR_ICON,
		value: {
			relativePath: path.join(relativePath, item),
			label: item,
			mustLoadChildItems: false,
			isDir: true
		}
	};
}

function makeFileItem(item, relativePath) {
	return {
		label: item,
		icon: uiConsts.FILE_ICON,
		value: {
			relativePath: path.join(relativePath, item),
			label: item,
			mustLoadChildItems: false,
			isDir: false
		}
	};
}

function gatherAllFiles(relativePath) {
	relativePath = relativePath || '';
	relativePath = path.join(path.sep, relativePath);
	const searchFrom = path.join(confMgmt.getNexlStorageDir(), relativePath);

	if (!utils.isDirPathValid(searchFrom)) {
		logger.log.error(`Got unacceptable path [${searchFrom}]. This path is invalid or points outside a nexl JavaScript files root dir`);
		return Promise.reject('Unacceptable path');
	}

	const dirItems = [];
	return listDirItems(searchFrom)
		.then(currentDirItems => {

			// iterating over dir items and resolving sub dir items with promises
			const promises = [];
			currentDirItems.dirs.forEach(item => {
				const subDirRelativePath = path.join(relativePath, item);
				const promise = gatherAllFiles(subDirRelativePath)
					.then(subDirItems => {
						const dirItem = makeDirItem(item, relativePath, subDirItems);
						dirItems.push(dirItem);
					});
				promises.push(promise);
			});

			// running promises to resolve sub dir items
			return Promise.all(promises)
				.then(x => {
					dirItems.sort(sortFilesFunc);
					const fileItems = [];

					// now iterating over file items
					currentDirItems.files.forEach(item => {
						const fileItem = makeFileItem(item, relativePath);
						fileItems.push(fileItem);
					});

					fileItems.sort(sortFilesFunc);

					return Promise.resolve(dirItems.concat(fileItems));
				});
		});
}

function cacheStorageFiles() {
	const storageDir = confMgmt.getNexlStorageDir();
	logger.log.debug(`Caching files list in [${storageDir}] directory`);

	return gatherAllFiles().then(
		(result) => {
			TREE_ITEMS = result;
			logger.log.debug(`Files are gathered`);
			return Promise.resolve();
		}
	);
}

function findOccurrencesInFileRegex(fileContent, regex) {
	return fileContent.split(/[\r\n]/).map(function (line, i) {
		if (regex.test(line)) {
			return {
				line: line,
				number: i + 1
			};
		}
	}).filter(Boolean);
}

function findOccurrencesInFileSimple(fileContent, text, matchCase) {
	if (!matchCase) {
		fileContent = fileContent.toLowerCase();
	}

	return fileContent.split(/[\r\n]/).map(function (line, i) {
		if (line.indexOf(text) >= 0) {
			return {
				line: line,
				number: i + 1
			};
		}
	}).filter(Boolean);
}

function gatherFilesList(list, root) {
	for (let index in root) {
		const item = root[index];
		if (item.value.isDir === true) {
			gatherFilesList(list, item.items);
			continue;
		}

		list.push(item.value.relativePath);
	}
}

function findInFilesInner(root, data) {
	const filesList = [];
	gatherFilesList(filesList, root);

	let searchFunc, searchType;

	if (data[di.IS_REGEX]) {
		let flags = 'g';
		flags += (data[di.MATCH_CASE] ? '' : 'i');
		searchType = new RegExp(data[di.TEXT], flags);
		searchFunc = findOccurrencesInFileRegex;
	} else {
		searchType = data[di.MATCH_CASE] ? data[di.TEXT] : data[di.TEXT].toLowerCase();
		searchFunc = findOccurrencesInFileSimple;
	}

	const result = {};
	const promises = [];

	filesList.forEach(fileName => {
		const fullPath = path.join(confMgmt.getNexlStorageDir(), fileName);

		const promise = fsx.readFile(fullPath, {encoding: confConsts.ENCODING_UTF8}).then(fileContent => {
			const occurrences = searchFunc(fileContent, searchType, data[di.MATCH_CASE]);
			if (occurrences.length > 0) {
				result[fileName] = occurrences;
			}
		});
		promises.push(promise);
	});

	return Promise.all(promises).then(_ => Promise.resolve(result));
}

function findDir(dir, dirName) {
	for (let key in dir) {
		let item = dir[key];

		if (item.value.isDir !== true) {
			continue;
		}

		if (item.value.label === dirName) {
			return item;
		}
	}
}

function findInFiles(data) {
	const normalizedPath = path.normalize(data[di.RELATIVE_PATH]);

	// is root dir ?
	if (normalizedPath === path.sep) {
		return findInFilesInner(TREE_ITEMS, data);
	}

	// searching for target dir
	const pathItems = normalizedPath.split(path.sep);
	let dir = TREE_ITEMS;

	for (let index in pathItems) {
		dir = findDir(dir, pathItems[index]);

		// relativePath doesn't exist
		if (dir === undefined) {
			return Promise.resolve({});
		}

		dir = dir.items;
	}

	return findInFilesInner(dir, data);
}

// --------------------------------------------------------------------------------
module.exports.loadFileFromStorage = loadFileFromStorage;
module.exports.saveFileToStorage = saveFileToStorage;
module.exports.mkdir = mkdir;
module.exports.deleteItem = deleteItem;
module.exports.rename = rename;
module.exports.move = move;
module.exports.findInFiles = findInFiles;

module.exports.gatherAllFiles = gatherAllFiles;

module.exports.cacheStorageFiles = cacheStorageFiles;
module.exports.getTreeItems = () => TREE_ITEMS;
// --------------------------------------------------------------------------------
<commit_msg>- added MAX_FIND_IN_FILES_OCCURRENCES - fixed find in files bugs - added tests<commit_after>const path = require('path');
const j79 = require('j79-utils');

const fsx = require('./fsx');
const logger = require('./logger');
const confMgmt = require('./conf-mgmt');
const confConsts = require('../common/conf-constants');
const uiConsts = require('../common/ui-constants');
const di = require('../common/data-interchange-constants');
const utils = require('./utils');

// todo : allow to configure
const MAX_FIND_IN_FILES_OCCURRENCES = 1000;

let TREE_ITEMS = [];

function sortFilesFunc(a, b) {
	if (a.label.toUpperCase() > b.label.toUpperCase()) {
		return 1;
	}
	if (a.label.toUpperCase() < b.label.toUpperCase()) {
		return -1;
	}
	return 0;
}

function assembleStorageFilePath(relativePath) {
	if (!utils.isFilePathValid(relativePath)) {
		logger.log.error('The [%s] path is unacceptable', relativePath);
		return Promise.reject('Unacceptable path');
	}

	const fullPath = path.join(confMgmt.getNexlStorageDir(), relativePath || '');

	if (!utils.isFilePathValid(fullPath)) {
		logger.log.error('The [%s] path is unacceptable', fullPath);
		return Promise.reject('Unacceptable path');
	}

	return Promise.resolve(fullPath);
}

function assembleStorageDirPath(relativePath) {
	if (!utils.isDirPathValid(relativePath)) {
		logger.log.error('The [%s] path is unacceptable', relativePath);
		return Promise.reject('Unacceptable path');
	}

	const fullPath = path.join(confMgmt.getNexlStorageDir(), relativePath || '');

	if (!utils.isDirPathValid(fullPath)) {
		logger.log.error('The [%s] path is unacceptable', fullPath);
		return Promise.reject('Unacceptable path');
	}

	return Promise.resolve(fullPath);
}

function loadFileFromStorage(relativePath) {
	return assembleStorageFilePath(relativePath).then(
		(fullPath) => {
			return fsx.exists(fullPath).then(
				(isExists) => {
					if (!isExists) {
						logger.log.error('The [%s] JavaScript file doesn\'t exist', fullPath);
						return Promise.reject('JavaScript file doesn\'t exist !');
					}

					const encoding = confMgmt.getNexlSettingsCached()[confConsts.SETTINGS.STORAGE_FILES_ENCODING];
					return fsx.readFile(fullPath, {encoding: encoding});
				});
		}
	);
}

function saveFileToStorageInnerInner(fullPath, content) {
	const data = {};

	const encoding = confMgmt.getNexlSettingsCached()[confConsts.SETTINGS.STORAGE_FILES_ENCODING];

	return fsx.writeFile(fullPath, content, {encoding: encoding})
		.then(_ => fsx.stat(fullPath))
		.then(stat => Promise.resolve(data[di.FILE_LOAD_TIME] = stat.mtime.getTime()))
		.then(cacheStorageFiles)
		.then(_ => data);
}

function saveFileToStorageInner(fullPath, content, fileLoadTime) {
	if (fileLoadTime === undefined) {
		return saveFileToStorageInnerInner(fullPath, content);
	}

	// comparing fileLoadTime to last file modification time
	return fsx.stat(fullPath)
		.then(stat => {
			if (fileLoadTime >= stat.mtime.getTime()) {
				// file was modified on server before the fileLoadTime, just saving...
				return saveFileToStorageInnerInner(fullPath, content);
			}

			// file on the server was modified after it was opened by client
			// sending back newer file content
			const encoding = confMgmt.getNexlSettingsCached()[confConsts.SETTINGS.STORAGE_FILES_ENCODING];
			return fsx.readFile(fullPath, {encoding: encoding})
				.then(newerFileContent => {
					const data = {};
					data[di.FILE_BODY] = newerFileContent;
					data[di.FILE_LOAD_TIME] = stat.mtime.getTime();
					return data;
				});
		});
}

function saveFileToStorage(relativePath, content, fileLoadTime) {
	return assembleStorageFilePath(relativePath)
		.then(fullPath => {
			return saveFileToStorageInner(fullPath, content, fileLoadTime);
		});
}

function mkdir(relativePath) {
	return assembleStorageFilePath(relativePath).then(
		(fullPath) => {
			return fsx.exists(fullPath).then((isExists) => {
				if (isExists) {
					logger.log.error('The [%s] directory or file already exists', fullPath);
					return Promise.reject('Directory or file already exists');
				}

				return fsx.mkdir(fullPath);
			});
		})
		.then(cacheStorageFiles);
}

function deleteItem(relativePath) {
	return assembleStorageFilePath(relativePath)
		.then(fsx.deleteItem)
		.then(cacheStorageFiles);
}

function rename(oldRelativePath, newRelativePath) {
	return assembleStorageFilePath(newRelativePath).then(
		(newFullPath) => {
			return fsx.exists(newFullPath).then(
				(isExists) => {
					if (isExists) {
						logger.log.error('Cannot rename a [%s] to [%s] because the [%s] already exists', oldRelativePath, newRelativePath, newRelativePath);
						return Promise.reject('Item with the same name already exists');
					}

					return assembleStorageFilePath(oldRelativePath).then(
						(oldFullPath) => {
							return fsx.rename(oldFullPath, newFullPath);
						}
					);

				}
			);
		}
	)
		.then(cacheStorageFiles);
}

function moveInner(sourceStuff, destStuff) {
	return fsx.exists(sourceStuff).then(
		(isSrcExists) => {
			if (!isSrcExists) {
				logger.log.error('Failed to move a [%s] source item to [%s] destination item. Reason : source item doesn\'t exist', sourceStuff, destStuff);
				return Promise.reject('Source item doesn\'t exist');
			}

			const destItem = path.join(destStuff, path.basename(sourceStuff));

			return fsx.exists(destItem).then(
				(isDestExists) => {
					if (isDestExists) {
						logger.log.error('Failed to move a [%s] source item to [%s] destination item. Reason : destination item already exists', sourceStuff, destItem);
						return Promise.reject('Destination item already exist');
					}

					// moving...
					return fsx.move(sourceStuff, destItem);
				}
			);
		}
	);
}

function move(source, dest) {
	const data = {};
	return assembleStorageFilePath(source)
		.then(sourceFullPath => Promise.resolve(data.sourceFullPath = sourceFullPath))
		.then(_ => assembleStorageDirPath(dest))
		.then(destFullPath => Promise.resolve(data.destFullPath = destFullPath))
		.then(_ => moveInner(data.sourceFullPath, data.destFullPath))
		.then(cacheStorageFiles);
}

function listDirItems(fullPath) {
	const dirItems = [];
	const fileItems = [];

	return fsx.readdir(fullPath)
		.then(items => {
			const promises = [];

			items.forEach(item => {
				const itemFullPath = path.join(fullPath, item);
				const promise = fsx.stat(itemFullPath)
					.then(itemStat => {
						if (itemStat.isDirectory()) {
							dirItems.push(item);
						}

						if (itemStat.isFile()) {
							fileItems.push(item);
						}
					});

				promises.push(promise);
			});

			return Promise.all(promises)
				.then(items => {
					return Promise.resolve({
						dirs: dirItems,
						files: fileItems
					});
				});
		});
}

function makeDirItem(item, relativePath, subDirItems) {
	return {
		label: item,
		items: subDirItems,
		icon: uiConsts.DIR_ICON,
		value: {
			relativePath: path.join(relativePath, item),
			label: item,
			mustLoadChildItems: false,
			isDir: true
		}
	};
}

function makeFileItem(item, relativePath) {
	return {
		label: item,
		icon: uiConsts.FILE_ICON,
		value: {
			relativePath: path.join(relativePath, item),
			label: item,
			mustLoadChildItems: false,
			isDir: false
		}
	};
}

function gatherAllFiles(relativePath) {
	relativePath = relativePath || '';
	relativePath = path.join(path.sep, relativePath);
	const searchFrom = path.join(confMgmt.getNexlStorageDir(), relativePath);

	if (!utils.isDirPathValid(searchFrom)) {
		logger.log.error(`Got unacceptable path [${searchFrom}]. This path is invalid or points outside a nexl JavaScript files root dir`);
		return Promise.reject('Unacceptable path');
	}

	const dirItems = [];
	return listDirItems(searchFrom)
		.then(currentDirItems => {

			// iterating over dir items and resolving sub dir items with promises
			const promises = [];
			currentDirItems.dirs.forEach(item => {
				const subDirRelativePath = path.join(relativePath, item);
				const promise = gatherAllFiles(subDirRelativePath)
					.then(subDirItems => {
						const dirItem = makeDirItem(item, relativePath, subDirItems);
						dirItems.push(dirItem);
					});
				promises.push(promise);
			});

			// running promises to resolve sub dir items
			return Promise.all(promises)
				.then(x => {
					dirItems.sort(sortFilesFunc);
					const fileItems = [];

					// now iterating over file items
					currentDirItems.files.forEach(item => {
						const fileItem = makeFileItem(item, relativePath);
						fileItems.push(fileItem);
					});

					fileItems.sort(sortFilesFunc);

					return Promise.resolve(dirItems.concat(fileItems));
				});
		});
}

function cacheStorageFiles() {
	const storageDir = confMgmt.getNexlStorageDir();
	logger.log.debug(`Caching files list in [${storageDir}] directory`);

	return gatherAllFiles().then(
		(result) => {
			TREE_ITEMS = result;
			logger.log.debug(`Files are gathered`);
			return Promise.resolve();
		}
	);
}

function gatherFilesList(list, root) {
	for (let index in root) {
		const item = root[index];
		if (item.value.isDir === true) {
			gatherFilesList(list, item.items);
			continue;
		}

		list.push(item.value.relativePath);
	}
}

function findInFilesInner(root, data) {
	function findOccurrencesInFileRegex(fileContent, regex) {
		return fileContent.split(/\r\n|\r|\n/).map(function (line, i) {
			if (maxOccurrences < 0) {
				return;
			}
			if (line.match(regex) !== null) {
				maxOccurrences--;
				return {
					line: line,
					number: i + 1
				};
			}
		}).filter(Boolean);
	}

	function findOccurrencesInFileSimple(fileContent, aText, matchCase) {
		const text = matchCase ? aText : aText.toLowerCase();

		return fileContent.split(/\r\n|\r|\n/).map(function (aLine, i) {
			if (maxOccurrences < 0) {
				return;
			}
			const line = matchCase ? aLine : aLine.toLowerCase();
			if (line.indexOf(text) >= 0) {
				maxOccurrences--;
				return {
					line: aLine,
					number: i + 1
				};
			}
		}).filter(Boolean);
	}

	const filesList = [];
	gatherFilesList(filesList, root);

	let searchFunc, searchType;

	if (data[di.IS_REGEX]) {
		let flags = 'g';
		flags += (data[di.MATCH_CASE] ? '' : 'i');
		searchType = new RegExp(data[di.TEXT], flags);
		searchFunc = findOccurrencesInFileRegex;
	} else {
		searchType = data[di.MATCH_CASE] ? data[di.TEXT] : data[di.TEXT].toLowerCase();
		searchFunc = findOccurrencesInFileSimple;
	}

	const result = {};
	const promises = [];
	let maxOccurrences = MAX_FIND_IN_FILES_OCCURRENCES;

	filesList.forEach(fileName => {
		const fullPath = path.join(confMgmt.getNexlStorageDir(), fileName);

		if (maxOccurrences < 0) {
			return;
		}

		const promise = fsx.readFile(fullPath, {encoding: confConsts.ENCODING_UTF8}).then(fileContent => {

			if (maxOccurrences < 0) {
				return;
			}

			const occurrences = searchFunc(fileContent, searchType, data[di.MATCH_CASE]);
			if (occurrences.length > 0) {
				maxOccurrences--;
				result[fileName] = occurrences;
			}
		});
		promises.push(promise);
	});

	return Promise.all(promises).then(_ => Promise.resolve(result));
}

function findDir(dir, dirName) {
	for (let key in dir) {
		let item = dir[key];

		if (item.value.isDir !== true) {
			continue;
		}

		if (item.value.label === dirName) {
			return item;
		}
	}
}

function findInFiles(data) {
	let normalizedPath = path.normalize(data[di.RELATIVE_PATH]);

	// is root dir ?
	if (normalizedPath === path.sep) {
		return findInFilesInner(TREE_ITEMS, data);
	}

	// trimming slashes
	normalizedPath = normalizedPath.replace(/^[\\/]+|[\\/]+$/g, '');

	// searching for target dir
	const pathItems = normalizedPath.split(path.sep);
	let dir = TREE_ITEMS;

	for (let index in pathItems) {
		dir = findDir(dir, pathItems[index]);

		// relativePath doesn't exist
		if (dir === undefined) {
			return Promise.resolve({});
		}

		dir = dir.items;
	}

	return findInFilesInner(dir, data);
}

// --------------------------------------------------------------------------------
module.exports.loadFileFromStorage = loadFileFromStorage;
module.exports.saveFileToStorage = saveFileToStorage;
module.exports.mkdir = mkdir;
module.exports.deleteItem = deleteItem;
module.exports.rename = rename;
module.exports.move = move;
module.exports.findInFiles = findInFiles;

module.exports.gatherAllFiles = gatherAllFiles;

module.exports.cacheStorageFiles = cacheStorageFiles;
module.exports.getTreeItems = () => TREE_ITEMS;
// --------------------------------------------------------------------------------
<|endoftext|>


<commit_before>var cluster = require('cluster');
var net = require('net');

if (cluster.isMaster) {
  // The constraint of 4 processes allows a better comparison to the Hive
  // threading model, wherein the default libuv thread pool size is 4.
  for (var i = 0; i < 4; i++) {
    cluster.fork();
  }
} else {
  net.createServer(function(conn) {
    conn.on('data', function(data) {
      conn.end('' + eval(data.toString()));
    });
  }).listen('/tmp/hive.sock');
}
<commit_msg>Fair comparison, I suppose<commit_after>var cluster = require('cluster');
var net = require('net');

if (cluster.isMaster) {
  // The constraint of 4 processes allows a better comparison to the Hive
  // threading model, wherein the default libuv thread pool size is 4.
  for (var i = 0; i < 4; i++) {
    cluster.fork();
  }
} else {
  net.createServer(function(conn) {
    conn.on('data', function(data) {
      conn.end(JSON.stringify(eval(data.toString())));
    });
  }).listen('/tmp/hive.sock');
}
<|endoftext|>


<commit_before>import PropTypes from 'prop-types';
import React from 'react';

/**
 * Container for buttons displayed at the bottom of a form.
 *
 * Example:
 *
 * <FormActions>
 *   <FormActions.Primary>
 *     <Button>Save</Button>
 *   </FormActions.Primary>
 *   <FormActions.Secondary>
 *     <Button>Delete</Button>
 *   </FormActions.Secondary>
 * </FormActions>
 */
export default function FormActions({ children }) {
  return (

      {children}

  );
}
FormActions.propTypes = {
  children: PropTypes.node,
};
FormActions.defaultProps = {
  children: null,
};

/**
 * Container for the primary actions (floated to the right).
 */
FormActions.Primary = function FormActionsPrimary({ children }) {
  return (

{children}

  );
};
FormActions.Primary.propTypes = {
  children: PropTypes.node,
};
FormActions.Primary.defaultProps = {
  children: null,
};

/**
 * Container for the secondary actions (floated to the left).
 */
FormActions.Secondary = function FormActionsSecondary({ children }) {
  return (

{children}

  );
};
FormActions.Secondary.propTypes = {
  children: PropTypes.node,
};
FormActions.Secondary.defaultProps = {
  children: null,
};
<commit_msg>Add CreateRecipePage<commit_after>import { Spin } from 'antd';
import PropTypes from 'prop-types';
import React from 'react';

/**
 * Container for buttons displayed at the bottom of a form.
 *
 * Example:
 *
 * <FormActions>
 *   <FormActions.Primary>
 *     <Button>Save</Button>
 *   </FormActions.Primary>
 *   <FormActions.Secondary>
 *     <Button>Delete</Button>
 *   </FormActions.Secondary>
 * </FormActions>
 */
export default function FormActions({ children, isLoading }) {
  const Wrapper = isLoading ? Spin : 'span';
  return (

      <Wrapper>
        {children}
      </Wrapper>

  );
}
FormActions.propTypes = {
  children: PropTypes.node,
  isLoading: PropTypes.bool,
};
FormActions.defaultProps = {
  children: null,
  isLoading: false,
};

/**
 * Container for the primary actions (floated to the right).
 */
FormActions.Primary = function FormActionsPrimary({ children }) {
  return (

{children}

  );
};
FormActions.Primary.propTypes = {
  children: PropTypes.node,
};
FormActions.Primary.defaultProps = {
  children: null,
};

/**
 * Container for the secondary actions (floated to the left).
 */
FormActions.Secondary = function FormActionsSecondary({ children }) {
  return (

{children}

  );
};
FormActions.Secondary.propTypes = {
  children: PropTypes.node,
};
FormActions.Secondary.defaultProps = {
  children: null,
};
<|endoftext|>


<commit_before>var csv_data; // global variable with complete data

// constant
var nutritionals = [
	"nutrition_score_uk_100g",
	"nutrition_score_fr_100g",
	"sodium_100g",
	"salt_100g",
	"proteins_100g",
	"energy_100g",
	"saturated_fat_100g",
	"sugars_100g",
	"fat_100g",
	"carbohydrates_100g"
];

data = d3.csv('static/data/data.csv')
	.row(function(r) {
		return {
			product_name: r.product_name,
			code_country: r.code_country,
			category: r.pnns_groups_1,
			subcategory: r.pnns_groups_2,
			nutrition_score_uk_100g: +r["nutrition-score-uk_100g"],
			nutrition_score_fr_100g: +r["nutrition-score-fr_100g"],
			sodium_100g: +r.sodium_100g,
			salt_100g: +r.salt_100g,
			proteins_100g: +r.proteins_100g,
			energy_100g: +r.energy_100g,
			saturated_fat_100g: +r["saturated-fat_100g"],
			sugars_100g: +r.sugars_100g,
			fat_100g: +r.fat_100g,
			carbohydrates_100g: +r.carbohydrates_100g
		}
	})
	.get(function(error, rows) {
		console.log(rows);
		csv_data = rows;
	});

var test_new_data_0 = {country_id: "DEU", category: null};
var test_new_data_1 = {country_id: null, category: ["root", "Sugary sncacks"]};

function rename_nested(data, level) {
	//console.log("[RENAME_NESTED] input (data, level)");
	//console.log(data);
	//console.log(level);
	var children = [];
	if (data.values != null)
		children = data.values.map(function(d) {return rename_nested(d, level+1);});
	return {
		name: data.key,
		level: level,
		children: children
	};
}

function prune_nested(nested_data, level, category) {
	/*
	 * Prune the nested data: only one element up until "level", then all of its children
	 */
	//console.log("[PRUNE] arguments received (nested_data, level, category");
	//console.log(nested_data);
	//console.log(level);
	//console.log(category);
	var children;
	// if we are at the children we want to display
	if (nested_data.level > level) children = [];
	// if we are at the node clicked on by the user
	else if (nested_data.level === level && nested_data.name === category) {
		children = nested_data.children.map(function(d) {return prune_nested(d, level, category);});
	}
	// if we are at the brother nodes that we do not want to display
	else if (nested_data.level === level)  return null;
	// if we are at a (grand)parent or (grand)uncle nodes
	else {
		children = nested_data.children
			.map(function(d) {return prune_nested(d, level, category);})
			.filter(function(d) {return d != null;});
		// if all children are null, then we should not display the node
		if (children.length === 0) return null;
	}
	//nested_data["children"] = children;
	console.log("[PRUNE] output nested_data");
	console.log(nested_data);
	return {
		name: nested_data.name,
		level: nested_data.level,
		children: children
	};
}

function compute_data(new_data) {
	/* new_data is an object with possible fields :
	 *   country_id (string): used in case the user click on a country on the map
	 *   query (string): used in case the user click on the tree afte
	 *   level (int)
	 *   category (string)
	 */
	console.log("[COMPUTE_DATA]: received argument");
	console.log(new_data);
	var country_id_list;
	var nested_data;
	var stats;
	// Reset case
	if("query" in new_data && new_data.query === "reset") {
		// we compute the tree
		nested_data = {
			name: "root",
			level: 0,
			children: d3.nest()
				.key(function(d) { return d.category; })
				.rollup(function(l) { return null; })
				.entries(csv_data)
				.map(function(d) {
					return {
						name: d.key,
						level: 1,
						children: []
					};
				})
		};
		// we compute the stats
		stats = nutritionals.map(function(n) {
			return {name: n,
				mean: d3.mean(csv_data, function(d) { return d[n] })};
		});
		// and we only show the selected contry
		country_id_list = [];
		query = new_data.country_id;
	}
	// Fist case : the country_id
	else if("country_id" in new_data && new_data.country_id != null) {
		// we filter on the selected country
		var useful_data = csv_data.filter(function(d) {
			return (d.code_country === new_data.country_id)
		});
		// we compute the tree
		nested_data = {
			name: "root",
			level: 0,
			children: d3.nest()
				.key(function(d) { return d.category; })
				.rollup(function(l) { return null; })
				.entries(useful_data)
				.map(function(d) {
					return {
						name: d.key,
						level: 1,
						children: []
					};
				})
		};
		// we compute the stats
		stats = nutritionals.map(function(n) {
			return {name: n,
				mean: d3.mean(useful_data, function(d) { return d[n] })};
		});
		// and we only show the selected contry
		country_id_list = [new_data.country_id];
		query = new_data.country_id;
	}
	// First case next step : a category or a product has been selected
	else if ("category" in new_data && new_data.category != null &&
		 "level" in new_data && new_data.level != null &
		 "query" in new_data && new_data.query != null) {
		console.log("manage category !");
		// we filter on the selected country
		var useful_data = csv_data.filter(function(d) {
			return (d.code_country === new_data.query)
		});
		// we compute the tree
		nested_data = {
			name: "root",
			level: 0,
			children: d3.nest()
				.key(function(d) { return d.category; })
				.key(function(d) { return d.subcategory; })
				.key(function(d) { return d.product_name; })
				.rollup(function(l) { return null; })
				.entries(useful_data)
				.map(function(d) {return rename_nested(d, 1);})
		};
		// we prune the tree
		console.log("[COMPUTE_DATA]: full tree before pruning");
		console.log(nested_data);

		nested_data = prune_nested(nested_data, new_data.level, new_data.category);

		console.log("[COMPUTE_DATA]: tree after pruning");
		console.log(nested_data);

		// we compute the stats
		stats = nutritionals.map(function(n) {
			return {name: n,
				mean: d3.mean(useful_data, function(d) { return d[n] })};
		});
		// and we only show the selected contry
		country_id_list = [query];
		query = new_data.query;
	}
	update_all({
		country_id_list: country_id_list,
		tree: nested_data,
		stats: stats,
		query: query
	});
}

function update_all(data) {
	console.log("update_all");
	console.log(data);

	update_map(data.country_id_list);
	update_tree(data.tree,data.query);
	//update_bars(data.stats);
}
<commit_msg>call update_bars with stats object<commit_after>var csv_data; // global variable with complete data

// constant
var nutritionals = [
	"nutrition_score_uk_100g",
	"nutrition_score_fr_100g",
	"sodium_100g",
	"salt_100g",
	"proteins_100g",
	"energy_100g",
	"saturated_fat_100g",
	"sugars_100g",
	"fat_100g",
	"carbohydrates_100g"
];

data = d3.csv('static/data/data.csv')
	.row(function(r) {
		return {
			product_name: r.product_name,
			code_country: r.code_country,
			category: r.pnns_groups_1,
			subcategory: r.pnns_groups_2,
			nutrition_score_uk_100g: +r["nutrition-score-uk_100g"],
			nutrition_score_fr_100g: +r["nutrition-score-fr_100g"],
			sodium_100g: +r.sodium_100g,
			salt_100g: +r.salt_100g,
			proteins_100g: +r.proteins_100g,
			energy_100g: +r.energy_100g,
			saturated_fat_100g: +r["saturated-fat_100g"],
			sugars_100g: +r.sugars_100g,
			fat_100g: +r.fat_100g,
			carbohydrates_100g: +r.carbohydrates_100g
		}
	})
	.get(function(error, rows) {
		console.log(rows);
		csv_data = rows;
	});

var test_new_data_0 = {country_id: "DEU", category: null};
var test_new_data_1 = {country_id: null, category: ["root", "Sugary sncacks"]};

function rename_nested(data, level) {
	//console.log("[RENAME_NESTED] input (data, level)");
	//console.log(data);
	//console.log(level);
	var children = [];
	if (data.values != null)
		children = data.values.map(function(d) {return rename_nested(d, level+1);});
	return {
		name: data.key,
		level: level,
		children: children
	};
}

function prune_nested(nested_data, level, category) {
	/*
	 * Prune the nested data: only one element up until "level", then all of its children
	 */
	//console.log("[PRUNE] arguments received (nested_data, level, category");
	//console.log(nested_data);
	//console.log(level);
	//console.log(category);
	var children;
	// if we are at the children we want to display
	if (nested_data.level > level) children = [];
	// if we are at the node clicked on by the user
	else if (nested_data.level === level && nested_data.name === category) {
		children = nested_data.children.map(function(d) {return prune_nested(d, level, category);});
	}
	// if we are at the brother nodes that we do not want to display
	else if (nested_data.level === level)  return null;
	// if we are at a (grand)parent or (grand)uncle nodes
	else {
		children = nested_data.children
			.map(function(d) {return prune_nested(d, level, category);})
			.filter(function(d) {return d != null;});
		// if all children are null, then we should not display the node
		if (children.length === 0) return null;
	}
	//nested_data["children"] = children;
	//console.log("[PRUNE] output nested_data");
	//console.log(nested_data);
	return {
		name: nested_data.name,
		level: nested_data.level,
		children: children
	};
}

function compute_data(new_data) {
	/* new_data is an object with possible fields :
	 *   country_id (string): used in case the user click on a country on the map
	 *   query (string): used in case the user click on the tree afte
	 *   level (int)
	 *   category (string)
	 */
	console.log("[COMPUTE_DATA]: received argument");
	console.log(new_data);
	var country_id_list;
	var nested_data;
	var stats;
	// Reset case
	if("query" in new_data && new_data.query === "reset") {
		// we compute the tree
		nested_data = {
			name: "root",
			level: 0,
			children: d3.nest()
				.key(function(d) { return d.category; })
				.rollup(function(l) { return null; })
				.entries(csv_data)
				.map(function(d) {
					return {
						name: d.key,
						level: 1,
						children: []
					};
				})
		};
		// and we only show the selected contry
		country_id_list = [];
		query = new_data.country_id;
	}
	// Fist case : the country_id
	else if("country_id" in new_data && new_data.country_id != null) {
		// we filter on the selected country
		var useful_data = csv_data.filter(function(d) {
			return (d.code_country === new_data.country_id)
		});
		// we compute the tree
		nested_data = {
			name: "root",
			level: 0,
			children: d3.nest()
				.key(function(d) { return d.category; })
				.rollup(function(l) { return null; })
				.entries(useful_data)
				.map(function(d) {
					return {
						name: d.key,
						level: 1,
						children: []
					};
				})
		};
		// and we only show the selected contry
		country_id_list = [new_data.country_id];
		query = new_data.country_id;
	}
	// First case next step : a category or a product has been selected
	else if ("category" in new_data && new_data.category != null &&
		 "level" in new_data && new_data.level != null &
		 "query" in new_data && new_data.query != null) {
		console.log("manage category !");
		// we filter on the selected country
		var useful_data = csv_data.filter(function(d) {
			return (d.code_country === new_data.query)
		});
		// we compute the tree
		nested_data = {
			name: "root",
			level: 0,
			children: d3.nest()
				.key(function(d) { return d.category; })
				.key(function(d) { return d.subcategory; })
				.key(function(d) { return d.product_name; })
				.rollup(function(l) { return null; })
				.entries(useful_data)
				.map(function(d) {return rename_nested(d, 1);})
		};
		// we prune the tree
		console.log("[COMPUTE_DATA]: full tree before pruning");
		console.log(nested_data);

		nested_data = prune_nested(nested_data, new_data.level, new_data.category);

		console.log("[COMPUTE_DATA]: tree after pruning");
		console.log(nested_data);

		// and we only show the selected contry
		country_id_list = [query];
		query = new_data.query;
	}
	// we compute the stats
	stats = {
		product: null,
		others: {
			name: "All Products",
			data: nutritionals.map(function(n) {
				return {
					name: n,
					mean: d3.mean(csv_data, function(d) { return d[n] })
				};
			})
		}
	};
	update_all({
		country_id_list: country_id_list,
		tree: nested_data,
		stats: stats,
		query: query
	});
}

function update_all(data) {
	console.log("update_all");
	console.log(data);

	update_map(data.country_id_list);
	update_tree(data.tree,data.query);
	update_bars(data.stats);
}
<|endoftext|>