<commit_before>/*global window annyang*/
(function plainOldJs(window, annyang) {
  'use strict';

  var Hey = function initHey(settings) {
    /*eslint-disable*/
    var Pointer = new window.Pointer()
    , i
    , self = this
    /*eslint-enable*/
    , onStartEvent = new window.CustomEvent('Hey:start')
    , onEndEvent = new window.CustomEvent('Hey:end')
    , onDetectionEvent = new window.CustomEvent('Hey:detection')
    , onDetectionMatchEvent = new window.CustomEvent('Hey:detection-match')
    , onDetectionNotMatchEvent = new window.CustomEvent('Hey:detection-not-match')
    , onErrorsEvent = new window.CustomEvent('Hey:error')
    , defaultLang = 'en-EN';

    if (settings
      && settings.langs
      && settings.langs.length > 0) {

      for (i; i <= settings.langs.length; i += 1) {
        annyang.setLanguage(settings.langs[i]);
      }
    } else {

      annyang.setLanguage(defaultLang);
    }

    if (settings && settings.debug) {
      annyang.debug(settings.debug);
    }

    this.commands = {
      'select next element': function selectElementByClass(detection) {
        Pointer.dehighlight();
        Pointer.next();
        Pointer.highlight();
        window.console.info('Select next element', detection);
      },
      'select next element by id *detect': function selectElementById(detection) {
        Pointer.dehighlight();
        Pointer.next('#' + detection);
        Pointer.highlight();
        window.console.info('Select next element by id', detection);
      },
      'select next element by tag *detect': function selectElementByTag(detection) {
        Pointer.dehighlight();
        Pointer.next('<' + detection.replace('<', '').replace('>', '') + '>');
        Pointer.highlight();
        window.console.info('Select next element by id', detection);
      },
      'select next element by class *detect': function selectElementByClass(detection) {
        Pointer.dehighlight();
        Pointer.next('.' + detection.replace('.', ''));
        Pointer.highlight();
        window.console.info('Select next element by class', detection);
      },
      'select next element by classes *detect': function selectElementByClasses(detection) {
        Pointer.dehighlight();
        Pointer.next(detection);
        Pointer.highlight();
        window.console.info('Select next element by classes', detection);
      },
      'deselect elements': function deselectAllElements(detection) {
        Pointer.dehighlight();
        Pointer = new window.Pointer();
        window.console.info('Deselect all elements', detection);
      }
    };
    //mic access allowed
    annyang.addCallback('start', function onHeyStartEvent(data) {
      onStartEvent.eventData = data;
      window.dispatchEvent(onStartEvent);
    });
    annyang.addCallback('error', function onHeyErrorEvent(data) {
      onErrorsEvent.eventData = data;
      window.dispatchEvent(onErrorsEvent);
    });
    annyang.addCallback('end', function onHeyEndEvent(data) {
      onEndEvent.eventData = data;
      window.dispatchEvent(onEndEvent);
    });
    annyang.addCallback('result', function onHeyResultEvent(data) {
      onDetectionEvent.eventData = data;
      window.dispatchEvent(onDetectionEvent);
    });
    annyang.addCallback('resultMatch', function onHeyResultMatchEvent(data) {
      onDetectionMatchEvent.eventData = data;
      window.dispatchEvent(onDetectionMatchEvent);
    });
    annyang.addCallback('resultNotMatch', function onHeyResultNotMatchEvent(data) {
      onDetectionNotMatchEvent.eventData = data;
      window.dispatchEvent(onDetectionNotMatchEvent);
    });

    annyang.setLanguage(this.lang);
    annyang.addCommands(this.commands, false);
  };

  Hey.prototype.start = function startHey() {
    annyang.debug(true);
    annyang.start({
      'autoRestart': false,
      'continuous': true
    });
  };

  Hey.prototype.plug = function plugPlugin(plugin) {
    var i = 0;

    if (plugin && plugin.langs && plugin.langs.length > 0) {
      for (i; i < plugin.langs.length; i += 1) {

        annyang.setLanguage(plugin.langs[i]);
      }
    }
    if (plugin && plugin.commands) {

      annyang.addCommands(plugin.commands);
    }
  };

  window.Hey = new Hey();
}(window, annyang));
<commit_msg>linting<commit_after>/*global window annyang*/
(function plainOldJs(window, annyang) {
  'use strict';

  var Hey = function initHey(settings) {
    /*eslint-disable*/
    var Pointer = new window.Pointer()
    , i
    , that = this
    /*eslint-enable*/
    , onStartEvent = new window.CustomEvent('Hey:start')
    , onEndEvent = new window.CustomEvent('Hey:end')
    , onDetectionEvent = new window.CustomEvent('Hey:detection')
    , onDetectionMatchEvent = new window.CustomEvent('Hey:detection-match')
    , onDetectionNotMatchEvent = new window.CustomEvent('Hey:detection-not-match')
    , onErrorsEvent = new window.CustomEvent('Hey:error')
    , defaultLang = 'en-EN';

    if (settings
      && settings.langs
      && settings.langs.length > 0) {

      for (i; i <= settings.langs.length; i += 1) {
        annyang.setLanguage(settings.langs[i]);
      }
    } else {

      annyang.setLanguage(defaultLang);
    }

    if (settings && settings.debug) {
      annyang.debug(settings.debug);
    }

    this.commands = {
      'select next element': function selectElementByClass(detection) {
        Pointer.dehighlight();
        Pointer.next();
        Pointer.highlight();
        window.console.info('Select next element', detection);
      },
      'select next element by id *detect': function selectElementById(detection) {
        Pointer.dehighlight();
        Pointer.next('#' + detection);
        Pointer.highlight();
        window.console.info('Select next element by id', detection);
      },
      'select next element by tag *detect': function selectElementByTag(detection) {
        Pointer.dehighlight();
        Pointer.next('<' + detection.replace('<', '').replace('>', '') + '>');
        Pointer.highlight();
        window.console.info('Select next element by id', detection);
      },
      'select next element by class *detect': function selectElementByClass(detection) {
        Pointer.dehighlight();
        Pointer.next('.' + detection.replace('.', ''));
        Pointer.highlight();
        window.console.info('Select next element by class', detection);
      },
      'select next element by classes *detect': function selectElementByClasses(detection) {
        Pointer.dehighlight();
        Pointer.next(detection);
        Pointer.highlight();
        window.console.info('Select next element by classes', detection);
      },
      'deselect elements': function deselectAllElements(detection) {
        Pointer.dehighlight();
        Pointer = new window.Pointer();
        window.console.info('Deselect all elements', detection);
      }
    };
    //mic access allowed
    annyang.addCallback('start', function onHeyStartEvent(data) {
      onStartEvent.eventData = data;
      window.dispatchEvent(onStartEvent);
    });
    annyang.addCallback('error', function onHeyErrorEvent(data) {
      onErrorsEvent.eventData = data;
      window.dispatchEvent(onErrorsEvent);
    });
    annyang.addCallback('end', function onHeyEndEvent(data) {
      onEndEvent.eventData = data;
      window.dispatchEvent(onEndEvent);
    });
    annyang.addCallback('result', function onHeyResultEvent(data) {
      onDetectionEvent.eventData = data;
      window.dispatchEvent(onDetectionEvent);
    });
    annyang.addCallback('resultMatch', function onHeyResultMatchEvent(data) {
      onDetectionMatchEvent.eventData = data;
      window.dispatchEvent(onDetectionMatchEvent);
    });
    annyang.addCallback('resultNotMatch', function onHeyResultNotMatchEvent(data) {
      onDetectionNotMatchEvent.eventData = data;
      window.dispatchEvent(onDetectionNotMatchEvent);
    });

    annyang.setLanguage(this.lang);
    annyang.addCommands(this.commands, false);
    that.createHtml();
  };

  Hey.prototype.createHtml = function createHtml() {

    this.html = window.document.createElement('div');
    this.html.innerHTML = '<img height="25" src="data:image/gif;base64,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"/>';
    this.html.style.cssText = 'border:5px solid #444; text-align:center;position:fixed;bottom:2%;margin:0 auto;left:2%;width:200px;background:rgba(0,0,0,0.7); z-index:9999999999999;border-radius:5px;line-height:25px;color:white;';
    window.document.body.appendChild(this.html);
  };

  Hey.prototype.showHtml = function showHtml() {
    this.html.style.visibility = 'visible';
  };

  Hey.prototype.start = function startHey() {
    annyang.debug(true);
    annyang.start({
      'autoRestart': false,
      'continuous': true
    });
  };

  Hey.prototype.plug = function plugPlugin(plugin) {
    var i = 0;

    if (plugin && plugin.langs && plugin.langs.length > 0) {
      for (i; i < plugin.langs.length; i += 1) {

        annyang.setLanguage(plugin.langs[i]);
      }
    }
    if (plugin && plugin.commands) {

      annyang.addCommands(plugin.commands);
    }
  };

  window.Hey = new Hey();
}(window, annyang));
<|endoftext|>


<commit_before>'use strict';

var
  debug = require('debug')('gitevents-webhook'),
  crypto = require('crypto'),
  parser = require('markdown-parse'),
  GitHubApi = require('github');

Object.prototype.findById = function(id) {
  for (var i = 0; i < this.length; i++) {
    if (this[i].id === id) {
      return i;
    }
  }
  return -1;
};

