<commit_before>import Q from 'q';
import * as fs from 'fs';
import * as toml from 'toml';
import _ from 'lodash';

import Trello from 'node-trello';
import { PivotalClient as Pivotal } from './pivotal';

const config = toml.parse(fs.readFileSync('config.toml'));

Q.longStackSupport = true;

function storyify(card) {
    let story = {
        name: card.name,
        description: card.desc,
        story_type: 'feature',
        labels: [],
    };
    for (let label of card.labels) {
        switch (label.name) {
        case 'Urgent to be done':
        case 'Needs to be done':
            story.current_state = 'unstarted';
            break;
        case 'Good idea to do':
        case 'Nice to do':
        case 'Icebox':
            story.current_state = 'unscheduled';
            break;
        case 'Bug':
            story.story_type = 'bug';
            break;
        default:
            story.labels.push({ name: label.name });
        }
    }
    return story;
}

async function fn2() {
    let trelloAPI = new Trello(config.trello.key, config.trello.token);
    let pivotalAPI = new Pivotal(config.pivotal.token);

    const trelloGet = Q.nbind(trelloAPI.get, trelloAPI);

    const ptLogin = trelloGet('/1/members/me').then((me) => console.info("Logged in to trello as %s!", me.fullName));
    const ppLogin = pivotalAPI.get('/me').then((me) => console.info("Logged into Pivotal as %s!", me.name));

    await Q.all([ptLogin, ppLogin]);

    const boardURL = `/1/boards/${config.trello.board}`;

    let cards = trelloGet(`${boardURL}/cards/visible/`)
        .then((ret) => ret.filter((card) => _.includes(config.trello.lists, card.idList)));

    for (let card of await cards) {
        // console.info(card);
        console.info('Transfering across card "%s"!', card.name);
        let story = await pivotalAPI.post(`/projects/${config.pivotal.project}/stories`, storyify(card));
        console.info('Created story %s!', story.id);
        // break;
    }
}

(async function() {
    try {
        await fn2();
    } catch (e) {
        console.error('Something went wrong: ', e);
    }
})();
<commit_msg>Match users between projects<commit_after>import Q from 'q';
import * as fs from 'fs';
import * as toml from 'toml';
import _ from 'lodash';

import Trello from 'node-trello';
import { PivotalClient as Pivotal } from './pivotal';

const config = toml.parse(fs.readFileSync('config.toml'));

Q.longStackSupport = true;

let memberMap = new Map();

function storyify(card) {
    let story = {
        name: card.name,
        description: card.desc,
        story_type: 'feature',
        labels: [],
    };
    for (let label of card.labels) {
        switch (label.name) {
        case 'Urgent to be done':
        case 'Needs to be done':
            story.current_state = 'unstarted';
            break;
        case 'Good idea to do':
        case 'Nice to do':
        case 'Icebox':
            story.current_state = 'unscheduled';
            break;
        case 'Bug':
            story.story_type = 'bug';
            break;
        default:
            story.labels.push({ name: label.name });
        }
    }
    return story;
}

function nameContains(a, b) {
    return a.indexOf(b) !== -1;
}

async function fn2() {
    let trelloAPI = new Trello(config.trello.key, config.trello.token);
    let pivotalAPI = new Pivotal(config.pivotal.token);

    const trelloGet = Q.nbind(trelloAPI.get, trelloAPI);

    const ptLogin = trelloGet('/1/members/me').then((me) => console.info("Logged in to trello as %s!", me.fullName));
    const ppLogin = pivotalAPI.get('/me').then((me) => console.info("Logged into Pivotal as %s!", me.name));

    await Q.all([ptLogin, ppLogin]);

    const boardURL = `/1/boards/${config.trello.board}`;
    const projectURL = `/projects/${config.pivotal.project}`;

    const ptMembers = trelloGet(`${boardURL}/members`, { fields: 'fullName' });
    const ppMembers = pivotalAPI.get(`${projectURL}/memberships`, { fields: 'person(name)' }).then((members) => _.map(members, 'person'));

    const [trelloMembers, pivotalMembers] = await Promise.all([ptMembers, ppMembers]);

    for (let tMember of trelloMembers) {
        let tName = tMember.fullName.toLowerCase();
        for (let pMember of pivotalMembers) {
            let pName = pMember.name.toLowerCase();
            if (tName === pName || nameContains(tName, pName) || nameContains(pName, tName)) {
                memberMap.set(tMember.id, pMember.id);
                pivotalMembers.splice(pivotalMembers.indexOf(pMember), 1);
                console.info("Matched Trello user %s (%s) with Pivotal User %s (%s)!", tName, tMember.id, pName, pMember.id);
                break;
            }
        }
    }

    let cards = trelloGet(`${boardURL}/cards/visible/`)
        .then((ret) => ret.filter((card) => _.includes(config.trello.lists, card.idList)));

    for (let card of await cards) {
        // console.info(card);
        console.info('Transfering across card "%s"!', card.name);
        let story = await pivotalAPI.post(`${projectURL}/stories`, storyify(card));
        console.info('Created story %s!', story.id);
        // break;
    }
}

(async function() {
    try {
        await fn2();
    } catch (e) {
        console.error('Something went wrong: ', e);
    }
})();
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 Limerun Project Contributors
 * Portions Copyright (c) 2015 Internet of Protocols Assocation (IOPA)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var Server = require('./src/server/udpServer.js');
var Client = require('./src/server/udpClient.js');

module.exports.createServer = function(options, appFunc){return new Server(options, appFunc);}
module.exports.Server = Server;
module.exports.Client = Client;
<commit_msg>copyright<commit_after>/*
 * Copyright (c) 2015 Internet of Protocols Alliance (IOPA)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var Server = require('./src/server/udpServer.js');
var Client = require('./src/server/udpClient.js');

module.exports.createServer = function(options, appFunc){return new Server(options, appFunc);}
module.exports.Server = Server;
module.exports.Client = Client;
<|endoftext|>


<commit_before>import {run, Rx} from '@cycle/core';
import {makeDOMDriver, h} from '@cycle/dom';
import CycleTimeTravel from 'cycle-time-travel';
import $ from 'jquery';
import _ from 'lodash';
import rhyme from 'rhyme';

const INSTRUCTIONS = `
Write your sick raps in the text box below.

Reach the end of the line and don't know where to go?

Hit TAB on your keyboard or RHYME on the screen

And there you will find the word for your scheme

Don't like it? That's cool, hit it again

You'll get a new rhyme for your rap and then

Impress all your friends with your linguistic skill

And do it again, now you know the drill.

Ghostwriter supports an AA BB rhyming scheme. Have fun, y'all!
`;

Rx.config.longStackSupport = true;

function log (label) {
  return console.log.bind(console, label);
}

function keyPressed (key, number) {
  return ev => {
    return ev.key === key || ev.keyIdentifier === key || ev.keyCode === number;
  };
}

function appendNextRhyme (wordToRhyme, state, madeRhyme) {
  if (wordToRhyme === state.lastWord) {
    const words = state.text.split(' ');

    const textWithoutRhyme = words
      .slice(0, words.length - 1)
      .join(' ');

    return `${textWithoutRhyme} ${madeRhyme.toLowerCase()}`;
  } else {
    return `${state.text} ${madeRhyme.toLowerCase()}`;
  }
}

function addRhyme (rhymingDictionary) {
  return state => {
    const wordToRhyme = lastWord(state.text);
    const availableRhymes = rhymingDictionary.rhyme(wordToRhyme);
    const madeRhyme = _.shuffle(availableRhymes).slice(0, 1)[0];

    if (_.isEmpty(availableRhymes)) {
      return Object.assign({}, state, {notification: 'No Rhymes'});
    }

    const text = appendNextRhyme(wordToRhyme, state, madeRhyme);

    const stateUpdates = {
      text,
      notification: '',
      lastWord: wordToRhyme
    };

    return Object.assign({}, state, stateUpdates);
  };
}

function lastWord (text) {
  return _.chain(text.split('\n'))
    .map(_.trim)
    .select(line => line !== '')
    .map(line => line.split(' '))
    .thru(lines => {
      if (lines.length > 1) {
        return lines[lines.length - 2];
      }

      return _.last(lines);
    })
    .last().value();
}

function updateText (textEnteredByUser) {
  return state => Object.assign({}, state, {text: textEnteredByUser, notification: ''});
}

function toggleInstructionVisibility (state) {
  return Object.assign(
    {},
    state,
    {instructionsVisible: !state.instructionsVisible}
  );
}

function main ({DOM}) {
  const toggleInstructionVisibility$ = DOM
    .select('.toggle-instructions')
    .events('click')
    .map(_ => toggleInstructionVisibility);

  const textUpdate$ = DOM.select('.text').events('input')
    .map(event => event.target.value);

  const keyPress$ = DOM.select('.container').events('keydown');

  const tabPress$ = keyPress$.filter(keyPressed('Tab', 9));

  const rhymePress$ = Rx.Observable.merge(
    tabPress$,
    DOM.select('.rhyme').events('click')
  );

  const rhymingDictionary$ = Rx.Observable.fromCallback(rhyme)();

  rhymePress$.forEach(ev => ev.preventDefault());

  const action$ = Rx.Observable.merge(
    rhymePress$.withLatestFrom(rhymingDictionary$, (ev, rhymingDictionary) => addRhyme(rhymingDictionary)),
    textUpdate$.map(text => updateText(text)),
    toggleInstructionVisibility$
  );

  const initialState = {
    text: '',
    notification: '',
    instructionsVisible: true
  };

  const state$ = action$.scan((state, action) => action(state), initialState)
    .startWith(initialState)
    .do(function (state) {
      console.log('state', JSON.stringify(state));
    });

  return {
    DOM: state$.map(({text, notification, instructionsVisible}) => (
      h('.container', [
        h('button.toggle-instructions', `${instructionsVisible ? 'HIDE' : 'SHOW'} INSTRUCTIONS`),
        h('.instructions', {innerHTML: INSTRUCTIONS, style: {display: instructionsVisible ? 'block' : 'none'}}),
        h('.app-inner', [
          h('button.rhyme', 'RHYME'),
          h('.text', [
            h('.notification', notification),
            h('textarea', {rows: 18, value: text})
          ])
        ])
      ])
    ))
  };
}

const drivers = {
  DOM: makeDOMDriver('.app')
};

$(() => run(main, drivers));
<commit_msg>Adds support for ABAB rhyme scheme, closes #5<commit_after>import {run, Rx} from '@cycle/core';
import {makeDOMDriver, h} from '@cycle/dom';
import CycleTimeTravel from 'cycle-time-travel';
import $ from 'jquery';
import _ from 'lodash';
import rhyme from 'rhyme';

const INSTRUCTIONS = `
Write your sick raps in the text box below.

Reach the end of the line and don't know where to go?

Hit TAB on your keyboard or RHYME on the screen

And there you will find the word for your scheme

Don't like it? That's cool, hit it again

You'll get a new rhyme for your rap and then

Impress all your friends with your linguistic skill

And do it again, now you know the drill.

`;

Rx.config.longStackSupport = true;

function log (label) {
  return console.log.bind(console, label);
}

function keyPressed (key, number) {
  return ev => {
    return ev.key === key || ev.keyIdentifier === key || ev.keyCode === number;
  };
}

function appendNextRhyme (wordToRhyme, state, madeRhyme) {
  if (wordToRhyme === state.lastWord) {
    const words = state.text.split(' ');

    const textWithoutRhyme = words
      .slice(0, words.length - 1)
      .join(' ');

    return `${textWithoutRhyme.trim()} ${madeRhyme.toLowerCase()}`;
  } else {
    return `${state.text.trim()} ${madeRhyme.toLowerCase()}`;
  }
}

function addRhyme (rhymingDictionary) {
  return state => {
    const wordToRhyme = findWordToRhyme(state);
    const availableRhymes = rhymingDictionary.rhyme(wordToRhyme);
    const madeRhyme = _.shuffle(availableRhymes).slice(0, 1)[0];

    if (_.isEmpty(availableRhymes)) {
      return Object.assign({}, state, {notification: 'No Rhymes'});
    }

    const text = appendNextRhyme(wordToRhyme, state, madeRhyme);

    const stateUpdates = {
      text,
      notification: '',
      lastWord: wordToRhyme
    };

    return Object.assign({}, state, stateUpdates);
  };
}

function selectRhymeScheme (rhymeScheme) {
  return state => Object.assign({}, state, {rhymeScheme});
}

function findWordToRhyme (state) {
  const lineToRhymeWith = {
    'AABB': 1,
    'ABAB': 2
  };

  return lastWord(state.text, lineToRhymeWith[state.rhymeScheme]);
}

function lastWord (text, lineOffset) {
  return _.chain(text.split('\n'))
    .map(_.trim)
    .select(line => line !== '')
    .map(line => line.split(' '))
    .thru(lines => {
      if (lines.length > lineOffset) {
        return lines[lines.length - 1 - lineOffset];
      }

      return _.last(lines);
    })
    .last().value();
}

function updateText (textEnteredByUser) {
  return state => Object.assign({}, state, {text: textEnteredByUser, notification: ''});
}

function toggleInstructionVisibility (state) {
  return Object.assign(
    {},
    state,
    {instructionsVisible: !state.instructionsVisible}
  );
}

function main ({DOM}) {
  const toggleInstructionVisibility$ = DOM
    .select('.toggle-instructions')
    .events('click')
    .map(_ => toggleInstructionVisibility);

  const textUpdate$ = DOM.select('.text').events('input')
    .map(event => event.target.value);

  const keyPress$ = DOM.select('.container').events('keydown');

  const tabPress$ = keyPress$.filter(keyPressed('Tab', 9));

  const rhymePress$ = Rx.Observable.merge(
    tabPress$,
    DOM.select('.rhyme').events('click')
  );

  const selectRhymeScheme$ = DOM
    .select('.rhyme-schemes input')
    .events('change')
    .map(event => selectRhymeScheme(event.target.value));

  const rhymingDictionary$ = Rx.Observable.fromCallback(rhyme)();

  rhymePress$.forEach(ev => ev.preventDefault());

  const action$ = Rx.Observable.merge(
    rhymePress$.withLatestFrom(rhymingDictionary$, (ev, rhymingDictionary) => addRhyme(rhymingDictionary)),
    textUpdate$.map(text => updateText(text)),
    toggleInstructionVisibility$,
    selectRhymeScheme$
  );

  const initialState = {
    text: '',
    notification: '',
    instructionsVisible: true,
    rhymeScheme: 'AABB'
  };

  const state$ = action$.scan((state, action) => action(state), initialState)
    .startWith(initialState)
    .do(function (state) {
      console.log('state', JSON.stringify(state));
    });

  return {
    DOM: state$.map(({text, notification, instructionsVisible, rhymeScheme}) => (
      h('.container', [
        h('button.toggle-instructions', `${instructionsVisible ? 'HIDE' : 'SHOW'} INSTRUCTIONS`),
        h('.instructions', {innerHTML: INSTRUCTIONS, style: {display: instructionsVisible ? 'block' : 'none'}}),
        h('.app-inner', [
          h('button.rhyme', 'RHYME'),
          h('a', {href: 'https://www.wikiwand.com/en/Rhyme_scheme', target: '_blank'}, 'SELECT A RHYME SCHEME'),
          h('.rhyme-schemes', [
            h('input', {type: 'radio', value: 'AABB', name:'rhyme-scheme', checked: true}),
            h('label', 'AABB'),
            h('input', {type: 'radio', name:'rhyme-scheme', value: 'ABAB'}),
            h('label', 'ABAB')
          ]),
          h('.text', [
            h('.notification', notification),
            h('textarea', {rows: 18, value: text})
          ])
        ])
      ])
    ))
  };
}

const drivers = {
  DOM: makeDOMDriver('.app')
};

$(() => run(main, drivers));
<|endoftext|>


<commit_before>/**
 * Expose `getElementCenter`
 */

