<commit_before>'use strict';

var _ = require('lodash'),
  path = require('path'),
  fs = require('fs-extra'),
  chalk = require('chalk'),
  walk = require('simple-walk'),
  css = require('css'),
  // formattor = require('formattor'),
  nunjucks = require('nunjucks'),
  // env = new nunjucks.Environment(),
  debug = false,
  extraFields = ['type', 'position'],
  StyleGuide;

// Prints an message & value
function logMsg(msg, value) {
  if (debug) {
    console.log(chalk.bold.gray('%s\n'), msg);
    console.log(chalk.gray('%j\n'), value);
  }
}
// Prints an object
function log(o) {
  if (debug) {
    // console.log(chalk.gray(formattor(o, {method: 'json'})));
    separator('Object');
    console.log(chalk.gray('%j\n'), o);
  }
}
// Prints a separator
function separator(title) {
  if (debug) {
    console.log(chalk.gray('%s%s%s'), _.repeat('=', 10), title ,_.repeat('=', 10));
  }
}

// Accepts in arguments of files
StyleGuide = function (config) {
  this.templates  = 'templates';
  this.source = config.source;
  this.output = config.output;
  debug = config.debug;

  this.setFiles();
};

// Read the css file
StyleGuide.prototype.getFile = function (source) {
  separator('START');
  logMsg('\n1) Get the file from ', source);
  return fs.readFileSync(source, 'utf8');
};

// Parse the CSS file
StyleGuide.prototype.getParsedCss = function (source) {
  var file = this.getFile(source);

  logMsg('1a) Parsed Css', source);
  return file ? css.parse(file) : '';
};

// Map the data to the format we would like
function addInfo(items) {
  return _.map(items, function (item) {

    item.selectors = _.map(item.selectors, function (selectorItem) {
      var value = selectorItem.split('.'),
        selector = value[0],
        state = value[1] || 'none';

      return {
        selector: selector,
        state: state
      };
    });

    item.declarations = _.map(item.declarations, function (item) {
      return _.omit(item, extraFields);
    });

    logMsg('2) Mapped these items:  ', item.selectors);
  });

}

StyleGuide.prototype.getData = function (data) {
  var styles = _.chain(data)
  .map(function (item) {
    return _.omit(item, extraFields);
  })
  .tap(addInfo)
  .tap(log)
  .value();

  logMsg('3) Retrieved Data: ', styles[0].selectors[0]);

  return styles;
};

// Set files
StyleGuide.prototype.setFiles = function () {

  var fileIndex,
    myCss,
    data,
    link,
    menu = [],
    files = walk.match(this.source, /(\.css)$/gi) || [];

  for (fileIndex in files) {
    if (files.hasOwnProperty(fileIndex)) {
      link = path.basename(files[fileIndex]);
      myCss = this.getParsedCss(files[fileIndex]);
      data = this.getData(myCss.stylesheet.rules);
      menu.push(link);

      logMsg('4) Create html page for ', link);
      this.render(fileIndex, path.join(this.templates, 'page.tpl'), {title: link, rules: data});
    }
  }

  // Render first page
  logMsg('4a) Create index page with links ', menu);
  this.render('', path.join(this.templates, 'index.tpl'), {menu: menu});
};

// Copies module & project css
StyleGuide.prototype.copyFiles = function () {
  // Copy css folder with autostyles module css
  fs.copySync(path.resolve('.','app'), path.join(this.output, 'css'));
  // Copy css folder containing the project files
  fs.copySync(this.source, path.join(this.output, 'css'));

  logMsg('5) Copy Files to ', this.output);
};

// Write out file to specified folder
StyleGuide.prototype.writeFiles = function (filename, content) {
  logMsg('5a) Write Files', filename);

  fs.outputFile(filename, content, function (err) {
    if (err) {
      console.log('Error: ', err);
      process.exit(1);
    } else {
      process.exit(0);
    }
  });
};

// Output rendered file
StyleGuide.prototype.render = function (index, filename, data) {
  var res = nunjucks.render(filename, data),
    file = filename.replace(this.templates, this.output).replace('.tpl', index + '.html');

  this.copyFiles(this.source, this.output);
  this.writeFiles(file, res);

  logMsg('6) Output the rendered file ', filename);
};

module.exports = StyleGuide;
<commit_msg>Index: Added error handling for render<commit_after>'use strict';

var _ = require('lodash'),
  path = require('path'),
  fs = require('fs-extra'),
  chalk = require('chalk'),
  walk = require('simple-walk'),
  css = require('css'),
  // formattor = require('formattor'),
  nunjucks = require('nunjucks'),
  // env = new nunjucks.Environment(),
  debug = false,
  extraFields = ['type', 'position'],
  StyleGuide;

// Prints an message & value
function logMsg(msg, value) {
  if (debug) {
    console.log(chalk.bold.gray('%s\n'), msg);
    console.log(chalk.gray('%j\n'), value);
  }
}
// Prints an object
function log(o) {
  if (debug) {
    // console.log(chalk.gray(formattor(o, {method: 'json'})));
    separator('Object');
    console.log(chalk.gray('%j\n'), o);
  }
}
// Prints a separator
function separator(title) {
  if (debug) {
    console.log(chalk.gray('%s%s%s'), _.repeat('=', 10), title ,_.repeat('=', 10));
  }
}

// Accepts in arguments of files
StyleGuide = function (config) {
  this.templates  = 'templates';
  this.source = config.source;
  this.output = config.output;
  debug = config.debug;

  this.setFiles();
};

// Read the css file
StyleGuide.prototype.getFile = function (source) {
  separator('START');
  logMsg('\n1) Get the file from ', source);
  return fs.readFileSync(source, 'utf8');
};

// Parse the CSS file
StyleGuide.prototype.getParsedCss = function (source) {
  var file = this.getFile(source);

  logMsg('1a) Parsed Css', source);
  return file ? css.parse(file) : '';
};

// Map the data to the format we would like
function addInfo(items) {
  return _.map(items, function (item) {

    item.selectors = _.map(item.selectors, function (selectorItem) {
      var value = selectorItem.split('.'),
        selector = value[0],
        state = value[1] || 'none';

      return {
        selector: selector,
        state: state
      };
    });

    item.declarations = _.map(item.declarations, function (item) {
      return _.omit(item, extraFields);
    });

    logMsg('2) Mapped these items:  ', item.selectors);
  });

}

StyleGuide.prototype.getData = function (data) {
  var styles = _.chain(data)
  .map(function (item) {
    return _.omit(item, extraFields);
  })
  .tap(addInfo)
  .tap(log)
  .value();

  logMsg('3) Retrieved Data: ', styles[0].selectors[0]);

  return styles;
};

// Set files
StyleGuide.prototype.setFiles = function () {

  var fileIndex,
    myCss,
    data,
    link,
    menu = [],
    files = walk.match(this.source, /(\.css)$/gi) || [];

  for (fileIndex in files) {
    if (files.hasOwnProperty(fileIndex)) {
      link = path.basename(files[fileIndex]);
      myCss = this.getParsedCss(files[fileIndex]);
      data = this.getData(myCss.stylesheet.rules);
      menu.push(link);

      logMsg('4) Create html page for ', link);
      this.render(fileIndex, path.join(this.templates, 'page.tpl'), {title: link, rules: data});
    }
  }

  // Render first page
  logMsg('4a) Create index page with links ', menu);
  this.render('', path.join(this.templates, 'index.tpl'), {menu: menu});
};

// Copies module & project css
StyleGuide.prototype.copyFiles = function () {
  // Copy css folder with autostyles module css
  fs.copySync(path.resolve('.','app'), path.join(this.output, 'css'));
  // Copy css folder containing the project files
  fs.copySync(this.source, path.join(this.output, 'css'));

  logMsg('5) Copy Files to ', this.output);
};

// Write out file to specified folder
StyleGuide.prototype.writeFiles = function (filename, content) {
  logMsg('5a) Write Files', filename);

  fs.outputFile(filename, content, function (err) {
    if (err) {
      console.log('Error: ', err);
      process.exit(1);
    } else {
      process.exit(0);
    }
  });
};

// Output rendered file
StyleGuide.prototype.render = function (index, filename, data) {
  var self = this,
    file;

  nunjucks.render(filename, data, function (err, res) {
    if (err) {
      console.error(chalk.bold.underline.red(filename), err.stack);
      process.exit(1);
    } else {
      file = filename.replace(self.templates, self.output).replace('.tpl', index + '.html');
      self.copyFiles(self.source, self.output);
      self.writeFiles(file, res);
    }
  });

  logMsg('6) Output the rendered file ', filename);
};

module.exports = StyleGuide;
<|endoftext|>


<commit_before>var fs = require('fs')
var url = require('url')
var http = require('http')
var mime = require('mime')
var path = require('path')
var static = require('node-static')

var sessions = {}
var maxUsers = 4

var port = process.env.PORT || 4567

var client = path.join(path.dirname(__filename), 'public/')

var server = http.createServer(function (request, response) {
  var headers = {
    'Cache-Control': 'no-cache, no-store',
    'Pragma': 'no-cache',
    'Expires': '0'
  }

  var segments = request.url.split('/')

  if (segments[1] === 'request' || segments[1] === 'response') {
    var _sessionId = segments[2]
    var _userId = segments[3]

    if (!_sessionId || !_userId) {
      response.writeHead(401)
      response.end
      return
    }

    if (segments[1] === 'request') {
      var _peer
      var _peerId = segments[4]
      var _session = sessions[_sessionId]

      if (!_session || !(_peer = _session.users[_peerId])) {
        console.log('boom')
        response.writeHead(401)
        response.end()
        return
      }

      var body = ''

      request.on('data', function (data) {
        body = body + data
      })

      request.on('end', function () {
        var event = 'data:' + body.replace(/\n/g, "\n" + 'data:') + "\n"

        _peer.response.write('event:user-' + _userId + "\n" + event + "\n")

        console.log('@' + _sessionId + ' - ' + _userId + ' => ' + _peerId + '.')
      })

      headers['Content-Type'] = 'text/event-stream'

      response.writeHead(204, headers)
      response.end()
    } else if (segments[1] === 'response') {
      console.log('@' + _sessionId + ' - ' + _userId + ' joined.')

      headers['Content-Type'] = 'text/event-stream'

      response.writeHead(200, headers)

      function keepAlive (res) {
        res.write(":\n")
        res.keepAliveTimer = setTimeout(arguments.callee, 30000, res)
      }
      keepAlive(response)

      var _session = sessions[_sessionId]

      if (!_session) {
        _session = sessions[_sessionId] = {
          'users': {}
        }
      }

      if (Object.keys(_session.users).length > maxUsers - 1) {
        response.write('event:full' + "\n" + 'data:' + _sessionId + "\n\n")

        clearTimeout(response.keepAliveTimer)
        response.end()
        return
      }

      var _user = _session.users[_userId]

      if (!_user) {
        _user = _session.users[_userId] = {}

        for (var _id in _session.users) {
          var res = _session.users[_id].response

          if (res) {
            clearTimeout(res.keepAliveTimer)
            keepAlive(res)

            response.write('event:join' + "\n" + 'data:' + _id + "\n\n")
            res.write('event:join' + "\n" + 'data:' + _userId + "\n\n")
            console.log(_id + ' ' + _userId)
          }
        }
      } else if (_user.response) {
        _user.response.end()
        clearTimeout(_user.response.keepAliveTimer)
        _user.response = null
      }

      _user.response = response

      request.on('close', function () {
        for (var _id in _session.users) {
          if (_id === _userId) {
            continue
          }

          var res = _session.users[_id].response

          res.write('event:leave' + "\n" + 'data:' + _userId + "\n\n")
        }
      })
    }

    return
  }

  route(request, response)
})