module.exports = function(config) {
  if (!config) {
    throw new Error('No configuration found');
  }

  var github = new GitHubApi({
    // required
    version: '3.0.0',
    // optional
    debug: false,
    protocol: 'https',
    timeout: 5000,
    headers: {
      'user-agent': 'GitEvents' // GitHub is happy with a unique user agent
    }
  });

  return {
    process: function(payload, callback) {
      debug('action: ' + payload.action);

      github.authenticate({
        type: 'oauth',
        token: config.github.token
      });

      if (payload.action === 'opened') {
        // do nothing
        return callback(null);
      } else if (payload.action === 'labeled') {
        debug('label: ' + payload.label.name);

        github.user.getFrom({
          user: payload.sender.login
        }, function(error, user) {

          if (payload.issue && payload.issue.body) {
            var file;

            parser(payload.issue.body, function(error, body) {
              if (error) {
                throw new Error(error);
              } else {
                if (payload.label.name === config.labels.proposal) {
                  // process talk proposal

                  var proposal = {
                    id: payload.issue.id,
                    type: 'proposal',
                    speaker: {
                      name: user.name,
                      location: user.location,
                      github: user.id,
                      gravatar: user.gravatar_id,
                      avatar: user.avatar_url
                    },
                    title: payload.issue.title,
                    description: body.html
                  };

                  if (body.attributes.twitter) {
                    proposal.speaker.twitter = body.attributes.twitter;
                  }

                  if (body.attributes.language) {
                    proposal.language = body.attributes.language;
                  }

                  if (body.attributes.level) {
                    proposal.level = body.attributes.level;
                  }

                  if (body.attributes.tags) {
                    proposal.tags = body.attributes.tags;
                  }

                  github.repos.getContent({
                    user: config.github.user,
                    repo: config.github.repo,
                    path: 'proposals.json'
                  }, function(error, proposals) {
                    if (error && error.code === 404) {
                      // create an array for all future proposals and store on GitHub.
                      debug('proposals.json doesn\'t exist. Creating.')
                      proposals = [];
                      proposal.updated_at = new Date().toJSON();
                      proposal.created_at = new Date().toJSON();
                      proposals.push(proposal);

                      file = new Buffer(JSON.stringify(proposals, null, 2)).toString('base64');

                      github.repos.createContent({
                        user: config.github.user,
                        repo: config.github.repo,
                        path: 'proposals.json',
                        content: file,
                        message: 'Created proposals'
                      }, function(error, res) {
                        if (error) {
                          throw new Error(error);
                        }
                        return callback(null, proposal);
                      });
                    } else if (error) {
                      throw new Error(error);
                    } else {
                      // get proposals and update
                      var updatedProposals, message;

                      try {
                        updatedProposals = JSON.parse(new Buffer(proposals.content, 'base64').toString('ascii'));
                      } catch (error) {
                        throw new Error(error);
                      }

                      var id = updatedProposals.findById(proposal.id);
                      if (id !== -1) {
                        debug('Proposal exists. Update.');

                        // update the proposal; don't change the speaker
                        proposal.updated_at = new Date().toJSON();
                        proposal.created_at = updatedProposals[id].created_at;
                        proposal.speaker = updatedProposals[id].speaker;
                        updatedProposals[id] = proposal;
                        message = 'Updated proposal by ' + proposal.speaker.github;
                      } else {
                        debug('Push new proposal.')

                        proposal.created_at = new Date().toJSON();
                        updatedProposals.push(proposal);
                        message = 'New proposal by ' + proposal.speaker.github;
                      }

                      file = new Buffer(JSON.stringify(updatedProposals, null, 2)).toString('base64');

                      github.repos.updateFile({
                        user: config.github.user,
                        repo: config.github.repo,
                        path: 'proposals.json',
                        sha: proposals.sha,
                        content: file,
                        message: message
                      }, function (error, res) {
                        if (error) {
                          debug(error);
                          throw new Error(error);
                        }
                        debug('All done. Returning.')
                        return callback(null, proposal);
                      });
                    }
                  });
                } else if (payload.issue.label === config.labels.job) {
                  // process jobs
                  return callback(null);
                } else {
                  // process others
                  return callback(null);
                }
              }
            });
          }
        });
      } else {
        throw new Error('Unknown error occured.');
      }
    }
  };
};
<commit_msg>semicolons and usernames instead of ids<commit_after>'use strict';

var
  debug = require('debug')('gitevents-webhook'),
  crypto = require('crypto'),
  parser = require('markdown-parse'),
  GitHubApi = require('github');

Object.prototype.findById = function(id) {
  for (var i = 0; i < this.length; i++) {
    if (this[i].id === id) {
      return i;
    }
  }
  return -1;
};

module.exports = function(config) {
  if (!config) {
    throw new Error('No configuration found');
  }

  var github = new GitHubApi({
    // required
    version: '3.0.0',
    // optional
    debug: false,
    protocol: 'https',
    timeout: 5000,
    headers: {
      'user-agent': 'GitEvents' // GitHub is happy with a unique user agent
    }
  });

  return {
    process: function(payload, callback) {
      debug('action: ' + payload.action);

      github.authenticate({
        type: 'oauth',
        token: config.github.token
      });

      if (payload.action === 'opened') {
        // do nothing
        return callback(null);
      } else if (payload.action === 'labeled') {
        debug('label: ' + payload.label.name);

        github.user.getFrom({
          user: payload.sender.login
        }, function(error, user) {

          if (payload.issue && payload.issue.body) {
            var file;

            parser(payload.issue.body, function(error, body) {
              if (error) {
                throw new Error(error);
              } else {
                if (payload.label.name === config.labels.proposal) {
                  // process talk proposal

                  var proposal = {
                    id: payload.issue.id,
                    type: 'proposal',
                    speaker: {
                      id: user.id,
                      name: user.name,
                      location: user.location,
                      github: user.login,
                      gravatar: user.gravatar_id,
                      avatar: user.avatar_url
                    },
                    title: payload.issue.title,
                    description: body.html
                  };

                  if (body.attributes.twitter) {
                    proposal.speaker.twitter = body.attributes.twitter;
                  }

                  if (body.attributes.language) {
                    proposal.language = body.attributes.language;
                  }

                  if (body.attributes.level) {
                    proposal.level = body.attributes.level;
                  }

                  if (body.attributes.tags) {
                    proposal.tags = body.attributes.tags;
                  }

                  github.repos.getContent({
                    user: config.github.user,
                    repo: config.github.repo,
                    path: 'proposals.json'
                  }, function(error, proposals) {
                    if (error && error.code === 404) {
                      // create an array for all future proposals and store on GitHub.
                      debug('proposals.json doesn\'t exist. Creating.');
                      proposals = [];
                      proposal.updated_at = new Date().toJSON();
                      proposal.created_at = new Date().toJSON();
                      proposals.push(proposal);

                      file = new Buffer(JSON.stringify(proposals, null, 2)).toString('base64');

                      github.repos.createContent({
                        user: config.github.user,
                        repo: config.github.repo,
                        path: 'proposals.json',
                        content: file,
                        message: 'Created proposals'
                      }, function(error, res) {
                        if (error) {
                          throw new Error(error);
                        }
                        return callback(null, proposal);
                      });
                    } else if (error) {
                      throw new Error(error);
                    } else {
                      // get proposals and update
                      var updatedProposals, message;

                      try {
                        updatedProposals = JSON.parse(new Buffer(proposals.content, 'base64').toString('ascii'));
                      } catch (error) {
                        throw new Error(error);
                      }

                      var id = updatedProposals.findById(proposal.id);
                      if (id !== -1) {
                        debug('Proposal exists. Update.');

                        // update the proposal; don't change the speaker
                        proposal.updated_at = new Date().toJSON();
                        proposal.created_at = updatedProposals[id].created_at;
                        proposal.speaker = updatedProposals[id].speaker;
                        updatedProposals[id] = proposal;
                        message = 'Updated proposal by ' + proposal.speaker.github;
                      } else {
                        debug('Push new proposal.');

                        proposal.created_at = new Date().toJSON();
                        updatedProposals.push(proposal);
                        message = 'New proposal by ' + proposal.speaker.github;
                      }

                      file = new Buffer(JSON.stringify(updatedProposals, null, 2)).toString('base64');

                      github.repos.updateFile({
                        user: config.github.user,
                        repo: config.github.repo,
                        path: 'proposals.json',
                        sha: proposals.sha,
                        content: file,
                        message: message
                      }, function (error, res) {
                        if (error) {
                          debug(error);
                          throw new Error(error);
                        }
                        debug('All done. Returning.');
                        return callback(null, proposal);
                      });
                    }
                  });
                } else if (payload.issue.label === config.labels.job) {
                  // process jobs
                  return callback(null);
                } else {
                  // process others
                  return callback(null);
                }
              }
            });
          }
        });
      } else {
        throw new Error('Unknown error occured.');
      }
    }
  };
};
<|endoftext|>


<commit_before>var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var fs = require('fs');
var node_mpv = require('node-mpv');
var path = require('path');
var stats = require('./stats.js');
var low = require('lowdb');

// constants
const db = low('db.json');
db.defaults(
    {
        "radio_stations": [
            {
                "name": "Trójka",
                "url": "http://stream3.polskieradio.pl:8954/listen.pls"
            },
            {
                "name": "RMF Classic",
                "url": "http://www.rmfon.pl/n/rmfclassic.pls"
            },
            {
                "name": "Zet Gold",
                "url": "http://www.emsoft.strefa.pl/inne/zetgold.m3u"
            },
            {
                "name": "Radio Zet",
                "url": "http://zet-net-01.cdn.eurozet.pl:8400/listen.pls"
            },
            {
                "name": "RMF FM",
                "url": "http://www.rmfon.pl/n/rmffm.pls"
            }
        ],
        "lastStation": 0
    }).value();

const index = fs.readFileSync('index.html', 'utf-8');
const radio_stations = db.get('radio_stations').value();
const mpv = new node_mpv({ "audio_only" : true });

// sole variable, it seems
var currentStreamId = db.get('lastStation').value();

// start server
http.listen(8080, function () {
    // load last station on start-up
    mpv.loadFile(radio_stations[currentStreamId]["url"]);
})

// react to button clicks
io.on('connection', function(socket){
    socket.on('click', function(id) {
        mpv.loadFile(radio_stations[id]["url"]);
        io.emit('enableButton', currentStreamId);
        io.emit('disableButton', id);
        currentStreamId = id;
        db.set('lastStation', id).value();
    });
});

// HTML-related stuff
app.use(express.static(path.join(__dirname, '/public')))
app.get('/', function (req, res) {
    html = ''
    for (i = 0; i < radio_stations.length; i++) {
        name = radio_stations[i]["name"]
        btndisabled = currentStreamId == i ? 'disabled' : '';

        html += `

${name}

                    <button class="pure-button pure-button-primary"
                            id="${i}"
                            onclick="buttonClick(this.id)"
                            ${btndisabled}>włącz</button>

`;
    }

    res.send(index.replace('##INSERT_THINGS_HERE##', html))
})

app.get('/stats', function(req, res) {
    res.send(stats.getStats());
});

// vim: set ft=javascript ts=4 sw=4 sts=4 tw=0 fenc=utf-8 et:
<commit_msg>automatically restart playback<commit_after>var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var fs = require('fs');
var node_mpv = require('node-mpv');
var path = require('path');
var stats = require('./stats.js');
var low = require('lowdb');

// constants
const db = low('db.json');
db.defaults(
    {
        "radio_stations": [
            {
                "name": "Trójka",
                "url": "http://stream3.polskieradio.pl:8954/listen.pls"
            },
            {
                "name": "RMF Classic",
                "url": "http://www.rmfon.pl/n/rmfclassic.pls"
            },
            {
                "name": "Zet Gold",
                "url": "http://www.emsoft.strefa.pl/inne/zetgold.m3u"
            },
            {
                "name": "Radio Zet",
                "url": "http://zet-net-01.cdn.eurozet.pl:8400/listen.pls"
            },
            {
                "name": "RMF FM",
                "url": "http://www.rmfon.pl/n/rmffm.pls"
            }
        ],
        "lastStation": 0
    }).value();