module.exports = getElementCenter;

/**
 * Get an `element`s center (x,y)
 * @param {Object} element
 * @returns {Object}
 */

function getElementCenter(element) {
  var dimensions = element.getBoundingClientRect();
  var centerYCoord = element.offsetTop + (dimensions.height / 2);
  var centerXCoord = dimensions.left + (dimensions.width / 2);
  return {
    y: centerYCoord,
    x: centerXCoord
  };
}
<commit_msg>account for parent elements being positioned relatively<commit_after>/**
 * Expose `getElementCenter`
 */

module.exports = getElementCenter;

/**
 * Get an `element`s center (x,y)
 * @param {Object} element
 * @returns {Object}
 */

function getElementCenter(element) {
  var dimensions = element.getBoundingClientRect();
  var centerYCoord = element.top + window.pageYOffset + (dimensions.height / 2);
  var centerXCoord = dimensions.left window.pageXOffset + (dimensions.width / 2);
  return {
    y: centerYCoord,
    x: centerXCoord
  };
}
<|endoftext|>


<commit_before>"use strict"

var fs = require('fs')
var path = require("path")
var debug = require('debug')('linklocal')
var once = require('once')
var mkdirp = require('mkdirp')
var rimraf = require('rimraf')
var assert = require('assert')
var map = require('map-limit')

var linklocal = module.exports = function linklocal(dirpath, pkgpath, done) {
  if (arguments.length === 2) {
    done = pkgpath
    pkgpath = path.resolve(dirpath, 'package.json')
    return linklocal(dirpath, pkgpath, done)
  }
  assert.equal(typeof dirpath, 'string', 'dirpath should be a string')
  assert.equal(typeof pkgpath, 'string', 'pkgpath should be a string')
  assert.equal(typeof done, 'function', 'done should be a function')

  done = once(done)
  var node_modules = path.join(
    path.resolve(dirpath),
    'node_modules'
  )
  getLocals(dirpath, pkgpath, function(err, locals) {
    if (err) return done(err)
    doLink(locals, node_modules, done)
  })
}

module.exports.link = module.exports

module.exports.link.recursive = function linklocalRecursive(dirpath, pkgpath, done) {
  if (arguments.length === 2) {
    done = pkgpath
    pkgpath = path.resolve(dirpath, 'package.json')
    return linklocal.recursive(dirpath, pkgpath, done)
  }
  assert.equal(typeof dirpath, 'string', 'dirpath should be a string')
  assert.equal(typeof pkgpath, 'string', 'pkgpath should be a string')
  assert.equal(typeof done, 'function', 'done should be a function')

  done = once(done)
  var allLinkedDirs = []

  _linklocalRecursive(pkgpath, done)

  function _linklocalRecursive(pkgpath, done) {
    _linklocal(pkgpath, function(err, linkedDirs) {
      if (err) return done(err)
      linkedDirs = linkedDirs || []
      map(linkedDirs, 1, function(link, next) {
        _linklocalRecursive(path.resolve(link.src, 'package.json'), function(err, moreLinks) {
          if (err) return next(err)
          return next(null, [link].concat(moreLinks || []))
        })
      }, function(err, links) {
        if (err) return done(err)
        done(null, links.reduce(function(all, cur) {
          return all.concat(cur)
        }, []))
      })
    })
  }
}

function _linklocal(pkgpath, done) {
  assert.equal(typeof pkgpath, 'string', 'pkgpath should be a string')
  assert.equal(typeof done, 'function', 'done should be a function')
  done = once(done)
  var realPkgPath = fs.realpathSync(path.dirname(pkgpath))
  linklocal(realPkgPath, pkgpath, function(err, linkedDirs) {
    if (err) return done(err)
    done(null, linkedDirs)
  })
}

module.exports.unlink = function unlinklocal(dirpath, pkgpath, done) {
  if (arguments.length === 2) {
    done = pkgpath
    pkgpath = path.resolve(dirpath, 'package.json')
    return unlinklocal(dirpath, pkgpath, done)
  }
  assert.equal(typeof dirpath, 'string', 'dirpath should be a string')
  assert.equal(typeof pkgpath, 'string', 'pkgpath should be a string')
  assert.equal(typeof done, 'function', 'done should be a function')

  done = once(done)
  var node_modules = path.join(
    path.resolve(dirpath),
    'node_modules'
  )

  getLocals(dirpath, pkgpath, function(err, locals) {
    if (err) return done(err)
    doUnlink(locals, node_modules, done)
  })
}

module.exports.unlink.recursive = function unlinklocalRecursive(dirpath, pkgpath, done) {
  if (arguments.length === 2) {
    done = pkgpath
    pkgpath = path.resolve(dirpath, 'package.json')
    return linklocal.unlink.recursive(dirpath, pkgpath, done)
  }
  assert.equal(typeof dirpath, 'string', 'dirpath should be a string')
  assert.equal(typeof pkgpath, 'string', 'pkgpath should be a string')
  assert.equal(typeof done, 'function', 'done should be a function')

  done = once(done)
  findLinks(pkgpath, fs.realpathSync(pkgpath), function(err, links) {
    if (err) return done(err)
    map(links, Infinity, function(link, next) {
      fs.realpath(path.dirname(link), function(err, realPath) {
        if (err) return next(err)
        next(null, path.join(realPath, path.basename(link)))
      })
    }, function(err, links) {
      if (err) return done(err)
      links = links.filter(function(item, index, arr) {
        return arr.indexOf(item) === index
      })
      .sort(function(dirA, dirB) {
        if (dirA === dirB) return 0
        if (dirB.indexOf(dirA) === 0) return 1
        return -1
      })
      map(links, Infinity, function(item, next) {
        fs.lstat(item, function(err, stat) {
          if (err) return next(err)
          return next(null, stat.isSymbolicLink())
        })
      }, function(err, isSymbolicLink) {
        if (err) return done(err)
        var symlinks = links.filter(function(link, i) {
          return isSymbolicLink[i]
        })
        map(symlinks, Infinity, function(symlink, next) {
          fs.readlink(symlink, function(err, rel) {
            if (err) return next(err)
            var src = path.resolve(symlink, rel)
            fs.unlink(symlink, function(err) {
              if (err) return next(err)
              next(null, {src: src, link: symlink})
            })
          })
        }, done)
      })
    })
  })

  function findLinks(pkgpath, realPath, done) {
    assert.equal(typeof pkgpath, 'string', 'pkgpath should be a string')
    done = once(done)

    var pkgDirpath = path.dirname(pkgpath)
    var realDirpath = fs.realpathSync(path.dirname(realPath))
    var node_modules = path.join(
      path.resolve(pkgDirpath),
      'node_modules'
    )

    var links = []
    getLocals(realDirpath, pkgpath, function(err, locals) {
      if (err) return done(err)
      var pending = 0
      var links = locals.filter(function(dir) {
        return fs.existsSync(dir)
      }).map(function(dir) {
        var pkg = JSON.parse(fs.readFileSync(path.resolve(dir, 'package.json')))
        var name = pkg.name
        return path.join(node_modules, name)
      }).filter(function(dir) {
        return fs.existsSync(dir)
      })
      if (!links.length) return done(null, links)
      links.forEach(function(dir) {
        links.push(dir)
        pending++
        findLinks(path.resolve(dir, 'package.json'), path.resolve(dir, 'package.json'), function(err, subLinks) {
          if (err) return done(err)
          links = links.concat(subLinks)
          if (!--pending) return done(null, links)
        })
      })
    })
  }
}