function route (req, res) {
  var segments = req.url.split('/')

  switch (segments[1]) {
    case '':
      displayPage('/index.html', req, res)
      break
    case 's':
      displayPage('/session.html', req, res)
      break
    default:
      var file = new static.Server('./public')
      file.serve(req, res)
  }

  return
}

function displayPage (uri, req, res) {
  file = path.join(client, uri)

  fs.stat(file, function (error, stats) {
    if (error || !stats.isFile()) {
      res.writeHead(404)
      res.end()
      return
    }

    fs.readFile(file, 'binary', function(error, resource) {
      res.writeHead(200, { 'Content-Type': 'text/html' })
      res.write(resource, 'binary')
      res.end()
    })
  })
}

server.listen(port)

console.log('Server is running on port ' + port)
<commit_msg>Refactor: change signaling protocol from eventsource to websocket<commit_after>var Hapi = require('hapi')

var server = new Hapi.Server()

server.connection({ port: 4567, labels: ['signal'] })
server.connection({ port: 8000, labels: ['client'] })
server.register([
  require('./signal'),
  require('inert'),
  require('./client')
], function (error) {
  if (error) {
    throw error
  }

  server.start(function () {
    console.log('Server started at: ' + server.info.uri + '.')
  })
})
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import Modal from 'react-modal';
import Formsy from 'formsy-react';
import 'react-select/dist/react-select.css';
import { checkStatus } from '../../actions/utils';
import { SERVER_API_BASE as serverApiBase } from 'config';
import FRC from 'formsy-react-components';

const { Input, Textarea, Select } = FRC;
import { modalStyle as customStyles } from '../../styles.js';

export const getLanguages = () => {
  return fetch(serverApiBase + 'languages/', {
    headers: {
      'Content-Type': 'application/json',
      Authorization: 'Token ' + sessionStorage.token,
    },
  })
    .then(checkStatus)
    .then(languages => {
      const langs = languages.results.map(language => ({
        value: language.id,
        label: language.name,
      }));
      return {
        options: langs,
        complete: true,
      };
    })
    .catch(error => {
      console.log('request failed', error);
    });
};

export default class CreateDistrict extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: '',
      languages: [],
      disabled: false,
      canSubmit: false,
      languages: {
        isLoading: true,
        list: [],
      },
      mgmt: {
        isLoading: true,
        list: [],
      },
      institutionCategories: {
        isLoading: true,
        list: [],
      },
    };
    this.handleChange = this.handleChange.bind(this);
    this.enableSubmitButton = this.enableSubmitButton.bind(this);
    this.disableSubmitButton = this.disableSubmitButton.bind(this);
    this.submitForm = this.submitForm.bind(this);
  }

  componentDidMount() {
    //getLanguages();
  }

  enableSubmitButton() {
    this.setState({
      canSubmit: true,
    });
  }

  disableSubmitButton() {
    this.setState({
      canSubmit: false,
    });
  }

  handleChange(e) {
    this.setState({
      name: e.target.value,
    });
  }

  selectLanguage = value => {
    this.setState({
      languages: value,
    });
  };

  submitForm() {
    var myform = this.myform.getModel();
    //  console.log(myform.institutionLang)
    let copy = {};
    copy.dise_code = myform.institutionDise_code;
    //  copy.mgmt = myform.institutionMgmt;
    copy.institution_gender = myform.institutionGender;
    //  copy.languages = myform.institutionLang;
    copy.name = myform.name;
    copy.address = myform.institutionAddress;
    copy.area = myform.institutionArea;
    copy.landmark = myform.institutionLandmark;
    copy.pincode = myform.institutionPincode;
    copy.cat = myform.institutionCat;
    //  console.log(copy)
    let languages = [];

    for (let i = 0; i < myform.institutionLang.length; i++) {
      languages.push(parseInt(myform.institutionLang[i]));
    }
    copy.languages = languages;
    this.props.save(copy);
  }

  render() {
    const schoolCategory = [
      { value: 'lower', label: 'Lower' },
      { value: 'upper', label: 'Upper' },
      { value: 'middle', label: 'Middle' },
    ];
    const selectOptions = [
      { value: 'co-ed', label: 'Co-Ed' },
      { value: 'boys', label: 'Boys' },
      { value: 'girls', label: 'Girls' },
    ];
    const singleSelectOptions = [{ value: '', label: 'Please select…' }, ...selectOptions];
    //  console.log(this.props);
    return (
      <Modal
        contentLabel="Create Institution"
        isOpen={this.props.isOpen}
        onRequestClose={this.props.onCloseModal}
        style={customStyles}
      >

              <button
                type="button"
                className="close"
                onClick={this.props.onCloseModal}
                aria-label="Close"
              >
                ×
              </button>

{this.props.title}

              <Formsy.Form
                onValidSubmit={this.submitForm}
                onValid={this.enableSubmitButton}
                onInvalid={this.disableSubmitButton}
                disabled={this.state.disabled}
                ref={ref => (this.myform = ref)}
              >
                <Input
                  name="name"
                  id="name"
                  value=""
                  label="School Name:"
                  type="text"
                  value=""
                  placeholder={this.props.placeHolder}
                  required
                  validations="minLength:1"
                />
                <Textarea
                  rows={3}
                  cols={40}
                  name="institutionAddress"
                  label="Address :"
                  value=""
                  required
                  validations="minLength:1"
                />

                <Input
                  name="institutionArea"
                  id="institutionArea"
                  label="Area:"
                  type="text"
                  value=""
                  className="form-control"
                />
                <Input
                  name="institutionLandmark"
                  id="institutionLandmark"
                  label="Landmark:"
                  type="text"
                  value=""
                  className="form-control"
                />
                <Input
                  name="institutionPincode"
                  id="institutionPincode"
                  label="Pincode:"
                  type="text"
                  value=""
                  className="form-control"
                />
                <Select
                  name="institutionCat"
                  label="Category:"
                  value={schoolCategory[0]}
                  options={schoolCategory}
                />
                <Select
                  multiple
                  name="institutionLang"
                  label="Medium:"
                  value={[this.props.languages.list[0].value]}
                  options={this.props.languages.list}
                  required
                />
                <Select
                  name="institutionGender"
                  label="Gender:"
                  value={selectOptions[0].value}
                  options={selectOptions}
                  required
                />
                <Input
                  name="institutionDise_code"
                  id="institutionDise_code"
                  value=""
                  label="DISE Code:"
                  type="text"
                  className="form-control"
                />
                {/*Languages
                <Select.Async multi name="form-field-name" value={this.state.languages} loadOptions={getLanguages} onChange={this.selectLanguage}/>*/}
              </Formsy.Form>

              <button type="button" className="btn btn-default" onClick={this.props.onCloseModal}>
                Discard
              </button>
              <button
                type="button"
                disabled={!this.state.canSubmit}
                className="btn btn-primary"
                onClick={this.submitForm}
              >
                Save
              </button>

      </Modal>
    );
  }
}
<commit_msg>Fixed: Creation of institution inside cluster (#233)<commit_after>import React, { Component } from 'react';
import Modal from 'react-modal';
import Formsy from 'formsy-react';
import 'react-select/dist/react-select.css';
import {checkStatus} from '../../actions/utils';
import { getInstitutionCategories } from '../utils'
import {SERVER_API_BASE as serverApiBase} from 'config';

import FRC from 'formsy-react-components';

const { Input, Textarea, Select } = FRC;
import { modalStyle as customStyles } from '../../styles.js';

export const getLanguages = () => {
  return fetch(serverApiBase + 'languages/', {
    headers: {
      'Content-Type': 'application/json',
      Authorization: 'Token ' + sessionStorage.token,
    },
  })
    .then(checkStatus)
    .then(languages => {
      const langs = languages.results.map(language => ({
        value: language.id,
        label: language.name,
      }));
      return {
        options: langs,
        complete: true,
      };
    })
    .catch(error => {
      console.log('request failed', error);
    });
};

export default class CreateDistrict extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: '',
      languages: [],
      disabled: false,
      canSubmit: false,
      languages: {
        isLoading: true,
        list: [],
      },
      mgmt: {
        isLoading: true,
        list: [],
      },
      institutionCategories: {
        isLoading: true,
        list: [],
      },
    };
    this.handleChange = this.handleChange.bind(this);
    this.enableSubmitButton = this.enableSubmitButton.bind(this);
    this.disableSubmitButton = this.disableSubmitButton.bind(this);
    this.submitForm = this.submitForm.bind(this);
  }

  componentDidMount() {
    //getLanguages();
    getInstitutionCategories().then(categories => {
      const cat = categories.results.filter(cat => {
        return cat.category_type === 1
      })
      .map(category => ({
        value: category.id,
        label: category.name
      }))

      this.setState({
        institutionCategories: {
          isLoading: false,
          list: cat
        }
      })
    })
  }

  enableSubmitButton() {
    this.setState({
      canSubmit: true,
    });
  }

  disableSubmitButton() {
    this.setState({
      canSubmit: false,
    });
  }

  handleChange(e) {
    this.setState({
      name: e.target.value,
    });
  }

  selectLanguage = value => {
    this.setState({
      languages: value,
    });
  };

  submitForm() {
    var myform = this.myform.getModel();
    //  console.log(myform.institutionLang)
    let copy = {};
    copy.dise_code = myform.institutionDise_code;
    //  copy.mgmt = myform.institutionMgmt;
    copy.institution_gender = myform.institutionGender;
    //  copy.languages = myform.institutionLang;
    copy.name = myform.name;
    copy.address = myform.institutionAddress;
    copy.area = myform.institutionArea;
    copy.landmark = myform.institutionLandmark;
    copy.pincode = myform.institutionPincode;
    copy.cat = myform.institutionCat;
    //  console.log(copy)
    let languages = [];

    for (let i = 0; i < myform.institutionLang.length; i++) {
      languages.push(parseInt(myform.institutionLang[i]));
    }
    copy.languages = languages;
    this.props.save(copy);
  }

 render() {
   let { institutionCategories } = this.state

   const selectOptions = [
           {value: 'co-ed', label: 'Co-Ed'},
           {value: 'boys', label: 'Boys'},
           {value: 'girls', label: 'Girls'},
       ];
   const singleSelectOptions = [
       {value: '', label: 'Please select…'},
       ...selectOptions
   ];
  //  console.log(this.props);
  return (
    <Modal contentLabel="Create Institution" isOpen={ this.props.isOpen } onRequestClose={ this.props.onCloseModal } style={ customStyles }>

              <button
                type="button"
                className="close"
                onClick={this.props.onCloseModal}
                aria-label="Close"
              >
                ×
              </button>

{this.props.title}

              <Formsy.Form
                onValidSubmit={this.submitForm}
                onValid={this.enableSubmitButton}
                onInvalid={this.disableSubmitButton}
                disabled={this.state.disabled}
                ref={ref => (this.myform = ref)}
              >
                <Input
                  name="name"
                  id="name"
                  value=""
                  label="School Name:"
                  type="text"
                  value=""
                  placeholder={this.props.placeHolder}
                  required
                  validations="minLength:1"
                />
                <Textarea
                  rows={3}
                  cols={40}
                  name="institutionAddress"
                  label="Address :"
                  value=""
                  required
                  validations="minLength:1"
                />

                <Input
                  name="institutionArea"
                  id="institutionArea"
                  label="Area:"
                  type="text"
                  value=""
                  className="form-control"
                />
                <Input name="institutionPincode"
                 id="institutionPincode"
                 label="Pincode:" type="text"
                 value = ""
                 className="form-control"
                 />
                 <Select
                 name="institutionCat"
                 label="Category:"
                 value = {institutionCategories.list[0]}
                 options={institutionCategories.list}
                 />
                 <Select
                   multiple
                   name="institutionLang"
                   label="Medium:"
                   value = {[this.props.languages.list[0].value]}
                   options={this.props.languages.list}
                   required
                 />
                 <Select
                   name="institutionGender"
                   label="Gender:"
                   value ={selectOptions[0].value}
                   options={selectOptions}
                   required
                 />
                 <Input name="institutionDise_code"
                    id="institutionDise_code"
                    value=""
                    label="DISE Code:" type="text"
                    className="form-control"
                  />

              <Select.Async multi name="form-field-name" value={this.state.languages} loadOptions={getLanguages} onChange={this.selectLanguage}/>*/}
              </Formsy.Form>

              <button type="button" className="btn btn-default" onClick={this.props.onCloseModal}>
                Discard
              </button>
              <button
                type="button"
                disabled={!this.state.canSubmit}
                className="btn btn-primary"
                onClick={this.submitForm}
              >
                Save
              </button>

      </Modal>
    );
  }
}
<|endoftext|>