const index = fs.readFileSync('index.html', 'utf-8');
const radio_stations = db.get('radio_stations').value();
const mpv = new node_mpv({ "audio_only" : true });

// sole variable, it seems
var currentStreamId = db.get('lastStation').value();

// start server
http.listen(8080, function () {
    // load last station on start-up
    mpv.loadFile(radio_stations[currentStreamId]["url"]);
})

// react to button clicks
io.on('connection', function(socket){
    socket.on('click', function(id) {
        mpv.loadFile(radio_stations[id]["url"]);
        io.emit('enableButton', currentStreamId);
        io.emit('disableButton', id);
        currentStreamId = id;
        db.set('lastStation', id).value();
    });
});

// HTML-related stuff
app.use(express.static(path.join(__dirname, '/public')))
app.get('/', function (req, res) {
    html = ''
    for (i = 0; i < radio_stations.length; i++) {
        name = radio_stations[i]["name"]
        btndisabled = currentStreamId == i ? 'disabled' : '';

        html += `

${name}

                    <button class="pure-button pure-button-primary"
                            id="${i}"
                            onclick="buttonClick(this.id)"
                            ${btndisabled}>włącz</button>

`;
    }

    res.send(index.replace('##INSERT_THINGS_HERE##', html))
})

app.get('/stats', function(req, res) {
    res.send(stats.getStats());
});

// restart playback
mpv.on('stopped', function() {
    mpv.loadFile(radio_stations[currentStreamId]["url"]);
});

// vim: set ft=javascript ts=4 sw=4 sts=4 tw=0 fenc=utf-8 et:
<|endoftext|>


<commit_before>import {defineOption} from "../edit"
import {eventMixin} from "../util/event"
import {AssertionError} from "../util/error"

import {rebaseSteps} from "./rebase"
export {rebaseSteps}

// !! This module implements an API into which a communication channel
// for collaborative editing can be hooked. See [this
// guide](guide/collab.html) for more details and an example.

// :: ?Object #path=collab #kind=option
//
// When given, enables the collaborative editing framework for the
// editor. Will register itself of the `Collab` class as
// `.mod.collab`.
//
// If the object given has a `version` property, that will determine
// the starting version number of the collaborative editing.

defineOption("collab", false, (pm, value) => {
  if (pm.mod.collab) {
    pm.mod.collab.detach()
    pm.mod.collab = null
  }

  if (value) {
    pm.mod.collab = new Collab(pm, value)
  }
})

// ;; This class accumulates changes that have to be sent to the
// central authority in the collaborating group, signals an event when
// it has something to send, and makes it possible to integrate
// changes made by peers into our local document. It is created and
// attached to the editor (under `.mod.collab`) by setting the
// `collab` option.
//
// Includes the [event mixin](#EventMixin).
class Collab {
  constructor(pm, options) {
    this.pm = pm
    this.options = options

    // :: number
    // The version number of the last update received from the central
    // authority. Starts at 0 or the value of the `version` property
    // in the option object, for the editor's value when the option
    // was enabled.
    this.version = options.version || 0
    this.versionDoc = pm.doc

    this.unconfirmedSteps = []
    this.unconfirmedMaps = []

    pm.on("transform", this.onTransform = transform => {
      for (let i = 0; i < transform.steps.length; i++) {
        this.unconfirmedSteps.push(transform.steps[i])
        this.unconfirmedMaps.push(transform.maps[i])
      }
      // :: () #path=Collab#events#mustSend
      // Fired when there are new steps to send to the central
      // authority. Consumers should respond by calling
      // `sendableSteps` and pushing those to the authority.
      this.signal("mustSend")
    })
    pm.on("beforeSetDoc", this.onSetDoc = () => {
      throw new AssertionError("setDoc is not supported on a collaborative editor")
    })
    pm.history.allowCollapsing = false
  }

  detach() {
    this.pm.off("transform", this.onTransform)
    this.pm.off("beforeSetDoc", this.onSetDoc)
    this.pm.history.allowCollapsing = true
  }

  // :: () -> bool
  // Reports whether the editor has any unsent steps.
  hasSendableSteps() {
    return this.unconfirmedSteps.length > 0
  }

  // :: () → {version: number, doc: Node, steps: [Step]}
  // Provides the data describing the editor's unconfirmed steps. The
  // version and array of steps are the things you'd send to the
  // central authority. The whole return value must be passed to
  // [`confirmSteps`](#Collab.confirmSteps) when the steps go through.
  sendableSteps() {
    return {
      version: this.version,
      doc: this.pm.doc,
      steps: this.unconfirmedSteps.slice()
    }
  }

  // :: ({version: number, doc: Node, steps: [Step]})
  // Tells the module that a set of unconfirmed steps have been
  // accepted by the central authority, and can now be considered
  // confirmed.
  confirmSteps(sendable) {
    this.unconfirmedSteps.splice(0, sendable.steps.length)
    this.unconfirmedMaps.splice(0, sendable.steps.length)
    this.version += sendable.steps.length
    this.versionDoc = sendable.doc
  }

  // :: ([Step]) → [PosMap]
  // Pushes a set of steps (made by peers and received from the
  // central authority) into the editor. This will rebase any
  // unconfirmed steps over these steps.
  //
  // Returns the [position maps](#PosMap) produced by applying the
  // steps.
  receive(steps) {
    let doc = this.versionDoc
    let maps = steps.map(step => {
      let result = step.apply(doc)
      doc = result.doc
      return result.map
    })
    this.version += steps.length
    this.versionDoc = doc

    let rebased = rebaseSteps(doc, maps, this.unconfirmedSteps, this.unconfirmedMaps)
    this.unconfirmedSteps = rebased.transform.steps.slice()
    this.unconfirmedMaps = rebased.transform.maps.slice()

    this.pm.updateDoc(rebased.doc, rebased.mapping)
    this.pm.history.rebased(maps, rebased.transform, rebased.positions)
    return maps
  }
}

eventMixin(Collab)
<commit_msg>Fix type docs<commit_after>import {defineOption} from "../edit"
import {eventMixin} from "../util/event"
import {AssertionError} from "../util/error"

import {rebaseSteps} from "./rebase"
export {rebaseSteps}

// !! This module implements an API into which a communication channel
// for collaborative editing can be hooked. See [this
// guide](guide/collab.html) for more details and an example.

// :: ?Object #path=collab #kind=option
//
// When given, enables the collaborative editing framework for the
// editor. Will register itself of the `Collab` class as
// `.mod.collab`.
//
// If the object given has a `version` property, that will determine
// the starting version number of the collaborative editing.

defineOption("collab", false, (pm, value) => {
  if (pm.mod.collab) {
    pm.mod.collab.detach()
    pm.mod.collab = null
  }

  if (value) {
    pm.mod.collab = new Collab(pm, value)
  }
})

// ;; This class accumulates changes that have to be sent to the
// central authority in the collaborating group, signals an event when
// it has something to send, and makes it possible to integrate
// changes made by peers into our local document. It is created and
// attached to the editor (under `.mod.collab`) by setting the
// `collab` option.
//
// Includes the [event mixin](#EventMixin).
class Collab {
  constructor(pm, options) {
    this.pm = pm
    this.options = options

    // :: number
    // The version number of the last update received from the central
    // authority. Starts at 0 or the value of the `version` property
    // in the option object, for the editor's value when the option
    // was enabled.
    this.version = options.version || 0
    this.versionDoc = pm.doc

    this.unconfirmedSteps = []
    this.unconfirmedMaps = []

    pm.on("transform", this.onTransform = transform => {
      for (let i = 0; i < transform.steps.length; i++) {
        this.unconfirmedSteps.push(transform.steps[i])
        this.unconfirmedMaps.push(transform.maps[i])
      }
      // :: () #path=Collab#events#mustSend
      // Fired when there are new steps to send to the central
      // authority. Consumers should respond by calling
      // `sendableSteps` and pushing those to the authority.
      this.signal("mustSend")
    })
    pm.on("beforeSetDoc", this.onSetDoc = () => {
      throw new AssertionError("setDoc is not supported on a collaborative editor")
    })
    pm.history.allowCollapsing = false
  }

  detach() {
    this.pm.off("transform", this.onTransform)
    this.pm.off("beforeSetDoc", this.onSetDoc)
    this.pm.history.allowCollapsing = true
  }

  // :: () → bool
  // Reports whether the editor has any unsent steps.
  hasSendableSteps() {
    return this.unconfirmedSteps.length > 0
  }

  // :: () → {version: number, doc: Node, steps: [Step]}
  // Provides the data describing the editor's unconfirmed steps. The
  // version and array of steps are the things you'd send to the
  // central authority. The whole return value must be passed to
  // [`confirmSteps`](#Collab.confirmSteps) when the steps go through.
  sendableSteps() {
    return {
      version: this.version,
      doc: this.pm.doc,
      steps: this.unconfirmedSteps.slice()
    }
  }

  // :: ({version: number, doc: Node, steps: [Step]})
  // Tells the module that a set of unconfirmed steps have been
  // accepted by the central authority, and can now be considered
  // confirmed.
  confirmSteps(sendable) {
    this.unconfirmedSteps.splice(0, sendable.steps.length)
    this.unconfirmedMaps.splice(0, sendable.steps.length)
    this.version += sendable.steps.length
    this.versionDoc = sendable.doc
  }

  // :: ([Step]) → [PosMap]
  // Pushes a set of steps (made by peers and received from the
  // central authority) into the editor. This will rebase any
  // unconfirmed steps over these steps.
  //
  // Returns the [position maps](#PosMap) produced by applying the
  // steps.
  receive(steps) {
    let doc = this.versionDoc
    let maps = steps.map(step => {
      let result = step.apply(doc)
      doc = result.doc
      return result.map
    })
    this.version += steps.length
    this.versionDoc = doc

    let rebased = rebaseSteps(doc, maps, this.unconfirmedSteps, this.unconfirmedMaps)
    this.unconfirmedSteps = rebased.transform.steps.slice()
    this.unconfirmedMaps = rebased.transform.maps.slice()

    this.pm.updateDoc(rebased.doc, rebased.mapping)
    this.pm.history.rebased(maps, rebased.transform, rebased.positions)
    return maps
  }
}

eventMixin(Collab)
<|endoftext|>


<commit_before>'use strict'

var fs = require('fs')
var path = require('path')
var asyncCache = require('async-cache')
var afterAll = require('after-all-results')
var errorCallsites = require('error-callsites')
var loadSourceMap = require('load-source-map')
var debug = require('debug')('stackman')

var isAbsolute = path.isAbsolute || require('path-is-absolute')