function getLocals(dirpath, pkgpath, done) {
  fs.realpath(dirpath, function(err, dirpath) {
    if (err) return done(err)
    fs.realpath(pkgpath, function(err, pkgpath) {
      if (err) return done(err)
      assert.equal(typeof dirpath, 'string', 'dirpath should be a string')
      assert.equal(typeof pkgpath, 'string', 'pkgpath should be a string')
      var pkg = JSON.parse(fs.readFileSync(pkgpath))
      var deps = getDependencies(pkg)
      var locals = Object.keys(deps).filter(function(name) {
        var val = deps[name]
        return isLocal(val)
      }).map(function(name) {
        var pkgPath = deps[name]
        pkgPath = pkgPath.replace(/^file:/g, '')
        return path.resolve(dirpath, pkgPath)
      })
      done(null, locals)
    })
  })
}

function getDependencies(pkg) {
  var deps = pkg.dependencies || {}
  var devDependencies = pkg.devDependencies || {}
  for (var name in devDependencies) {
    deps[name] = devDependencies[name]
  }
  return deps
}

function isLocal(val) {
  return (
    val.indexOf('.') === 0 ||
    val.indexOf('/') === 0 ||
    val.indexOf('file:') === 0
  )
}

function doLink(packages, node_modules, done) {
  packages = packages || []
  var pending = packages.length
  var dests = []
  if (!packages.length) return done(null, [])
  packages.forEach(function(dir) {
    fs.realpath(dir, function(err, dir) {
      if (err) return done(err)
      var pkg = require(path.resolve(dir, 'package.json'))
      var name = pkg.name
      var dest = path.join(node_modules, name)
      var rel = path.relative(path.dirname(dest), dir)
      mkdirp(path.dirname(dest), function(err) {
        if (err && err.code !== 'EEXISTS') return done(err)
        fs.realpath(dest, function(err, realPath) {
          if (err && err.code !== 'ENOENT') return done(err)
          if (realPath && dest !== realPath) {
            rel = path.relative(dest, dir)
            if (realPath === dir) return skip()
          }
          fs.lstat(dest, function(err, stat) {
            if (err && err.code === 'ENOENT') return link()
            if (err) return done(err)
            if (!stat.isSymbolicLink()) return rimraf(dest, link)
            fs.unlink(dest, link)
          })
        })
      })

      function link(err) {
        if (err) return done(err)
        fs.symlink(rel, dest, 'junction', bump)
      }

      function bump(err) {
        if (err) return done(err)
        fs.realpath(path.dirname(dest), function(err, realPath) {
          dest = path.join(realPath, path.basename(dest))
          dests.push({link: dest, src: dir})
          debug('Linked ' + name + ' into ./' + path.relative(process.cwd(), dest))
          if (!--pending) return done(null, dests)
        })
      }

      function skip(err) {
        if (err) return done(err)
        if (!--pending) return done(null, dests)
      }
    })
  })
}

function doUnlink(packages, node_modules, done) {
  packages = packages || []
  var pending = packages.length
  var dests = []
  if (!packages.length) return done(null, [])
  packages.forEach(function(dir) {
    fs.realpath(dir, function(err, dir) {
      if (err) return done(err)
      var pkg = require(path.resolve(dir, 'package.json'))
      var name = pkg.name
      var dest = path.join(node_modules, name)
      fs.lstat(dest, function(err, stat) {
        if (err && err.code === 'ENOENT') return bump()
        if (err) return done(err)
        if (!stat || !stat.isSymbolicLink()) return bump()
        fs.readlink(dest, function(err, src) {
          if (err) return done(err)
          fs.unlink(dest, function(err) {
            if (err) return done(err)
            fs.realpath(path.dirname(dest), function(err, realPath) {
              if (err) return done(err)
              dest = path.join(realPath, path.basename(dest))
              dests.push({link: dest, src: src})
              debug('Unlinked ' + name + ' from ./' + path.relative(process.cwd(), dest))
              bump()
            })
          })
        })
      })

      function bump() {
        if (!--pending) return done(null, dests)
      }
    })
  })
}
<commit_msg>Fix linklocal unlink destination paths.<commit_after>"use strict"

var fs = require('fs')
var path = require("path")
var debug = require('debug')('linklocal')
var once = require('once')
var mkdirp = require('mkdirp')
var rimraf = require('rimraf')
var assert = require('assert')
var map = require('map-limit')

var linklocal = module.exports = function linklocal(dirpath, pkgpath, done) {
  if (arguments.length === 2) {
    done = pkgpath
    pkgpath = path.resolve(dirpath, 'package.json')
    return linklocal(dirpath, pkgpath, done)
  }
  assert.equal(typeof dirpath, 'string', 'dirpath should be a string')
  assert.equal(typeof pkgpath, 'string', 'pkgpath should be a string')
  assert.equal(typeof done, 'function', 'done should be a function')

  done = once(done)
  var node_modules = path.join(
    path.resolve(dirpath),
    'node_modules'
  )
  getLocals(dirpath, pkgpath, function(err, locals) {
    if (err) return done(err)
    doLink(locals, node_modules, done)
  })
}

module.exports.link = module.exports

module.exports.link.recursive = function linklocalRecursive(dirpath, pkgpath, done) {
  if (arguments.length === 2) {
    done = pkgpath
    pkgpath = path.resolve(dirpath, 'package.json')
    return linklocal.recursive(dirpath, pkgpath, done)
  }
  assert.equal(typeof dirpath, 'string', 'dirpath should be a string')
  assert.equal(typeof pkgpath, 'string', 'pkgpath should be a string')
  assert.equal(typeof done, 'function', 'done should be a function')

  done = once(done)
  var allLinkedDirs = []

  _linklocalRecursive(pkgpath, done)

  function _linklocalRecursive(pkgpath, done) {
    _linklocal(pkgpath, function(err, linkedDirs) {
      if (err) return done(err)
      linkedDirs = linkedDirs || []
      map(linkedDirs, 1, function(link, next) {
        _linklocalRecursive(path.resolve(link.src, 'package.json'), function(err, moreLinks) {
          if (err) return next(err)
          return next(null, [link].concat(moreLinks || []))
        })
      }, function(err, links) {
        if (err) return done(err)
        done(null, links.reduce(function(all, cur) {
          return all.concat(cur)
        }, []))
      })
    })
  }
}

function _linklocal(pkgpath, done) {
  assert.equal(typeof pkgpath, 'string', 'pkgpath should be a string')
  assert.equal(typeof done, 'function', 'done should be a function')
  done = once(done)
  var realPkgPath = fs.realpathSync(path.dirname(pkgpath))
  linklocal(realPkgPath, pkgpath, function(err, linkedDirs) {
    if (err) return done(err)
    done(null, linkedDirs)
  })
}

module.exports.unlink = function unlinklocal(dirpath, pkgpath, done) {
  if (arguments.length === 2) {
    done = pkgpath
    pkgpath = path.resolve(dirpath, 'package.json')
    return unlinklocal(dirpath, pkgpath, done)
  }
  assert.equal(typeof dirpath, 'string', 'dirpath should be a string')
  assert.equal(typeof pkgpath, 'string', 'pkgpath should be a string')
  assert.equal(typeof done, 'function', 'done should be a function')

  done = once(done)
  var node_modules = path.join(
    path.resolve(dirpath),
    'node_modules'
  )

  getLocals(dirpath, pkgpath, function(err, locals) {
    if (err) return done(err)
    doUnlink(locals, node_modules, done)
  })
}

module.exports.unlink.recursive = function unlinklocalRecursive(dirpath, pkgpath, done) {
  if (arguments.length === 2) {
    done = pkgpath
    pkgpath = path.resolve(dirpath, 'package.json')
    return linklocal.unlink.recursive(dirpath, pkgpath, done)
  }
  assert.equal(typeof dirpath, 'string', 'dirpath should be a string')
  assert.equal(typeof pkgpath, 'string', 'pkgpath should be a string')
  assert.equal(typeof done, 'function', 'done should be a function')

  done = once(done)
  findLinks(pkgpath, fs.realpathSync(pkgpath), function(err, links) {
    if (err) return done(err)
    map(links, Infinity, function(link, next) {
      fs.realpath(path.dirname(link), function(err, realPath) {
        if (err) return next(err)
        next(null, path.join(realPath, path.basename(link)))
      })
    }, function(err, links) {
      if (err) return done(err)
      links = links.filter(function(item, index, arr) {
        return arr.indexOf(item) === index
      })
      .sort(function(dirA, dirB) {
        if (dirA === dirB) return 0
        if (dirB.indexOf(dirA) === 0) return 1
        return -1
      })
      map(links, Infinity, function(item, next) {
        fs.lstat(item, function(err, stat) {
          if (err) return next(err)
          return next(null, stat.isSymbolicLink())
        })
      }, function(err, isSymbolicLink) {
        if (err) return done(err)
        var symlinks = links.filter(function(link, i) {
          return isSymbolicLink[i]
        })
        map(symlinks, Infinity, function(symlink, next) {
          fs.readlink(symlink, function(err, rel) {
            if (err) return next(err)
            var src = path.resolve(symlink, rel)
            fs.unlink(symlink, function(err) {
              if (err) return next(err)
              next(null, {src: src, link: symlink})
            })
          })
        }, done)
      })
    })
  })

  function findLinks(pkgpath, realPath, done) {
    assert.equal(typeof pkgpath, 'string', 'pkgpath should be a string')
    done = once(done)

    var pkgDirpath = path.dirname(pkgpath)
    var realDirpath = fs.realpathSync(path.dirname(realPath))
    var node_modules = path.join(
      path.resolve(pkgDirpath),
      'node_modules'
    )

    var links = []
    getLocals(realDirpath, pkgpath, function(err, locals) {
      if (err) return done(err)
      var pending = 0
      var links = locals.filter(function(dir) {
        return fs.existsSync(dir)
      }).map(function(dir) {
        var pkg = JSON.parse(fs.readFileSync(path.resolve(dir, 'package.json')))
        var name = pkg.name
        return path.join(node_modules, name)
      }).filter(function(dir) {
        return fs.existsSync(dir)
      })
      if (!links.length) return done(null, links)
      links.forEach(function(dir) {
        links.push(dir)
        pending++
        findLinks(path.resolve(dir, 'package.json'), path.resolve(dir, 'package.json'), function(err, subLinks) {
          if (err) return done(err)
          links = links.concat(subLinks)
          if (!--pending) return done(null, links)
        })
      })
    })
  }
}

function getLocals(dirpath, pkgpath, done) {
  fs.realpath(dirpath, function(err, dirpath) {
    if (err) return done(err)
    fs.realpath(pkgpath, function(err, pkgpath) {
      if (err) return done(err)
      assert.equal(typeof dirpath, 'string', 'dirpath should be a string')
      assert.equal(typeof pkgpath, 'string', 'pkgpath should be a string')
      var pkg = JSON.parse(fs.readFileSync(pkgpath))
      var deps = getDependencies(pkg)
      var locals = Object.keys(deps).filter(function(name) {
        var val = deps[name]
        return isLocal(val)
      }).map(function(name) {
        var pkgPath = deps[name]
        pkgPath = pkgPath.replace(/^file:/g, '')
        return path.resolve(dirpath, pkgPath)
      })
      done(null, locals)
    })
  })
}