<commit_before>#!/usr/bin/env electron

const path = require('path')
const minimist = require('minimist')
const electron = require('electron')
const isDev = require('electron-is-dev')
const contextMenu = require('electron-context-menu')
const debug = require('electron-debug')
const mkdirp = require('mkdirp')
const series = require('run-series')
const styles = require('mapeo-styles')
const { fork } = require('child_process')
const middleware = require('hoist')

const app = electron.app
const BrowserWindow = electron.BrowserWindow

const logger = require('./src/logger')
const miscellaneousIpc = require('./src/main/ipc')
const createMenu = require('./src/main/menu')
const windowStateKeeper = require('./src/main/window-state')

// HACK: enable GPU graphics acceleration on some older laptops
app.commandLine.appendSwitch('ignore-gpu-blacklist', 'true')

// Setup some handy dev tools shortcuts (only activates in dev mode)
// See https://github.com/sindresorhus/electron-debug
debug({ showDevTools: false })

// Handle uncaught errors
// XXX(KM): why aren't we enabling this?
// catchErrors({ onError: handleError })

var win = null
var splash = null
var bg = null
var mainWindowState = null
var serverProcess = null
var ipc = new middleware.Client()

var gotTheLock = app.requestSingleInstanceLock()

if (!gotTheLock) {
  // Didn't get a lock, because another instance is open, so we quit
  process.exit(0)
} else {
  app.on('second-instance', () => {
    // Someone tried to run a second instance, we should focus our window.
    if (win) {
      if (win.isMinimized()) win.restore()
      win.focus()
    }
  })
}

// Path to `userData`, operating system specific, see
// https://github.com/atom/electron/blob/master/docs/api/app.md#appgetpathname
var userDataPath = app.getPath('userData')

var argv = minimist(process.argv.slice(2), {
  default: {
    port: 5000,
    datadir: path.join(userDataPath, 'kappa.db'),
    tileport: 5005
  },
  boolean: ['headless', 'debug'],
  alias: {
    p: 'port',
    t: 'tileport',
    d: 'debug'
  }
})

if (argv.headless) startSequence()
else app.once('ready', openWindow)

app.on('before-quit', beforeQuit)
app.on('window-all-closed', function () {
  app.quit()
})

function openWindow () {
  // TODO: get a socket name that isn't open ..
  var _socketName = 'mapeo1'
  logger.log('got socket', _socketName)
  ipc.on('error', function (err) {
    logger.error(err)
    electron.dialog.showErrorBox('Error', err)
  })
  ipc.connect(_socketName)

  if (!win) {
    win = createWindow(_socketName)
    splash = createSplashWindow()
  }

  if (isDev) {
    bg = createBgWindow(_socketName)
    try {
      var {
        default: installExtension,
        REACT_DEVELOPER_TOOLS
      } = require('electron-devtools-installer')
    } catch (e) {}
    installExtension(REACT_DEVELOPER_TOOLS)
      .then(name => logger.log(`Added Extension:  ${name}`))
      .catch(err => logger.log('An error occurred: ', err))
  } else {
    createBackgroundProcess(_socketName)
  }
  createMenu(ipc)

  // Emitted when the window is closed.
  win.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    win = null
    splash = null
    bg = null
    app.quit()
  })

  startSequence()
}

function startupMsg (txt) {
  return function (done) {
    logger.log('[STARTUP] ' + txt)
    done()
  }
}

function startSequence () {
  // The app startup sequence
  series(
    [
      initDirectories,
      startupMsg('Initialized directories'),

      createServers,
      startupMsg('Started node-ipc servers'),

      notifyReady,
      startupMsg('Notified the frontend that backend is ready')
    ],
    function (err) {
      if (err) logger.error('STARTUP FAILED', err)
      else logger.log('STARTUP success!')
    }
  )
}

function initDirectories (done) {
  startupMsg('Unpacking Styles')
  // This is necessary to make sure that the styles and presets directory
  // are writable by the user
  mkdirp.sync(path.join(userDataPath, 'styles'))
  mkdirp.sync(path.join(userDataPath, 'presets'))
  mkdirp.sync(argv.datadir)
  styles.unpackIfNew(userDataPath, function (err) {
    if (err) logger.error('[ERROR] while unpacking styles:', err)
  })
  done()
}

function createServers (done) {
  // TODO: rename/refactor
  miscellaneousIpc(win)

  logger.log('initializing mapeo', userDataPath, argv.port)
  var opts = {
    userDataPath,
    datadir: argv.datadir,
    port: argv.port,
    tileport: argv.tileport
  }

  ipc.send('listen', opts, function (err, port) {
    if (err) throw new Error('fatal: could not get port', err)
    logger.log('listen port got back', port)
    global.osmServerHost = '127.0.0.1:' + port
    logger.log(global.osmServerHost)
    done()
  })
}

function notifyReady (done) {
  win.webContents.on('did-finish-load', () => {
    setTimeout(() => {
      var IS_TEST = process.env.NODE_ENV === 'test'
      if (IS_TEST) win.setSize(1000, 800, false)
      if (argv.debug) win.webContents.openDevTools()

      win.maximize()
      splash.destroy()
      win.show()
      done()
    }, 1000)
  })
}

function createWindow (socketName) {
  var APP_NAME = app.getName()
  var INDEX = 'file://' + path.join(__dirname, './index.html')
  mainWindowState = windowStateKeeper({
    defaultWidth: 1000,
    defaultHeight: 800
  })
  var win = new BrowserWindow({
    x: mainWindowState.x,
    y: mainWindowState.y,
    width: mainWindowState.width,
    height: mainWindowState.height,
    title: APP_NAME,
    show: false,
    alwaysOnTop: false,
    titleBarStyle: 'hidden',
    icon: path.resolve(__dirname, 'static', 'mapeo_256x256.png'),
    webPreferences: {
      nodeIntegration: true,
      preload: path.resolve(__dirname, 'src', 'windows', 'index-preload.js')
    }
  })
  mainWindowState.manage(win)

  win.loadURL(INDEX)

  win.webContents.on('did-finish-load', () => {
    if (process.env.NODE_ENV === 'test') win.setSize(1000, 800, false)
    if (argv.debug) win.webContents.openDevTools()
    win.webContents.send('set-socket', {
      name: socketName
    })
  })
  return win
}

// Create a hidden background window
function createBgWindow (socketName) {
  var win = new BrowserWindow({
    x: 0,
    y: 0,
    width: 700,
    height: 700,
    show: argv.debug,
    webPreferences: {
      nodeIntegration: true
    }
  })
  console.log('loading bg window')
  var BG = 'file://' + path.join(__dirname, './src/windows/background.html')
  win.loadURL(BG)
  win.webContents.on('did-finish-load', () => {
    if (argv.debug) bg.webContents.openDevTools()
    win.webContents.send('set-socket', {
      name: socketName
    })
  })
  win.on('closed', () => {
    console.log('background window closed')
    app.quit()
  })
  return win
}

function createSplashWindow () {
  var SPLASH = 'file://' + path.join(__dirname, './src/windows/splash.html')
  var splash = new BrowserWindow({
    width: 450,
    height: 410,
    center: true,
    transparent: true,
    resizable: false,
    frame: false
  })
  splash.loadURL(SPLASH)
  return splash
}

function createBackgroundProcess (socketName) {
  console.log('creating background process')
  serverProcess = fork(path.join(__dirname, 'src', 'windows', 'background.js'), [
    '--subprocess',
    app.getVersion(),
    socketName
  ])

  serverProcess.on('message', msg => {
    console.log(msg)
  })
}

contextMenu({
  showLookUpSelection: false,
  showCopyImage: true,
  showSaveImageAs: true,
  showInspectElement: isDev
})

function beforeQuit (e) {
  // Cancel quit and wait for server to close
  e.preventDefault()

  var CLOSING = 'file://' + path.join(__dirname, './closing.html')
  var closingWin = new BrowserWindow({
    width: 600,
    height: 400,
    frame: false,
    show: false,
    alwaysOnTop: false
  })
  closingWin.loadURL(CLOSING)
  const closingTimeoutId = setTimeout(() => {
    closingWin.show()
  }, 300)

  // 'close' event will gracefully close databases and wait for pending sync
  // TODO: Show the user that a sync is pending finishing
  console.log('ipc.send close')
  ipc.send('close', null, () => {
    console.log('closed')
    clearTimeout(closingTimeoutId)
    if (serverProcess) serverProcess.kill()
    try { closingWin.close() } catch (e) {}
    closingWin = null
    serverProcess = null
    app.exit()
  })
}

// function handleError (error) {
//   logger.error('uncaughtException in Node:', error)
//   if (app && win) win.webContents.send('error', error.stack)
// }
<commit_msg>fix: uncaught reference/bad typo in index.js<commit_after>#!/usr/bin/env electron

const path = require('path')
const minimist = require('minimist')
const electron = require('electron')
const isDev = require('electron-is-dev')
const contextMenu = require('electron-context-menu')
const debug = require('electron-debug')
const mkdirp = require('mkdirp')
const series = require('run-series')
const styles = require('mapeo-styles')
const { fork } = require('child_process')
const middleware = require('electron-rabbit')