var fileCache = asyncCache({
  max: 500,
  load: function (file, cb) {
    debug('reading %s', file)
    fs.readFile(file, {encoding: 'utf8'}, cb)
  }
})

var sourceMapCache = asyncCache({
  max: 100,
  load: function (file, cb) {
    debug('loading source map for %s', file)
    loadSourceMap(file, cb)
  }
})

var LINES_OF_CONTEXT = 7
var ESCAPED_REGEX_PATH_SEP = path.sep === '/' ? '/' : '\\\\'
var MODULE_FOLDER_REGEX = new RegExp('.*node_modules' + ESCAPED_REGEX_PATH_SEP + '([^' + ESCAPED_REGEX_PATH_SEP + ']*)')

exports.callsites = callsites
exports.properties = properties
exports.sourceContexts = sourceContexts

function callsites (err, opts, cb) {
  if (typeof opts === 'function') return callsites(err, null, opts)

  var _callsites = errorCallsites(err)

  if (!validStack(_callsites)) {
    process.nextTick(function () {
      cb(new Error('Could not process callsites'))
    })
  } else if (!opts || opts.sourcemap !== false) {
    sourcemapify(_callsites, function (err) {
      if (err) return cb(err)
      _callsites.forEach(extendCallsite)
      cb(null, _callsites)
    })
  } else {
    _callsites.forEach(extendCallsite)
    process.nextTick(function () {
      cb(null, _callsites)
    })
  }
}

function properties (err) {
  var properties = {}
  Object.keys(err).forEach(function (key) {
    if (key === 'stack') return // 'stack' seems to be enumerable in Node 0.11
    var val = err[key]
    if (val === null) return // null is typeof object and well break the switch below
    switch (typeof val) {
      case 'function':
        return
      case 'object':
        // ignore all objects except Dates
        if (typeof val.toISOString !== 'function') return
        val = val.toISOString()
    }
    properties[key] = val
  })
  return properties
}

function sourceContexts (callsites, opts, cb) {
  if (typeof opts === 'function') return sourceContexts(callsites, null, opts)
  if (!opts) opts = {}

  var next = afterAll(cb)

  callsites.forEach(function (callsite) {
    if (callsite.isNode()) {
      next()(null, null)
    } else {
      callsite.sourceContext(opts, next())
    }
  })
}

function validStack (callsites) {
  return Array.isArray(callsites) &&
         typeof callsites[0] === 'object' &&
         typeof callsites[0].getFileName === 'function'
}

function getRelativeFileName () {
  var filename = this.getFileName()
  if (!filename) return
  var root = process.cwd()
  if (root[root.length - 1] !== path.sep) root += path.sep
  return !~filename.indexOf(root) ? filename : filename.substr(root.length)
}

function getTypeNameSafely () {
  try {
    return this.getTypeName()
  } catch (e) {
    // This seems to happen sometimes when using 'use strict',
    // stemming from `getTypeName`.
    // [TypeError: Cannot read property 'constructor' of undefined]
    return null
  }
}

function getFunctionNameSanitized () {
  var fnName = this.getFunctionName()
  if (fnName) return fnName
  var typeName = this.getTypeNameSafely()
  if (typeName) return typeName + '.' + (this.getMethodName() || '<anonymous>')
  return '<anonymous>'
}

function getModuleName () {
  var filename = this.getFileName() || ''
  var match = filename.match(MODULE_FOLDER_REGEX)
  return match ? match[1] : null
}

function isApp () {
  return !this.isNode() && !~(this.getFileName() || '').indexOf('node_modules' + path.sep)
}

function isModule () {
  return !!~(this.getFileName() || '').indexOf('node_modules' + path.sep)
}

function isNode () {
  if (this.isNative()) return true
  var filename = this.getFileName() || ''
  return (!isAbsolute(filename) && filename[0] !== '.')
}

function sourceContext (opts, cb) {
  if (this.isNode()) {
    return process.nextTick(cb, new Error('Can\'t get source context of a Node core callsite'))
  }
  if (typeof opts === 'function') {
    cb = opts
    opts = {}
  }

  var callsite = this
  var filename = this.getFileName() || ''
  var source = this.sourcemap
    ? this.sourcemap.sourceContentFor(filename, true)
    : null

  if (source) {
    process.nextTick(function () {
      cb(null, parseSource(source, callsite, opts))
    })
  } else {
    fileCache.get(filename, function (err, source) {
      if (err) {
        debug('error reading %s: %s', filename, err.message)
        cb(err)
      } else {
        cb(null, parseSource(source, callsite, opts))
      }
    })
  }
}

function parseSource (source, callsite, opts) {
  var lines = source.split(/\r?\n/)
  var linesOfContext = opts.lines || LINES_OF_CONTEXT
  var lineno = callsite.getLineNumber()
  return {
    pre: lines.slice(Math.max(0, lineno - (linesOfContext + 1)), lineno - 1),
    line: lines[lineno - 1],
    post: lines.slice(lineno, lineno + linesOfContext)
  }
}

function sourcemapify (callsites, cb) {
  var next = afterAll(function (err, consumers) {
    if (err) return cb(err)

    consumers.forEach(function (consumer, index) {
      if (!consumer) return
      Object.defineProperty(callsites[index], 'sourcemap', {
        writable: false,
        value: consumer
      })
    })

    cb()
  })

  callsites.forEach(function (callsite) {
    getSourceMapConsumer(callsite, next())
  })
}

function getSourceMapConsumer (callsite, cb) {
  if (isNode.call(callsite)) return process.nextTick(cb)
  var filename = callsite.getFileName()
  sourceMapCache.get(filename, cb)
}

function extendCallsite (callsite) {
  var getLineNumber = callsite.getLineNumber
  var getColumnNumber = callsite.getColumnNumber
  var getFileName = callsite.getFileName
  var position = null
  var properties = {
    getRelativeFileName: {
      writable: false,
      value: getRelativeFileName
    },
    getTypeNameSafely: {
      writable: false,
      value: getTypeNameSafely
    },
    getFunctionNameSanitized: {
      writable: false,
      value: getFunctionNameSanitized
    },
    getModuleName: {
      writable: false,
      value: getModuleName
    },
    isApp: {
      writable: false,
      value: isApp
    },
    isModule: {
      writable: false,
      value: isModule
    },
    isNode: {
      writable: false,
      value: isNode
    },
    sourceContext: {
      writable: false,
      value: sourceContext
    }
  }

  if (callsite.sourcemap) {
    properties.getFileName = {
      writable: false,
      value: function () {
        var filename = getFileName.call(callsite)
        var sourceFile = getPosition().source
        if (!sourceFile) return filename
        var sourceDir = path.dirname(filename)
        return path.resolve(path.join(sourceDir, sourceFile))
      }
    }
    properties.getLineNumber = {
      writable: false,
      value: function () {
        return getPosition().line || getLineNumber.call(callsite)
      }
    }
    properties.getColumnNumber = {
      writable: false,
      value: function () {
        return getPosition().column || getColumnNumber.call(callsite)
      }
    }
  }

  Object.defineProperties(callsite, properties)

  function getPosition () {
    if (!position) {
      position = callsite.sourcemap.originalPositionFor({
        line: getLineNumber.call(callsite),
        column: getColumnNumber.call(callsite)
      })
    }

    return position
  }
}
<commit_msg>Allow custom CallSite properties to be overwritten<commit_after>'use strict'

var fs = require('fs')
var path = require('path')
var asyncCache = require('async-cache')
var afterAll = require('after-all-results')
var errorCallsites = require('error-callsites')
var loadSourceMap = require('load-source-map')
var debug = require('debug')('stackman')

var isAbsolute = path.isAbsolute || require('path-is-absolute')

var fileCache = asyncCache({
  max: 500,
  load: function (file, cb) {
    debug('reading %s', file)
    fs.readFile(file, {encoding: 'utf8'}, cb)
  }
})

var sourceMapCache = asyncCache({
  max: 100,
  load: function (file, cb) {
    debug('loading source map for %s', file)
    loadSourceMap(file, cb)
  }
})

var LINES_OF_CONTEXT = 7
var ESCAPED_REGEX_PATH_SEP = path.sep === '/' ? '/' : '\\\\'
var MODULE_FOLDER_REGEX = new RegExp('.*node_modules' + ESCAPED_REGEX_PATH_SEP + '([^' + ESCAPED_REGEX_PATH_SEP + ']*)')

exports.callsites = callsites
exports.properties = properties
exports.sourceContexts = sourceContexts

function callsites (err, opts, cb) {
  if (typeof opts === 'function') return callsites(err, null, opts)

  var _callsites = errorCallsites(err)

  if (!validStack(_callsites)) {
    process.nextTick(function () {
      cb(new Error('Could not process callsites'))
    })
  } else if (!opts || opts.sourcemap !== false) {
    sourcemapify(_callsites, function (err) {
      if (err) return cb(err)
      _callsites.forEach(extendCallsite)
      cb(null, _callsites)
    })
  } else {
    _callsites.forEach(extendCallsite)
    process.nextTick(function () {
      cb(null, _callsites)
    })
  }
}

function properties (err) {
  var properties = {}
  Object.keys(err).forEach(function (key) {
    if (key === 'stack') return // 'stack' seems to be enumerable in Node 0.11
    var val = err[key]
    if (val === null) return // null is typeof object and well break the switch below
    switch (typeof val) {
      case 'function':
        return
      case 'object':
        // ignore all objects except Dates
        if (typeof val.toISOString !== 'function') return
        val = val.toISOString()
    }
    properties[key] = val
  })
  return properties
}

function sourceContexts (callsites, opts, cb) {
  if (typeof opts === 'function') return sourceContexts(callsites, null, opts)
  if (!opts) opts = {}

  var next = afterAll(cb)

  callsites.forEach(function (callsite) {
    if (callsite.isNode()) {
      next()(null, null)
    } else {
      callsite.sourceContext(opts, next())
    }
  })
}

function validStack (callsites) {
  return Array.isArray(callsites) &&
         typeof callsites[0] === 'object' &&
         typeof callsites[0].getFileName === 'function'
}

function getRelativeFileName () {
  var filename = this.getFileName()
  if (!filename) return
  var root = process.cwd()
  if (root[root.length - 1] !== path.sep) root += path.sep
  return !~filename.indexOf(root) ? filename : filename.substr(root.length)
}

function getTypeNameSafely () {
  try {
    return this.getTypeName()
  } catch (e) {
    // This seems to happen sometimes when using 'use strict',
    // stemming from `getTypeName`.
    // [TypeError: Cannot read property 'constructor' of undefined]
    return null
  }
}

function getFunctionNameSanitized () {
  var fnName = this.getFunctionName()
  if (fnName) return fnName
  var typeName = this.getTypeNameSafely()
  if (typeName) return typeName + '.' + (this.getMethodName() || '<anonymous>')
  return '<anonymous>'
}