function getDependencies(pkg) {
  var deps = pkg.dependencies || {}
  var devDependencies = pkg.devDependencies || {}
  for (var name in devDependencies) {
    deps[name] = devDependencies[name]
  }
  return deps
}

function isLocal(val) {
  return (
    val.indexOf('.') === 0 ||
    val.indexOf('/') === 0 ||
    val.indexOf('file:') === 0
  )
}

function doLink(packages, node_modules, done) {
  packages = packages || []
  var pending = packages.length
  var dests = []
  if (!packages.length) return done(null, [])
  packages.forEach(function(dir) {
    fs.realpath(dir, function(err, dir) {
      if (err) return done(err)
      var pkg = require(path.resolve(dir, 'package.json'))
      var name = pkg.name
      var dest = path.join(node_modules, name)
      var rel = path.relative(path.dirname(dest), dir)
      mkdirp(path.dirname(dest), function(err) {
        if (err && err.code !== 'EEXISTS') return done(err)
        fs.realpath(dest, function(err, realPath) {
          if (err && err.code !== 'ENOENT') return done(err)
          if (realPath && dest !== realPath) {
            rel = path.relative(dest, dir)
            if (realPath === dir) return skip()
          }
          fs.lstat(dest, function(err, stat) {
            if (err && err.code === 'ENOENT') return link()
            if (err) return done(err)
            if (!stat.isSymbolicLink()) return rimraf(dest, link)
            fs.unlink(dest, link)
          })
        })
      })

      function link(err) {
        if (err) return done(err)
        fs.symlink(rel, dest, 'junction', bump)
      }

      function bump(err) {
        if (err) return done(err)
        fs.realpath(path.dirname(dest), function(err, realPath) {
          dest = path.join(realPath, path.basename(dest))
          dests.push({link: dest, src: dir})
          debug('Linked ' + name + ' into ./' + path.relative(process.cwd(), dest))
          if (!--pending) return done(null, dests)
        })
      }

      function skip(err) {
        if (err) return done(err)
        if (!--pending) return done(null, dests)
      }
    })
  })
}

function doUnlink(packages, node_modules, done) {
  packages = packages || []
  var pending = packages.length
  var dests = []
  if (!packages.length) return done(null, [])
  packages.forEach(function(dir) {
    fs.realpath(dir, function(err, dir) {
      if (err) return done(err)
      var pkg = require(path.resolve(dir, 'package.json'))
      var name = pkg.name
      var dest = path.join(node_modules, name)
      fs.lstat(dest, function(err, stat) {
        if (err && err.code === 'ENOENT') return bump()
        if (err) return done(err)
        if (!stat || !stat.isSymbolicLink()) return bump()
        fs.readlink(dest, function(err, src) {
          if (err) return done(err)
          fs.unlink(dest, function(err) {
            if (err) return done(err)
            fs.realpath(path.dirname(dest), function(err, realPath) {
              if (err) return done(err)
              dest = path.join(realPath, path.basename(dest))
              src = path.resolve(realPath, src)
              dests.push({link: dest, src: src})
              debug('Unlinked ' + name + ' from ./' + path.relative(process.cwd(), dest))
              bump()
            })
          })
        })
      })

      function bump() {
        if (!--pending) return done(null, dests)
      }
    })
  })
}
<|endoftext|>


<commit_before>let haar = require('haar-engine');

haar.engine();
haar.app.get('/', (req, res) => {
  res.json('Haar API');
});
haar.server.listen(3000);
<commit_msg>index: adding initial endpoint<commit_after>const haar = require('haar-engine');

haar.engine();
haar.app.get('/', (req, res) => {
  res.json('Haar API');
});
haar.server.listen(3000);
<|endoftext|>


<commit_before>/**
 * index.js
 */
"use strict";
{
  /* api */
  const {Input, Output} = require("./modules/native-message");
  const {concatArgs, isString, throwErr} = require("./modules/common");
  const {
    convUriToFilePath, createDir, createFile, getFileNameFromFilePath,
    getFileTimestamp, isExecutable, isFile, removeDir, removeDirSync, readFile,
  } = require("./modules/file-util");
  const {execFile} = require("child_process");
  const os = require("os");
  const path = require("path");
  const process = require("process");

  /* constants */
  const {
    EDITOR_CONFIG_GET, EDITOR_CONFIG_RES, HOST, LABEL, LOCAL_FILE_VIEW,
    PROCESS_CHILD, TMP_FILES, TMP_FILES_PB, TMP_FILES_PB_REMOVE,
    TMP_FILE_CREATE, TMP_FILE_DATA_PORT, TMP_FILE_GET, TMP_FILE_RES,
  } = require("./modules/constant");
  const APP = `${process.pid}`;
  const CHAR = "utf8";
  const CMD_ARGS = "cmdArgs";
  const DIR_TMP = [os.tmpdir(), LABEL, APP];
  const DIR_TMP_FILES = [...DIR_TMP, TMP_FILES];
  const DIR_TMP_FILES_PB = [...DIR_TMP, TMP_FILES_PB];
  const EDITOR_PATH = "editorPath";
  const FILE_AFTER_ARGS = "fileAfterCmdArgs";

  /* variables */
  const vars = {
    [CMD_ARGS]: [],
    [EDITOR_PATH]: "",
    [FILE_AFTER_ARGS]: false,
  };

  /**
   * host message
   * @param {*} message - message
   * @param {string} status - status
   * @returns {Object} - host message object
   */
  const hostMsg = (message, status) => ({
    [HOST]: {
      message, status,
      pid: APP,
    },
  });

  /**
   * handle rejection
   * @param {*} e - Error or any
   * @returns {void}
   */
  const handleReject = e => {
    e = (new Output()).encode(hostMsg(e, "error"));
    e && process.stdout.write(e);
  };

  /* child process */
  /**
   * spawn child process
   * @param {string} file - file path
   * @returns {Object} - Promise.<Object>, ?ChildProcess
   */
  const spawnChildProcess = file => new Promise(resolve => {
    const app = vars[EDITOR_PATH];
    const pos = vars[FILE_AFTER_ARGS] || false;
    let args = vars[CMD_ARGS] || [], proc;
    if (isFile(file) && isExecutable(app)) {
      const argA = pos && args || [file.replace(/\\/g, "\\\\")];
      const argB = pos && [file.replace(/\\/g, "\\\\")] || args;
      const opt = {
        cwd: null,
        encoding: CHAR,
        env: process.env,
      };
      args = concatArgs(argA, argB);
      proc = execFile(app, args, opt, (e, stdout, stderr) => {
        const output = new Output();
        if (e) {
          e = output.encode(e);
          e && process.stderr.write(e);
        }
        if (stderr) {
          stderr = output.encode(
            hostMsg(`${stderr}: ${app}`, `${PROCESS_CHILD}_stderr`)
          );
          stderr && process.stdout.write(stderr);
        }
        if (stdout) {
          stdout = output.encode(
            hostMsg(`${stdout}: ${app}`, `${PROCESS_CHILD}_stdout`)
          );
          stdout && process.stdout.write(stdout);
        }
      });
    }
    resolve(proc || null);
  });

  /* output */
  /**
   * write stdout
   * @param {*} msg - message
   * @returns {Object} - Promise.<?boolean>
   */
  const writeStdout = msg => new Promise(resolve => {
    msg = (new Output()).encode(msg);
    resolve(msg && process.stdout.write(msg) || null);
  });

  /**
   * port app status
   * @returns {Object} - Promise.<?boolean>
   */
  const portAppStatus = () => writeStdout(hostMsg(EDITOR_CONFIG_GET, "ready"));

  /**
   * port editor config
   * @param {string} data - editor config
   * @param {string} editorConfig - editor config file path
   * @returns {Object} - Promise.<?boolean>
   */
  const portEditorConfig = (data, editorConfig) => new Promise(resolve => {
    let msg;
    try {
      data = data && JSON.parse(data);
      if (data) {
        const {editorPath} = data;
        const editorName = getFileNameFromFilePath(editorPath);
        const executable = isExecutable(editorPath);
        const items = Object.keys(data);
        if (items.length) {
          for (const item of items) {
            vars[item] = data[item];
          }
        }
        msg = {
          [EDITOR_CONFIG_RES]: {
            editorConfig, editorName, editorPath, executable,
          },
        };
      }
    } catch (e) {
      msg = hostMsg(`${e}: ${editorConfig}`, "error");
    }
    resolve(msg || null);
  }).then(writeStdout);

  /**
   * port file data
   * @param {string} filePath - file path
   * @param {Object} data - file data
   * @returns {Object} - Promise.<?boolean>
   */
  const portFileData = (filePath, data = {}) => new Promise(resolve => {
    let msg;
    if (isString(filePath)) {
      data.filePath = filePath;
      msg = {
        [TMP_FILE_DATA_PORT]: {filePath, data},
      };
    }
    resolve(msg || null);
  }).then(writeStdout);

  /**
   * port temporary file
   * @param {Object} obj - temporary file data object
   * @returns {Object} - Promise.<?boolean>
   */
  const portTmpFile = (obj = {}) => new Promise(resolve => {
    const msg = Object.keys(obj).length && {
      [TMP_FILE_RES]: obj,
    };
    resolve(msg || null);
  }).then(writeStdout);

  /* temporary files */
  /**
   * remove private temporary files
   * @param {boolean} bool - remove
   * @returns {Object} - ?Promise.<void>
   */
  const removePrivateTmpFiles = bool =>
    !!bool && removeDir(path.join(...DIR_TMP_FILES_PB)).then(() =>
      createDir(DIR_TMP_FILES_PB)
    ) || null;

  /**
   * create temporary file
   * @param {Object} obj - temporary file data object
   * @returns {Object} - Promise.<Object>, temporary file data
   */
  const createTmpFile = (obj = {}) => new Promise(resolve => {
    const {data, value} = obj;
    let func;
    if (data) {
      const {dir, fileName, host, tabId, windowId} = data;
      const arr = dir && windowId && tabId && host &&
                    [...DIR_TMP, dir, windowId, tabId, host];
      func = arr && fileName && createDir(arr).then(dPath =>
        dPath === path.join(...arr) &&
          createFile(path.join(dPath, fileName), value)
      ).then(filePath => filePath && {filePath, data} || null);
    }
    resolve(func || null);
  });

  /**
   * append file timestamp
   * @param {Object} data - temporary file data
   * @returns {Object} - Promise.<Object>, temporary file data
   */
  const appendTimestamp = (data = {}) => new Promise(resolve => {
    const {filePath} = data;
    const timestamp = filePath && getFileTimestamp(filePath);
    data.timestamp = timestamp || 0;
    resolve(data);
  });

  /**
   * extract temporary file data
   * @param {Array} arr - array containing temporary file data and value
   * @returns {Object} - Promise.<Object>, temporary file data object
   */
  const extractTmpFileData = (arr = []) => new Promise(resolve => {
    let obj;
    if (Array.isArray(arr) && arr.length) {
      const [data, value] = arr;
      obj = {data, value};
    }
    resolve(obj || null);
  });

  /**
   * get temporary file
   * @param {Object} obj - temporary file data
   * @returns {Object} - Promise.<Object>
   */
  const getTmpFile = (obj = {}) => {
    const {filePath} = obj;
    const func = [];
    if (filePath) {
      func.push(appendTimestamp(obj));
      func.push(readFile(filePath));
    }
    return Promise.all(func).then(extractTmpFileData);
  };

  /* local files */
  /**
   * get editor config
   * @param {string} filePath - editor config file path
   * @returns {Object} - Promise.<Array.<*>>
   */
  const getEditorConfig = filePath => {
    const func = [];
    filePath = isString(filePath) && filePath.length && filePath ||
               path.resolve(path.join(".", "editorconfig.json"));
    if (isFile(filePath)) {
      func.push(
        readFile(filePath).then(data => portEditorConfig(data, filePath))
      );
    } else {
      func.push(writeStdout(hostMsg(`${filePath} is not a file.`, "warn")));
      func.push(writeStdout({[EDITOR_CONFIG_RES]: null}));
    }
    return Promise.all(func);
  };

  /**
   * view local file
   * @param {string} uri - local file uri
   * @returns {Object} - Promise.<Object>, ChildProcess
   */
  const viewLocalFile = uri => convUriToFilePath(uri).then(spawnChildProcess);

  /* handlers */
  /**
   * handle created temporary file
   * @param {Object} obj - temporary file data
   * @returns {Object} - Promise.<Array.<*>>
   */
  const handleCreatedTmpFile = (obj = {}) => {
    const {filePath, data} = obj;
    const func = [];
    if (filePath) {
      func.push(spawnChildProcess(filePath));
      func.push(portFileData(filePath, data));
    }
    return Promise.all(func);
  };

  /**
   * handle message
   * @param {*} msg - message
   * @returns {Object} - Promise.<Array<*>>
   */
  const handleMsg = msg => {
    const func = [];
    const items = msg && Object.keys(msg);
    if (items && items.length) {
      for (const item of items) {
        const obj = msg[item];
        switch (item) {
          case EDITOR_CONFIG_GET:
            func.push(getEditorConfig(obj));
            break;
          case LOCAL_FILE_VIEW:
            func.push(viewLocalFile(obj));
            break;
          case TMP_FILE_CREATE:
            func.push(createTmpFile(obj).then(handleCreatedTmpFile));
            break;
          case TMP_FILE_GET:
            func.push(getTmpFile(obj).then(portTmpFile));
            break;
          case TMP_FILES_PB_REMOVE:
            func.push(removePrivateTmpFiles(obj));
            break;
          default:
            func.push(
              writeStdout(hostMsg(`No handler found for ${item}.`, "warn"))
            );
        }
      }
    } else {
      func.push(writeStdout(hostMsg(`No handler found for ${msg}.`, "warn")));
    }
    return Promise.all(func);
  };

  /* input */
  const input = new Input();

  /**
   * read stdin
   * @param {string|Buffer} chunk - chunk
   * @returns {Object} - ?Promise.<Array.<*>>
   */
  const readStdin = chunk => {
    const arr = input.decode(chunk);
    const func = [];
    Array.isArray(arr) && arr.length && arr.forEach(msg => {
      msg && func.push(handleMsg(msg));
    });
    return func.length && Promise.all(func).catch(handleReject) || null;
  };

  /* exit */
  /**
   * handle exit
   * @param {number} code - exit code
   * @returns {void}
   */
  const handleExit = code => {
    const msg = (new Output()).encode(hostMsg(`exit ${code || 0}`, "exit"));
    removeDirSync(path.join(...DIR_TMP));
    msg && process.stdout.write(msg);
  };

  /* process */
  process.on("exit", handleExit);
  process.on("uncaughtException", throwErr);
  process.on("unhandleRejection", handleReject);
  process.stdin.on("data", readStdin);

  /* startup */
  Promise.all([
    createDir(DIR_TMP_FILES),
    createDir(DIR_TMP_FILES_PB),
  ]).then(portAppStatus).catch(handleReject);
}
<commit_msg>Fix JSDoc<commit_after>/**
 * index.js
 */