const app = electron.app
const BrowserWindow = electron.BrowserWindow

const logger = require('./src/logger')
const miscellaneousIpc = require('./src/main/ipc')
const createMenu = require('./src/main/menu')
const windowStateKeeper = require('./src/main/window-state')

// HACK: enable GPU graphics acceleration on some older laptops
app.commandLine.appendSwitch('ignore-gpu-blacklist', 'true')

// Setup some handy dev tools shortcuts (only activates in dev mode)
// See https://github.com/sindresorhus/electron-debug
debug({ showDevTools: false })

// Handle uncaught errors
// XXX(KM): why aren't we enabling this?
// catchErrors({ onError: handleError })

var win = null
var splash = null
var bg = null
var mainWindowState = null
var serverProcess = null
var ipc = new middleware.Client()

var gotTheLock = app.requestSingleInstanceLock()

if (!gotTheLock) {
  // Didn't get a lock, because another instance is open, so we quit
  process.exit(0)
} else {
  app.on('second-instance', () => {
    // Someone tried to run a second instance, we should focus our window.
    if (win) {
      if (win.isMinimized()) win.restore()
      win.focus()
    }
  })
}

// Path to `userData`, operating system specific, see
// https://github.com/atom/electron/blob/master/docs/api/app.md#appgetpathname
var userDataPath = app.getPath('userData')

var argv = minimist(process.argv.slice(2), {
  default: {
    port: 5000,
    datadir: path.join(userDataPath, 'kappa.db'),
    tileport: 5005
  },
  boolean: ['headless', 'debug'],
  alias: {
    p: 'port',
    t: 'tileport',
    d: 'debug'
  }
})

if (argv.headless) startSequence()
else app.once('ready', openWindow)

app.on('before-quit', beforeQuit)
app.on('window-all-closed', function () {
  app.quit()
})

function openWindow () {
  // TODO: get a socket name that isn't open ..
  var _socketName = 'mapeo1'
  logger.log('got socket', _socketName)
  ipc.on('error', function (err) {
    logger.error(err)
    electron.dialog.showErrorBox('Error', err)
  })
  ipc.connect(_socketName)

  if (!win) {
    win = createWindow(_socketName)
    splash = createSplashWindow()
  }

  if (isDev) {
    bg = createBgWindow(_socketName)
    try {
      var {
        default: installExtension,
        REACT_DEVELOPER_TOOLS
      } = require('electron-devtools-installer')
    } catch (e) {}
    installExtension(REACT_DEVELOPER_TOOLS)
      .then(name => logger.log(`Added Extension:  ${name}`))
      .catch(err => logger.log('An error occurred: ', err))
  } else {
    createBackgroundProcess(_socketName)
  }
  createMenu(ipc)

  // Emitted when the window is closed.
  win.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    win = null
    splash = null
    bg = null
    app.quit()
  })

  startSequence()
}

function startupMsg (txt) {
  return function (done) {
    logger.log('[STARTUP] ' + txt)
    done()
  }
}

function startSequence () {
  // The app startup sequence
  series(
    [
      initDirectories,
      startupMsg('Initialized directories'),

      createServers,
      startupMsg('Started node-ipc servers'),

      notifyReady,
      startupMsg('Notified the frontend that backend is ready')
    ],
    function (err) {
      if (err) logger.error('STARTUP FAILED', err)
      else logger.log('STARTUP success!')
    }
  )
}

function initDirectories (done) {
  startupMsg('Unpacking Styles')
  // This is necessary to make sure that the styles and presets directory
  // are writable by the user
  mkdirp.sync(path.join(userDataPath, 'styles'))
  mkdirp.sync(path.join(userDataPath, 'presets'))
  mkdirp.sync(argv.datadir)
  styles.unpackIfNew(userDataPath, function (err) {
    if (err) logger.error('[ERROR] while unpacking styles:', err)
  })
  done()
}

function createServers (done) {
  // TODO: rename/refactor
  miscellaneousIpc(win)

  logger.log('initializing mapeo', userDataPath, argv.port)
  var opts = {
    userDataPath,
    datadir: argv.datadir,
    port: argv.port,
    tileport: argv.tileport
  }

  ipc.send('listen', opts, function (err, port) {
    if (err) throw new Error('fatal: could not get port', err)
    logger.log('listen port got back', port)
    global.osmServerHost = '127.0.0.1:' + port
    logger.log(global.osmServerHost)
    done()
  })
}

function notifyReady (done) {
  win.webContents.on('did-finish-load', () => {
    setTimeout(() => {
      var IS_TEST = process.env.NODE_ENV === 'test'
      if (IS_TEST) win.setSize(1000, 800, false)
      if (argv.debug) win.webContents.openDevTools()

      win.maximize()
      splash.destroy()
      win.show()
      done()
    }, 1000)
  })
}

function createWindow (socketName) {
  var APP_NAME = app.getName()
  var INDEX = 'file://' + path.join(__dirname, './index.html')
  mainWindowState = windowStateKeeper({
    defaultWidth: 1000,
    defaultHeight: 800
  })
  var win = new BrowserWindow({
    x: mainWindowState.x,
    y: mainWindowState.y,
    width: mainWindowState.width,
    height: mainWindowState.height,
    title: APP_NAME,
    show: false,
    alwaysOnTop: false,
    titleBarStyle: 'hidden',
    icon: path.resolve(__dirname, 'static', 'mapeo_256x256.png'),
    webPreferences: {
      nodeIntegration: true,
      preload: path.resolve(__dirname, 'src', 'windows', 'index-preload.js')
    }
  })
  mainWindowState.manage(win)

  win.loadURL(INDEX)

  win.webContents.on('did-finish-load', () => {
    if (process.env.NODE_ENV === 'test') win.setSize(1000, 800, false)
    if (argv.debug) win.webContents.openDevTools()
    win.webContents.send('set-socket', {
      name: socketName
    })
  })
  return win
}

// Create a hidden background window
function createBgWindow (socketName) {
  var win = new BrowserWindow({
    x: 0,
    y: 0,
    width: 700,
    height: 700,
    show: argv.debug,
    webPreferences: {
      nodeIntegration: true
    }
  })
  console.log('loading bg window')
  var BG = 'file://' + path.join(__dirname, './src/windows/background.html')
  win.loadURL(BG)
  win.webContents.on('did-finish-load', () => {
    if (argv.debug) bg.webContents.openDevTools()
    win.webContents.send('set-socket', {
      name: socketName
    })
  })
  win.on('closed', () => {
    console.log('background window closed')
    app.quit()
  })
  return win
}

function createSplashWindow () {
  var SPLASH = 'file://' + path.join(__dirname, './src/windows/splash.html')
  var splash = new BrowserWindow({
    width: 450,
    height: 410,
    center: true,
    transparent: true,
    resizable: false,
    frame: false
  })
  splash.loadURL(SPLASH)
  return splash
}

function createBackgroundProcess (socketName) {
  console.log('creating background process')
  serverProcess = fork(path.join(__dirname, 'src', 'windows', 'background.js'), [
    '--subprocess',
    app.getVersion(),
    socketName
  ])

  serverProcess.on('message', msg => {
    console.log(msg)
  })
}

contextMenu({
  showLookUpSelection: false,
  showCopyImage: true,
  showSaveImageAs: true,
  showInspectElement: isDev
})

function beforeQuit (e) {
  // Cancel quit and wait for server to close
  e.preventDefault()

  var CLOSING = 'file://' + path.join(__dirname, './closing.html')
  var closingWin = new BrowserWindow({
    width: 600,
    height: 400,
    frame: false,
    show: false,
    alwaysOnTop: false
  })
  closingWin.loadURL(CLOSING)
  const closingTimeoutId = setTimeout(() => {
    closingWin.show()
  }, 300)

  // 'close' event will gracefully close databases and wait for pending sync
  // TODO: Show the user that a sync is pending finishing
  console.log('ipc.send close')
  ipc.send('close', null, () => {
    console.log('closed')
    clearTimeout(closingTimeoutId)
    if (serverProcess) serverProcess.kill()
    try { closingWin.close() } catch (e) {}
    closingWin = null
    serverProcess = null
    app.exit()
  })
}

// function handleError (error) {
//   logger.error('uncaughtException in Node:', error)
//   if (app && win) win.webContents.send('error', error.stack)
// }
<|endoftext|>


<commit_before>// svg example with dragging
// Only works as expected on the first drag
// Need to deal with offset better

let x = 100;
let y = 100;

function update() {
    x += 1;
    y -= 0.25;
    m.redraw()
}
const interval = setInterval(update, 100);

let draggedItem = null;
let start = {}
let offset = {}

show(() => {
    return m("svg", { width: 600, height: 200},
        m("rect[height='200'][width='600'][x='0'][y='0']", {
            style: {"stroke": "black", "fill": "none", "stroke-width": "1"}
        }),
        m("circle", {
            cx: x,
            cy: y,
            r: 50,
            stroke: "green",
            "stroke-width": 4,
            fill: "orange",
            onmousedown: (event) => {
                draggedItem = event.target
                start = { x: event.clientX, y: event.clientY }
                console.log("start", start)
                offset = { x: 0, y: 0 }
            },
            onmousemove: (event) => {
                if (draggedItem === event.target) {
                    let x = event.clientX - start.x + offset.x
                    let y = event.clientY - start.y + offset.y
                    event.target.setAttribute("transform", "translate(" + x + "," + y + ")")
                } else {
                    draggedItem = null
                }
            },
            onmouseup: () => draggedItem = null,
        })
    )
}, { onclose: () => clearInterval(interval) })
<commit_msg>Update svg-with-dragging.js<commit_after>// svg example with
// May not keep up with fast drags

let draggedItem = null;
let dragStart = {}
let objectStart = {}

show(() => {
    return m("svg", { width: 600, height: 200},
        m("rect[height='200'][width='600'][x='0'][y='0']", {
            style: {"stroke": "black", "fill": "none", "stroke-width": "1"}
        }),
        m("circle", {
            cx: 100,
            cy: 100,
            r: 50,
            stroke: "green",
            "stroke-width": 4,
            fill: "orange",
            onmousedown: (event) => {
                draggedItem = event.target
                dragStart = { x: event.clientX, y: event.clientY }
                objectStart = { x: parseInt(event.target.cx.baseVal.value), y: parseInt(event.target.cy.baseVal.value) }
            },
            onmousemove: (event) => {
                console.log("dragging", draggedItem)
                if (draggedItem === event.target) {
                    const dx = event.clientX - dragStart.x
                    const dy = event.clientY - dragStart.y
                    const newX = objectStart.x + dx
                    const newY = objectStart.y + dy
                    event.target.setAttribute("cx", newX)
                    event.target.setAttribute("cy", newY)
                }
            },
            onmouseup: () => {
                draggedItem = null
                console.log("stop dragging", draggedItem)
            },
        })
    )
}, { onclose: () => clearInterval(interval) })
<|endoftext|>


<commit_before>var util = require('util');
var urlLib = require('url');

var async = require('async');
var request = require('request');
var cheerio = require('cheerio');
var Bitly = require('bitly');