function getModuleName () {
  var filename = this.getFileName() || ''
  var match = filename.match(MODULE_FOLDER_REGEX)
  return match ? match[1] : null
}

function isApp () {
  return !this.isNode() && !~(this.getFileName() || '').indexOf('node_modules' + path.sep)
}

function isModule () {
  return !!~(this.getFileName() || '').indexOf('node_modules' + path.sep)
}

function isNode () {
  if (this.isNative()) return true
  var filename = this.getFileName() || ''
  return (!isAbsolute(filename) && filename[0] !== '.')
}

function sourceContext (opts, cb) {
  if (this.isNode()) {
    return process.nextTick(cb, new Error('Can\'t get source context of a Node core callsite'))
  }
  if (typeof opts === 'function') {
    cb = opts
    opts = {}
  }

  var callsite = this
  var filename = this.getFileName() || ''
  var source = this.sourcemap
    ? this.sourcemap.sourceContentFor(filename, true)
    : null

  if (source) {
    process.nextTick(function () {
      cb(null, parseSource(source, callsite, opts))
    })
  } else {
    fileCache.get(filename, function (err, source) {
      if (err) {
        debug('error reading %s: %s', filename, err.message)
        cb(err)
      } else {
        cb(null, parseSource(source, callsite, opts))
      }
    })
  }
}

function parseSource (source, callsite, opts) {
  var lines = source.split(/\r?\n/)
  var linesOfContext = opts.lines || LINES_OF_CONTEXT
  var lineno = callsite.getLineNumber()
  return {
    pre: lines.slice(Math.max(0, lineno - (linesOfContext + 1)), lineno - 1),
    line: lines[lineno - 1],
    post: lines.slice(lineno, lineno + linesOfContext)
  }
}

function sourcemapify (callsites, cb) {
  var next = afterAll(function (err, consumers) {
    if (err) return cb(err)

    consumers.forEach(function (consumer, index) {
      if (!consumer) return
      Object.defineProperty(callsites[index], 'sourcemap', {
        writable: true,
        value: consumer
      })
    })

    cb()
  })

  callsites.forEach(function (callsite) {
    getSourceMapConsumer(callsite, next())
  })
}

function getSourceMapConsumer (callsite, cb) {
  if (isNode.call(callsite)) return process.nextTick(cb)
  var filename = callsite.getFileName()
  sourceMapCache.get(filename, cb)
}

function extendCallsite (callsite) {
  var getLineNumber = callsite.getLineNumber
  var getColumnNumber = callsite.getColumnNumber
  var getFileName = callsite.getFileName
  var position = null
  var properties = {
    getRelativeFileName: {
      writable: true,
      value: getRelativeFileName
    },
    getTypeNameSafely: {
      writable: true,
      value: getTypeNameSafely
    },
    getFunctionNameSanitized: {
      writable: true,
      value: getFunctionNameSanitized
    },
    getModuleName: {
      writable: true,
      value: getModuleName
    },
    isApp: {
      writable: true,
      value: isApp
    },
    isModule: {
      writable: true,
      value: isModule
    },
    isNode: {
      writable: true,
      value: isNode
    },
    sourceContext: {
      writable: true,
      value: sourceContext
    }
  }

  if (callsite.sourcemap) {
    properties.getFileName = {
      writable: true,
      value: function () {
        var filename = getFileName.call(callsite)
        var sourceFile = getPosition().source
        if (!sourceFile) return filename
        var sourceDir = path.dirname(filename)
        return path.resolve(path.join(sourceDir, sourceFile))
      }
    }
    properties.getLineNumber = {
      writable: true,
      value: function () {
        return getPosition().line || getLineNumber.call(callsite)
      }
    }
    properties.getColumnNumber = {
      writable: true,
      value: function () {
        return getPosition().column || getColumnNumber.call(callsite)
      }
    }
  }

  Object.defineProperties(callsite, properties)

  function getPosition () {
    if (!position) {
      position = callsite.sourcemap.originalPositionFor({
        line: getLineNumber.call(callsite),
        column: getColumnNumber.call(callsite)
      })
    }

    return position
  }
}
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash'),
	async = require('async');

function init(opts) {
	this.__grappling = {
		middleware: {},
		hooks     : [],
		opts      : _.defaults({}, opts, {
			strict: true
		})
	};
}

function parseHook(hook) {
	var parsed = (hook) ? hook.split(':') : [],
		n = parsed.length;
	return {
		type: parsed[n - 2],
		name: parsed[n - 1]
	};
}

/**
 *
 * @param instance grappling-hook instance
 * @param hookType qualifier
 * @param hookName action
 * @param args
 * @api private
 */
function addMiddleware(instance, hook, args) {
	var fns = _.flatten(args),
		cache = instance.__grappling,
		mw = [];
	if (!cache.middleware[hook]) {
		if (cache.opts.strict) throw new Error('Hooks for ' + hook + ' are not supported.');
	} else {
		mw = cache.middleware[hook];
	}
	cache.middleware[hook] = mw.concat(fns);
}

function iterateMiddleware(context, middleware, args, done) {
	args = args || [];
	async.eachSeries(middleware, function(callback, next) {
			if (callback.length > args.length) {
				//async
				callback.apply(context, args.concat(next));
			} else {
				//sync
				callback.apply(context, args);
				next();
			}
		}, done || function(err) {
			if (err) {
				throw err;
			}
	});
}

/**
 *
 * @param hookObj
 * @returns {*}
 * @api private
 */
function qualifyHook(hookObj) {
	if (!hookObj.name || !hookObj.type) {
		throw new Error('Only qualified hooks are allowed, e.g. "pre:save", not "save"');
	}
	return hookObj;
}

function createHooks(instance, config) {
	_.each(config, function(fn, hook) {
		var hookObj = parseHook(hook);
		instance[hookObj.name] = function() {
			var args = _.toArray(arguments),
				n = args.length - 1,
				middleware = instance.getMiddleware('pre:' + hookObj.name),
				callback = _.isFunction(args[n]) ? args.shift() : undefined;
			middleware.push(function(next) {
				args.push(next);
				fn.apply(instance, args);
			});
			middleware = middleware.concat(instance.getMiddleware('post:' + hookObj.name));
			iterateMiddleware(instance, middleware, null, callback);
		};
	});
}

var methods = {
	/**
	 * Adds middleware to a pre-hook
	 *
	 * @param {String} action
	 * @param {(...Function|Function[])} fn - middleware to call
	 * @api public
	 */
	pre: function() {
		var args = _.toArray(arguments);
		addMiddleware(this, 'pre:' + args.shift(), args);
		return this;
	},

	/**
	 * Adds middleware to a post-hook
	 *
	 * @param {String} action
	 * @param {(...Function|Function[])} fn - middleware to call
	 * @api public
	 */
	post: function() {
		var args = _.toArray(arguments);
		addMiddleware(this, 'post:' + args.shift(), args);
		return this;
	},

	/**
	 * Adds middleware to a hook
	 *
	 * @param {String} hook - qualified hook e.g. `pre:save`
	 * @param {(...Function|Function[])} fn - middleware to call
	 * @api public
	 */
	hook: function() {
		var args = _.toArray(arguments);
		qualifyHook(parseHook(args[0]));
		addMiddleware(this, args.shift(), args);
		return this;
	},

	/**
	 * Removes (a) hook(s) for `hook`
	 * @example
	 * //removes `onFieldSave` as a `pre:save` middleware
	 * field.unhook( 'pre:save', onFieldSave );
	 * @example
	 * //removes all middleware for `pre:save`
	 * field.unhook('pre:save');
	 * @example
	 * //removes all middleware for `pre:save` and `post:save`
	 * field.unhook('save');
	 * @example
	 * //removes ALL middleware
	 * field.unhook();
	 * @param {String} [hook] - (qualified) hooks e.g. `pre:save` or `save`
	 * @param {(...Function|Function[])} [fn] - function(s) to be removed
	 */
	unhook: function() {
		var fns = _.toArray(arguments),
			hook = fns.shift(),
			hookObj = parseHook(hook),
			middleware = this.__grappling.middleware;
		if (hookObj.type || fns.length) {
			qualifyHook(hookObj);
			if (middleware[hook]) middleware[hook] = (fns.length ) ? _.without.apply(null, [middleware[hook]].concat(fns)) : [];
		} else if (hookObj.name) {
			if (middleware['pre:' + hookObj.name]) middleware['pre:' + hookObj.name] = [];
			if (middleware['post:' + hookObj.name]) middleware['post:' + hookObj.name] = [];
		} else {
			_.each(middleware, function(callbacks, hook) {
				middleware[hook] = [];
			});
		}
		return this;
	},

	hookable: function(hook) {
		qualifyHook(parseHook(hook));
		return (this.__grappling.opts.strict) ? !!this.__grappling.middleware[hook] : true;
	},

	/**
	 * Explicitly declare hooks
	 * @param {(...string|string[])} hooks - (qualified) hooks e.g. `pre:save` or `save`
	 */
	allowHooks: function() {
		var args = _.flatten(_.toArray(arguments));
		_.each(args, function(hook) {
			var hookObj = parseHook(hook),
				middleware = this.__grappling.middleware;
			if (hookObj.type) {
				if (hookObj.type !== 'pre' && hookObj.type !== 'post') {
					throw new Error('Only "pre" and "post" types are allowed, not "' + hookObj.type + '"');
				}
				middleware[hook] = middleware[hook] || [];
			} else if (hookObj.name) {
				middleware['pre:' + hookObj.name] = middleware['pre:' + hookObj.name] || [];
				middleware['post:' + hookObj.name] = middleware['post:' + hookObj.name] || [];
			}
		}, this);
		return this;
	},

	/**
	 * Wraps methods/functions with `pre` and/or `post` hooks
	 * @example
	 * //wrap existing methods
	 * instance.addHooks('save', 'pre:remove');
	 * @example
	 * //add method and wrap it
	 * instance.addHooks({
	 *   save: instance._upload,
	 *   "pre:remove": function(){
	 *   	//...
	 *   }
	 * });
	 * @param {(...String|String[]|...Object|Object[])} method - method(s) that need(s) to emit `pre` and `post` events
	 */
	addHooks: function() {
		var args = _.flatten(_.toArray(arguments)),
			config = {};
		_.each(args, function(mixed) {
			if (_.isString(mixed)) {
				var hookObj = parseHook(mixed),
					fn = this[hookObj.name];
				if (!fn) throw new Error('Cannot add hooks to undeclared method:"' + hookObj.name + '"'); //non-existing method
				config[mixed] = fn;
			} else if (_.isObject(mixed)) {
				_.defaults(config, mixed);
			}// todo: else throw?
		}, this);
		this.allowHooks(_.keys(config));
		createHooks(this, config);
		return this;
	},

	/**
	 * Calls all middleware subscribed to the `hook` and passes remaining parameters to them
	 * @param {*} [context] - the context in which the middleware will be called
	 * @param {String} hook - qualified hook e.g. `pre:save`
	 * @param {...*} [parameters] - any parameters you wish to pass to the middleware.
	 * @param {Function} [callback] - will be called when all middleware have finished
	 */
	callHook: function(context, hook) {
		var args = _.toArray(arguments),
			done;
		if (_.isString(context)) {
			hook = context;
			context = this;
		} else {
			args.shift(); //drop `context`
		}
		args.shift();//drop `hook`
		if (_.isFunction(args[args.length - 1])) {
			done = args.pop(); //drop callback
		}
		args = _.flatten(args);// in case parameters were passed in as an array; this is 2-dim, we need 1-dim
		iterateMiddleware(context, this.getMiddleware(hook), args, done);
		return this;
	},

	/**
	 *
	 * @param hook - qualified hook, e.g. `pre:save`
	 * @returns {Function[]}
	 */
	getMiddleware: function(hook) {
		qualifyHook(parseHook(hook));
		return this.__grappling.middleware[hook] || [];
	},

	/**
	 *
	 * @param hook - qualified hook, e.g. `pre:save`
	 * @returns {boolean}
	 */
	hasMiddleware: function(hook) {
		return this.getMiddleware(hook).length > 0;
	}
};