"use strict";
{
  /* api */
  const {Input, Output} = require("./modules/native-message");
  const {concatArgs, isString, throwErr} = require("./modules/common");
  const {
    convUriToFilePath, createDir, createFile, getFileNameFromFilePath,
    getFileTimestamp, isExecutable, isFile, removeDir, removeDirSync, readFile,
  } = require("./modules/file-util");
  const {execFile} = require("child_process");
  const os = require("os");
  const path = require("path");
  const process = require("process");

  /* constants */
  const {
    EDITOR_CONFIG_GET, EDITOR_CONFIG_RES, HOST, LABEL, LOCAL_FILE_VIEW,
    PROCESS_CHILD, TMP_FILES, TMP_FILES_PB, TMP_FILES_PB_REMOVE,
    TMP_FILE_CREATE, TMP_FILE_DATA_PORT, TMP_FILE_GET, TMP_FILE_RES,
  } = require("./modules/constant");
  const APP = `${process.pid}`;
  const CHAR = "utf8";
  const CMD_ARGS = "cmdArgs";
  const DIR_TMP = [os.tmpdir(), LABEL, APP];
  const DIR_TMP_FILES = [...DIR_TMP, TMP_FILES];
  const DIR_TMP_FILES_PB = [...DIR_TMP, TMP_FILES_PB];
  const EDITOR_PATH = "editorPath";
  const FILE_AFTER_ARGS = "fileAfterCmdArgs";

  /* variables */
  const vars = {
    [CMD_ARGS]: [],
    [EDITOR_PATH]: "",
    [FILE_AFTER_ARGS]: false,
  };

  /**
   * host message
   * @param {*} message - message
   * @param {string} status - status
   * @returns {Object} - host message object
   */
  const hostMsg = (message, status) => ({
    [HOST]: {
      message, status,
      pid: APP,
    },
  });

  /**
   * handle rejection
   * @param {*} e - Error or any
   * @returns {boolean} - false
   */
  const handleReject = e => {
    e = (new Output()).encode(hostMsg(e, "error"));
    e && process.stdout.write(e);
    return false;
  };

  /* child process */
  /**
   * spawn child process
   * @param {string} file - file path
   * @returns {Object} - Promise.<?ChildProcess>
   */
  const spawnChildProcess = file => new Promise(resolve => {
    const app = vars[EDITOR_PATH];
    const pos = vars[FILE_AFTER_ARGS] || false;
    let args = vars[CMD_ARGS] || [], proc;
    if (isFile(file) && isExecutable(app)) {
      const argA = pos && args || [file.replace(/\\/g, "\\\\")];
      const argB = pos && [file.replace(/\\/g, "\\\\")] || args;
      const opt = {
        cwd: null,
        encoding: CHAR,
        env: process.env,
      };
      args = concatArgs(argA, argB);
      proc = execFile(app, args, opt, (e, stdout, stderr) => {
        const output = new Output();
        if (e) {
          e = output.encode(e);
          e && process.stderr.write(e);
        }
        if (stderr) {
          stderr = output.encode(
            hostMsg(`${stderr}: ${app}`, `${PROCESS_CHILD}_stderr`)
          );
          stderr && process.stdout.write(stderr);
        }
        if (stdout) {
          stdout = output.encode(
            hostMsg(`${stdout}: ${app}`, `${PROCESS_CHILD}_stdout`)
          );
          stdout && process.stdout.write(stdout);
        }
      });
    }
    resolve(proc || null);
  });

  /* output */
  /**
   * write stdout
   * @param {*} msg - message
   * @returns {Object} - Promise.<?boolean>
   */
  const writeStdout = msg => new Promise(resolve => {
    msg = (new Output()).encode(msg);
    resolve(msg && process.stdout.write(msg) || null);
  });

  /**
   * port app status
   * @returns {Object} - Promise.<AsyncFunction>
   */
  const portAppStatus = () => writeStdout(hostMsg(EDITOR_CONFIG_GET, "ready"));

  /**
   * port editor config
   * @param {string} data - editor config
   * @param {string} editorConfig - editor config file path
   * @returns {Object} - Promise.<?boolean>
   */
  const portEditorConfig = (data, editorConfig) => new Promise(resolve => {
    let msg;
    try {
      data = data && JSON.parse(data);
      if (data) {
        const {editorPath} = data;
        const editorName = getFileNameFromFilePath(editorPath);
        const executable = isExecutable(editorPath);
        const items = Object.keys(data);
        if (items.length) {
          for (const item of items) {
            vars[item] = data[item];
          }
        }
        msg = {
          [EDITOR_CONFIG_RES]: {
            editorConfig, editorName, editorPath, executable,
          },
        };
      }
    } catch (e) {
      msg = hostMsg(`${e}: ${editorConfig}`, "error");
    }
    resolve(msg || null);
  }).then(writeStdout);

  /**
   * port file data
   * @param {string} filePath - file path
   * @param {Object} data - file data
   * @returns {Object} - Promise.<AsyncFunction>
   */
  const portFileData = (filePath, data = {}) => new Promise(resolve => {
    let msg;
    if (isString(filePath)) {
      data.filePath = filePath;
      msg = {
        [TMP_FILE_DATA_PORT]: {filePath, data},
      };
    }
    resolve(msg || null);
  }).then(writeStdout);

  /**
   * port temporary file
   * @param {Object} obj - temporary file data object
   * @returns {Object} - Promise.<AsyncFunction>
   */
  const portTmpFile = (obj = {}) => new Promise(resolve => {
    const msg = Object.keys(obj).length && {
      [TMP_FILE_RES]: obj,
    };
    resolve(msg || null);
  }).then(writeStdout);

  /* temporary files */
  /**
   * remove private temporary files
   * @param {boolean} bool - remove
   * @returns {Object} - ?Promise.<AsyncFunction>
   */
  const removePrivateTmpFiles = bool =>
    !!bool && removeDir(path.join(...DIR_TMP_FILES_PB)).then(() =>
      createDir(DIR_TMP_FILES_PB)
    ) || null;

  /**
   * create temporary file
   * @param {Object} obj - temporary file data object
   * @returns {Object} - Promise.<Object>, temporary file data
   */
  const createTmpFile = (obj = {}) => new Promise(resolve => {
    const {data, value} = obj;
    let func;
    if (data) {
      const {dir, fileName, host, tabId, windowId} = data;
      const arr = dir && windowId && tabId && host &&
                    [...DIR_TMP, dir, windowId, tabId, host];
      func = arr && fileName && createDir(arr).then(dPath =>
        dPath === path.join(...arr) &&
          createFile(path.join(dPath, fileName), value)
      ).then(filePath => filePath && {filePath, data} || null);
    }
    resolve(func || null);
  });

  /**
   * append file timestamp
   * @param {Object} data - temporary file data
   * @returns {Object} - Promise.<Object>, temporary file data
   */
  const appendTimestamp = (data = {}) => new Promise(resolve => {
    const {filePath} = data;
    const timestamp = filePath && getFileTimestamp(filePath);
    data.timestamp = timestamp || 0;
    resolve(data);
  });

  /**
   * extract temporary file data
   * @param {Array} arr - array containing temporary file data and value
   * @returns {Object} - Promise.<Object>, temporary file data object
   */
  const extractTmpFileData = (arr = []) => new Promise(resolve => {
    let obj;
    if (Array.isArray(arr) && arr.length) {
      const [data, value] = arr;
      obj = {data, value};
    }
    resolve(obj || null);
  });

  /**
   * get temporary file
   * @param {Object} obj - temporary file data
   * @returns {Object} - Promise.<AsyncFunction>
   */
  const getTmpFile = (obj = {}) => {
    const {filePath} = obj;
    const func = [];
    if (filePath) {
      func.push(appendTimestamp(obj));
      func.push(readFile(filePath));
    }
    return Promise.all(func).then(extractTmpFileData);
  };

  /* local files */
  /**
   * get editor config
   * @param {string} filePath - editor config file path
   * @returns {Object} - Promise.<Array>
   */
  const getEditorConfig = filePath => {
    const func = [];
    filePath = isString(filePath) && filePath.length && filePath ||
               path.resolve(path.join(".", "editorconfig.json"));
    if (isFile(filePath)) {
      func.push(
        readFile(filePath).then(data => portEditorConfig(data, filePath))
      );
    } else {
      func.push(writeStdout(hostMsg(`${filePath} is not a file.`, "warn")));
      func.push(writeStdout({[EDITOR_CONFIG_RES]: null}));
    }
    return Promise.all(func);
  };

  /**
   * view local file
   * @param {string} uri - local file uri
   * @returns {Object} - Promise.<AsyncFunction>
   */
  const viewLocalFile = uri => convUriToFilePath(uri).then(spawnChildProcess);

  /* handlers */
  /**
   * handle created temporary file
   * @param {Object} obj - temporary file data
   * @returns {Object} - Promise.<Array>
   */
  const handleCreatedTmpFile = (obj = {}) => {
    const {filePath, data} = obj;
    const func = [];
    if (filePath) {
      func.push(spawnChildProcess(filePath));
      func.push(portFileData(filePath, data));
    }
    return Promise.all(func);
  };

  /**
   * handle message
   * @param {*} msg - message
   * @returns {Object} - Promise.<Array>
   */
  const handleMsg = msg => {
    const func = [];
    const items = msg && Object.keys(msg);
    if (items && items.length) {
      for (const item of items) {
        const obj = msg[item];
        switch (item) {
          case EDITOR_CONFIG_GET:
            func.push(getEditorConfig(obj));
            break;
          case LOCAL_FILE_VIEW:
            func.push(viewLocalFile(obj));
            break;
          case TMP_FILE_CREATE:
            func.push(createTmpFile(obj).then(handleCreatedTmpFile));
            break;
          case TMP_FILE_GET:
            func.push(getTmpFile(obj).then(portTmpFile));
            break;
          case TMP_FILES_PB_REMOVE:
            func.push(removePrivateTmpFiles(obj));
            break;
          default:
            func.push(
              writeStdout(hostMsg(`No handler found for ${item}.`, "warn"))
            );
        }
      }
    } else {
      func.push(writeStdout(hostMsg(`No handler found for ${msg}.`, "warn")));
    }
    return Promise.all(func);
  };

  /* input */
  const input = new Input();

  /**
   * read stdin
   * @param {string|Buffer} chunk - chunk
   * @returns {Object} - ?Promise.<Array>
   */
  const readStdin = chunk => {
    const arr = input.decode(chunk);
    const func = [];
    Array.isArray(arr) && arr.length && arr.forEach(msg => {
      msg && func.push(handleMsg(msg));
    });
    return func.length && Promise.all(func).catch(handleReject) || null;
  };

  /* exit */
  /**
   * handle exit
   * @param {number} code - exit code
   * @returns {void}
   */
  const handleExit = code => {
    const msg = (new Output()).encode(hostMsg(`exit ${code || 0}`, "exit"));
    removeDirSync(path.join(...DIR_TMP));
    msg && process.stdout.write(msg);
  };

  /* process */
  process.on("exit", handleExit);
  process.on("uncaughtException", throwErr);
  process.on("unhandleRejection", handleReject);
  process.stdin.on("data", readStdin);

  /* startup */
  Promise.all([
    createDir(DIR_TMP_FILES),
    createDir(DIR_TMP_FILES_PB),
  ]).then(portAppStatus).catch(handleReject);
}
<|endoftext|>