var log = require('logmagic').local('treslek.plugins.url');
var config = require('./config.json');

request = request.defaults({
  sendImmediately: true,
  timeout: 10000,
  headers: {
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36"
  }
});

/*
 * URL plugin
 *   - creates a hook that checks for urls. It then grabs the title
 *     and outputs that to the channel.
 *   Thanks to https://github.com/Floobits/floobot for scraping logic
 */
var Url = function() {
  this.hooks = ['url'];
};

/*
 * Helper function for shortening a url with bitly.
 */
var shortenUrl = function(bitly, url, callback) {
  if (!bitly) {
    callback(null, url);
    return;
  }

  bitly.shorten(url, function(err, resp) {
    if (err) {
      log.error('Error shortening url', {err: err, url: url});
      callback(err);
      return;
    }

    callback(null, resp.data.url || url);
  });
};

function parseYoutube(path, parsed) {
  var title, views, likes, dislikes, rating;

  if (path.match(/^\/watch/) === null) {
    return;
  }

  title = parsed('#eow-title').text().replace(/\n/g, ' ').replace(/^\s+/, '').replace(/\s+$/, '');
  views = parsed('#watch7-views-info > div.watch-view-count').text().replace(/[\s]/g, '') || 0;
  likes = parsed('#watch-like > span.yt-uix-button-content').text().replace(/[\s,]/g, '') || 0;
  dislikes = parsed('#watch-dislike > span.yt-uix-button-content').text().replace(/[\s,]/g, '') || 0;
  likes = parseInt(likes, 10);
  dislikes = parseInt(dislikes, 10);
  console.log(likes, dislikes);
  rating = Math.round(100 * likes / (likes + dislikes));

  return util.format("%s | %s views %s%% like", title, views, rating);
}

function parseTwitter(path, parsed) {
  var user, title, retweets, favorites;

  if (path.match("^\\/\\w+\\/status\\/\\d+") === null) {
    return;
  }

  user = parsed("div.permalink-tweet-container div.permalink-header a > span.username.js-action-profile-name > b").text();
  title = parsed("div.permalink-tweet-container p.tweet-text").text().replace(/\n/g, ' ').replace(/^\s+/, '').replace(/\s+$/, '');
  retweets = parsed("div.tweet-stats-container > ul.stats > li.js-stat-count.js-stat-retweets.stat-count > a > strong").text().replace(/\s/g, "") || 0;
  favorites = parsed("div.tweet-stats-container > ul.stats > li.js-stat-count.js-stat-favorites.stat-count > a > strong").text().replace(/\s/g, "") || 0;

  return util.format("<@%s> %s (%s retweets, %s favorites)", user, title, retweets, favorites);
}

function parseReddit(path, parsed) {
  var rating, title, score, comments;

  if (path.match('^\\/r\\/\\w+\\/comments') === null) {
    return;
  }

  title = parsed('p.title > a.title').text().replace(/\n/g, ' ').replace(/^\s+/, '').replace(/\s+$/, '');
  score = parsed('div.score > span.number').text();
  comments = parsed('div.entry > ul.flat-list > li.first > a.comments').text();

  return util.format('%s (%s upvotes, %s)', title, score, comments);
}

/*
 * URL hook.
 *   Searchs a message for any urls, and then request each url.
 *   If the url returns a content-type of 'text/html', attempt
 *   to get the page title. If not, return the content type. If
 *   bitly is configured, shorten urls as well.
 */