function mixin(instance, opts) {
	init.call(instance, opts);
	_.extend(instance, methods);
	return instance;
}

function attach(clazz, opts) {
	mixin(clazz.prototype, opts);
	return clazz;
}

/**
 *
 * @param {Object} [opts]
 * @param {Boolean} [opts.strict=true] - Will disallow subscribing to middleware bar the explicitly registered ones.
 * @returns {*}
 */
function create(opts) {
	return mixin({}, opts);
}

module.exports = {
	mixin : mixin,
	create: create,
	attach: attach
};
<commit_msg>Fixing code style + linter issues<commit_after>'use strict';

var _ = require('lodash');
var async = require('async');

function init(opts) {
	this.__grappling = {
		middleware: {},
		hooks: [],
		opts: _.defaults({}, opts, {
			strict: true
		})
	};
}

function parseHook(hook) {
	var parsed = (hook) ? hook.split(':') : [],
		n = parsed.length;
	return {
		type: parsed[n - 2],
		name: parsed[n - 1]
	};
}

/**
 *
 * @param instance grappling-hook instance
 * @param hookType qualifier
 * @param hookName action
 * @param args
 * @api private
 */
function addMiddleware(instance, hook, args) {
	var fns = _.flatten(args),
		cache = instance.__grappling,
		mw = [];
	if (!cache.middleware[hook]) {
		if (cache.opts.strict) throw new Error('Hooks for ' + hook + ' are not supported.');
	} else {
		mw = cache.middleware[hook];
	}
	cache.middleware[hook] = mw.concat(fns);
}

function iterateMiddleware(context, middleware, args, done) {
	args = args || [];
	async.eachSeries(middleware, function(callback, next) {
			if (callback.length > args.length) {
				//async
				callback.apply(context, args.concat(next));
			} else {
				//sync
				callback.apply(context, args);
				next();
			}
		}, done || function(err) {
			if (err) {
				throw err;
			}
	});
}

/**
 *
 * @param hookObj
 * @returns {*}
 * @api private
 */
function qualifyHook(hookObj) {
	if (!hookObj.name || !hookObj.type) {
		throw new Error('Only qualified hooks are allowed, e.g. "pre:save", not "save"');
	}
	return hookObj;
}

function createHooks(instance, config) {
	_.each(config, function(fn, hook) {
		var hookObj = parseHook(hook);
		instance[hookObj.name] = function() {
			var args = _.toArray(arguments),
				n = args.length - 1,
				middleware = instance.getMiddleware('pre:' + hookObj.name),
				callback = _.isFunction(args[n]) ? args.shift() : undefined;
			middleware.push(function(next) {
				args.push(next);
				fn.apply(instance, args);
			});
			middleware = middleware.concat(instance.getMiddleware('post:' + hookObj.name));
			iterateMiddleware(instance, middleware, null, callback);
		};
	});
}

var methods = {
	/**
	 * Adds middleware to a pre-hook
	 *
	 * @param {String} action
	 * @param {(...Function|Function[])} fn - middleware to call
	 * @api public
	 */
	pre: function() {
		var args = _.toArray(arguments);
		addMiddleware(this, 'pre:' + args.shift(), args);
		return this;
	},

	/**
	 * Adds middleware to a post-hook
	 *
	 * @param {String} action
	 * @param {(...Function|Function[])} fn - middleware to call
	 * @api public
	 */
	post: function() {
		var args = _.toArray(arguments);
		addMiddleware(this, 'post:' + args.shift(), args);
		return this;
	},

	/**
	 * Adds middleware to a hook
	 *
	 * @param {String} hook - qualified hook e.g. `pre:save`
	 * @param {(...Function|Function[])} fn - middleware to call
	 * @api public
	 */
	hook: function() {
		var args = _.toArray(arguments);
		qualifyHook(parseHook(args[0]));
		addMiddleware(this, args.shift(), args);
		return this;
	},

	/**
	 * Removes (a) hook(s) for `hook`
	 * @example
	 * //removes `onFieldSave` as a `pre:save` middleware
	 * field.unhook( 'pre:save', onFieldSave );
	 * @example
	 * //removes all middleware for `pre:save`
	 * field.unhook('pre:save');
	 * @example
	 * //removes all middleware for `pre:save` and `post:save`
	 * field.unhook('save');
	 * @example
	 * //removes ALL middleware
	 * field.unhook();
	 * @param {String} [hook] - (qualified) hooks e.g. `pre:save` or `save`
	 * @param {(...Function|Function[])} [fn] - function(s) to be removed
	 */
	unhook: function() {
		var fns = _.toArray(arguments),
			hook = fns.shift(),
			hookObj = parseHook(hook),
			middleware = this.__grappling.middleware;
		if (hookObj.type || fns.length) {
			qualifyHook(hookObj);
			if (middleware[hook]) middleware[hook] = (fns.length ) ? _.without.apply(null, [middleware[hook]].concat(fns)) : [];
		} else if (hookObj.name) {
			if (middleware['pre:' + hookObj.name]) middleware['pre:' + hookObj.name] = [];
			if (middleware['post:' + hookObj.name]) middleware['post:' + hookObj.name] = [];
		} else {
			_.each(middleware, function(callbacks, hook) {
				middleware[hook] = [];
			});
		}
		return this;
	},

	hookable: function(hook) {
		qualifyHook(parseHook(hook));
		return (this.__grappling.opts.strict) ? !!this.__grappling.middleware[hook] : true;
	},

	/**
	 * Explicitly declare hooks
	 * @param {(...string|string[])} hooks - (qualified) hooks e.g. `pre:save` or `save`
	 */
	allowHooks: function() {
		var args = _.flatten(_.toArray(arguments));
		_.each(args, function(hook) {
			var hookObj = parseHook(hook),
				middleware = this.__grappling.middleware;
			if (hookObj.type) {
				if (hookObj.type !== 'pre' && hookObj.type !== 'post') {
					throw new Error('Only "pre" and "post" types are allowed, not "' + hookObj.type + '"');
				}
				middleware[hook] = middleware[hook] || [];
			} else if (hookObj.name) {
				middleware['pre:' + hookObj.name] = middleware['pre:' + hookObj.name] || [];
				middleware['post:' + hookObj.name] = middleware['post:' + hookObj.name] || [];
			}
		}, this);
		return this;
	},

	/**
	 * Wraps methods/functions with `pre` and/or `post` hooks
	 * @example
	 * //wrap existing methods
	 * instance.addHooks('save', 'pre:remove');
	 * @example
	 * //add method and wrap it
	 * instance.addHooks({
	 *   save: instance._upload,
	 *   "pre:remove": function(){
	 *   	//...
	 *   }
	 * });
	 * @param {(...String|String[]|...Object|Object[])} method - method(s) that need(s) to emit `pre` and `post` events
	 */
	addHooks: function() {
		var args = _.flatten(_.toArray(arguments)),
			config = {};
		_.each(args, function(mixed) {
			if (_.isString(mixed)) {
				var hookObj = parseHook(mixed),
					fn = this[hookObj.name];
				if (!fn) throw new Error('Cannot add hooks to undeclared method:"' + hookObj.name + '"'); //non-existing method
				config[mixed] = fn;
			} else if (_.isObject(mixed)) {
				_.defaults(config, mixed);
			}// todo: else throw?
		}, this);
		this.allowHooks(_.keys(config));
		createHooks(this, config);
		return this;
	},

	/**
	 * Calls all middleware subscribed to the `hook` and passes remaining parameters to them
	 * @param {*} [context] - the context in which the middleware will be called
	 * @param {String} hook - qualified hook e.g. `pre:save`
	 * @param {...*} [parameters] - any parameters you wish to pass to the middleware.
	 * @param {Function} [callback] - will be called when all middleware have finished
	 */
	callHook: function(context, hook) {
		var args = _.toArray(arguments),
			done;
		if (_.isString(context)) {
			hook = context;
			context = this;
		} else {
			args.shift(); //drop `context`
		}
		args.shift();//drop `hook`
		if (_.isFunction(args[args.length - 1])) {
			done = args.pop(); //drop callback
		}
		args = _.flatten(args);// in case parameters were passed in as an array; this is 2-dim, we need 1-dim
		iterateMiddleware(context, this.getMiddleware(hook), args, done);
		return this;
	},

	/**
	 *
	 * @param hook - qualified hook, e.g. `pre:save`
	 * @returns {Function[]}
	 */
	getMiddleware: function(hook) {
		qualifyHook(parseHook(hook));
		return this.__grappling.middleware[hook] || [];
	},

	/**
	 *
	 * @param hook - qualified hook, e.g. `pre:save`
	 * @returns {boolean}
	 */
	hasMiddleware: function(hook) {
		return this.getMiddleware(hook).length > 0;
	}
};

function mixin(instance, opts) {
	init.call(instance, opts);
	_.extend(instance, methods);
	return instance;
}

function attach(clazz, opts) {
	mixin(clazz.prototype, opts);
	return clazz;
}

/**
 *
 * @param {Object} [opts]
 * @param {Boolean} [opts.strict=true] - Will disallow subscribing to middleware bar the explicitly registered ones.
 * @returns {*}
 */
function create(opts) {
	return mixin({}, opts);
}