<commit_before>'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var Knob = function (_React$Component) {
  _inherits(Knob, _React$Component);

  function Knob(props) {
    _classCallCheck(this, Knob);

    var _this = _possibleConstructorReturn(this, (Knob.__proto__ || Object.getPrototypeOf(Knob)).call(this, props));

    _this.getArcToValue = function (v) {
      var startAngle = void 0;
      var endAngle = void 0;
      var angle = !_this.props.log ? (v - _this.props.min) * _this.angleArc / (_this.props.max - _this.props.min) : Math.log(Math.pow(v / _this.props.min, _this.angleArc)) / Math.log(_this.props.max / _this.props.min);
      if (!_this.props.clockwise) {
        startAngle = _this.endAngle + 0.00001;
        endAngle = startAngle - angle - 0.00001;
      } else {
        startAngle = _this.startAngle - 0.00001;
        endAngle = startAngle + angle + 0.00001;
      }
      if (_this.props.cursor) {
        startAngle = endAngle - _this.cursorExt;
        endAngle += _this.cursorExt;
      }
      return {
        startAngle: startAngle,
        endAngle: endAngle,
        acw: !_this.props.clockwise && !_this.props.cursor
      };
    };

    _this.coerceToStep = function (v) {
      var val = !_this.props.log ? ~~((v < 0 ? -0.5 : 0.5) + v / _this.props.step) * _this.props.step : Math.pow(_this.props.step, ~~((Math.abs(v) < 1 ? -0.5 : 0.5) + Math.log(v) / Math.log(_this.props.step)));
      val = Math.max(Math.min(val, _this.props.max), _this.props.min);
      if (isNaN(val)) {
        val = 0;
      }
      return Math.round(val * 1000) / 1000;
    };

    _this.eventToValue = function (e) {
      var bounds = _this.canvasRef.getBoundingClientRect();
      var x = e.clientX - bounds.left;
      var y = e.clientY - bounds.top;
      var a = Math.atan2(x - _this.w / 2, _this.w / 2 - y) - _this.angleOffset;
      if (!_this.props.clockwise) {
        a = _this.angleArc - a - 2 * Math.PI;
      }
      if (_this.angleArc !== Math.PI * 2 && a < 0 && a > -0.5) {
        a = 0;
      } else if (a < 0) {
        a += Math.PI * 2;
      }
      var val = !_this.props.log ? a * (_this.props.max - _this.props.min) / _this.angleArc + _this.props.min : Math.pow(_this.props.max / _this.props.min, a / _this.angleArc) * _this.props.min;
      return _this.coerceToStep(val);
    };

    _this.handleMouseDown = function (e) {
      _this.props.onChange(_this.eventToValue(e));
      document.addEventListener('mousemove', _this.handleMouseMove);
      document.addEventListener('mouseup', _this.handleMouseUp);
      document.addEventListener('keyup', _this.handleEsc);
    };

    _this.handleMouseMove = function (e) {
      e.preventDefault();
      _this.props.onChange(_this.eventToValue(e));
    };

    _this.handleMouseUp = function (e) {
      _this.props.onChangeEnd(_this.eventToValue(e));
      document.removeEventListener('mousemove', _this.handleMouseMove);
      document.removeEventListener('mouseup', _this.handleMouseUp);
      document.removeEventListener('keyup', _this.handleEsc);
    };

    _this.handleTouchStart = function (e) {
      e.preventDefault();
      _this.touchIndex = e.targetTouches.length - 1;
      _this.props.onChange(_this.eventToValue(e.targetTouches[_this.touchIndex]));
      document.addEventListener('touchmove', _this.handleTouchMove, { passive: false });
      document.addEventListener('touchend', _this.handleTouchEnd);
      document.addEventListener('touchcancel', _this.handleTouchEnd);
    };

    _this.handleTouchMove = function (e) {
      e.preventDefault();
      _this.props.onChange(_this.eventToValue(e.targetTouches[_this.touchIndex]));
    };

    _this.handleTouchEnd = function (e) {
      _this.props.onChangeEnd(_this.eventToValue(e.changedTouches[_this.touchIndex]));
      document.removeEventListener('touchmove', _this.handleTouchMove);
      document.removeEventListener('touchend', _this.handleTouchEnd);
      document.removeEventListener('touchcancel', _this.handleTouchEnd);
    };

    _this.handleEsc = function (e) {
      if (e.keyCode === 27) {
        e.preventDefault();
        _this.handleMouseUp();
      }
    };

    _this.handleTextInput = function (e) {
      var val = Math.max(Math.min(+e.target.value, _this.props.max), _this.props.min) || _this.props.min;
      _this.props.onChange(val);
    };

    _this.handleWheel = function (e) {
      e.preventDefault();
      if (e.deltaX > 0 || e.deltaY > 0) {
        _this.props.onChange(_this.coerceToStep(!_this.props.log ? _this.props.value + _this.props.step : _this.props.value * _this.props.step));
      } else if (e.deltaX < 0 || e.deltaY < 0) {
        _this.props.onChange(_this.coerceToStep(!_this.props.log ? _this.props.value - _this.props.step : _this.props.value / _this.props.step));
      }
    };

    _this.handleArrowKey = function (e) {
      if (e.keyCode === 37 || e.keyCode === 40) {
        e.preventDefault();
        _this.props.onChange(_this.coerceToStep(!_this.props.log ? _this.props.value - _this.props.step : _this.props.value / _this.props.step));
      } else if (e.keyCode === 38 || e.keyCode === 39) {
        e.preventDefault();
        _this.props.onChange(_this.coerceToStep(!_this.props.log ? _this.props.value + _this.props.step : _this.props.value * _this.props.step));
      }
    };

    _this.inputStyle = function () {
      return {
        width: (_this.w / 2 + 4 >> 0) + 'px',
        height: (_this.w / 3 >> 0) + 'px',
        position: 'absolute',
        verticalAlign: 'middle',
        marginTop: (_this.w / 3 >> 0) + 'px',
        marginLeft: '-' + (_this.w * 3 / 4 + 2 >> 0) + 'px',
        border: 0,
        background: 'none',
        font: _this.props.fontWeight + ' ' + (_this.w / _this.digits >> 0) + 'px ' + _this.props.font,
        textAlign: 'center',
        color: _this.props.inputColor || _this.props.fgColor,
        padding: '0px',
        WebkitAppearance: 'none'
      };
    };

    _this.renderCentre = function () {
      if (_this.props.displayInput) {
        return _react2.default.createElement('input', {
          style: _this.inputStyle(),
          type: 'text',
          value: _this.props.value,
          onChange: _this.handleTextInput,
          onKeyDown: _this.handleArrowKey,
          readOnly: _this.props.readOnly || _this.props.disableTextInput
        });
      } else if (_this.props.displayCustom && typeof _this.props.displayCustom === 'function') {
        return _this.props.displayCustom();
      }
      return null;
    };

    _this.render = function () {
      return _react2.default.createElement(
        'div',
        {
          style: { width: _this.w, height: _this.h, display: 'inline-block' },
          onWheel: _this.props.readOnly || _this.props.disableMouseWheel ? null : _this.handleWheel
        },
        _react2.default.createElement('canvas', {
          ref: function ref(_ref) {
            _this.canvasRef = _ref;
          },
          style: { width: '100%', height: '100%' },
          onMouseDown: _this.props.readOnly ? null : _this.handleMouseDown,
          title: _this.props.title ? _this.props.title + ': ' + _this.props.value : _this.props.value
        }),
        _this.renderCentre()
      );
    };

    _this.w = _this.props.width || 200;
    _this.h = _this.props.height || _this.w;
    _this.cursorExt = _this.props.cursor === true ? 0.3 : _this.props.cursor / 100;
    _this.angleArc = _this.props.angleArc * Math.PI / 180;
    _this.angleOffset = _this.props.angleOffset * Math.PI / 180;
    _this.startAngle = 1.5 * Math.PI + _this.angleOffset;
    _this.endAngle = 1.5 * Math.PI + _this.angleOffset + _this.angleArc;
    _this.digits = Math.max(String(Math.abs(_this.props.min)).length, String(Math.abs(_this.props.max)).length, 2) + 2;
    return _this;
  }

  _createClass(Knob, [{
    key: 'componentDidMount',
    value: function componentDidMount() {
      this.drawCanvas();
      if (!this.props.readOnly) {
        this.canvasRef.addEventListener('touchstart', this.handleTouchStart, { passive: false });
      }
    }
  }, {
    key: 'componentDidUpdate',
    value: function componentDidUpdate() {
      this.drawCanvas();
    }
  }, {
    key: 'componentWillUnmount',
    value: function componentWillUnmount() {
      this.canvasRef.removeEventListener('touchstart', this.handleTouchStart);
    }
  }, {
    key: 'drawCanvas',
    value: function drawCanvas() {
      this.canvasRef.width = this.w; // clears the canvas
      this.canvasRef.height = this.h;
      var ctx = this.canvasRef.getContext('2d');
      this.xy = this.w / 2; // coordinates of canvas center
      this.lineWidth = this.xy * this.props.thickness;
      this.radius = this.xy - this.lineWidth / 2;
      ctx.lineWidth = this.lineWidth;
      ctx.lineCap = this.props.lineCap;
      // background arc
      ctx.beginPath();
      ctx.strokeStyle = this.props.bgColor;
      ctx.arc(this.xy, this.xy, this.radius, this.endAngle - 0.00001, this.startAngle + 0.00001, true);
      ctx.stroke();
      // foreground arc
      var a = this.getArcToValue(this.props.value);
      ctx.beginPath();
      ctx.strokeStyle = this.props.fgColor;
      ctx.arc(this.xy, this.xy, this.radius, a.startAngle, a.endAngle, a.acw);
      ctx.stroke();
    }
  }]);

  return Knob;
}(_react2.default.Component);