Url.prototype.url = function(bot, to, from, msg, callback) {
  var urlReg = /(http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/gi,
      matches = msg.match(urlReg),
      bitly;

  if (!matches) {
    callback();
    return;
  }

  if (config.bitlyUser !== '' && config.bitlyApiKey !== '') {
    bitly = new Bitly(config.bitlyUser, config.bitlyApiKey);
  }

  async.forEach(matches, function(url, callback) {
    request(url, function(err, res, body) {
      var response,
          parsed,
          parsedUrl,
          title,
          contentType;

      if (err || res.statusCode === 404) {
        if (err) {
          log.error('Error retrieving url', {url: url, err: err});
          callback();
          return;
        } else {
          log.error('Error retrieving url. Got response.', {url: url, err: err});
          callback();
          return;
        }
      }

      if (res.statusCode === 200) {
        contentType = res.headers['content-type'].split(';')[0];
        if (contentType !== 'text/html') {
          title = contentType;
        } else {
          parsed = cheerio.load(body);
          title = parsed('title').eq(0).text().replace(/\n/g, ' ').replace(/^\s+/, '');
        }
      }

      title = title || contentType;

      // Strip auth from parsed URL before
      parsedUrl = urlLib.parse(url);
      if (parsedUrl.auth) {
        delete parsedUrl.auth;
      }
      url = urlLib.format(parsedUrl);

      shortenUrl(bitly, url, function(err, shortUrl) {
        domain = parsedUrl.hostname.split('.').slice(-2).join('.');
        if (domain === 'youtube.com') {
          response = parseYoutube(parsedUrl.path, parsed) + ' | ' + shortUrl;
        } else if (domain === 'twitter.com') {
          response = parseTwitter(parsedUrl.path, parsed) + ' | ' + shortUrl;
        } else if (domain === 'reddit.com') {
          response = parseReddit(parsedUrl.path, parsed) + ' | ' + shortUrl;
        }

        if (!response) {
          if (typeof title == 'undefined') {
            response = parsedUrl.hostname + ' | ' + shortUrl;
          } else {
            response = title + ' | ' + shortUrl;
          }
        }
        bot.say(to, response);
        callback();
      });

    });
  }, callback);
};

exports.Plugin = Url;
<commit_msg>Be more concise and only get the title from the <head> tag.<commit_after>var util = require('util');
var urlLib = require('url');

var async = require('async');
var request = require('request');
var cheerio = require('cheerio');
var Bitly = require('bitly');

var log = require('logmagic').local('treslek.plugins.url');
var config = require('./config.json');

request = request.defaults({
  sendImmediately: true,
  timeout: 10000,
  headers: {
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36"
  }
});

/*
 * URL plugin
 *   - creates a hook that checks for urls. It then grabs the title
 *     and outputs that to the channel.
 *   Thanks to https://github.com/Floobits/floobot for scraping logic
 */
var Url = function() {
  this.hooks = ['url'];
};

/*
 * Helper function for shortening a url with bitly.
 */
var shortenUrl = function(bitly, url, callback) {
  if (!bitly) {
    callback(null, url);
    return;
  }

  bitly.shorten(url, function(err, resp) {
    if (err) {
      log.error('Error shortening url', {err: err, url: url});
      callback(err);
      return;
    }

    callback(null, resp.data.url || url);
  });
};

function parseYoutube(path, parsed) {
  var title, views, likes, dislikes, rating;

  if (path.match(/^\/watch/) === null) {
    return;
  }

  title = parsed('#eow-title').text().replace(/\n/g, ' ').replace(/^\s+/, '').replace(/\s+$/, '');
  views = parsed('#watch7-views-info > div.watch-view-count').text().replace(/[\s]/g, '') || 0;
  likes = parsed('#watch-like > span.yt-uix-button-content').text().replace(/[\s,]/g, '') || 0;
  dislikes = parsed('#watch-dislike > span.yt-uix-button-content').text().replace(/[\s,]/g, '') || 0;
  likes = parseInt(likes, 10);
  dislikes = parseInt(dislikes, 10);
  console.log(likes, dislikes);
  rating = Math.round(100 * likes / (likes + dislikes));

  return util.format("%s | %s views %s%% like", title, views, rating);
}

function parseTwitter(path, parsed) {
  var user, title, retweets, favorites;

  if (path.match("^\\/\\w+\\/status\\/\\d+") === null) {
    return;
  }

  user = parsed("div.permalink-tweet-container div.permalink-header a > span.username.js-action-profile-name > b").text();
  title = parsed("div.permalink-tweet-container p.tweet-text").text().replace(/\n/g, ' ').replace(/^\s+/, '').replace(/\s+$/, '');
  retweets = parsed("div.tweet-stats-container > ul.stats > li.js-stat-count.js-stat-retweets.stat-count > a > strong").text().replace(/\s/g, "") || 0;
  favorites = parsed("div.tweet-stats-container > ul.stats > li.js-stat-count.js-stat-favorites.stat-count > a > strong").text().replace(/\s/g, "") || 0;

  return util.format("<@%s> %s (%s retweets, %s favorites)", user, title, retweets, favorites);
}

function parseReddit(path, parsed) {
  var rating, title, score, comments;

  if (path.match('^\\/r\\/\\w+\\/comments') === null) {
    return;
  }

  title = parsed('p.title > a.title').text().replace(/\n/g, ' ').replace(/^\s+/, '').replace(/\s+$/, '');
  score = parsed('div.score > span.number').text();
  comments = parsed('div.entry > ul.flat-list > li.first > a.comments').text();

  return util.format('%s (%s upvotes, %s)', title, score, comments);
}

/*
 * URL hook.
 *   Searchs a message for any urls, and then request each url.
 *   If the url returns a content-type of 'text/html', attempt
 *   to get the page title. If not, return the content type. If
 *   bitly is configured, shorten urls as well.
 */
Url.prototype.url = function(bot, to, from, msg, callback) {
  var urlReg = /(http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/gi,
      matches = msg.match(urlReg),
      bitly;

  if (!matches) {
    callback();
    return;
  }

  if (config.bitlyUser !== '' && config.bitlyApiKey !== '') {
    bitly = new Bitly(config.bitlyUser, config.bitlyApiKey);
  }

  async.forEach(matches, function(url, callback) {
    request(url, function(err, res, body) {
      var response,
          parsed,
          parsedUrl,
          title,
          contentType;

      if (err || res.statusCode === 404) {
        if (err) {
          log.error('Error retrieving url', {url: url, err: err});
          callback();
          return;
        } else {
          log.error('Error retrieving url. Got response.', {url: url, err: err});
          callback();
          return;
        }
      }

      if (res.statusCode === 200) {
        contentType = res.headers['content-type'].split(';')[0];
        if (contentType !== 'text/html') {
          title = contentType;
        } else {
          parsed = cheerio.load(body);
          title = parsed('head title').text().replace(/\n/g, ' ').replace(/^\s+/, '');
        }
      }

      title = title || contentType;

      // Strip auth from parsed URL before
      parsedUrl = urlLib.parse(url);
      if (parsedUrl.auth) {
        delete parsedUrl.auth;
      }
      url = urlLib.format(parsedUrl);

      shortenUrl(bitly, url, function(err, shortUrl) {
        domain = parsedUrl.hostname.split('.').slice(-2).join('.');
        if (domain === 'youtube.com') {
          response = parseYoutube(parsedUrl.path, parsed) + ' | ' + shortUrl;
        } else if (domain === 'twitter.com') {
          response = parseTwitter(parsedUrl.path, parsed) + ' | ' + shortUrl;
        } else if (domain === 'reddit.com') {
          response = parseReddit(parsedUrl.path, parsed) + ' | ' + shortUrl;
        }

        if (!response) {
          if (typeof title == 'undefined') {
            response = parsedUrl.hostname + ' | ' + shortUrl;
          } else {
            response = title + ' | ' + shortUrl;
          }
        }
        bot.say(to, response);
        callback();
      });

    });
  }, callback);
};

exports.Plugin = Url;
<|endoftext|>


<commit_before>var Runner = require( './lib/runner' );
var chalk  = require( 'chalk' );
var debug  = require( 'debug' )( 'bouncer' );

var Bouncer = function( options ) {
  debug( 'Initialized Bouncer' );

  this.options = {
    runner : {
      url            : options.url,
      allowedDomains : options.allowedDomains,
      log            : options.log || chalk.bgBlue.white.bold
    },
    wpt : {
      pollResults : 10,
      requests    : true,
      runs        : options.runs || 1,
      server      : options.server || 'www.webpagetest.org',
      timeout     : 480
    }
  }
}

Bouncer.prototype.run = function( callback ) {
  if ( !this.options.runner.url ) {
    callback( ' -> No url to run against defined <- ' );

    return;
  }

  if (
    !this.options.runner.allowedDomains ||
    !this.options.runner.allowedDomains.length
  ) {
    callback( ' -> No allowed domains set <- ' );

    return;
  }

  this.options.log( ' (╯°□°)╯  Starting to bounce ' );
  this.options.log( ' Set WPT server: ' );
  this.options.log( ' -> ' + this.options.wpt.server + '\n' );

  this.runner = new Runner( this.options );

  this.runner.run( function( err, data ) {
    if ( err ) {
      callback( err );

      return;
    }

    callback( null, data );
  } );
};

module.exports = Bouncer;
<commit_msg>fixed bugs in logging<commit_after>var Runner = require( './lib/runner' );
var chalk  = require( 'chalk' );
var debug  = require( 'debug' )( 'bouncer' );

var Bouncer = function( options ) {
  debug( 'Initialized Bouncer' );

  this.options = {
    runner : {
      url            : options.url,
      allowedDomains : options.allowedDomains,
      log            : options.log || function( message ) {
        console.log( chalk.bgBlue.white.bold( message ) );
      }
    },
    wpt : {
      pollResults : 10,
      requests    : true,
      runs        : options.runs || 1,
      server      : options.server || 'www.webpagetest.org',
      timeout     : 480
    }
  }
}

Bouncer.prototype.run = function( callback ) {
  if ( !this.options.runner.url ) {
    callback( ' -> No url to run against defined <- ' );

    return;
  }

  if (
    !this.options.runner.allowedDomains ||
    !this.options.runner.allowedDomains.length
  ) {
    callback( ' -> No allowed domains set <- ' );

    return;
  }

  this.options.runner.log( ' (╯°□°)╯  Starting to bounce ' );
  this.options.runner.log( ' Set WPT server: ' );
  this.options.runner.log( ' -> ' + this.options.wpt.server + '\n' );

  this.runner = new Runner( this.options );

  this.runner.run( function( err, data ) {
    if ( err ) {
      callback( err );

      return;
    }

    callback( null, data );
  } );
};

module.exports = Bouncer;
<|endoftext|>


<commit_before>/**
 * XadillaX created at 2015-03-11 13:53:05
 *
 * Copyright (c) 2015 Huaban.com, all rights
 * reserved
 */
require("should");
var async = require("async");
var illyria = require("illyria");
var illyria2 = require("../");

describe("client protocol", function() {
    var SERVER_PORT = 2399;
    var server, client;

    function init(callback) {
        async.waterfall([
            function(callback) {
                if(server) {
                    server.close(callback);
                } else callback();
            }
        ], function() {
            server = illyria.createServer({
                port: SERVER_PORT
            });
            callback();
        });
    }

    function startup(callback) {
        server.listen(function() {
            client = illyria2.createClient("127.0.0.1", SERVER_PORT, {
                runTimeout: 1000,
                retryInterval: 1000,
                reconnect: true
            });

            client.connect(function() {
                callback();
            });
        });
    }

    describe("match old server", function() {
        before(function(done) {
            init(function() {
                server.expose({
                    name: "test",
                    methods: {
                        echo: function(req, resp) {
                            req.params().should.be.eql("illyria");
                            resp.send("illyria");
                        },

                        json: function(req, resp) {
                            req.param("json").should.be.eql(true);
                            req.params().should.be.eql({ json: true });
                            resp.send(req.params());
                        },

                        error: function(req, resp) {
                            resp.json({ err: "test error" });
                        },

                        cut: function(req/**, resp*/) {
                            req.socket.end();
                            req.socket.destroy();
                        },

                        eecho: function(req, resp) {
                            resp.send(req.params());
                        }
                    }
                });

                startup(done);
            });
        });

        it("should received \"echo\"", function(done) {
            client.send("test", "echo", "illyria", function(err, data) {
                if(err) err.should.be.empty;
                data.should.be.eql("illyria");
                done();
            });
        });

        it("should received { json: true }", function(done) {
            client.send("test", "json", { json: true }, function(err, data) {
                if(err) err.should.be.empy;
                data.should.be.eql({ json: true });
                done();
            });
        });

        it("should received { json: null }", function(done) {
            client.send("test", "eecho", { json: 1 / 0 }, function(err, data) {
                if(err) err.should.be.empty;
                data.should.be.eql({ json: null });
                done();
            });
        });

        it("should received error", function(done) {
            client.send("test", "error", {}, function(err) {
                (err instanceof Error).should.be.eql(true);
                err.message.should.be.eql("test error");
                done();
            });
        });

        it("should echo the whole body", function(done) {
            var _data = "";
            for(var i = 0; i < 1000000; i++) {
                _data += "a";
            }

            client.send("test", "eecho", _data, function(err, data) {
                if(err) err.should.be.empy;
                data.should.be.eql(_data);
                done();
            });
        });

        it("should reconnect and ok", function(done) {
            client.send("test", "cut", {}, function(err) {
                err.message.indexOf("Timeout").should.not.be.eql(-1);

                setTimeout(function() {
                    client.send("test", "json", { json: true }, function(err, data) {
                        if(err) err.should.be.empy;
                        data.should.be.eql({ json: true });
                        done();
                    });
                }, 500);
            });
        });

        it("should occur error and reconnect", function(done) {
            var errors = [ "manually error", "ISocket: sending on a bad socket." ];
            client.on("error", function(err) {
                if(errors[0] === undefined) return;
                err.message.should.be.eql(errors[0]);
                errors.shift();
            });

            client.socket.socket.emit("error", new Error("manually error"));

            client.send("test", "echo", "illyria", function() {});

            setTimeout(function() {
                client.send("test", "echo", "illyria", function(err, data) {
                    if(err) err.should.be.empy;
                    data.should.be.eql("illyria");
                    done();
                });
            }, 1500);
        });

        it("should reconnect after several tries", function(done) {
            this.timeout(100000);

            // var errors = [ "manually error", "ISocket: sending on a bad socket." ];
            server.close();
            server = null;
            client.socket.socket.end();

            var times = 0;
            var reconnectedEmitted = false;
            client.on("error", function(err) {
                if(!process.env.ZK_NO_WARN) console.log(">>>", err.message);
            });
            client.on("tryReconnect", function(after) {
                client.connectStatus().should.be.eql("RECONNECTING");
                if(!process.env.ZK_NO_WARN) console.log("auto reconnect after " + after + "ms.");
                after.should.be.eql(Math.pow(2, times++) * 1000);
            });

            setTimeout(function() {
                init(function() {
                    server.expose({
                        name: "test",
                        methods: {
                            echo: function(req, resp) {
                                req.params().should.be.eql("illyria");
                                resp.send("illyria");
                            }
                        }
                    });

                    var send = function() {
                        client.send("test", "echo", "illyria", function(err, echo) {
                            if(err) {
                                err.message.should.be.eql("Timeout when send and wait for response after 1000ms.");
                                return setTimeout(send, 1000);
                            }

                            client.connectStatus().should.be.eql("CONNECTED");
                            echo.should.be.eql("illyria");
                            times.should.be.above(0);
                            reconnectedEmitted.should.be.eql(true);
                            done();
                        });
                    };

                    server.listen(function() {
                        client.on("connected", function() {
                            reconnectedEmitted = true;
                            if(!process.env.ZK_NO_WARN) console.log("connected");
                        });
                        setTimeout(send, 1000);
                    });
                });
            }, 7000);
        });
    });
});

<commit_msg>modify a test case<commit_after>/**
 * XadillaX created at 2015-03-11 13:53:05
 *
 * Copyright (c) 2015 Huaban.com, all rights
 * reserved
 */
require("should");
var async = require("async");
var illyria = require("illyria");
var illyria2 = require("../");

describe("client protocol", function() {
    var SERVER_PORT = 2399;
    var server, client;

    function init(callback) {
        async.waterfall([
            function(callback) {
                if(server) {
                    server.close(callback);
                } else callback();
            }
        ], function() {
            server = illyria.createServer({
                port: SERVER_PORT
            });
            callback();
        });
    }

    function startup(callback) {
        server.listen(function() {
            client = illyria2.createClient("127.0.0.1", SERVER_PORT, {
                runTimeout: 1000,
                retryInterval: 1000,
                reconnect: true
            });

            client.connect(function() {
                callback();
            });
        });
    }

    describe("match old server", function() {
        before(function(done) {
            init(function() {
                server.expose({
                    name: "test",
                    methods: {
                        echo: function(req, resp) {
                            req.params().should.be.eql("illyria");
                            resp.send("illyria");
                        },

                        json: function(req, resp) {
                            req.param("json").should.be.eql(true);
                            req.params().should.be.eql({ json: true });
                            resp.send(req.params());
                        },

                        error: function(req, resp) {
                            resp.json({ err: "test error" });
                        },

                        cut: function(req/**, resp*/) {
                            req.socket.end();
                            req.socket.destroy();
                        },

                        eecho: function(req, resp) {
                            resp.send(req.params());
                        }
                    }
                });

                startup(done);
            });
        });

        it("should received \"echo\"", function(done) {
            client.send("test", "echo", "illyria", function(err, data) {
                if(err) err.should.be.empty;
                data.should.be.eql("illyria");
                done();
            });
        });

        it("should received { json: true }", function(done) {
            client.send("test", "json", { json: true }, function(err, data) {
                if(err) err.should.be.empy;
                data.should.be.eql({ json: true });
                done();
            });
        });

        it("should received { json: null }", function(done) {
            client.send("test", "eecho", { json: 1 / 0, nosj: 1 }, function(err, data) {
                if(err) err.should.be.empty;
                data.should.be.eql({ json: null, nosj: 1 });
                done();
            });
        });

        it("should received error", function(done) {
            client.send("test", "error", {}, function(err) {
                (err instanceof Error).should.be.eql(true);
                err.message.should.be.eql("test error");
                done();
            });
        });

        it("should echo the whole body", function(done) {
            var _data = "";
            for(var i = 0; i < 1000000; i++) {
                _data += "a";
            }

            client.send("test", "eecho", _data, function(err, data) {
                if(err) err.should.be.empy;
                data.should.be.eql(_data);
                done();
            });
        });

        it("should reconnect and ok", function(done) {
            client.send("test", "cut", {}, function(err) {
                err.message.indexOf("Timeout").should.not.be.eql(-1);

                setTimeout(function() {
                    client.send("test", "json", { json: true }, function(err, data) {
                        if(err) err.should.be.empy;
                        data.should.be.eql({ json: true });
                        done();
                    });
                }, 500);
            });
        });

        it("should occur error and reconnect", function(done) {
            var errors = [ "manually error", "ISocket: sending on a bad socket." ];
            client.on("error", function(err) {
                if(errors[0] === undefined) return;
                err.message.should.be.eql(errors[0]);
                errors.shift();
            });

            client.socket.socket.emit("error", new Error("manually error"));

            client.send("test", "echo", "illyria", function() {});

            setTimeout(function() {
                client.send("test", "echo", "illyria", function(err, data) {
                    if(err) err.should.be.empy;
                    data.should.be.eql("illyria");
                    done();
                });
            }, 1500);
        });

        it("should reconnect after several tries", function(done) {
            this.timeout(100000);

            // var errors = [ "manually error", "ISocket: sending on a bad socket." ];
            server.close();
            server = null;
            client.socket.socket.end();

            var times = 0;
            var reconnectedEmitted = false;
            client.on("error", function(err) {
                if(!process.env.ZK_NO_WARN) console.log(">>>", err.message);
            });
            client.on("tryReconnect", function(after) {
                client.connectStatus().should.be.eql("RECONNECTING");
                if(!process.env.ZK_NO_WARN) console.log("auto reconnect after " + after + "ms.");
                after.should.be.eql(Math.pow(2, times++) * 1000);
            });

            setTimeout(function() {
                init(function() {
                    server.expose({
                        name: "test",
                        methods: {
                            echo: function(req, resp) {
                                req.params().should.be.eql("illyria");
                                resp.send("illyria");
                            }
                        }
                    });

                    var send = function() {
                        client.send("test", "echo", "illyria", function(err, echo) {
                            if(err) {
                                err.message.should.be.eql("Timeout when send and wait for response after 1000ms.");
                                return setTimeout(send, 1000);
                            }

                            client.connectStatus().should.be.eql("CONNECTED");
                            echo.should.be.eql("illyria");
                            times.should.be.above(0);
                            reconnectedEmitted.should.be.eql(true);
                            done();
                        });
                    };

                    server.listen(function() {
                        client.on("connected", function() {
                            reconnectedEmitted = true;
                            if(!process.env.ZK_NO_WARN) console.log("connected");
                        });
                        setTimeout(send, 1000);
                    });
                });
            }, 7000);
        });
    });
});

<|endoftext|>


<commit_before>var _ = require('lodash');

module.exports = function (source) {
  this.cacheable && this.cacheable();
  var template = _.template(source, null, this.options.tplSettings);
  return 'var _ = require(\'lodash\');\nmodule.exports = ' + template;
};
<commit_msg>Don't force users to use lodash<commit_after>var _ = require('lodash');

module.exports = function (source) {
  this.cacheable && this.cacheable();
  var template = _.template(source, null, this.options.tplSettings);
  return 'module.exports = ' + template;
};
<|endoftext|>


<commit_before>/*global describe:true, it:true, before:true, after:true */

var
	chai   = require('chai'),
	assert = chai.assert,
	expect = chai.expect,
	should = chai.should(),
	child  = require('child_process'),
	fs     = require('fs')
	;

var LocalNode = require('../lib/localnode');

function nodeFixture()
{
	var opts = { id: 'test-id', dbpath: './test/t3' };
	var node = new LocalNode(opts);

	return node;
}

describe('LocalNode', function()
{
	var node = nodeFixture();

	describe('constructor', function()
	{
		it('throws if no options passed', function()
		{
			function shouldThrow()
			{
				var node = new LocalNode();
			}
			shouldThrow.should.throw(Error);
		});

		it('throws if no ID passed', function()
		{
			function shouldThrow()
			{
				var node = new LocalNode({ foo: 'bar' });
			}
			shouldThrow.should.throw(Error);
		});

		it('throws if no dbpath passed', function()
		{
			function shouldThrow()
			{
				var node = new LocalNode({ id: 'bar' });
			}
			shouldThrow.should.throw(Error);
		});

		it('can construct a node when passed the required options', function(done)
		{
			var opts =
			{
				id: 'test-id',
				dbpath: './test/t1',
				logger: 'not-a-logger-yet'
			};

			var node = new LocalNode(opts);
			assert.equal(node.id, opts.id);
			assert.equal(node.logger, opts.logger);
			assert.ok(node.db);
			node.db.close(done);
		});

		it('creates the dbpath if needed', function(done)
		{
			assert.ok(!fs.existsSync('./test/t2'), 'test db path exists already!');
			var opts = { id: 'test-id', dbpath: './test/t2' };
			var node = new LocalNode(opts);

			node.db.on('ready', function()
			{
				assert.ok(fs.existsSync('./test/t2'), 'test db path was not created');
				node.db.close(done);
			});
		});

		it('wraps the db with level-sublevel', function(done)
		{
			var opts = { id: 'test-id', dbpath: './test/t1' };
			var node = new LocalNode(opts);
			var db = node.db;

			assert.ok(db.sublevel, 'db has not been sublevel-ified');
			assert.ok(typeof db.sublevel === 'function', 'db has not been sublevel-ified');
			db.close(done);
		});

		it('wraps the db with level-ttl', function(done)
		{
			var opts = { id: 'test-id', dbpath: './test/t1' };
			var node = new LocalNode(opts);
			var db = node.db;

			assert.ok(db.ttl, 'db has not been wrapped with ttl()');
			assert.ok(typeof db.ttl === 'function', 'db has not been wrapped with ttl()');
			db.close(done);
		});
	});

	describe('set()', function()
	{
		it('requires that you pass a string bucket', function()
		{
			function shouldThrow()
			{
				node.set();
			}
			shouldThrow.should.throw(Error);
		});

		it('requires that you pass a string id', function()
		{
			function shouldThrow()
			{
				node.set('bucket');
			}
			shouldThrow.should.throw(Error);
		});

		it('returns a promise', function(done)
		{
			var result = node.set('bucket', '1', 'I am a value.');
			assert.ok(result.then);
			assert.equal(typeof result.then, 'function', 'not a promise');

			result.then(function(reply)
			{
				assert.equal(reply, 'OK');
				done();
			})
			.fail(function(err)
			{
				should.not.exist(err);
			}).done();
		});

		it('stores an object with crc & modification timestamp', function(done)
		{
			node.get('bucket', '1')
			.then(function(result)
			{
				assert.ok(result, 'did not find a value!');
				assert.equal(typeof result, 'object', 'did not store an object');
				assert.ok(result.ts, 'no timestamp');
				assert.equal(typeof result.ts, 'number');
				assert.ok(result.etag, 'no etag hash');
				assert.ok(result.payload, 'no payload holding the value');
				done();
			})
			.fail(function(err)
			{
				should.not.exist(err);
			})
			.done();
		});

		it('stores strings successfully', function(done)
		{
			node.get('bucket', '1')
			.then(function(result)
			{
				assert.ok(result.payload, 'no payload holding the value');
				assert.equal(typeof result.payload, 'string');
				assert.equal(result.payload, 'I am a value.');

				done();
			})
			.fail(function(err)
			{
				should.not.exist(err);
			})
			.done();
		});

		it('stores buffers successfully', function(done)
		{
			var buf = new Buffer(8);
			buf.fill(1);

			node.set('bucket', '2', buf)
			.then(function()
			{
				return node.get('bucket', '2');
			})
			.then(function(result)
			{
				assert.ok(result.payload, 'no payload holding the value');
				assert.ok(Buffer.isBuffer(result.payload));
				assert.equal(result.payload.length, 8);
				assert.equal(result.payload[0], 1);
				done();
			})
			.fail(function(err)
			{
				should.not.exist(err);
			})
			.done();
		});

		it('stores objects successfully', function(done)
		{
			var value =
			{
				foo: 'foo',
				bar: 'bar',
				baz: ['hunt', 'the', 'wumpus']
			};

			node.set('bucket', '3', value)
			.then(function()
			{
				return node.get('bucket', '3');
			})
			.then(function(result)
			{
				var stored = result.payload;
				assert.ok(stored, 'no payload holding the value');
				assert.equal(typeof stored, 'object', 'did not get an object back');
				assert.ok(stored.foo);
				assert.equal(stored.foo, 'foo');
				assert.ok(stored.bar);
				assert.equal(stored.bar, 'bar');
				assert.ok(stored.baz);
				assert.ok(Array.isArray(stored.baz), 'array subitem not stored correctly');
				done();
			})
			.fail(function(err)
			{
				should.not.exist(err);
			})
			.done();
		});

	});

	describe('get()', function()
	{
		it('returns a promise', function()
		{
			var result = node.get('bucket', '1');
			assert.ok(result.then);
			assert.equal(typeof result.then, 'function', 'not a promise');
		});

		it('can fetch a previously-stored value', function(done)
		{
			node.get('bucket', '1')
			.then(function(result)
			{
				assert.ok(result, 'did not find a value!');
				done();
			})
			.fail(function(err)
			{
				should.not.exist(err);
			})
			.done();
		});

		it('returns an empty value for non-existent keys');
	});

	describe('del()', function()
	{
		it('removes an item from storage');
		it('is silent when removing an item that does not exist');
	});

	describe('TTLs', function()
	{
		it('has TTL tests');
	});

	after(function()
	{
		child.exec('rm -rf ./test/t1');
		child.exec('rm -rf ./test/t2');
		child.exec('rm -rf ./test/t3');
	});
});
<commit_msg>One more test, and I have to call it quits for the morning.<commit_after>/*global describe:true, it:true, before:true, after:true */

var
	chai   = require('chai'),
	assert = chai.assert,
	expect = chai.expect,
	should = chai.should(),
	child  = require('child_process'),
	fs     = require('fs')
	;

var LocalNode = require('../lib/localnode');

function nodeFixture()
{
	var opts = { id: 'test-id', dbpath: './test/t3' };
	var node = new LocalNode(opts);

	return node;
}

describe('LocalNode', function()
{
	var node = nodeFixture();

	describe('constructor', function()
	{
		it('throws if no options passed', function()
		{
			function shouldThrow()
			{
				var node = new LocalNode();
			}
			shouldThrow.should.throw(Error);
		});

		it('throws if no ID passed', function()
		{
			function shouldThrow()
			{
				var node = new LocalNode({ foo: 'bar' });
			}
			shouldThrow.should.throw(Error);
		});

		it('throws if no dbpath passed', function()
		{
			function shouldThrow()
			{
				var node = new LocalNode({ id: 'bar' });
			}
			shouldThrow.should.throw(Error);
		});

		it('can construct a node when passed the required options', function(done)
		{
			var opts =
			{
				id: 'test-id',
				dbpath: './test/t1',
				logger: 'not-a-logger-yet'
			};

			var node = new LocalNode(opts);
			assert.equal(node.id, opts.id);
			assert.equal(node.logger, opts.logger);
			assert.ok(node.db);
			node.db.close(done);
		});

		it('creates the dbpath if needed', function(done)
		{
			assert.ok(!fs.existsSync('./test/t2'), 'test db path exists already!');
			var opts = { id: 'test-id', dbpath: './test/t2' };
			var node = new LocalNode(opts);

			node.db.on('ready', function()
			{
				assert.ok(fs.existsSync('./test/t2'), 'test db path was not created');
				node.db.close(done);
			});
		});

		it('wraps the db with level-sublevel', function(done)
		{
			var opts = { id: 'test-id', dbpath: './test/t1' };
			var node = new LocalNode(opts);
			var db = node.db;

			assert.ok(db.sublevel, 'db has not been sublevel-ified');
			assert.ok(typeof db.sublevel === 'function', 'db has not been sublevel-ified');
			db.close(done);
		});

		it('wraps the db with level-ttl', function(done)
		{
			var opts = { id: 'test-id', dbpath: './test/t1' };
			var node = new LocalNode(opts);
			var db = node.db;

			assert.ok(db.ttl, 'db has not been wrapped with ttl()');
			assert.ok(typeof db.ttl === 'function', 'db has not been wrapped with ttl()');
			db.close(done);
		});
	});

	describe('set()', function()
	{
		it('requires that you pass a string bucket', function()
		{
			function shouldThrow()
			{
				node.set();
			}
			shouldThrow.should.throw(Error);
		});

		it('requires that you pass a string id', function()
		{
			function shouldThrow()
			{
				node.set('bucket');
			}
			shouldThrow.should.throw(Error);
		});

		it('returns a promise', function(done)
		{
			var result = node.set('bucket', '1', 'I am a value.');
			assert.ok(result.then);
			assert.equal(typeof result.then, 'function', 'not a promise');

			result.then(function(reply)
			{
				assert.equal(reply, 'OK');
				done();
			})
			.fail(function(err)
			{
				should.not.exist(err);
			}).done();
		});

		it('stores an object with crc & modification timestamp', function(done)
		{
			node.get('bucket', '1')
			.then(function(result)
			{
				assert.ok(result, 'did not find a value!');
				assert.equal(typeof result, 'object', 'did not store an object');
				assert.ok(result.ts, 'no timestamp');
				assert.equal(typeof result.ts, 'number');
				assert.ok(result.etag, 'no etag hash');
				assert.ok(result.payload, 'no payload holding the value');
				done();
			})
			.fail(function(err)
			{
				should.not.exist(err);
			})
			.done();
		});

		it('stores strings successfully', function(done)
		{
			node.get('bucket', '1')
			.then(function(result)
			{
				assert.ok(result.payload, 'no payload holding the value');
				assert.equal(typeof result.payload, 'string');
				assert.equal(result.payload, 'I am a value.');

				done();
			})
			.fail(function(err)
			{
				should.not.exist(err);
			})
			.done();
		});

		it('stores buffers successfully', function(done)
		{
			var buf = new Buffer(8);
			buf.fill(1);

			node.set('bucket', '2', buf)
			.then(function()
			{
				return node.get('bucket', '2');
			})
			.then(function(result)
			{
				assert.ok(result.payload, 'no payload holding the value');
				assert.ok(Buffer.isBuffer(result.payload));
				assert.equal(result.payload.length, 8);
				assert.equal(result.payload[0], 1);
				done();
			})
			.fail(function(err)
			{
				should.not.exist(err);
			})
			.done();
		});

		it('stores objects successfully', function(done)
		{
			var value =
			{
				foo: 'foo',
				bar: 'bar',
				baz: ['hunt', 'the', 'wumpus']
			};

			node.set('bucket', '3', value)
			.then(function()
			{
				return node.get('bucket', '3');
			})
			.then(function(result)
			{
				var stored = result.payload;
				assert.ok(stored, 'no payload holding the value');
				assert.equal(typeof stored, 'object', 'did not get an object back');
				assert.ok(stored.foo);
				assert.equal(stored.foo, 'foo');
				assert.ok(stored.bar);
				assert.equal(stored.bar, 'bar');
				assert.ok(stored.baz);
				assert.ok(Array.isArray(stored.baz), 'array subitem not stored correctly');
				done();
			})
			.fail(function(err)
			{
				should.not.exist(err);
			})
			.done();
		});

	});

	describe('get()', function()
	{
		it('returns a promise', function()
		{
			var result = node.get('bucket', '1');
			assert.ok(result.then);
			assert.equal(typeof result.then, 'function', 'not a promise');
		});

		it('can fetch a previously-stored value', function(done)
		{
			node.get('bucket', '1')
			.then(function(result)
			{
				assert.ok(result, 'did not find a value!');
				done();
			})
			.fail(function(err)
			{
				should.not.exist(err);
			})
			.done();
		});

		it('returns an empty value for non-existent keys', function(done)
		{
			node.get('bucket', '12')
			.then(function(result)
			{
				assert.equal(result, null, 'expected null for non-existent keys!');
				done();
			})
			.fail(function(err)
			{
				should.not.exist(err);
			})
			.done();
		});
	});

	describe('del()', function()
	{
		it('returns a promise', function()
		{
			var result = node.del('bucket', '1');
			assert.ok(result.then);
			assert.equal(typeof result.then, 'function', 'not a promise');
		});

		it('removes an item from storage', function(done)
		{
			node.get('bucket', '1')
			.then(function(result)
			{
				assert.equal(result, null, 'expected null for a deleted key');
				done();
			})
			.fail(function(err)
			{
				should.not.exist(err);
			})
			.done();
		});

		it('is silent when removing an item that does not exist', function(done)
		{
			node.del('bucket', '1')
			.then(function(reply)
			{
				assert.ok(reply);
				assert.equal(reply, 'OK');
				done();
			})
			.fail(function(err)
			{
				should.not.exist(err);
			})
			.done();
		});
	});

	describe('TTLs', function()
	{
		it('has TTL tests');
	});

	describe('keystreams', function()
	{

	});

	describe('shutdown', function()
	{
		it('closes the db', function(done)
		{
			node.shutdown()
			.then(function(reply)
			{
				// silence on success?
				done();
			})
			.fail(function(err)
			{
				should.not.exist(err);
			})
			.done();
		});
	});

	after(function()
	{
		child.exec('rm -rf ./test/t1');
		child.exec('rm -rf ./test/t2');
		child.exec('rm -rf ./test/t3');
	});
});
<|endoftext|>


<commit_before>var assert = require('assert');
var Completion = require('../');
var testUtils = require('./utils/index');

// DEV: Internal util test
// TODO: We should break this into another lib
describe('A command', function () {
  before(function () {
    this.command = 'git ad|README';
  });
  describe('broken down into parameters', function () {
    before(function () {
      this.params = testUtils.commandToParams(this.command);
    });
    it('is as expected', function () {
      assert.deepEqual(this.params, {
        cursor: 6,
        line: 'git adREADME'
      });
    });
  });
});

function completeCommand() {
  before(function (done) {
    var that = this;
    this.completion.complete(this.params, function (err, results) {
      that.actual = results;
      done(err);
    });
  });
}

function assertExpected() {
  assert.deepEqual(this.actual, this.expected);
}

describe('A partial command with one completion match', function () {
  before(function () {
    this.params = testUtils.commandToParams('npm pub|');
    this.expected = ['publish'];
    this.completion = new Completion({
      npm: {
        publish: null
      }
    });
  });

  describe('being completed', function () {
    completeCommand();
    it('returns its match', assertExpected);
  });
});

describe('A partial command with multiple completions', function () {
  before(function () {
    this.params = testUtils.commandToParams('git ch|');
    this.expected = ['checkout', 'cherry-pick'];
    this.completion = new Completion({
      git: {
        checkout: function (params, cb) {
          cb(null, ['hello.world']);
        },
        'cherry-pick': function (params, cb) {
          cb(null, ['maraschino']);
        }
      }
    });
  });

  describe('being completed', function () {
    completeCommand();
    it('returns all of its matches', assertExpected);
  });
});

describe.only('A partial command in junction with the item', function () {
  before(function () {
    this.params = testUtils.commandToParams('git che|world');
    this.expected = ['checkout', 'cherry-pick'];
    this.completion = new Completion({
      git: {
        checkout: function (params, cb) {
          cb(null, ['hello.world']);
        },
        'cherry-pick': function (params, cb) {
          cb(null, ['maraschino']);
        }
      }
    });
  });

  describe('being completed', function () {
    completeCommand();
    it('returns the command\'s match', assertExpected);
  });
});
<commit_msg>Adding two more cases for terminal commands<commit_after>var assert = require('assert');
var Completion = require('../');
var testUtils = require('./utils/index');

// DEV: Internal util test
// TODO: We should break this into another lib
describe('A command', function () {
  before(function () {
    this.command = 'git ad|README';
  });
  describe('broken down into parameters', function () {
    before(function () {
      this.params = testUtils.commandToParams(this.command);
    });
    it('is as expected', function () {
      assert.deepEqual(this.params, {
        cursor: 6,
        line: 'git adREADME'
      });
    });
  });
});

function completeCommand() {
  before(function (done) {
    var that = this;
    this.completion.complete(this.params, function (err, results) {
      that.actual = results;
      done(err);
    });
  });
}

function assertExpected() {
  assert.deepEqual(this.actual, this.expected);
}

describe('A partial command with one completion match', function () {
  before(function () {
    this.params = testUtils.commandToParams('npm pub|');
    this.expected = ['publish'];
    this.completion = new Completion({
      npm: {
        publish: null
      }
    });
  });

  describe('being completed', function () {
    completeCommand();
    it('returns its match', assertExpected);
  });
});

describe('A partial command with multiple completions', function () {
  before(function () {
    this.params = testUtils.commandToParams('git ch|');
    this.expected = ['checkout', 'cherry-pick'];
    this.completion = new Completion({
      git: {
        checkout: function (params, cb) {
          cb(null, ['hello.world']);
        },
        'cherry-pick': function (params, cb) {
          cb(null, ['maraschino']);
        }
      }
    });
  });

  describe('being completed', function () {
    completeCommand();
    it('returns all of its matches', assertExpected);
  });
});

describe('A partial command in junction with the item', function () {
  before(function () {
    this.params = testUtils.commandToParams('git che|world');
    this.expected = ['checkout', 'cherry-pick'];
    this.completion = new Completion({
      git: {
        checkout: function (params, cb) {
          cb(null, ['hello.world']);
        },
        'cherry-pick': function (params, cb) {
          cb(null, ['maraschino']);
        }
      }
    });
  });

  describe('being completed', function () {
    completeCommand();
    it('returns the command\'s match', assertExpected);
  });
});

describe('A terminal command', function () {
  before(function () {
    this.params = testUtils.commandToParams('npm publish|');
    this.expected = ['publish'];
    this.completion = new Completion({
      npm: {
        publish: null
      }
    });
  });

  describe('being completed', function () {
    completeCommand();
    it('returns the command (for spacing)', assertExpected);
  });
});

describe.only('A terminal command with whitespace', function () {
  before(function () {
    this.params = testUtils.commandToParams('npm publish |');
    this.expected = [];
    this.completion = new Completion({
      npm: {
        publish: null
      }
    });
  });

  describe('being completed', function () {
    completeCommand();
    it('returns the command (for spacing)', assertExpected);
  });
});
<|endoftext|>