module.exports = {
	mixin: mixin,
	create: create,
	attach: attach
};
<|endoftext|>


<commit_before>
var util = require('util')
  , stream = require('stream')
var isstream = require('isstream')

util.inherits(BulkStream, stream.Readable)
module.exports = BulkStream

function BulkStream () {
  stream.Readable.call(this)

  var self = this
  self._items = []
  self._streams = []
  self._index = 0
}

BulkStream.prototype.append = function (item) {
  var self = this
  if (isstream(item)) {
    item.pause()
    self._streams.push(item)
  }
  self._items.push(item)
}

BulkStream.prototype._read = function (n) {
  var self = this

  if (self._index === self._items.length) {
    // process.nextTick(function () {
    //   self.push(null)
    // })
    return
  }

  var item = self._items[self._index]
  if (item._reading) {
    return
  }

  if (isstream(item)) {
    item._reading = true
    item.on('readable', function () {
      var chunk = item.read()
      if (chunk === null) {
        self._index++
        self._read()
      }
      else {
        self.push(chunk)
      }
    })
  }
  else {
    self._index++
    self.push(item)
  }
}
<commit_msg>Push null on read end<commit_after>
var util = require('util')
  , stream = require('stream')
var isstream = require('isstream')

util.inherits(BulkStream, stream.Readable)
module.exports = BulkStream

function BulkStream () {
  stream.Readable.call(this)

  var self = this
  self._items = []
  self._streams = []
  self._index = 0
}

BulkStream.prototype.append = function (item) {
  var self = this
  if (isstream(item)) {
    item.pause()
    self._streams.push(item)
  }
  self._items.push(item)
}

BulkStream.prototype._read = function (n) {
  var self = this

  if (self._index === self._items.length) {
    self.push(null)
    return
  }

  var item = self._items[self._index]
  if (item._reading) {
    return
  }

  if (isstream(item)) {
    item._reading = true
    item.on('readable', function () {
      var chunk = item.read()
      if (chunk === null) {
        self._index++
        self._read()
      }
      else {
        self.push(chunk)
      }
    })
  }
  else {
    self._index++
    self.push(item)
  }
}
<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */
var color = require("color")

/**
 * PostCSS plugin to convert colors
 *
 * @param {Object} options
 */
module.exports = function plugin(options) {
  options = options || {}
  options.rebeccapurple = options.rebeccapurple !== undefined ? options.rebeccapurple : true
  options.hwb = options.hwb !== undefined ? options.hwb : true
  options.hexAlpha = options.hexAlpha !== undefined ? options.hexAlpha : true
  options.color = options.color !== undefined ? options.color : true

  return function(style) {
    style.eachDecl(function transformDecl(dec) {
      if (!dec.value) {
        return
      }

      dec.value = transform(dec.value, dec.source, options)
    })
  }
}

/**
 * Transform colors to rgb() or rgba() on a declaration value
 *
 * @param {String} string
 * @return {String}
 */
function transform(string, source, options) {
  // order of transformation is important

  try {
    if (options.rebeccapurple && string.indexOf("rebeccapurple") > -1) {
      string = transformRebeccapurple(string, source)
    }
  }
  catch (e) {
    throw new Error(gnuMessage(e.message, source))
  }

  return string
}

/**
 * Transform rebeccapurple color to rgb()
 *
 * @param  {String} string declaration value
 * @return {String}        converted declaration value to rgba()
 */
function transformRebeccapurple(string) {
  return string.replace(/(rebeccapurple)\b/gi, color("rebeccapurple").rgbString())
}

/**
 * return GNU style message
 *
 * @param {String} message
 * @param {Object} source
 */
function gnuMessage(message, source) {
  return (source ? (source.file ? source.file : "<css input>") + ":" + source.start.line + ":" + source.start.column : "") + " " + message
}
<commit_msg>Udpate gnuMessage function when no source available<commit_after>/**
 * Module dependencies.
 */
var color = require("color")

/**
 * PostCSS plugin to convert colors
 *
 * @param {Object} options
 */
module.exports = function plugin(options) {
  options = options || {}
  options.rebeccapurple = options.rebeccapurple !== undefined ? options.rebeccapurple : true
  options.hwb = options.hwb !== undefined ? options.hwb : true
  options.hexAlpha = options.hexAlpha !== undefined ? options.hexAlpha : true
  options.color = options.color !== undefined ? options.color : true

  return function(style) {
    style.eachDecl(function transformDecl(dec) {
      if (!dec.value) {
        return
      }

      dec.value = transform(dec.value, dec.source, options)
    })
  }
}

/**
 * Transform colors to rgb() or rgba() on a declaration value
 *
 * @param {String} string
 * @return {String}
 */
function transform(string, source, options) {
  // order of transformation is important

  try {
    if (options.rebeccapurple && string.indexOf("rebeccapurple") > -1) {
      string = transformRebeccapurple(string, source)
    }
  }
  catch (e) {
    throw new Error(gnuMessage(e.message, source))
  }

  return string
}

/**
 * Transform rebeccapurple color to rgb()
 *
 * @param  {String} string declaration value
 * @return {String}        converted declaration value to rgba()
 */
function transformRebeccapurple(string) {
  return string.replace(/(rebeccapurple)\b/gi, color("rebeccapurple").rgbString())
}

/**
 * return GNU style message
 *
 * @param {String} message
 * @param {Object} source
 */
function gnuMessage(message, source) {
  return (source ? (source.file ? source.file : "<css input>") + ":" + source.start.line + ":" + source.start.column + " " : "") + message
}
<|endoftext|>


<commit_before>'use strict';

var util = require('./lib/util');
util.fold = require('./lib/fold');

exports = module.exports = Parth;

function Parth(){

  if(!(this instanceof Parth)){ return new Parth(); }
  this.cache = { paths: [ ], regexp: [ ], masterRE: [ ]  };
}

// ## Parth.boil(path [, o])
// > premise: normalize a path, obtain its depth so one can classify it
//
// arguments
//  - `path` type `string` or `array`
//  - `o` type `object` holding all extra information
//
// return
//  - `this` so the method is chainable
//