Knob.propTypes = {
  value: _react2.default.PropTypes.number.isRequired,
  onChange: _react2.default.PropTypes.func.isRequired,
  onChangeEnd: _react2.default.PropTypes.func,
  min: _react2.default.PropTypes.number,
  max: _react2.default.PropTypes.number,
  step: _react2.default.PropTypes.number,
  log: _react2.default.PropTypes.bool,
  width: _react2.default.PropTypes.number,
  height: _react2.default.PropTypes.number,
  thickness: _react2.default.PropTypes.number,
  lineCap: _react2.default.PropTypes.oneOf(['butt', 'round']),
  bgColor: _react2.default.PropTypes.string,
  fgColor: _react2.default.PropTypes.string,
  inputColor: _react2.default.PropTypes.string,
  font: _react2.default.PropTypes.string,
  fontWeight: _react2.default.PropTypes.string,
  clockwise: _react2.default.PropTypes.bool,
  cursor: _react2.default.PropTypes.oneOfType([_react2.default.PropTypes.number, _react2.default.PropTypes.bool]),
  stopper: _react2.default.PropTypes.bool,
  readOnly: _react2.default.PropTypes.bool,
  disableTextInput: _react2.default.PropTypes.bool,
  displayInput: _react2.default.PropTypes.bool,
  displayCustom: _react2.default.PropTypes.func,
  angleArc: _react2.default.PropTypes.number,
  angleOffset: _react2.default.PropTypes.number,
  disableMouseWheel: _react2.default.PropTypes.bool,
  title: _react2.default.PropTypes.string
};
Knob.defaultProps = {
  min: 0,
  max: 100,
  step: 1,
  log: false,
  width: 200,
  height: 200,
  thickness: 0.35,
  lineCap: 'butt',
  bgColor: '#EEE',
  fgColor: '#EA2',
  inputColor: '',
  font: 'Arial',
  fontWeight: 'bold',
  clockwise: true,
  cursor: false,
  stopper: true,
  readOnly: false,
  disableTextInput: false,
  displayInput: true,
  angleArc: 360,
  angleOffset: 0,
  disableMouseWheel: false
};
exports.default = Knob;
<commit_msg>Updated index.js<commit_after>'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _propTypes = require('prop-types');

var _propTypes2 = _interopRequireDefault(_propTypes);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var Knob = function (_React$Component) {
  _inherits(Knob, _React$Component);

  function Knob(props) {
    _classCallCheck(this, Knob);

    var _this = _possibleConstructorReturn(this, (Knob.__proto__ || Object.getPrototypeOf(Knob)).call(this, props));

    _this.getArcToValue = function (v) {
      var startAngle = void 0;
      var endAngle = void 0;
      var angle = !_this.props.log ? (v - _this.props.min) * _this.angleArc / (_this.props.max - _this.props.min) : Math.log(Math.pow(v / _this.props.min, _this.angleArc)) / Math.log(_this.props.max / _this.props.min);
      if (!_this.props.clockwise) {
        startAngle = _this.endAngle + 0.00001;
        endAngle = startAngle - angle - 0.00001;
      } else {
        startAngle = _this.startAngle - 0.00001;
        endAngle = startAngle + angle + 0.00001;
      }
      if (_this.props.cursor) {
        startAngle = endAngle - _this.cursorExt;
        endAngle += _this.cursorExt;
      }
      return {
        startAngle: startAngle,
        endAngle: endAngle,
        acw: !_this.props.clockwise && !_this.props.cursor
      };
    };

    _this.getCanvasScale = function (ctx) {
      var devicePixelRatio = window.devicePixelRatio || window.screen.deviceXDPI / window.screen.logicalXDPI || // IE10
      1;
      var backingStoreRatio = ctx.webkitBackingStorePixelRatio || 1;
      return devicePixelRatio / backingStoreRatio;
    };

    _this.coerceToStep = function (v) {
      var val = !_this.props.log ? ~~((v < 0 ? -0.5 : 0.5) + v / _this.props.step) * _this.props.step : Math.pow(_this.props.step, ~~((Math.abs(v) < 1 ? -0.5 : 0.5) + Math.log(v) / Math.log(_this.props.step)));
      val = Math.max(Math.min(val, _this.props.max), _this.props.min);
      if (isNaN(val)) {
        val = 0;
      }
      return Math.round(val * 1000) / 1000;
    };

    _this.eventToValue = function (e) {
      var bounds = _this.canvasRef.getBoundingClientRect();
      var x = e.clientX - bounds.left;
      var y = e.clientY - bounds.top;
      var a = Math.atan2(x - _this.w / 2, _this.w / 2 - y) - _this.angleOffset;
      if (!_this.props.clockwise) {
        a = _this.angleArc - a - 2 * Math.PI;
      }
      if (_this.angleArc !== Math.PI * 2 && a < 0 && a > -0.5) {
        a = 0;
      } else if (a < 0) {
        a += Math.PI * 2;
      }
      var val = !_this.props.log ? a * (_this.props.max - _this.props.min) / _this.angleArc + _this.props.min : Math.pow(_this.props.max / _this.props.min, a / _this.angleArc) * _this.props.min;
      return _this.coerceToStep(val);
    };

    _this.handleMouseDown = function (e) {
      _this.props.onChange(_this.eventToValue(e));
      document.addEventListener('mousemove', _this.handleMouseMove);
      document.addEventListener('mouseup', _this.handleMouseUp);
      document.addEventListener('keyup', _this.handleEsc);
    };

    _this.handleMouseMove = function (e) {
      e.preventDefault();
      _this.props.onChange(_this.eventToValue(e));
    };

    _this.handleMouseUp = function (e) {
      if (_this.props.onChangeEnd) {
        _this.props.onChangeEnd(_this.eventToValue(e));
      }
      document.removeEventListener('mousemove', _this.handleMouseMove);
      document.removeEventListener('mouseup', _this.handleMouseUp);
      document.removeEventListener('keyup', _this.handleEsc);
    };

    _this.handleTouchStart = function (e) {
      e.preventDefault();
      _this.touchIndex = e.targetTouches.length - 1;
      _this.props.onChange(_this.eventToValue(e.targetTouches[_this.touchIndex]));
      document.addEventListener('touchmove', _this.handleTouchMove, { passive: false });
      document.addEventListener('touchend', _this.handleTouchEnd);
      document.addEventListener('touchcancel', _this.handleTouchEnd);
    };

    _this.handleTouchMove = function (e) {
      e.preventDefault();
      _this.props.onChange(_this.eventToValue(e.targetTouches[_this.touchIndex]));
    };

    _this.handleTouchEnd = function (e) {
      if (_this.props.onChangeEnd) {
        _this.props.onChangeEnd(_this.eventToValue(e));
      }
      document.removeEventListener('touchmove', _this.handleTouchMove);
      document.removeEventListener('touchend', _this.handleTouchEnd);
      document.removeEventListener('touchcancel', _this.handleTouchEnd);
    };

    _this.handleEsc = function (e) {
      if (e.keyCode === 27) {
        e.preventDefault();
        _this.handleMouseUp();
      }
    };

    _this.handleTextInput = function (e) {
      var val = Math.max(Math.min(+e.target.value, _this.props.max), _this.props.min) || _this.props.min;
      _this.props.onChange(val);
    };

    _this.handleWheel = function (e) {
      e.preventDefault();
      if (e.deltaX > 0 || e.deltaY > 0) {
        _this.props.onChange(_this.coerceToStep(!_this.props.log ? _this.props.value + _this.props.step : _this.props.value * _this.props.step));
      } else if (e.deltaX < 0 || e.deltaY < 0) {
        _this.props.onChange(_this.coerceToStep(!_this.props.log ? _this.props.value - _this.props.step : _this.props.value / _this.props.step));
      }
    };

    _this.handleArrowKey = function (e) {
      if (e.keyCode === 37 || e.keyCode === 40) {
        e.preventDefault();
        _this.props.onChange(_this.coerceToStep(!_this.props.log ? _this.props.value - _this.props.step : _this.props.value / _this.props.step));
      } else if (e.keyCode === 38 || e.keyCode === 39) {
        e.preventDefault();
        _this.props.onChange(_this.coerceToStep(!_this.props.log ? _this.props.value + _this.props.step : _this.props.value * _this.props.step));
      }
    };

    _this.inputStyle = function () {
      return {
        width: (_this.w / 2 + 4 >> 0) + 'px',
        height: (_this.w / 3 >> 0) + 'px',
        position: 'absolute',
        verticalAlign: 'middle',
        marginTop: (_this.w / 3 >> 0) + 'px',
        marginLeft: '-' + (_this.w * 3 / 4 + 2 >> 0) + 'px',
        border: 0,
        background: 'none',
        font: _this.props.fontWeight + ' ' + (_this.w / _this.digits >> 0) + 'px ' + _this.props.font,
        textAlign: 'center',
        color: _this.props.inputColor || _this.props.fgColor,
        padding: '0px',
        WebkitAppearance: 'none'
      };
    };

    _this.renderCentre = function () {
      if (_this.props.displayInput) {
        return _react2.default.createElement('input', {
          style: _this.inputStyle(),
          type: 'text',
          value: _this.props.value,
          onChange: _this.handleTextInput,
          onKeyDown: _this.handleArrowKey,
          readOnly: _this.props.readOnly || _this.props.disableTextInput
        });
      } else if (_this.props.displayCustom && typeof _this.props.displayCustom === 'function') {
        return _this.props.displayCustom();
      }
      return null;
    };

    _this.render = function () {
      return _react2.default.createElement(
        'div',
        {
          style: { width: _this.w, height: _this.h, display: 'inline-block' },
          onWheel: _this.props.readOnly || _this.props.disableMouseWheel ? null : _this.handleWheel
        },
        _react2.default.createElement('canvas', {
          ref: function ref(_ref) {
            _this.canvasRef = _ref;
          },
          style: { width: '100%', height: '100%' },
          onMouseDown: _this.props.readOnly ? null : _this.handleMouseDown,
          title: _this.props.title ? _this.props.title + ': ' + _this.props.value : _this.props.value
        }),
        _this.renderCentre()
      );
    };

    _this.w = _this.props.width || 200;
    _this.h = _this.props.height || _this.w;
    _this.cursorExt = _this.props.cursor === true ? 0.3 : _this.props.cursor / 100;
    _this.angleArc = _this.props.angleArc * Math.PI / 180;
    _this.angleOffset = _this.props.angleOffset * Math.PI / 180;
    _this.startAngle = 1.5 * Math.PI + _this.angleOffset;
    _this.endAngle = 1.5 * Math.PI + _this.angleOffset + _this.angleArc;
    _this.digits = Math.max(String(Math.abs(_this.props.min)).length, String(Math.abs(_this.props.max)).length, 2) + 2;
    return _this;
  }

  _createClass(Knob, [{
    key: 'componentDidMount',
    value: function componentDidMount() {
      this.drawCanvas();
      if (!this.props.readOnly) {
        this.canvasRef.addEventListener('touchstart', this.handleTouchStart, { passive: false });
      }
    }
  }, {
    key: 'componentDidUpdate',
    value: function componentDidUpdate() {
      this.drawCanvas();
    }
  }, {
    key: 'componentWillUnmount',
    value: function componentWillUnmount() {
      this.canvasRef.removeEventListener('touchstart', this.handleTouchStart);
    }

    // Calculate ratio to scale canvas to avoid blurriness on HiDPI devices

  }, {
    key: 'drawCanvas',
    value: function drawCanvas() {
      var ctx = this.canvasRef.getContext('2d');
      var scale = this.getCanvasScale(ctx);
      this.canvasRef.width = this.w * scale; // clears the canvas
      this.canvasRef.height = this.h * scale;
      ctx.scale(scale, scale);
      this.xy = this.w / 2; // coordinates of canvas center
      this.lineWidth = this.xy * this.props.thickness;
      this.radius = this.xy - this.lineWidth / 2;
      ctx.lineWidth = this.lineWidth;
      ctx.lineCap = this.props.lineCap;
      // background arc
      ctx.beginPath();
      ctx.strokeStyle = this.props.bgColor;
      ctx.arc(this.xy, this.xy, this.radius, this.endAngle - 0.00001, this.startAngle + 0.00001, true);
      ctx.stroke();
      // foreground arc
      var a = this.getArcToValue(this.props.value);
      ctx.beginPath();
      ctx.strokeStyle = this.props.fgColor;
      ctx.arc(this.xy, this.xy, this.radius, a.startAngle, a.endAngle, a.acw);
      ctx.stroke();
    }
  }]);

  return Knob;
}(_react2.default.Component);

Knob.propTypes = {
  value: _propTypes2.default.number.isRequired,
  onChange: _propTypes2.default.func.isRequired,
  onChangeEnd: _propTypes2.default.func,
  min: _propTypes2.default.number,
  max: _propTypes2.default.number,
  step: _propTypes2.default.number,
  log: _propTypes2.default.bool,
  width: _propTypes2.default.number,
  height: _propTypes2.default.number,
  thickness: _propTypes2.default.number,
  lineCap: _propTypes2.default.oneOf(['butt', 'round']),
  bgColor: _propTypes2.default.string,
  fgColor: _propTypes2.default.string,
  inputColor: _propTypes2.default.string,
  font: _propTypes2.default.string,
  fontWeight: _propTypes2.default.string,
  clockwise: _propTypes2.default.bool,
  cursor: _propTypes2.default.oneOfType([_propTypes2.default.number, _propTypes2.default.bool]),
  stopper: _propTypes2.default.bool,
  readOnly: _propTypes2.default.bool,
  disableTextInput: _propTypes2.default.bool,
  displayInput: _propTypes2.default.bool,
  displayCustom: _propTypes2.default.func,
  angleArc: _propTypes2.default.number,
  angleOffset: _propTypes2.default.number,
  disableMouseWheel: _propTypes2.default.bool,
  title: _propTypes2.default.string
};
Knob.defaultProps = {
  min: 0,
  max: 100,
  step: 1,
  log: false,
  width: 200,
  height: 200,
  thickness: 0.35,
  lineCap: 'butt',
  bgColor: '#EEE',
  fgColor: '#EA2',
  inputColor: '',
  font: 'Arial',
  fontWeight: 'bold',
  clockwise: true,
  cursor: false,
  stopper: true,
  readOnly: false,
  disableTextInput: false,
  displayInput: true,
  angleArc: 360,
  angleOffset: 0,
  disableMouseWheel: false
};
exports.default = Knob;
<|endoftext|>


<commit_before>var moves = require("./moves");
var coord = require("./coords");

var tables = {};
exports.tables = tables;

var build333MoveTable = function (move) {

    var state;
    tables[move] = {};

    // CO
    tables[move][0] = {};
    for (var hash=0; hash < Math.pow(3,8); hash++) {
        state = coord.invertHash(hash, 2, 8);
        tables[move][0][hash] = coord.getHash(moves.applyMoveCO(move, state), 2);
    }

    // EO
    tables[move][2] = {};
    for (var hash=0; hash < Math.pow(2, 12); hash++) {
        state = coord.invertHash(hash, 2, 12);
        tables[move][2][hash] = coord.getHash(moves.applyMoveEO(move, state), 1);
    }

    // Note: Because CP and EP track positions of groups of four pieces, and
    // the positions are independent of the four positions being tracked,
    // the same move table can be applied to all groups.

    //CP
    tables[move][1] = {};
    for (var hash=0; hash < Math.pow(9, 4); hash++) {
        state = coord.positionsToState(coord.invertHash(hash, 8, 4), [1,2,3,4], 8, 8);
        // Skip states that are missing a piece.
        if (state.indexOf(1)<0 || state.indexOf(2)<0 || state.indexOf(3)<0 || state.indexOf(4)<0) {
            continue;
        }
        tables[move][1][hash] = coord.getHash(coord.findPieces(moves.applyMoveCP(move, state), [1,2,3,4], 8), 8);
    }

    //EP
    tables[move][3] = {};
    for (var hash=0; hash < Math.pow(13, 4); hash++) {
        state = coord.positionsToState(coord.invertHash(hash, 12, 4), [1,2,3,4], 12, 12);
        // Skip states that are missing a piece.
        if (state.indexOf(1)<0 || state.indexOf(2)<0 || state.indexOf(3)<0 || state.indexOf(4)<0) {
            continue;
        }
        tables[move][3][hash] = coord.getHash(coord.findPieces(moves.applyMoveEP(move, state), [1,2,3,4], 12), 12);
    }

    // Centres
    tables[move][4] = {};
    for (var hash=0; hash < Math.pow(7,6); hash++) {
        state = coord.invertHash(hash, 6, 6);
        if (state.indexOf(1)<0 || state.indexOf(2)<0 || state.indexOf(3)<0 ||
            state.indexOf(4)<0 || state.indexOf(5)<0 || state.indexOf(6)<0) {
            continue;
        }
        tables[move][4][hash] = coord.getHash(moves.applyMoveCentr(move, state), 6);
    }
};

exports.build333MoveTable = build333MoveTable;

var moveLookup = function(move, state) {
    return [
        tables[move][0][state[0]],
        tables[move][1][state[1]],
        tables[move][1][state[2]],
        tables[move][2][state[3]],
        tables[move][3][state[4]],
        tables[move][3][state[5]],
        tables[move][3][state[6]],
        tables[move][4][state[7]]
    ];
};
exports.moveLookup = moveLookup;

// Test cases

/*
build333MoveTable("R");

var startStateRaw = [[0,0,0,0,0,0,0,0], [1,2,3,4,5,6,7,8], [0,0,0,0,0,0,0,0,0,0,0,0], [1,2,3,4,5,6,7,8,9,10,11,12], [1,2,3,4,5,6]];
var startState = coord.get333hashes(startStateRaw);

console.log(startState);

console.log(moveLookup("R", startState));

/**/
<commit_msg>Fix bug that was causing edge orientation in move tables to be incorrect<commit_after>var moves = require("./moves");
var coord = require("./coords");

var tables = {};
exports.tables = tables;

var build333MoveTable = function (move) {

    var state;
    tables[move] = {};

    // CO
    tables[move][0] = {};
    for (var hash=0; hash < Math.pow(3,8); hash++) {
        state = coord.invertHash(hash, 2, 8);
        tables[move][0][hash] = coord.getHash(moves.applyMoveCO(move, state), 2);
    }

    // EO
    tables[move][2] = {};
    for (var hash=0; hash < Math.pow(2, 12); hash++) {
        state = coord.invertHash(hash, 1, 12);
        tables[move][2][hash] = coord.getHash(moves.applyMoveEO(move, state), 1);
    }

    // Note: Because CP and EP track positions of groups of four pieces, and
    // the positions are independent of the four positions being tracked,
    // the same move table can be applied to all groups.

    //CP
    tables[move][1] = {};
    for (var hash=0; hash < Math.pow(9, 4); hash++) {
        state = coord.positionsToState(coord.invertHash(hash, 8, 4), [1,2,3,4], 8, 8);
        // Skip states that are missing a piece.
        if (state.indexOf(1)<0 || state.indexOf(2)<0 || state.indexOf(3)<0 || state.indexOf(4)<0) {
            continue;
        }
        tables[move][1][hash] = coord.getHash(coord.findPieces(moves.applyMoveCP(move, state), [1,2,3,4], 8), 8);
    }

    //EP
    tables[move][3] = {};
    for (var hash=0; hash < Math.pow(13, 4); hash++) {
        state = coord.positionsToState(coord.invertHash(hash, 12, 4), [1,2,3,4], 12, 12);
        // Skip states that are missing a piece.
        if (state.indexOf(1)<0 || state.indexOf(2)<0 || state.indexOf(3)<0 || state.indexOf(4)<0) {
            continue;
        }
        tables[move][3][hash] = coord.getHash(coord.findPieces(moves.applyMoveEP(move, state), [1,2,3,4], 12), 12);
    }

    // Centres
    tables[move][4] = {};
    for (var hash=0; hash < Math.pow(7,6); hash++) {
        state = coord.invertHash(hash, 6, 6);
        if (state.indexOf(1)<0 || state.indexOf(2)<0 || state.indexOf(3)<0 ||
            state.indexOf(4)<0 || state.indexOf(5)<0 || state.indexOf(6)<0) {
            continue;
        }
        tables[move][4][hash] = coord.getHash(moves.applyMoveCentr(move, state), 6);
    }
};

exports.build333MoveTable = build333MoveTable;

var moveLookup = function(move, state) {
    return [
        tables[move][0][state[0]],
        tables[move][1][state[1]],
        tables[move][1][state[2]],
        tables[move][2][state[3]],
        tables[move][3][state[4]],
        tables[move][3][state[5]],
        tables[move][3][state[6]],
        tables[move][4][state[7]]
    ];
};
exports.moveLookup = moveLookup;

// Test cases

/*
build333MoveTable("R");

var startStateRaw = [[0,0,0,0,0,0,0,0], [1,2,3,4,5,6,7,8], [0,0,0,0,0,0,0,0,0,0,0,0], [1,2,3,4,5,6,7,8,9,10,11,12], [1,2,3,4,5,6]];
var startState = coord.get333hashes(startStateRaw);

console.log(startState);

console.log(moveLookup("R", startState));

/**/
<|endoftext|>