var boilRE = /((?:\/|\?|\#)[^\/\?\# ]+|[^\. ]+\.)/g;

Parth.prototype.boil = function (path, o){
  o = o || { };  var stem = util.type(path);
  if(!stem.string && !stem.array){ return null; }

  o.input = (stem.string || util.fold(stem.array.join(' ')));
  o.path = o.input.replace(/[ ]+/g, ' ');
  o.stems = '';

  var url;
  if((url = o.path.match(/\/\S+/))){
    o.url = util.url.parse(url = url[0]);
    o.url = {
      href: url,
      hash: o.url.hash,
      query: o.url.query,
      pathname: url.replace(o.url.search + o.url.hash, ''),
    };
    o.path = o.path.replace(o.url.href,
      o.url.pathname.replace(/[\/]+$/, '') || '/');
  }

  o.stems = o.path.replace(boilRE, '$& ').trim().split(/[ ]+/);
  o.index = o.depth = o.stems.length-1;
  return o.stems;
};

// ## Parth.set
// > premise: set a string, array path or regexp path
// > TODO: implement regexp input, not done yet :D
//
// arguments
//  - `path` type `string` or `array`
//  - `opt` type `object` optional holding all extra information
//
// return
//  - `this` so the method is chainable
//
Parth.prototype.set = function(path, o){
  this.boil(path, (o = o || { }));

  o.found = this.cache.paths[o.depth];
  if(o.found && (o.index = o.found.indexOf(o.path)) > -1){
    o.regexp = o.found[o.index];
    return this;
  }

  var cache = this.cache;
  // prepare paths, regexp and masterRE arrays
  if(cache.regexp.length < o.depth + 1){
    o.index = cache.regexp.length;
    while(o.index < o.depth + 1){
      cache.paths.push([ ]);
      cache.regexp.push([ ]);
      o.index = cache.masterRE.push(null);
    }
  }

  o.regexp = o.path
    .replace(/\S+/g, function(stem){
      o.sep = (/\//).test(stem) ? '\\/\\#\\?' : '\\.';
      return stem.replace(/(\:\w+)(\(.+?\))?/g, function($0, $1, $2){
        o.params = o.params || { };
        o.params[$1] = $2 || '([^' + o.sep + '^]+)';
        return $1;
      });
    }).replace(/[\/\.\?\#]+/g, '\\$&')
      .replace(/\:\w+/g, function($0){ return o.params[$0]; });

  if(o.url && o.url.pathname.length > 1){
    o.regexp = o.regexp.replace(/\/\S+/, '$&\\/?');
  }
  o.regexp = o.regexp.replace(/\^\]\+/g, ' ]+');
  o.regexp = new RegExp('^' + o.regexp, o.strict ? '' : 'i');
  o.method = (/\(.+?\)/).test(o.path) ? 'unshift' : 'push';

  cache.paths[o.depth][o.method](o.path);
  cache.regexp[o.depth][o.method](o.regexp);
  cache.masterRE[o.depth] = new RegExp(cache.regexp[o.depth]
  .map(function(re){ return re.source.replace(/[\(\)]+/g,''); }).join('|'), 'i');

  return this;
};

// ## Parth.get
// > premise: get a string or array path
//
// arguments
//  - `path` type `string` or `array`
//  - `opt` type `object` optional
//
// return
//  - `output` type `object` with useful propeties
//
Parth.prototype.get = function(path, o){
  this.boil(path, (o = o || { }));

  var cache = this.cache, found = cache.masterRE;
  if(o.depth > found.length-1){ o.index = o.depth = found.length-1; }

  while(o.index > -1){
    if(found[o.index] && found[o.index].test(o.path)){
      o.depth = o.index; o.index = 0;
    } else if(!o.index){ o.depth = null; }
    o.index--;
  }
  if(o.depth === null){ return null; }

  o.index = 0;
  o.regexp = cache.regexp[o.depth];
  while(!o.regexp[o.index].test(o.path)){ o.index++; }
  o.stems = cache.paths[o.depth][o.index];
  o.regexp = cache.regexp[o.depth][o.index];

  o.index = 0;
  o.notFound = false; o.params = {};
  var param = o.path.match(o.regexp).slice(1);

  o.notFound = !(/[ ]+/).test(
      o.path.replace(
          o.stems.replace(/\:(\w+)(\(.+?\))?/g, function($0, $1){
            return (o.params[$1] = param[o.index++]);
          }), '')[0] || ' ');

  param = null; delete o.index; delete o.depth; // wipe
  return o;
};
<commit_msg>much better regexp for parameters<commit_after>'use strict';

var util = require('./lib/util');
util.fold = require('./lib/fold');

exports = module.exports = Parth;

function Parth(){

  if(!(this instanceof Parth)){ return new Parth(); }
  this.cache = { paths: [ ], regexp: [ ], masterRE: [ ]  };
}

// ## Parth.boil(path [, o])
// > premise: normalize a path, obtain its depth so one can classify it
//
// arguments
//  - `path` type `string` or `array`
//  - `o` type `object` holding all extra information
//
// return
//  - `this` so the method is chainable
//

var boilRE = /((?:\/|\?|\#)[^\/\?\# ]+|[^\. ]+\.)/g;

Parth.prototype.boil = function (path, o){
  o = o || { };  var stem = util.type(path);
  if(!stem.string && !stem.array){ return null; }

  o.input = (stem.string || util.fold(stem.array.join(' ')));
  o.path = o.input.replace(/[ ]+/g, ' ');
  o.stems = '';

  var url;
  if((url = o.path.match(/\/\S+/))){
    o.url = util.url.parse(url = url[0]);
    o.url = {
      href: url,
      hash: o.url.hash,
      query: o.url.query,
      pathname: url.replace(o.url.search + o.url.hash, ''),
    };
    o.path = o.path.replace(o.url.href,
      o.url.pathname.replace(/[\/]+$/, '') || '/');
  }

  o.stems = o.path.replace(boilRE, '$& ').trim().split(/[ ]+/);
  o.index = o.depth = o.stems.length-1;
  return o.stems;
};

// ## Parth.set
// > premise: set a string, array path or regexp path
// > TODO: implement regexp input, not done yet :D
//
// arguments
//  - `path` type `string` or `array`
//  - `o` type `object` optional holding all extra information
//
// return
//  - `this` so the method is chainable
//
Parth.prototype.set = function(path, o){
  this.boil(path, (o = o || { }));

  o.found = this.cache.paths[o.depth];
  if(o.found && (o.index = o.found.indexOf(o.path)) > -1){
    o.regexp = o.found[o.index];
    return this;
  }

  var cache = this.cache;
  // prepare paths, regexp and masterRE arrays
  if(cache.regexp.length < o.depth + 1){
    o.index = cache.regexp.length;
    while(o.index < o.depth + 1){
      cache.paths.push([ ]);
      cache.regexp.push([ ]);
      o.index = cache.masterRE.push(null);
    }
  }

  o.regexp = o.path
    .replace(/\S+/g, function(stem){
      o.sep = (/\//).test(stem) ? '\\/\\#\\?' : '\\.';
      return stem.replace(/(\:[^\/\\\?\#\.\( ]+)(\(.+?\))?/g, function($0, $1, $2){
        o.params = o.params || { };
        o.params[$1] = $2 || '([^' + o.sep + '^]+)';
        return $1;
      });
    }).replace(/[\/\.\?\#]+/g, '\\$&')
      .replace(/\:[^\/\\\?\#\.\( ]+/g, function($0){ return o.params[$0]; });

  if(o.url && o.url.pathname.length > 1){
    o.regexp = o.regexp.replace(/\/\S+/, '$&\\/?');
  }
  o.regexp = o.regexp.replace(/\^\]\+/g, ' ]+');
  o.regexp = new RegExp('^' + o.regexp, o.strict ? '' : 'i');
  o.method = (/\(.+?\)/).test(o.path) ? 'unshift' : 'push';

  cache.paths[o.depth][o.method](o.path);
  cache.regexp[o.depth][o.method](o.regexp);
  cache.masterRE[o.depth] = new RegExp(cache.regexp[o.depth]
  .map(function(re){ return re.source.replace(/[\(\)]+/g,''); }).join('|'), 'i');

  return this;
};

// ## Parth.get
// > premise: get a string or array path, return an object
//
// arguments
//  - `path` type `string` or `array`
//  - `o` type `object` optional holding all extra information
//
// return
//  - `o` type `object`
//
Parth.prototype.get = function(path, o){
  this.boil(path, (o = o || { }));

  var cache = this.cache, found = cache.masterRE;
  if(o.depth > found.length-1){ o.index = o.depth = found.length-1; }

  while(o.index > -1){
    if(found[o.index] && found[o.index].test(o.path)){
      o.depth = o.index; o.index = 0;
    } else if(!o.index){ o.depth = null; }
    o.index--;
  }
  if(o.depth === null){ return null; }

  o.index = 0;
  o.regexp = cache.regexp[o.depth];
  while(!o.regexp[o.index].test(o.path)){ o.index++; }
  o.stems = cache.paths[o.depth][o.index];
  o.regexp = cache.regexp[o.depth][o.index];

  o.index = 0;
  o.notFound = false; o.params = {};
  var param = o.path.match(o.regexp).slice(1);

  o.notFound = !(/[ ]+/).test(
      o.path.replace(
          o.stems.replace(/\:([^\/\\\?\#\.\( ]+)(\(.+?\))?/g, function($0, $1){
            var par = param[o.index++];
            return (o.params[$1] = Number(par) || par);
          }), '')[0] || ' ');

  param = null; delete o.index; // wipe
  return o;
};
<|endoftext|>


<commit_before>var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var fs = require('fs');
app.use(express.static(__dirname));
var list = require('badwords-list');
banned = list.array;

var data = fs.readFileSync("config.json", "utf8", function(err, data) {
	if (err) throw err;
});
var config = JSON.parse(data);

app.get('/', function(req, res) {
	var page = fs.readFileSync("./chat.html", "utf8", function(err, data) {
		if (err) throw err;
	});

	page = page.replace("***firebase-url***", config.firebase_url);
	res.send(page);
});

io.on('connection', function(socket){
	socket.on('chat message', function(msg, user){
		if(msg == '' || msg == undefined || msg == null) {
			return;
		}

		var allowed = true;
		var m = msg.split(' ');
		m.forEach(function(msg) {
			banned.forEach(function(word) {
				if(wordInString(msg, word)) {
					allowed = false;
				}
			});
		});

		if(allowed == false) {
			return;
		}

		msg = msg.replace(/</g, "<");
		msg = msg.replace(/>/g, ">");

		user = user.replace(/</g, "<");
		user = user.replace(/>/g, ">");

		io.emit('chat message', msg, user);
	});
});

function wordInString(s, word){
	return new RegExp( '\\b' + word + '\\b', 'i').test(s);
}

http.listen(config.port, function(){
		banned.push('SPAM');
    console.log('listening on Port ' + config.port);
});
<commit_msg>Unblocked word spam<commit_after>var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var fs = require('fs');
app.use(express.static(__dirname));
var list = require('badwords-list');
banned = list.array;

var data = fs.readFileSync("config.json", "utf8", function(err, data) {
	if (err) throw err;
});
var config = JSON.parse(data);

app.get('/', function(req, res) {
	var page = fs.readFileSync("./chat.html", "utf8", function(err, data) {
		if (err) throw err;
	});

	page = page.replace("***firebase-url***", config.firebase_url);
	res.send(page);
});

io.on('connection', function(socket){
	socket.on('chat message', function(msg, user){
		if(msg == '' || msg == undefined || msg == null) {
			return;
		}

		var allowed = true;
		var m = msg.split(' ');
		m.forEach(function(msg) {
			banned.forEach(function(word) {
				if(wordInString(msg, word)) {
					allowed = false;
				}
			});
		});

		if(allowed == false) {
			return;
		}

		msg = msg.replace(/</g, "<");
		msg = msg.replace(/>/g, ">");

		user = user.replace(/</g, "<");
		user = user.replace(/>/g, ">");

		io.emit('chat message', msg, user);
	});
});

function wordInString(s, word){
	return new RegExp( '\\b' + word + '\\b', 'i').test(s);
}

http.listen(config.port, function(){
    console.log('listening on Port ' + config.port);
});
<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var Emitter = require('emitter'),
    classes = require('classes'),
    Upload = require('upload'),
    events = require('events'),
    domify = require('domify')

var template = require('./template')

var cdpload = module.exports = function (el, options) {
  if (!(this instanceof cdpload)) return new cdpload(el, options)
  Emitter.call(this)

  this.el = el
  this.el.appendChild(domify(template))
  this.input = this.el.querySelector('.cdpload')

  this.classes = classes(el)
  this.events = events(el, this)

  this.events.bind('drop')
  this.events.bind('dragenter')
  this.events.bind('dragleave')
  this.events.bind('dragover')
  this.events.bind('click')
  this.events.bind('change .cdpload')
}

Emitter(cdpload.prototype)

cdpload.prototype.unbind = function () {
  this.events.unbind()
}

cdpload.prototype.ondragenter = function () {
  this.classes.add('over')
}

cdpload.prototype.ondragover = function (ev) {
  ev.preventDefault()
}

cdpload.prototype.ondragleave = function () {
  this.classes.remove('over')
}

cdpload.prototype.ondrop = function(ev){
  ev.stopPropagation()
  ev.preventDefault()

  this.classes.remove('over')
  this.upload(ev.dataTransfer.files)
  this.emit('drop', ev)
}

cdpload.prototype.click = function(){
  this.input.click()
}

cdpload.prototype.change = function(){
  this.upload(this.files);
}

cdpload.prototype.upload = function(files){
  var file = Array.prototype.shift.call(files)
  this.emit('upload', new Upload(file))
}<commit_msg>fix click and change event names<commit_after>
/**
 * Module dependencies.
 */

var Emitter = require('emitter'),
    classes = require('classes'),
    Upload = require('upload'),
    events = require('events'),
    domify = require('domify')

var template = require('./template')

var cdpload = module.exports = function (el, options) {
  if (!(this instanceof cdpload)) return new cdpload(el, options)
  Emitter.call(this)

  this.el = el
  this.el.appendChild(domify(template))
  this.input = this.el.querySelector('.cdpload')

  this.classes = classes(el)
  this.events = events(el, this)

  this.events.bind('drop')
  this.events.bind('dragenter')
  this.events.bind('dragleave')
  this.events.bind('dragover')
  this.events.bind('click')
  this.events.bind('change .cdpload')
}

Emitter(cdpload.prototype)

cdpload.prototype.unbind = function () {
  this.events.unbind()
}

cdpload.prototype.ondragenter = function () {
  this.classes.add('over')
}

cdpload.prototype.ondragover = function (ev) {
  ev.preventDefault()
}

cdpload.prototype.ondragleave = function () {
  this.classes.remove('over')
}

cdpload.prototype.ondrop = function(ev){
  ev.stopPropagation()
  ev.preventDefault()

  this.classes.remove('over')
  this.upload(ev.dataTransfer.files)
  this.emit('drop', ev)
}

cdpload.prototype.onclick = function(){
  this.input.click()
}

cdpload.prototype.onchange = function(){
  this.upload(this.files);
}

cdpload.prototype.upload = function(files){
  var file = Array.prototype.shift.call(files)
  this.emit('upload', new Upload(file))
}<|endoftext|>