<commit_before>// es6 runtime requirements
import 'babel-polyfill'

// their code
import express from 'express'
import sockets from 'socket.io'
import { json } from 'body-parser'
import { Server as http } from 'http'
import remail from 'email-regex'
import dom from 'vd'
import cors from 'cors'

// our code
import Slack from './slack'
import invite from './slack-invite'
import badge from './badge'
import splash from './splash'
import iframe from './iframe'
import log from './log'

export default function slackin ({
  token,
  interval = 5000, // jshint ignore:line
  org,
  css,
  coc,
  cors: useCors = true,
  path='/',
  channels,
  emails,
  silent = false // jshint ignore:line,
}){
  // must haves
  if (!token) throw new Error('Must provide a `token`.')
  if (!org) throw new Error('Must provide an `org`.')

  if (channels) {
    // convert to an array
    channels = channels.split(',').map((channel) => {
      // sanitize channel name
      if ('#' === channel[0]) return channel.substr(1)
      return channel
    })
  }

  if (emails) {
    // convert to an array
    emails = emails.split(',')
  }

  // setup app
  let app = express()
  let router = express.Router()
  let srv = http(app)
  srv.app = app

  let assets = __dirname + '/assets'

  // fetch data
  let slack = new Slack({ token, interval, org })

  slack.setMaxListeners(Infinity)

  // capture stats
  log(slack, silent)

  // middleware for waiting for slack
  router.use((req, res, next) => {
    if (slack.ready) return next()
    slack.once('ready', next)
  })

  if (useCors) {
    app.options('https://lemonlabs.io', cors())
    app.use(cors())
  }

  // splash page
  router.get('/', (req, res) => {
    let { name, logo } = slack.org
    let { active, total } = slack.users
    if (!name) return res.send(404)

    // Generated using http://arthurclemens.github.io/mithril-template-converter/index.html
    let nav = dom("nav.navbar.navbar-default style='padding: 10px 0;'",
      dom(".container",
        [
          dom(".navbar-header.page-scroll",
            [
              dom("button.navbar-toggle data-target='#bs-example-navbar-collapse-1' data-toggle='collapse' type='button'",
                [
                  dom("span.sr-only",
                    "Toggle navigation"
                  ),
                  dom("span.icon-bar"),
                  dom("span.icon-bar"),
                  dom("span.icon-bar")
                ]
              )
            ]
          ),
          dom(".collapse.navbar-collapse id='bs-example-navbar-collapse-1'",
            dom("ul.nav.navbar-nav.navbar-right",
              [
                dom("li.hidden",
                  dom("a href='#page-top'")
                ),
                dom("li.page-scroll",
                  dom("a href='//lemonlabs.io/#whatwedo'",
                    "What we do"
                  )
                ),
                dom("li.page-scroll",
                  dom("a href='//lemonlabs.io/#team'",
                    "The team"
                  )
                ),
                dom("li.page-scroll",
                  dom("a href='//lemonlabs.io/#contact'",
                    "Contact"
                  )
                )
              ]
            )
          )
        ]
      )
    );

    let footer = dom("footer.text-center",
      [
        dom(".footer-above",
          dom(".container",
            dom(".row",
              [
                dom(".footer-col.col-md-4",
                  [
                    dom("h3", "Lemon Labs Limited"),
                    dom("p", "Fleet, Hampshire")
                  ]
                ),
                dom(".footer-col.col-md-4",
                  [
                    dom("h3",
                      "Around the Web"
                    ),
                    dom("ul.list-inline",
                      [
                        dom("li",
                          dom("a.btn-social.btn-outline href='http://github.com/lemonlabsuk'",
                            dom("i.fa.fa-fw.fa-github")
                          )
                        ),
                        dom("li",
                          dom("a.btn-social.btn-outline href='https://www.linkedin.com/company/lemon-labs-limited'",
                            dom("i.fa.fa-fw.fa-linkedin")
                          )
                        )
                      ]
                    )
                  ]
                ),
                dom(".footer-col.col-md-4",
                  [
                    dom("h3",
                      "Credits"
                    ),
                    dom("p",
                      [
                        "Modified version of the ",
                        dom("a href='https://github.com/jeromelachaud/freelancer-theme/blob/master/LICENCE'",
                          "Apache 2.0"
                        ),
                        " licensed ",
                        dom("a href='https://github.com/jeromelachaud/freelancer-theme/'",
                          "freelancer"
                        ),
                        " theme for Jekyll"
                      ]
                    )
                  ]
                )
              ]
            )
          )
        ),
        dom(".footer-below",
          dom(".container",
            dom(".row style='margin-bottom:10px;'", dom(".col-lg-12", 'Powered by ', dom('a href=http://rauchg.com/slackin target=_blank', 'slackin'))),
            dom(".row", dom(".col-lg-12", "Copyright © Lemon Labs Limited 2017"))
          )
        )
        dom('script src="//lemonlabs.io/js/jquery-1.11.0.js"'),
        dom('script src="//lemonlabs.io/js/freelancer.js"')
      ]
    )

    let page = dom('html',
      dom('head',
        dom('title',
          'Join ', name, ' on Slack!'
        ),
        dom('meta name=viewport content="width=device-width,initial-scale=1.0,minimum-scale=1.0,user-scalable=no"'),
        dom('link rel="shortcut icon" href=//lemonlabs.io/img/favicon.ico'),
        css && dom('link rel=stylesheet', { href: css }),
        dom('link rel="stylesheet" href="//lemonlabs.io/css/font-awesome/css/font-awesome.min.css"'),
        dom('link href="//fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet" type="text/css"'),
        dom('link href="//fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic" rel="stylesheet" type="text/css"'),
        dom('link rel="stylesheet" href="//lemonlabs.io/style.css"')
      ),
      nav,
      splash({ coc, path, css, name, org, logo, channels, active, total }),
      footer
    )
    res.type('html')
    res.send(page.toHTML())
  })

  router.get('/data', (req, res) => {
    let { name, logo } = slack.org
    let { active, total } = slack.users
    res.send({
      name,
      org,
      coc,
      logo,
      channels,
      active,
      total
    })
  })

  // static files
  router.use('/assets', express.static(assets))

  // invite endpoint
  router.post('/invite', json(), (req, res, next) => {
    let chanId
    if (channels) {
      let channel = req.body.channel
      if (!channels.includes(channel)) {
        return res
        .status(400)
        .json({ msg: 'Not a permitted channel' })
      }
      chanId = slack.getChannelId(channel)
      if (!chanId) {
        return res
        .status(400)
        .json({ msg: `Channel not found "${channel}"` })
      }
    }

    let email = req.body.email

    if (!email) {
      return res
      .status(400)
      .json({ msg: 'No email provided' })
    }

    if (!remail().test(email)) {
      return res
      .status(400)
      .json({ msg: 'Invalid email' })
    }

    // Restricting email invites?
    if (emails && emails.indexOf(email) === -1) {
      return res
      .status(400)
      .json({ msg: 'Your email is not on the accepted email list' })
    }

    if (coc && '1' != req.body.coc) {
      return res
      .status(400)
      .json({ msg: 'Agreement to CoC is mandatory' })
    }

    invite({ token, org, email, channel: chanId }, err => {
      if (err) {
        if (err.message === `Sending you to Slack...`) {
          return res
          .status(303)
          .json({ msg: err.message, redirectUrl: `https://${org}.slack.com` })
        }

        return res
        .status(400)
        .json({ msg: err.message })
      }

      res
      .status(200)
      .json({ msg: 'WOOT. Check your email!' })
    })
  })

  // iframe
  router.get('/iframe', (req, res) => {
    let large = 'large' in req.query
    let { active, total } = slack.users
    res.type('html')
    res.send(iframe({ path, active, total, large }).toHTML())
  })

  router.get('/iframe/dialog', (req, res) => {
    let large = 'large' in req.query
    let { name } = slack.org
    let { active, total } = slack.users
    if (!name) return res.send(404)
    let dom = splash({ coc, path, name, org, channels, active, total, large, iframe: true })
    res.type('html')
    res.send(dom.toHTML())
  })

  router.get('/.well-known/acme-challenge/:id', (req, res) => {
    res.send(process.env.LETSENCRYPT_CHALLENGE)
  })

  // badge js
  router.use('/slackin.js', express.static(assets + '/badge.js'))

  // badge rendering
  router.get('/badge.svg', (req, res) => {
    res.type('svg')
    res.set('Cache-Control', 'max-age=0, no-cache')
    res.set('Pragma', 'no-cache')
    res.send(badge(slack.users).toHTML())
  })

  // realtime
  sockets(srv, {path: path + 'socket.io'}).on('connection', socket => {
    socket.emit('data', slack.users)
    let change = (key, val) => socket.emit(key, val)
    slack.on('change', change)
    socket.on('disconnect', () => {
      slack.removeListener('change', change)
    })
  })

  app.use(path, router);

  return srv
}
<commit_msg>Missing comma<commit_after>// es6 runtime requirements
import 'babel-polyfill'

// their code
import express from 'express'
import sockets from 'socket.io'
import { json } from 'body-parser'
import { Server as http } from 'http'
import remail from 'email-regex'
import dom from 'vd'
import cors from 'cors'

// our code
import Slack from './slack'
import invite from './slack-invite'
import badge from './badge'
import splash from './splash'
import iframe from './iframe'
import log from './log'

export default function slackin ({
  token,
  interval = 5000, // jshint ignore:line
  org,
  css,
  coc,
  cors: useCors = true,
  path='/',
  channels,
  emails,
  silent = false // jshint ignore:line,
}){
  // must haves
  if (!token) throw new Error('Must provide a `token`.')
  if (!org) throw new Error('Must provide an `org`.')

  if (channels) {
    // convert to an array
    channels = channels.split(',').map((channel) => {
      // sanitize channel name
      if ('#' === channel[0]) return channel.substr(1)
      return channel
    })
  }

  if (emails) {
    // convert to an array
    emails = emails.split(',')
  }

  // setup app
  let app = express()
  let router = express.Router()
  let srv = http(app)
  srv.app = app

  let assets = __dirname + '/assets'

  // fetch data
  let slack = new Slack({ token, interval, org })

  slack.setMaxListeners(Infinity)

  // capture stats
  log(slack, silent)

  // middleware for waiting for slack
  router.use((req, res, next) => {
    if (slack.ready) return next()
    slack.once('ready', next)
  })

  if (useCors) {
    app.options('https://lemonlabs.io', cors())
    app.use(cors())
  }

  // splash page
  router.get('/', (req, res) => {
    let { name, logo } = slack.org
    let { active, total } = slack.users
    if (!name) return res.send(404)

    // Generated using http://arthurclemens.github.io/mithril-template-converter/index.html
    let nav = dom("nav.navbar.navbar-default style='padding: 10px 0;'",
      dom(".container",
        [
          dom(".navbar-header.page-scroll",
            [
              dom("button.navbar-toggle data-target='#bs-example-navbar-collapse-1' data-toggle='collapse' type='button'",
                [
                  dom("span.sr-only",
                    "Toggle navigation"
                  ),
                  dom("span.icon-bar"),
                  dom("span.icon-bar"),
                  dom("span.icon-bar")
                ]
              )
            ]
          ),
          dom(".collapse.navbar-collapse id='bs-example-navbar-collapse-1'",
            dom("ul.nav.navbar-nav.navbar-right",
              [
                dom("li.hidden",
                  dom("a href='#page-top'")
                ),
                dom("li.page-scroll",
                  dom("a href='//lemonlabs.io/#whatwedo'",
                    "What we do"
                  )
                ),
                dom("li.page-scroll",
                  dom("a href='//lemonlabs.io/#team'",
                    "The team"
                  )
                ),
                dom("li.page-scroll",
                  dom("a href='//lemonlabs.io/#contact'",
                    "Contact"
                  )
                )
              ]
            )
          )
        ]
      )
    );

    let footer = dom("footer.text-center",
      [
        dom(".footer-above",
          dom(".container",
            dom(".row",
              [
                dom(".footer-col.col-md-4",
                  [
                    dom("h3", "Lemon Labs Limited"),
                    dom("p", "Fleet, Hampshire")
                  ]
                ),
                dom(".footer-col.col-md-4",
                  [
                    dom("h3",
                      "Around the Web"
                    ),
                    dom("ul.list-inline",
                      [
                        dom("li",
                          dom("a.btn-social.btn-outline href='http://github.com/lemonlabsuk'",
                            dom("i.fa.fa-fw.fa-github")
                          )
                        ),
                        dom("li",
                          dom("a.btn-social.btn-outline href='https://www.linkedin.com/company/lemon-labs-limited'",
                            dom("i.fa.fa-fw.fa-linkedin")
                          )
                        )
                      ]
                    )
                  ]
                ),
                dom(".footer-col.col-md-4",
                  [
                    dom("h3",
                      "Credits"
                    ),
                    dom("p",
                      [
                        "Modified version of the ",
                        dom("a href='https://github.com/jeromelachaud/freelancer-theme/blob/master/LICENCE'",
                          "Apache 2.0"
                        ),
                        " licensed ",
                        dom("a href='https://github.com/jeromelachaud/freelancer-theme/'",
                          "freelancer"
                        ),
                        " theme for Jekyll"
                      ]
                    )
                  ]
                )
              ]
            )
          )
        ),
        dom(".footer-below",
          dom(".container",
            dom(".row style='margin-bottom:10px;'", dom(".col-lg-12", 'Powered by ', dom('a href=http://rauchg.com/slackin target=_blank', 'slackin'))),
            dom(".row", dom(".col-lg-12", "Copyright © Lemon Labs Limited 2017"))
          )
        ),
        dom('script src="//lemonlabs.io/js/jquery-1.11.0.js"'),
        dom('script src="//lemonlabs.io/js/freelancer.js"')
      ]
    )

    let page = dom('html',
      dom('head',
        dom('title',
          'Join ', name, ' on Slack!'
        ),
        dom('meta name=viewport content="width=device-width,initial-scale=1.0,minimum-scale=1.0,user-scalable=no"'),
        dom('link rel="shortcut icon" href=//lemonlabs.io/img/favicon.ico'),
        css && dom('link rel=stylesheet', { href: css }),
        dom('link rel="stylesheet" href="//lemonlabs.io/css/font-awesome/css/font-awesome.min.css"'),
        dom('link href="//fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet" type="text/css"'),
        dom('link href="//fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic" rel="stylesheet" type="text/css"'),
        dom('link rel="stylesheet" href="//lemonlabs.io/style.css"')
      ),
      nav,
      splash({ coc, path, css, name, org, logo, channels, active, total }),
      footer
    )
    res.type('html')
    res.send(page.toHTML())
  })

  router.get('/data', (req, res) => {
    let { name, logo } = slack.org
    let { active, total } = slack.users
    res.send({
      name,
      org,
      coc,
      logo,
      channels,
      active,
      total
    })
  })

  // static files
  router.use('/assets', express.static(assets))

  // invite endpoint
  router.post('/invite', json(), (req, res, next) => {
    let chanId
    if (channels) {
      let channel = req.body.channel
      if (!channels.includes(channel)) {
        return res
        .status(400)
        .json({ msg: 'Not a permitted channel' })
      }
      chanId = slack.getChannelId(channel)
      if (!chanId) {
        return res
        .status(400)
        .json({ msg: `Channel not found "${channel}"` })
      }
    }

    let email = req.body.email

    if (!email) {
      return res
      .status(400)
      .json({ msg: 'No email provided' })
    }

    if (!remail().test(email)) {
      return res
      .status(400)
      .json({ msg: 'Invalid email' })
    }

    // Restricting email invites?
    if (emails && emails.indexOf(email) === -1) {
      return res
      .status(400)
      .json({ msg: 'Your email is not on the accepted email list' })
    }

    if (coc && '1' != req.body.coc) {
      return res
      .status(400)
      .json({ msg: 'Agreement to CoC is mandatory' })
    }

    invite({ token, org, email, channel: chanId }, err => {
      if (err) {
        if (err.message === `Sending you to Slack...`) {
          return res
          .status(303)
          .json({ msg: err.message, redirectUrl: `https://${org}.slack.com` })
        }

        return res
        .status(400)
        .json({ msg: err.message })
      }

      res
      .status(200)
      .json({ msg: 'WOOT. Check your email!' })
    })
  })

  // iframe
  router.get('/iframe', (req, res) => {
    let large = 'large' in req.query
    let { active, total } = slack.users
    res.type('html')
    res.send(iframe({ path, active, total, large }).toHTML())
  })

  router.get('/iframe/dialog', (req, res) => {
    let large = 'large' in req.query
    let { name } = slack.org
    let { active, total } = slack.users
    if (!name) return res.send(404)
    let dom = splash({ coc, path, name, org, channels, active, total, large, iframe: true })
    res.type('html')
    res.send(dom.toHTML())
  })

  router.get('/.well-known/acme-challenge/:id', (req, res) => {
    res.send(process.env.LETSENCRYPT_CHALLENGE)
  })

  // badge js
  router.use('/slackin.js', express.static(assets + '/badge.js'))

  // badge rendering
  router.get('/badge.svg', (req, res) => {
    res.type('svg')
    res.set('Cache-Control', 'max-age=0, no-cache')
    res.set('Pragma', 'no-cache')
    res.send(badge(slack.users).toHTML())
  })

  // realtime
  sockets(srv, {path: path + 'socket.io'}).on('connection', socket => {
    socket.emit('data', slack.users)
    let change = (key, val) => socket.emit(key, val)
    slack.on('change', change)
    socket.on('disconnect', () => {
      slack.removeListener('change', change)
    })
  })

  app.use(path, router);

  return srv
}
<|endoftext|>


<commit_before>const EventEmitter = require('events')
const Listr = require('listr')
const Observable = require('zen-observable')
const npmRun = require('npm-run')
const loader = require('./loader')

function shell (command) {
  return new Promise((resolve, reject) => {
    npmRun(command, {}, (error, stdout, stderr) => {
      if (error) {
        return reject(error)
      }
      resolve({ stdout, stderr })
    })
  })
}

/**
 * @param {object} allTasks    { <task name>: <function|string> }
 * @return {Promise}
 */
function runTasks (allTasks, selectTasksToRun) {
  const emitter = prepareTasks(allTasks)
  const tasks = selectTasksToRun(allTasks)

  const taskCalls = new Observable((observer) => {
    emitter.on('call', (taskName) => observer.next(taskName))
  })

  return createListr(tasks, taskCalls).run()
}

function createListr (tasks, taskCalls) {
  const taskList = Object.keys(tasks).map((taskName) =>
    ({
      title: taskName,
      task: () => new Observable((observer) => {
        // inform Listr when another task is run
        taskCalls
          .filter((calledTaskName) => calledTaskName !== taskName)
          .subscribe(observer)

        // run the initial task, map the task's promise to the observer so Listr is synced
        runTask(tasks[ taskName ], taskName)
          .then(() => observer.complete())
          .catch((error) => observer.error(error))
      })
    })
  )

  return new Listr(taskList)
}

function prepareTasks (tasks) {
  const emitter = new EventEmitter()
  observeFunctionTasks(tasks, emitter)
  resolveAndObserveStringTasks(tasks, emitter)
  return emitter
}

function observeFunctionTasks (tasks, emitter) {
  Object.keys(tasks)
    .filter((taskName) => typeof tasks[ taskName ] === 'function' && !taskName.match(/^__/))
    .forEach((taskName) => {
      const origMethod = tasks[ taskName ]

      tasks.__Rewire__(taskName, () => {
        emitter.emit('call', taskName)
        return origMethod.apply(null, arguments)
      })
    })
}

function resolveAndObserveStringTasks (tasks, emitter) {
  Object.keys(tasks)
    .filter((taskName) => typeof tasks[ taskName ] === 'string')
    .forEach((taskName) => {
      const command = tasks[ taskName ]
      tasks[ taskName ] = () => {
        emitter.emit('call', taskName)
        return shell(command)
      }
    })
}

/**
 * @param {function|string} task
 * @param {string} taskName
 * @return {Promise}
 */
function runTask (task, taskName) {
  if (typeof task === 'function') {
    return task()
  } else {
    // All string tasks have been resolved to `shell()` calls by resolveAndObserveStringTasks() at this point
    throw new Error(`Task must be function or string. Invalid task given: ${taskName} (type is ${typeof task})`)
  }
}

exports.shell = shell
exports.runTasks = runTasks
exports.loadTasksFromFile = loader.loadTasksFromFile
<commit_msg>Very minor code change<commit_after>const EventEmitter = require('events')
const Listr = require('listr')
const Observable = require('zen-observable')
const npmRun = require('npm-run')
const loader = require('./loader')

function shell (command) {
  return new Promise((resolve, reject) => {
    npmRun(command, {}, (error, stdout, stderr) => {
      if (error) {
        return reject(error)
      }
      resolve({ stdout, stderr })
    })
  })
}

/**
 * @param {object} allTasks    { <task name>: <function|string> }
 * @return {Promise}
 */
function runTasks (allTasks, selectTasksToRun) {
  const emitter = prepareTasks(allTasks)
  const tasks = selectTasksToRun(allTasks)

  const taskCalls = new Observable((observer) => {
    emitter.on('call', (taskName) => observer.next(taskName))
  })

  return createListr(tasks, taskCalls).run()
}

function prepareTasks (tasks) {
  const emitter = new EventEmitter()
  observeFunctionTasks(tasks, emitter)
  resolveAndObserveStringTasks(tasks, emitter)
  return emitter
}

function observeFunctionTasks (tasks, emitter) {
  if (!tasks.__Rewire__) { return }

  Object.keys(tasks)
    .filter((taskName) => typeof tasks[ taskName ] === 'function' && !taskName.match(/^__/))
    .forEach((taskName) => {
      const origMethod = tasks[ taskName ]

      tasks.__Rewire__(taskName, () => {
        emitter.emit('call', taskName)
        return origMethod.apply(null, arguments)
      })
    })
}

function resolveAndObserveStringTasks (tasks, emitter) {
  Object.keys(tasks)
    .filter((taskName) => typeof tasks[ taskName ] === 'string')
    .forEach((taskName) => {
      const command = tasks[ taskName ]
      tasks[ taskName ] = () => {
        emitter.emit('call', taskName)
        return shell(command)
      }
    })
}

function createListr (tasks, taskCalls) {
  const taskList = Object.keys(tasks).map((taskName) =>
    ({
      title: taskName,
      task: () => new Observable((observer) => {
        // inform Listr when another task is run
        taskCalls
          .filter((calledTaskName) => calledTaskName !== taskName)
          .subscribe(observer)

        // run the initial task, map the task's promise to the observer so Listr is synced
        runTask(tasks[ taskName ], taskName)
          .then(() => observer.complete())
          .catch((error) => observer.error(error))
      })
    })
  )

  return new Listr(taskList)
}

/**
 * @param {function|string} task
 * @param {string} taskName
 * @return {Promise}
 */
function runTask (task, taskName) {
  if (typeof task === 'function') {
    return task()
  } else {
    // All string tasks have been resolved to `shell()` calls by resolveAndObserveStringTasks() at this point
    throw new Error(`Task must be function or string. Invalid task given: ${taskName} (type is ${typeof task})`)
  }
}

exports.shell = shell
exports.runTasks = runTasks
exports.loadTasksFromFile = loader.loadTasksFromFile
<|endoftext|>


<commit_before>"use strict";

let constant = require("./constant.js"),
    exec     = require("./exec.js"),
    fs       = require("fs"),
    helper   = require("./helper.js"),
    path     = require("path");

const Bipbip = function(path, env) {
	if (exec.local("which rsync") == "rsync:\n") {
		helper.log("Missing rsync", "red");
		process.exit(1);
	}

	if (exec.local("which git") == "git:\n") {
		helper.log("Missing git", "red");
		process.exit(1);
	}

	// Prepare current configuration
	let fileConfig = require(path).config,
		envConfig = helper.merge(constant.default, fileConfig.default, fileConfig[env]),
		kill = function(message) {
			helper.log(message, "red");
			process.exit(1);
		};

	if (envConfig.servers === undefined) {
		kill("servers is required.");
	} else if (Array.isArray(envConfig.servers) === false) {
		kill("servers must be an array");
	}

	for (let i = envConfig.servers.length - 1; i >= 0; i--) {
		let server = envConfig.servers[i];

		if (server.user === undefined || typeof server.user != "string") {
			kill("servers." + i.toString() + ".user must be a string");
		} else if (server.host === undefined || typeof server.host != "string") {
			kill("servers." + i.toString() + ".host must be a string");
		} else if (server.to === undefined || typeof server.to != "string") {
			kill("servers." + i.toString() + ".to must be a string");
		}
	}

	if (typeof envConfig.repository === "object" && envConfig.repository !== null && envConfig.repository.url !== null && (envConfig.repository.branch === null && envConfig.repository.tag === null)) {
		kill("repository.branch or repository.tag is required.");
	}

	this.config = envConfig;
	this.internal = {
		release: exec.local('date +"%Y%d%m%H%M%S"').split("\n")[0]
	};
	this.file = path;
};

Bipbip.prototype.run = function() {
	if (this.config.repository !== null && this.config.repository.url !== null) {
		this.init();
	} else {
		this.config.workspace = path.dirname(this.file);
	}

	this.local();
	this.send();
	this.shared();
	this.remote();
	this.deploy();
	this.postDeploy();
	this.clean();
};

Bipbip.prototype.init = function() {
	if (fs.existsSync(this.config.workspace) === true) {
		try {
			exec.local("git rev-parse --git-dir", {
				cwd: this.config.workspace,
			});
		} catch (err) {
			fs.rmdirSync(this.config.workspace);
		}

		exec.local([
			"git reset --hard",
			"git fetch --all",
			"git fetch --tags"
		].join(" && "), {
			cwd: this.config.workspace,
		});

		if (this.config.repository.branch !== null) {
			exec.local(
				"git remote set-branches --add origin " + this.config.repository.branch, {
					cwd: this.config.workspace,
				});

			exec.local(
				"[ -n \"`git show-ref refs/heads/" + this.config.repository.branch + "`\" ] && git checkout -q " + this.config.repository.branch + " || git checkout -b " + this.config.repository.branch + " origin/" + this.config.repository.branch, {
				cwd: this.config.workspace,
			});

			exec.local(
				"git pull origin " + this.config.repository.branch, {
				cwd: this.config.workspace,
			});
		} else if (this.config.repository.tag !== null)  {
			exec.local(
				"git checkout -q refs/tags/" + this.config.repository.tag, {
				cwd: this.config.workspace,
			});

			exec.local(
				"git pull origin " + this.config.repository.tag, {
				cwd: this.config.workspace,
			});
		}
	} else {
		let gitOption = "";
		if (this.config.repository.options.submodules === true) {
			gitOption += " --recursive";
		}

		exec.local("git clone -b " + this.config.repository.branch + " " + this.config.repository.url + " --depth=1 " + this.config.workspace + gitOption);
	}
};

Bipbip.prototype.local = function() {
	if (this.config.commands.local.length > 0) {
		for (let i = 0; i < this.config.commands.local.length; i++) {
		    exec.local(this.config.commands.local[i], {
		    	cwd: this.config.workspace,
		    });
		}
	}
};

Bipbip.prototype.send = function() {
	let _ = function(server) {
		let remotePath = server.to + "/releases/" + this.internal.release;
		let lastRelease = this._execRemote(server, "ls -1t " + server.to + "/releases | head -n 1");

		this._execRemote(server, "mkdir -p " + server.to + "/releases");

		this._execRemote(
			server,
			helper.mkdir(
				server.to + "/shared"
				));

		if (lastRelease !== "") {
			let mkdirRemotePath = [
				"cp -R " + server.to + "/releases/" + lastRelease,
				remotePath
				].join(" ");

			this._execRemote(server, mkdirRemotePath);
		}

		let cmd = [
			"rsync",
			"-az",
			"--delete",
			this.config.ignores.map(function (item) {
				return "--exclude=" + item;
			}).join(" "),
			this.config.shared.files.map(function (item) {
				return "--exclude=" + item;
			}).join(" "),
			this.config.shared.folders.map(function (item) {
				return "--exclude=" + item;
			}).join(" "),
			this.config.workspace + "/",
			[
				[
					server.user, server.host].join("@"),
					remotePath
				].join(":")
			].join(" ");

		exec.local(cmd);
	};

	for (var i = this.config.servers.length - 1; i >= 0; i--) {
		_(this.config.servers[i]);
	}
};

Bipbip.prototype.shared = function() {
	let _ = function(server) {
		for (let i = this.config.shared.folders.length - 1; i >= 0; i--) {
			this._execRemote(
				server,
				helper.mkdir(
					server.to + "/shared/" + this.config.shared.folders[i]
					)
				);

			this._execRemote(
				server,
				helper.ln(
					server.to + "/shared/" + this.config.shared.folders[i],
					server.to + "/releases/" + this.internal.release + "/" + this.config.shared.folders[i]
					)
				);
		}

		for (let i = this.config.shared.files.length - 1; i >= 0; i--) {
			let folder = this.config.shared.files[i].substr(
				0,
				this.config.shared.files[i].lastIndexOf("/")
				);

			let file = this.config.shared.files[i].substr(
				this.config.shared.files[i].lastIndexOf("/")
				);

			this._execRemote(
				server,
				helper.mkdir(
					server.to + "/shared/" + folder
					)
				);

			if (file != "/") {
				this._execRemote(
					server,
					helper.touch(
						server.to + "/shared/" + folder + file
						)
					);

				this._execRemote(
					server,
					helper.ln(
						server.to + "/shared/" + this.config.shared.files[i],
						server.to + "/releases/" + this.internal.release + "/" + this.config.shared.files[i]
						)
					);
			} else {
				this._execRemote(
					server,
					helper.ln(
						server.to + "/shared/" + folder,
						server.to + "/releases/" + this.internal.release + "/" + folder
						)
					);
			}
		};
	};

	for (var i = servers.length - 1; i >= 0; i--) {
		_(servers[i]);
	}
};

Bipbip.prototype.remote = function() {
	let _ = function(server) {
		if (this.config.commands.remote.length > 0) {
			for (let i = 0; i < this.config.commands.remote.length; i++) {
			    this._execRemote(
			    	server,
			    	"cd " + server.to + "/releases/" + this.internal.release + " && " + this.config.commands.remote[i]
			    	);
			}
		}
	};

	for (var i = this.config.servers.length - 1; i >= 0; i--) {
		_(this.config.servers[i]);
	}
};

Bipbip.prototype.deploy = function() {
	let _ = function(server) {
		this._execRemote("rm -f " + server.to + "/current && ln -s " + server.to + "/releases/" + this.internal.release + " " + server.to + "/current");
	};

	for (var i = this.config.servers.length - 1; i >= 0; i--) {
		_(this.config.servers[i]);
	}
};

Bipbip.prototype.postDeploy = function() {
	let _ = function(server) {
		if (this.config.commands.postDeploy.length > 0) {
			for (let i = 0; i < this.config.commands.postDeploy.length; i++) {
			    this._execRemote("cd " + server.to + "/releases/" + this.internal.release + " && " + this.config.commands.postDeploy[i]);
			}
		}
	};

	for (var i = this.config.servers.length - 1; i >= 0; i--) {
		_(this.config.servers[i]);
	}
};

Bipbip.prototype.clean = function() {
	let _ = function(server) {
		this._execRemote("ls -1dt " + server.to + "/releases/* | tail -n +" + (this.config.releases + 1).toString() + " | xargs rm -rf");
	};

	for (var i = this.config.servers.length - 1; i >= 0; i--) {
		_(this.config.servers[i]);
	}
};

Bipbip.prototype._execRemote = function(server, command, escape) {
	return exec.remote(server, command, escape);
};

module.exports = Bipbip;
<commit_msg>[WIP] defined _this in local scope to use this into lambda function<commit_after>"use strict";

let constant = require("./constant.js"),
    exec     = require("./exec.js"),
    fs       = require("fs"),
    helper   = require("./helper.js"),
    path     = require("path");

const Bipbip = function(path, env) {
	if (exec.local("which rsync") == "rsync:\n") {
		helper.log("Missing rsync", "red");
		process.exit(1);
	}

	if (exec.local("which git") == "git:\n") {
		helper.log("Missing git", "red");
		process.exit(1);
	}

	// Prepare current configuration
	let fileConfig = require(path).config,
		envConfig = helper.merge(constant.default, fileConfig.default, fileConfig[env]),
		kill = function(message) {
			helper.log(message, "red");
			process.exit(1);
		};

	if (envConfig.servers === undefined) {
		kill("servers is required.");
	} else if (Array.isArray(envConfig.servers) === false) {
		kill("servers must be an array");
	}

	for (let i = envConfig.servers.length - 1; i >= 0; i--) {
		let server = envConfig.servers[i];

		if (server.user === undefined || typeof server.user != "string") {
			kill("servers." + i.toString() + ".user must be a string");
		} else if (server.host === undefined || typeof server.host != "string") {
			kill("servers." + i.toString() + ".host must be a string");
		} else if (server.to === undefined || typeof server.to != "string") {
			kill("servers." + i.toString() + ".to must be a string");
		}
	}

	if (typeof envConfig.repository === "object" && envConfig.repository !== null && envConfig.repository.url !== null && (envConfig.repository.branch === null && envConfig.repository.tag === null)) {
		kill("repository.branch or repository.tag is required.");
	}

	this.config = envConfig;
	this.internal = {
		release: exec.local('date +"%Y%d%m%H%M%S"').split("\n")[0]
	};
	this.file = path;
};

Bipbip.prototype.run = function() {
	if (this.config.repository !== null && this.config.repository.url !== null) {
		this.init();
	} else {
		this.config.workspace = path.dirname(this.file);
	}

	this.local();
	this.send();
	this.shared();
	this.remote();
	this.deploy();
	this.postDeploy();
	this.clean();
};

Bipbip.prototype.init = function() {
	if (fs.existsSync(this.config.workspace) === true) {
		try {
			exec.local("git rev-parse --git-dir", {
				cwd: this.config.workspace,
			});
		} catch (err) {
			fs.rmdirSync(this.config.workspace);
		}

		exec.local([
			"git reset --hard",
			"git fetch --all",
			"git fetch --tags"
		].join(" && "), {
			cwd: this.config.workspace,
		});

		if (this.config.repository.branch !== null) {
			exec.local(
				"git remote set-branches --add origin " + this.config.repository.branch, {
					cwd: this.config.workspace,
				});

			exec.local(
				"[ -n \"`git show-ref refs/heads/" + this.config.repository.branch + "`\" ] && git checkout -q " + this.config.repository.branch + " || git checkout -b " + this.config.repository.branch + " origin/" + this.config.repository.branch, {
				cwd: this.config.workspace,
			});

			exec.local(
				"git pull origin " + this.config.repository.branch, {
				cwd: this.config.workspace,
			});
		} else if (this.config.repository.tag !== null)  {
			exec.local(
				"git checkout -q refs/tags/" + this.config.repository.tag, {
				cwd: this.config.workspace,
			});

			exec.local(
				"git pull origin " + this.config.repository.tag, {
				cwd: this.config.workspace,
			});
		}
	} else {
		let gitOption = "";
		if (this.config.repository.options.submodules === true) {
			gitOption += " --recursive";
		}

		exec.local("git clone -b " + this.config.repository.branch + " " + this.config.repository.url + " --depth=1 " + this.config.workspace + gitOption);
	}
};

Bipbip.prototype.local = function() {
	if (this.config.commands.local.length > 0) {
		for (let i = 0; i < this.config.commands.local.length; i++) {
		    exec.local(this.config.commands.local[i], {
		    	cwd: this.config.workspace,
		    });
		}
	}
};

Bipbip.prototype.send = function() {
	let _this = this;

	let _ = function(server) {
		let remotePath = server.to + "/releases/" + _this.internal.release;
		let lastRelease = _this._execRemote(server, "ls -1t " + server.to + "/releases | head -n 1");

		_this._execRemote(server, "mkdir -p " + server.to + "/releases");

		_this._execRemote(
			server,
			helper.mkdir(
				server.to + "/shared"
				));

		if (lastRelease !== "") {
			let mkdirRemotePath = [
				"cp -R " + server.to + "/releases/" + lastRelease,
				remotePath
				].join(" ");

			_this._execRemote(server, mkdirRemotePath);
		}

		let cmd = [
			"rsync",
			"-az",
			"--delete",
			_this.config.ignores.map(function (item) {
				return "--exclude=" + item;
			}).join(" "),
			_this.config.shared.files.map(function (item) {
				return "--exclude=" + item;
			}).join(" "),
			_this.config.shared.folders.map(function (item) {
				return "--exclude=" + item;
			}).join(" "),
			_this.config.workspace + "/",
			[
				[
					server.user, server.host].join("@"),
					remotePath
				].join(":")
			].join(" ");

		exec.local(cmd);
	};

	for (var i = this.config.servers.length - 1; i >= 0; i--) {
		_(this.config.servers[i]);
	}
};

Bipbip.prototype.shared = function() {
	let _this = this;

	let _ = function(server) {
		for (let i = _this.config.shared.folders.length - 1; i >= 0; i--) {
			_this._execRemote(
				server,
				helper.mkdir(
					server.to + "/shared/" + _this.config.shared.folders[i]
					)
				);

			_this._execRemote(
				server,
				helper.ln(
					server.to + "/shared/" + _this.config.shared.folders[i],
					server.to + "/releases/" + _this.internal.release + "/" + _this.config.shared.folders[i]
					)
				);
		}

		for (let i = _this.config.shared.files.length - 1; i >= 0; i--) {
			let folder = _this.config.shared.files[i].substr(
				0,
				_this.config.shared.files[i].lastIndexOf("/")
				);

			let file = _this.config.shared.files[i].substr(
				_this.config.shared.files[i].lastIndexOf("/")
				);

			_this._execRemote(
				server,
				helper.mkdir(
					server.to + "/shared/" + folder
					)
				);

			if (file != "/") {
				_this._execRemote(
					server,
					helper.touch(
						server.to + "/shared/" + folder + file
						)
					);

				_this._execRemote(
					server,
					helper.ln(
						server.to + "/shared/" + _this.config.shared.files[i],
						server.to + "/releases/" + _this.internal.release + "/" + _this.config.shared.files[i]
						)
					);
			} else {
				_this._execRemote(
					server,
					helper.ln(
						server.to + "/shared/" + folder,
						server.to + "/releases/" + _this.internal.release + "/" + folder
						)
					);
			}
		};
	};

	for (var i = servers.length - 1; i >= 0; i--) {
		_(servers[i]);
	}
};

Bipbip.prototype.remote = function() {
	let _this = this;

	let _ = function(server) {
		if (_this.config.commands.remote.length > 0) {
			for (let i = 0; i < _this.config.commands.remote.length; i++) {
			    _this._execRemote(
			    	server,
			    	"cd " + server.to + "/releases/" + _this.internal.release + " && " + _this.config.commands.remote[i]
			    	);
			}
		}
	};

	for (var i = this.config.servers.length - 1; i >= 0; i--) {
		_(this.config.servers[i]);
	}
};

Bipbip.prototype.deploy = function() {
	let _this = this;

	let _ = function(server) {
		_this._execRemote("rm -f " + server.to + "/current && ln -s " + server.to + "/releases/" + _this.internal.release + " " + server.to + "/current");
	};

	for (var i = this.config.servers.length - 1; i >= 0; i--) {
		_(this.config.servers[i]);
	}
};

Bipbip.prototype.postDeploy = function() {
	let _this = this;

	let _ = function(server) {
		if (_this.config.commands.postDeploy.length > 0) {
			for (let i = 0; i < _this.config.commands.postDeploy.length; i++) {
			    _this._execRemote("cd " + server.to + "/releases/" + _this.internal.release + " && " + _this.config.commands.postDeploy[i]);
			}
		}
	};

	for (var i = this.config.servers.length - 1; i >= 0; i--) {
		_(this.config.servers[i]);
	}
};

Bipbip.prototype.clean = function() {
	let _this = this;

	let _ = function(server) {
		_this._execRemote("ls -1dt " + server.to + "/releases/* | tail -n +" + (_this.config.releases + 1).toString() + " | xargs rm -rf");
	};

	for (var i = this.config.servers.length - 1; i >= 0; i--) {
		_(this.config.servers[i]);
	}
};

Bipbip.prototype._execRemote = function(server, command, escape) {
	return exec.remote(server, command, escape);
};

module.exports = Bipbip;
<|endoftext|>


<commit_before>var constants = require('./constants'),
    Client = require('./client');

var gists = document.getElementsByClassName('gist-file');

// If there is no gists on the page, there is no point
// to do anything.
if (gists.length <= 0) return;

var client = new Client(constants.runnerURL, gists);

client.load(gists);
client.connect();<commit_msg>remove useless parameter in client init<commit_after>var constants = require('./constants'),
    Client = require('./client');

var gists = document.getElementsByClassName('gist-file');

// If there is no gists on the page, there is no point
// to do anything.
if (gists.length <= 0) return;

var client = new Client(constants.runnerURL);

client.load(gists);
client.connect();
<|endoftext|>


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

'use strict'

//
// Use in CLI:
//
//   Type "riot" for help.
//
// Use in Node:
//
//   var riot = require('riot/compiler')
//   riot.make({ from: 'foo', to: 'bar', compact: true })
//   riot.watch({ from: 'foo.tag', to: 'bar.js' })
//

// Include the available tasks
const
  Check       = require('./tasks/Check'),
  New         = require('./tasks/New'),
  Make        = require('./tasks/Make'),
  Watch       = require('./tasks/Watch'),
  helpers     = require('./helpers'),
  options     = require('./options'),
  path        = require('path'),
  chalk       = require('chalk'),
  co          = require('co'),
  optionator  = require('optionator')(options),
  API         =
  {
    help() {
      var h = optionator.generateHelp()
      helpers.log(h)
      return Promise.resolve(h)
    },
    version() {
      var v = helpers.getVersion()
      helpers.log(v)
      return Promise.resolve(v)
    },
    new(opt) { return new New(opt) },
    check(opt) { return new Check(opt) },
    make(opt) { return new Make(opt) },
    watch(opt) { return new Watch(opt) }
  }

/* istanbul ignore next */
const cli = co.wrap(function*(ar) {
  // Get CLI arguments
  let args, config

  // was an error thrown parsing the options?
  try {
    args = optionator.parse(
      ar ? ['node', path.resolve('lib')].concat(ar) : process.argv,
      options
    )
    config = args.config ? yield helpers.loadConfigFile(args.config) : {}
  } catch (e) {
    helpers.err(e)
    return e
  }

  // avoid unhandled rejections
  process.on('unhandledRejection', r => {throw r})

  // Translate args into options hash
  // extending args with the options loaded via config file
  helpers.extend(args, config)
  const opt = {
    compiler: {
      compact: args.compact,
      template: args.template, // html preprocessor
      style: args.style, // css preprocessor
      type: args.type, // javascript preprocessor
      brackets: args.brackets,
      entities: !!args.export,
      exclude: args.exclude,
      sourcemap: args.sourcemap ? 'inline' : false,
      expr: args.expr,
      modular: args.modular,
      silent: !!args.stdout || args.silent,
      whitespace: args.whitespace
    },
    ext: args.ext,
    css: args.css,
    new: args.new,
    export: args.export,
    colors: args.colors,
    parsers: args.parsers, // to extend the default compiler parsers
    from: args.from || !args.stdin && args._.shift(),
    to: args.to || !args.stdout && args._.shift(),
    stdin: !!args.stdin,
    stdout: !!args.stdout
  }

  // Call matching method
  const method =
    Object.keys(API).filter(v => args[v])[0] ||
    (opt.from || opt.stdin ? 'make' : 'help')

  // check whether the output should be colorized
  chalk.constructor({ enabled: !!opt.colors })

  // create isSilent as global variable
  global.isSilent = args.silent

  // flag used to detect wheter a task is triggered via command line or not
  opt.isCli = true

  return API[method](opt)
})

// this could be handy to someone who wants to have
// also access to the private cli parser function
API._cli = cli

// Run from CLI or as Node module
if (module.parent) {
  module.exports = API
/* istanbul ignore next */
} else cli()
<commit_msg>added: the esm option<commit_after>#!/usr/bin/env node

'use strict'

//
// Use in CLI:
//
//   Type "riot" for help.
//
// Use in Node:
//
//   var riot = require('riot/compiler')
//   riot.make({ from: 'foo', to: 'bar', compact: true })
//   riot.watch({ from: 'foo.tag', to: 'bar.js' })
//

// Include the available tasks
const
  Check       = require('./tasks/Check'),
  New         = require('./tasks/New'),
  Make        = require('./tasks/Make'),
  Watch       = require('./tasks/Watch'),
  helpers     = require('./helpers'),
  options     = require('./options'),
  path        = require('path'),
  chalk       = require('chalk'),
  co          = require('co'),
  optionator  = require('optionator')(options),
  API         =
  {
    help() {
      var h = optionator.generateHelp()
      helpers.log(h)
      return Promise.resolve(h)
    },
    version() {
      var v = helpers.getVersion()
      helpers.log(v)
      return Promise.resolve(v)
    },
    new(opt) { return new New(opt) },
    check(opt) { return new Check(opt) },
    make(opt) { return new Make(opt) },
    watch(opt) { return new Watch(opt) }
  }

/* istanbul ignore next */
const cli = co.wrap(function*(ar) {
  // Get CLI arguments
  let args, config

  // was an error thrown parsing the options?
  try {
    args = optionator.parse(
      ar ? ['node', path.resolve('lib')].concat(ar) : process.argv,
      options
    )
    config = args.config ? yield helpers.loadConfigFile(args.config) : {}
  } catch (e) {
    helpers.err(e)
    return e
  }

  // avoid unhandled rejections
  process.on('unhandledRejection', r => {throw r})

  // Translate args into options hash
  // extending args with the options loaded via config file
  helpers.extend(args, config)
  const opt = {
    compiler: {
      compact: args.compact,
      template: args.template, // html preprocessor
      style: args.style, // css preprocessor
      type: args.type, // javascript preprocessor
      brackets: args.brackets,
      entities: !!args.export,
      exclude: args.exclude,
      sourcemap: args.sourcemap ? 'inline' : false,
      expr: args.expr,
      modular: args.modular,
      esm: args.esm,
      silent: !!args.stdout || args.silent,
      whitespace: args.whitespace
    },
    ext: args.ext,
    css: args.css,
    new: args.new,
    export: args.export,
    colors: args.colors,
    parsers: args.parsers, // to extend the default compiler parsers
    from: args.from || !args.stdin && args._.shift(),
    to: args.to || !args.stdout && args._.shift(),
    stdin: !!args.stdin,
    stdout: !!args.stdout
  }

  // Call matching method
  const method =
    Object.keys(API).filter(v => args[v])[0] ||
    (opt.from || opt.stdin ? 'make' : 'help')

  // check whether the output should be colorized
  chalk.constructor({ enabled: !!opt.colors })

  // create isSilent as global variable
  global.isSilent = args.silent

  // flag used to detect wheter a task is triggered via command line or not
  opt.isCli = true

  return API[method](opt)
})

// this could be handy to someone who wants to have
// also access to the private cli parser function
API._cli = cli

// Run from CLI or as Node module
if (module.parent) {
  module.exports = API
/* istanbul ignore next */
} else cli()
<|endoftext|>


<commit_before>'use strict';

module.exports = function (pkg = {}) {
    const LF = '\n';

    const get = require('lodash.get');
    const stripIndents = require('common-tags').stripIndents;

    function codeFence(infoString = '') {
        return `${'`'.repeat(3)}${infoString}`;
    }

    function fencedCodeBlock(code, infoString = '') {
        return [
            codeFence(infoString),
            code,
            codeFence()
        ].join(LF);
    }

    function fencedShCodeBlock(code) {
        return fencedCodeBlock(`$ ${code}`, 'sh');
    }

    function h1(text) {
        return `${text}${LF}${'='.repeat(text.length)}`;
    }

    function h2(text) {
        return `${text}${LF}${'-'.repeat(text.length)}`;
    }

    let sections = [];

    // Header
    sections.push(stripIndents`
        ${h1(get(pkg, 'name', '<package name>'))}
        ${get(pkg, 'description', '_To be documented._')}
    `);

    // Usage
    sections.push(stripIndents`
        ${h2('Usage')}
        _To be documented._
    `);

    // Testing
    let testing = get(pkg, 'scripts.test') ? fencedShCodeBlock('npm test')
                                           : '_To be documented._';

    sections.push(stripIndents`
        ${h2('Testing')}
        ${testing}
    `);

    // License
    sections.push(stripIndents`
        ${h2('License')}
        ${get(pkg, 'license', '_To be documented._')}
    `);

    return sections.join(`${LF}${LF}`);
};
<commit_msg>Adding JSDoc comments.<commit_after>'use strict';

module.exports = function (pkg = {}) {
    const LF = '\n';

    const get = require('lodash.get');
    const stripIndents = require('common-tags').stripIndents;

    /**
     * @see http://spec.commonmark.org/0.27/#code-fence
     * @see http://spec.commonmark.org/0.27/#info-strings
     */
    function codeFence(infoString = '') {
        return `${'`'.repeat(3)}${infoString}`;
    }

    /**
     * @see http://spec.commonmark.org/0.27/#fenced-code-blocks
     * @see http://spec.commonmark.org/0.27/#info-string
     */
    function fencedCodeBlock(code, infoString = '') {
        return [
            codeFence(infoString),
            code,
            codeFence()
        ].join(LF);
    }

    /**
     * @see fencedCodeBlock
     */
    function fencedShCodeBlock(code) {
        return fencedCodeBlock(`$ ${code}`, 'sh');
    }

    /**
     * @see http://spec.commonmark.org/0.27/#setext-headings
     */
    function h1(text) {
        return `${text}${LF}${'='.repeat(text.length)}`;
    }

    /**
     * @see http://spec.commonmark.org/0.27/#setext-headings
     */
    function h2(text) {
        return `${text}${LF}${'-'.repeat(text.length)}`;
    }

    let sections = [];

    // Header
    sections.push(stripIndents`
        ${h1(get(pkg, 'name', '<package name>'))}
        ${get(pkg, 'description', '_To be documented._')}
    `);

    // Usage
    sections.push(stripIndents`
        ${h2('Usage')}
        _To be documented._
    `);

    // Testing
    let testing = get(pkg, 'scripts.test') ? fencedShCodeBlock('npm test')
                                           : '_To be documented._';

    sections.push(stripIndents`
        ${h2('Testing')}
        ${testing}
    `);

    // License
    sections.push(stripIndents`
        ${h2('License')}
        ${get(pkg, 'license', '_To be documented._')}
    `);

    return sections.join(`${LF}${LF}`);
};
<|endoftext|>


<commit_before>var express = require('express');
var url = require('url');
var net = require('net');
var path = require('path');
var fs = require('fs');
var EventEmitter = require('events').EventEmitter;
var exnted = require('util')._extend;
var util = require('../util');
var rules = require('./rules');
var https = require('./https');
var cert = require('./https/cert');
var rulesUtil = require('./rules/util');
var connect = require('./proxy/connect');
var config = require('../package.json');

function tunnelProxy(server, proxy) {

	server.on('connect', function(req, reqSocket, head) {//ws, wss, https proxy
		var tunnelUrl = req.url = util.setProtocol(req.url, true);
		var options = parseUrl();
		var resSocket, proxySocket;

		if (rulesUtil.intercepts(options.hostname)) {
			sendEstablished();
			https.dispatch(reqSocket, proxy, options.hostname);
			return;
		}

		abortIfUnavailable(reqSocket);
		function emitError(err) {
			resSocket && resSocket.destroy();
			proxySocket && proxySocket.destroy();
			reqSocket.destroy();
		}

		function abortIfUnavailable(socket) {
			socket.on('error', emitError).on('close', emitError);
		}

		function parseUrl(_tunnelUrl, port) {
			_tunnelUrl = _tunnelUrl || tunnelUrl;
			options = req.options = url.parse(_tunnelUrl);
			options.port = options.port || port || 443;
			return options;
		}

		function sendEstablished() {
			reqSocket.write('HTTP/1.1 200 Connection Established\r\nProxy-Agent: ' + config.name + '\r\n\r\n');
			return reqSocket;
		}

		function tunnel(url) {
			var now = Date.now();
			rules.resolveHost(url || tunnelUrl, function(err, ip) {
				req.host = ip;
				req.clientHost  = reqSocket.remoteAddress;
				req.error = err;
				req.dnsTime = Date.now() - now;
				proxy.emit('tunnel', req);

				if (err) {
					emitError(err);
					return;
				}

				resSocket = net.connect(options.port, ip, function() {
					sendEstablished();
		            resSocket.pipe(reqSocket).pipe(resSocket);
		        });
				abortIfUnavailable(resSocket);
			});
		}

		var _rules = req.rules = rules.resolveRules(tunnelUrl);
		var proxyUrl = util.rule.getMatcher(_rules.proxy);

		if (proxyUrl) {
			var _tunnelUrl = 'https:' + util.removeProtocol(proxyUrl);
			var now = Date.now();
			rules.resolveHost(_tunnelUrl, function(err, ip) {
				req.host = ip;
				req.error = err;
				req.dnsTime = Date.now() - now;
				parseUrl(_tunnelUrl, config.port);
				if (!err && util.isLocalAddress(ip) && options.port == config.port) {
					parseUrl();
					return tunnel();
				}
				proxy.emit('tunnelProxy', req);
				if (err) {
					emitError(err);
					return;
				}
				options.host = ip;
				connect(req, function(err, _proxySocket) {
					if (err) {
						return emitError();
					}
					proxySocket = _proxySocket;
					abortIfUnavailable(_proxySocket);
					sendEstablished().pipe(_proxySocket).pipe(reqSocket);
				});
			});
		} else {
			if (_rules.rule) {
				var _url = util.setProtocol(util.rule.getMatcher(_rules.rule), true);
				if (/^https:/i.test(_url)) {
					parseUrl(_url);
				} else {
					var port = util.getProtocol(_url);
					port = port.substring(0, port.length - 1);
					var localProtocol = port + 'sslport';
					if (port = config[localProtocol]) {
						proxy.emit(localProtocol, _url, tunnelUrl);
						parseUrl(_url);
						options.protocol = 'https:';
						options.hostname = '127.0.0.1';
						options.host = options.hostname + ':' + port;
						options.port = port;
						_url = 'ssl://' + options.host; //不解析_url的ip
					} else {
						_url = null;//如果规则无法处理，则直接访问
					}
				}
			}

			tunnel(_url);
		}
    });

	return server;
}

function preventThrowError(socket) {
	socket.removeListener('error', util.noop);
	socket.on('error', util.noop);
}

function proxy(conf) {
	if (conf) {
		['port', 'sockets', 'days', 'timeout',
		 'username', 'password', 'uipath', 'rules', 'debug']
			.forEach(function(name) {
				if (conf[name]) {
					config[name] = conf[name];
				}
			});

		if (Array.isArray(conf.ports)) {
			config.ports = config.ports.concat(conf.ports);
		}
	}

	if (!conf || typeof conf.middlewares != 'string') {
		if (!Array.isArray(conf.middlewares)) {
			config.middlewares = [];
		}
	} else {
		config.middlewares = conf.middlewares.trim().split(/\s*,\s*/g);
	}

	config.middlewares.map(util.resolvePath);

	var port = config.port;
	config.ports.forEach(function(name) {
		if (!/port$/.test(name) || name == 'port') {
			throw new Error('port name "' + name + '" must be end of "port", but not equals "port", like: ' + name + 'port');
		}
		config[name] = ++port;
	});

	var agentConfig = {
				maxSockets: config.sockets,
				keepAlive: config.keepAlive,
				keepAliveMsecs: config.keepAliveMsecs
			};
	config.httpAgent = config.debug ? false : new (require('http').Agent)(agentConfig).on('free', preventThrowError);
	config.httpsAgent = config.debug ? false : new (require('https').Agent)(agentConfig).on('free', preventThrowError);
	config.WEINRE_HOST = 'weinre.' + config.localUIHost;

	var app = express();
	var server = app.listen(config.port);
	var proxyEvents = new EventEmitter();
	var middlewares = ['./init',
	               '../biz']
				   .concat(require('./inspectors'))
				   .concat(config.middlewares)
	               .concat(require('./handlers'));

	proxyEvents.config = config;
	middlewares.forEach(function(mw) {
		mw && app.use((typeof mw == 'string' ? require(mw) : mw).bind(proxyEvents));
	});

	parseHosts(config);
	exportInterfaces(proxyEvents);
	tunnelProxy(server, proxyEvents);
	https.createServer(proxyEvents);
	require('./proxy')(proxyEvents);
	require('../biz/init')(proxyEvents);

	return proxyEvents;
}

function exportInterfaces(obj) {
	obj.rules = rules;
	obj.util = util;
	obj.rulesUtil = rulesUtil;
	return obj;
}

function parseHosts(config) {
	var rulesPath = config.rules;
	if (rulesPath) {
		try {
			rulesUtil.setPublicHosts(fs.readFileSync(path.resolve(rulesPath), {encoding: 'utf8'}));
			rulesUtil.enablePublicHosts();
		} catch(e) {}
	}

	rulesUtil.loadHosts(config);
}

process.on('uncaughtException', function(err){
	var stack = err.message;
	try {
		stack += '\r\n' + err.stack;
	} catch(e) {}
	fs.writeFileSync(path.join(process.cwd(), config.name + '.log'), '\r\n' + util.formatDate()  + '\r\n' +  stack + '\r\n', {flag: 'a'});
	console.error(stack);
	process.exit(1);
});

module.exports = exportInterfaces(proxy);<commit_msg>avoid throw error<commit_after>var express = require('express');
var url = require('url');
var net = require('net');
var path = require('path');
var fs = require('fs');
var EventEmitter = require('events').EventEmitter;
var exnted = require('util')._extend;
var util = require('../util');
var rules = require('./rules');
var https = require('./https');
var cert = require('./https/cert');
var rulesUtil = require('./rules/util');
var connect = require('./proxy/connect');
var config = require('../package.json');

function tunnelProxy(server, proxy) {

	server.on('connect', function(req, reqSocket, head) {//ws, wss, https proxy
		var tunnelUrl = req.url = util.setProtocol(req.url, true);
		var options = parseUrl();
		var resSocket, proxySocket;

		abortIfUnavailable(reqSocket);
		if (rulesUtil.intercepts(options.hostname)) {
			sendEstablished();
			https.dispatch(reqSocket, proxy, options.hostname);
			return;
		}

		var _rules = req.rules = rules.resolveRules(tunnelUrl);
		var proxyUrl = util.rule.getMatcher(_rules.proxy);

		if (proxyUrl) {
			var _tunnelUrl = 'https:' + util.removeProtocol(proxyUrl);
			var now = Date.now();
			rules.resolveHost(_tunnelUrl, function(err, ip) {
				req.host = ip;
				req.error = err;
				req.dnsTime = Date.now() - now;
				parseUrl(_tunnelUrl, config.port);
				if (!err && util.isLocalAddress(ip) && options.port == config.port) {
					parseUrl();
					return tunnel();
				}
				proxy.emit('tunnelProxy', req);
				if (err) {
					emitError(err);
					return;
				}
				options.host = ip;
				connect(req, function(err, _proxySocket) {
					if (err) {
						return emitError();
					}
					proxySocket = _proxySocket;
					abortIfUnavailable(_proxySocket);
					sendEstablished().pipe(_proxySocket).pipe(reqSocket);
				});
			});
		} else {
			if (_rules.rule) {
				var _url = util.setProtocol(util.rule.getMatcher(_rules.rule), true);
				if (/^https:/i.test(_url)) {
					parseUrl(_url);
				} else {
					var port = util.getProtocol(_url);
					port = port.substring(0, port.length - 1);
					var localProtocol = port + 'sslport';
					if (port = config[localProtocol]) {
						proxy.emit(localProtocol, _url, tunnelUrl);
						parseUrl(_url);
						options.protocol = 'https:';
						options.hostname = '127.0.0.1';
						options.host = options.hostname + ':' + port;
						options.port = port;
						_url = 'ssl://' + options.host; //不解析_url的ip
					} else {
						_url = null;//如果规则无法处理，则直接访问
					}
				}
			}

			tunnel(_url);
		}

		function emitError(err) {
			resSocket && resSocket.destroy();
			proxySocket && proxySocket.destroy();
			reqSocket.destroy();
		}

		function abortIfUnavailable(socket) {
			socket.on('error', emitError).on('close', emitError);
		}

		function parseUrl(_tunnelUrl, port) {
			_tunnelUrl = _tunnelUrl || tunnelUrl;
			options = req.options = url.parse(_tunnelUrl);
			options.port = options.port || port || 443;
			return options;
		}

		function sendEstablished() {
			reqSocket.write('HTTP/1.1 200 Connection Established\r\nProxy-Agent: ' + config.name + '\r\n\r\n');
			return reqSocket;
		}

		function tunnel(url) {
			var now = Date.now();
			rules.resolveHost(url || tunnelUrl, function(err, ip) {
				req.host = ip;
				req.clientHost  = reqSocket.remoteAddress;
				req.error = err;
				req.dnsTime = Date.now() - now;
				proxy.emit('tunnel', req);

				if (err) {
					emitError(err);
					return;
				}

				resSocket = net.connect(options.port, ip, function() {
					sendEstablished();
		            resSocket.pipe(reqSocket).pipe(resSocket);
		        });
				abortIfUnavailable(resSocket);
			});
		}
    });

	return server;
}

function preventThrowError(socket) {
	socket.removeListener('error', util.noop);
	socket.on('error', util.noop);
}

function proxy(conf) {
	if (conf) {
		['port', 'sockets', 'days', 'timeout',
		 'username', 'password', 'uipath', 'rules', 'debug']
			.forEach(function(name) {
				if (conf[name]) {
					config[name] = conf[name];
				}
			});

		if (Array.isArray(conf.ports)) {
			config.ports = config.ports.concat(conf.ports);
		}
	}

	if (!conf || typeof conf.middlewares != 'string') {
		if (!Array.isArray(conf.middlewares)) {
			config.middlewares = [];
		}
	} else {
		config.middlewares = conf.middlewares.trim().split(/\s*,\s*/g);
	}

	config.middlewares.map(util.resolvePath);

	var port = config.port;
	config.ports.forEach(function(name) {
		if (!/port$/.test(name) || name == 'port') {
			throw new Error('port name "' + name + '" must be end of "port", but not equals "port", like: ' + name + 'port');
		}
		config[name] = ++port;
	});

	var agentConfig = {
				maxSockets: config.sockets,
				keepAlive: config.keepAlive,
				keepAliveMsecs: config.keepAliveMsecs
			};
	config.httpAgent = config.debug ? false : new (require('http').Agent)(agentConfig).on('free', preventThrowError);
	config.httpsAgent = config.debug ? false : new (require('https').Agent)(agentConfig).on('free', preventThrowError);
	config.WEINRE_HOST = 'weinre.' + config.localUIHost;

	var app = express();
	var server = app.listen(config.port);
	var proxyEvents = new EventEmitter();
	var middlewares = ['./init',
	               '../biz']
				   .concat(require('./inspectors'))
				   .concat(config.middlewares)
	               .concat(require('./handlers'));

	proxyEvents.config = config;
	middlewares.forEach(function(mw) {
		mw && app.use((typeof mw == 'string' ? require(mw) : mw).bind(proxyEvents));
	});

	parseHosts(config);
	exportInterfaces(proxyEvents);
	tunnelProxy(server, proxyEvents);
	https.createServer(proxyEvents);
	require('./proxy')(proxyEvents);
	require('../biz/init')(proxyEvents);

	return proxyEvents;
}

function exportInterfaces(obj) {
	obj.rules = rules;
	obj.util = util;
	obj.rulesUtil = rulesUtil;
	return obj;
}

function parseHosts(config) {
	var rulesPath = config.rules;
	if (rulesPath) {
		try {
			rulesUtil.setPublicHosts(fs.readFileSync(path.resolve(rulesPath), {encoding: 'utf8'}));
			rulesUtil.enablePublicHosts();
		} catch(e) {}
	}

	rulesUtil.loadHosts(config);
}

process.on('uncaughtException', function(err){
	var stack = err.message;
	try {
		stack += '\r\n' + err.stack;
	} catch(e) {}
	fs.writeFileSync(path.join(process.cwd(), config.name + '.log'), '\r\n' + util.formatDate()  + '\r\n' +  stack + '\r\n', {flag: 'a'});
	console.error(stack);
	process.exit(1);
});

module.exports = exportInterfaces(proxy);<|endoftext|>


<commit_before>var type = require('type');
var Schema = require('./schema');
var Store = require('./idb-store');
var Index = require('./idb-index');
var range = require('./range');

/**
 * `indexedDB` reference.
 */

var indexedDB = window.indexedDB
  || window.msIndexedDB
  || window.mozIndexedDB
  || window.webkitIndexedDB;

/**
 * Expose `Treo`.
 */

exports = module.exports = Treo;

/**
 * Initialize new `Treo` instance.
 *
 * @param {String} name
 * @param {Schema} schema
 */

function Treo(name, schema) {
  if (!(this instanceof Treo)) return new Treo(name, schema);
  if (type(name) != 'string') throw new TypeError('`name` required');
  if (!(schema instanceof Schema)) throw new TypeError('not valid schema');

  this.name = name;
  this.status = 'close';
  this.origin = null;
  this.stores = {};
  this.version = schema.getVersion();
  this.upgradeCallback = createUpgradeCallback(schema._versions);

  // setup stores and indexes
  Object.keys(schema._stores).forEach(function(storeName) {
    var s = schema._stores[storeName];
    var store = this.stores[storeName] = new Store(this, s.name, s.opts);
    Object.keys(s.indexes).forEach(function(indexName) {
      var i = s.indexes[indexName];
      store.indexes[indexName] = new Index(store, i.name, i.field, i.opts);
    });
  }, this);
}

/**
 * Expose core classes.
 */

exports.schema = Schema;
exports.range = range;
exports.cmp = cmp;
exports.Treo = Treo;
exports.Schema = Schema;
exports.Store = Store;
exports.Index = Index;

/**
 * Drop.
 *
 * @param {Function} cb
 */

Treo.prototype.drop = function(cb) {
  var name = this.name;
  this.close(function(err) {
    if (err) return cb(err);
    var req = indexedDB.deleteDatabase(name);
    req.onerror = cb;
    req.onsuccess = function onsuccess() { cb() };
  });
};

/**
 * Close.
 *
 * @param {Function} cb
 */

Treo.prototype.close = function(cb) {
  if (this.status == 'close') return cb();
  this.getInstance(function(err, db) {
    if (err) return cb(err);
    db.origin = null;
    db.close();
    cb();
  });
};

/**
 * Get store by `name`.
 *
 * @param {String} name
 * @return {Store}
 */

Treo.prototype.store = function(name) {
  return this.stores[name];
};

/**
 * Get db instance. It starts opening transaction only once,
 * another requests will be scheduled to queue.
 *
 * @param {Function} cb
 */

Treo.prototype.getInstance = function(cb) {
  if (this.status == 'open') return cb(null, this.origin);
  if (this.status == 'opening') return this.queue.push(cb);

  this.status = 'opening';
  this.queue = [cb]; // queue callbacks

  var that = this;
  var req = indexedDB.open(this.name, this.version);

  req.onupgradeneeded = this.upgradeCallback;
  req.onerror = req.onblocked = function onerror(e) {
    that.status = 'error';
    that.queue.forEach(function(cb) { cb(e) });
    delete that.queue;
  };
  req.onsuccess = function onsuccess(e) {
    that.origin = e.target.result;
    that.status = 'open';
    that.queue.forEach(function(cb) { cb(null, that.origin) });
    delete that.queue;
  };
};

/**
 * Create new transaction for selected `stores`.
 *
 * @param {String} type (readwrite|readonly)
 * @param {Array} stores - follow indexeddb semantic
 * @param {Function} cb
 */

Treo.prototype.transaction = function(type, stores, cb) {
  this.getInstance(function(err, db) {
    err ? cb(err) : cb(null, db.transaction(stores, type));
  });
};

/**
 * Create callback for `upgradeneeded` event based on `versions`.
 *
 * @param {Object} versions
 * @return {Function}
 */

function createUpgradeCallback(versions) {
  var allVersions = Object.keys(versions)
    .map(function(v) { return parseInt(v, 10) }).sort();

  return function onupgradeneeded(e) {
    var db = e.target.result;
    var tr = e.target.transaction;

    allVersions.forEach(function(version) {
      if (e.oldVersion >= version) return;
      var versionSchema = versions[version];

      versionSchema.stores.forEach(function(store) {
        db.createObjectStore(store.name, { keyPath: store.opts.key });
      });

      versionSchema.indexes.forEach(function(index) {
        var store = tr.objectStore(index.store.name);
        var opts = { unique: index.opts.unique, multiEntry: index.opts.multi };
        store.createIndex(index.name, index.field, opts);
      });
    });
  };
}

/**
 * Compare 2 values using IndexedDB comparision algotihm.
 *
 * @param {Mixed} value1
 * @param {Mixed} value2
 * @return {Number} -1|0|1
 */

function cmp() {
  return indexedDB.cmp.apply(indexedDB, arguments);
}
<commit_msg>add treo.use<commit_after>var type = require('type');
var Schema = require('./schema');
var Store = require('./idb-store');
var Index = require('./idb-index');
var range = require('./range');

/**
 * `indexedDB` reference.
 */

var indexedDB = window.indexedDB
  || window.msIndexedDB
  || window.mozIndexedDB
  || window.webkitIndexedDB;

/**
 * Expose `Treo`.
 */

exports = module.exports = Treo;

/**
 * Initialize new `Treo` instance.
 *
 * @param {String} name
 * @param {Schema} schema
 */

function Treo(name, schema) {
  if (!(this instanceof Treo)) return new Treo(name, schema);
  if (type(name) != 'string') throw new TypeError('`name` required');
  if (!(schema instanceof Schema)) throw new TypeError('not valid schema');

  this.name = name;
  this.status = 'close';
  this.origin = null;
  this.stores = {};
  this.version = schema.getVersion();
  this.upgradeCallback = createUpgradeCallback(schema._versions);

  // setup stores and indexes
  Object.keys(schema._stores).forEach(function(storeName) {
    var s = schema._stores[storeName];
    var store = this.stores[storeName] = new Store(this, s.name, s.opts);
    Object.keys(s.indexes).forEach(function(indexName) {
      var i = s.indexes[indexName];
      store.indexes[indexName] = new Index(store, i.name, i.field, i.opts);
    });
  }, this);
}

/**
 * Expose core classes.
 */

exports.schema = Schema;
exports.range = range;
exports.cmp = cmp;
exports.Treo = Treo;
exports.Schema = Schema;
exports.Store = Store;
exports.Index = Index;

/**
 * Use the given plugin `fn(db, treo)`.
 *
 * @param {Function} fn
 * @return {Treo}
 */

Treo.prototype.use = function(fn) {
  fn(this, exports);
  return this;
};

/**
 * Drop.
 *
 * @param {Function} cb
 */

Treo.prototype.drop = function(cb) {
  var name = this.name;
  this.close(function(err) {
    if (err) return cb(err);
    var req = indexedDB.deleteDatabase(name);
    req.onerror = cb;
    req.onsuccess = function onsuccess() { cb() };
  });
};

/**
 * Close.
 *
 * @param {Function} cb
 */

Treo.prototype.close = function(cb) {
  if (this.status == 'close') return cb();
  this.getInstance(function(err, db) {
    if (err) return cb(err);
    db.origin = null;
    db.close();
    cb();
  });
};

/**
 * Get store by `name`.
 *
 * @param {String} name
 * @return {Store}
 */

Treo.prototype.store = function(name) {
  return this.stores[name];
};

/**
 * Get db instance. It starts opening transaction only once,
 * another requests will be scheduled to queue.
 *
 * @param {Function} cb
 */

Treo.prototype.getInstance = function(cb) {
  if (this.status == 'open') return cb(null, this.origin);
  if (this.status == 'opening') return this.queue.push(cb);

  this.status = 'opening';
  this.queue = [cb]; // queue callbacks

  var that = this;
  var req = indexedDB.open(this.name, this.version);

  req.onupgradeneeded = this.upgradeCallback;
  req.onerror = req.onblocked = function onerror(e) {
    that.status = 'error';
    that.queue.forEach(function(cb) { cb(e) });
    delete that.queue;
  };
  req.onsuccess = function onsuccess(e) {
    that.origin = e.target.result;
    that.status = 'open';
    that.queue.forEach(function(cb) { cb(null, that.origin) });
    delete that.queue;
  };
};

/**
 * Create new transaction for selected `stores`.
 *
 * @param {String} type (readwrite|readonly)
 * @param {Array} stores - follow indexeddb semantic
 * @param {Function} cb
 */

Treo.prototype.transaction = function(type, stores, cb) {
  this.getInstance(function(err, db) {
    err ? cb(err) : cb(null, db.transaction(stores, type));
  });
};

/**
 * Create callback for `upgradeneeded` event based on `versions`.
 *
 * @param {Object} versions
 * @return {Function}
 */

function createUpgradeCallback(versions) {
  var allVersions = Object.keys(versions)
    .map(function(v) { return parseInt(v, 10) }).sort();

  return function onupgradeneeded(e) {
    var db = e.target.result;
    var tr = e.target.transaction;

    allVersions.forEach(function(version) {
      if (e.oldVersion >= version) return;
      var versionSchema = versions[version];

      versionSchema.stores.forEach(function(store) {
        db.createObjectStore(store.name, { keyPath: store.opts.key });
      });

      versionSchema.indexes.forEach(function(index) {
        var store = tr.objectStore(index.store.name);
        var opts = { unique: index.opts.unique, multiEntry: index.opts.multi };
        store.createIndex(index.name, index.field, opts);
      });
    });
  };
}

/**
 * Compare 2 values using IndexedDB comparision algotihm.
 *
 * @param {Mixed} value1
 * @param {Mixed} value2
 * @return {Number} -1|0|1
 */

function cmp() {
  return indexedDB.cmp.apply(indexedDB, arguments);
}
<|endoftext|>


<commit_before>/*
 * NPM modules
 * */
MongoOplog = Npm.require('mongo-oplog');
ElasticSearch = Npm.require('elasticsearch');
MongoDriver = Npm.require('mongodb').MongoClient;

/*
 * Define main ESMongoSync object
 * */
ESMongoSync = {
  Oplog: {},
  EsClient: {},
  dbConnection: {
    db: {},
    connected: false
  },
  options: {
    watchedCollections: [],
    batches: [],
    documentsInBatch: 100,
    config: {}
  }
};

/*
 * Function to verify env variables
 * */
const unsetEnv = [];
const getSetStatus = (env, systemEnv) => systemEnv[env] ? true : false;
const verifySystemEnv = (mongoOplogUrl, elasticSearchUrl) => {
  const processEnv = ['SEARCH_MONGO_URL', 'SEARCH_ELASTIC_URL'];
  const serverEnv = process.env;
  if (!mongoOplogUrl || !elasticSearchUrl) {
    _.each(processEnv, env => {
      if (!getSetStatus(env, serverEnv)) {
        unsetEnv.push(env);
      }
    });
    return unsetEnv.length === 0;
  } else {
    return true;
  }
};

/*
 * Function to process batch request
 * */
const processSingleBatch = (currentBatch, callBack) => {
  let currentDocuments = currentBatch.splice(0, ESMongoSync.options.documentsInBatch * 2);
  if (currentDocuments.length > 0) {
    let bulk = [];
    let currentCollectionName = '';
    _.each(currentDocuments, Meteor.bindEnvironment((document, mainIndex) => {
      if (document.index) {
        currentCollectionName = document.index._type;
      }
      transform(getWatcherByCollection(currentCollectionName), document, Meteor.bindEnvironment(doc => {
        currentDocuments[mainIndex] = doc;
        bulk.push(doc);
        if (bulk.length === currentDocuments.length) {
          ESMongoSync.EsClient.bulk({
            body: currentDocuments
          }, Meteor.bindEnvironment((error, response) => {
            if (!error && !response.errors) {
              console.log('ESMongoSync: Number of documents indexed in batch - ', bulk.length / 2);
              processSingleBatch(currentBatch, callBack);
            } else {
              console.log(error);
            }
          }));
        }
      }));
    }));
  } else {
    callBack();
  }
};

/*
 * Function to process batches
 * */
const processBatches = (currentBatchLevel) => {
  let batchLevel = currentBatchLevel || 0;
  if (batchLevel === 0) {
    console.log('ESMongoSync: Number of documents in batch - ', ESMongoSync.options.documentsInBatch);
  }
  let currentBatch = ESMongoSync.options.batches[batchLevel];
  if (currentBatch) {
    processSingleBatch(currentBatch, Meteor.bindEnvironment(() => {
      processBatches(batchLevel + 1);
    }));
  } else {
    console.log('Batch processing complete!');
  }
};

/*
 * Function to pull documents from mongoDB and send to elastic search in batches provided by user
 * */
const createBatches = (currentPriorityLevel) => {
  let priorityLevel = currentPriorityLevel || 0;
  if (priorityLevel === 0) {
    console.log('ESMongoSync: Beginning batch creation');
  }
  let newWatchers = getWatcherAtLevel(ESMongoSync.options.watchedCollections, priorityLevel);
  if (newWatchers.length > 0) {
    console.log('ESMongoSync: Processing watchers on priority level ', priorityLevel);
    let checker = [];
    let mainDocuments = [];
    _.each(newWatchers, Meteor.bindEnvironment((watcher) => {
      console.log('ESMongoSync: Processing ', watcher.collectionName, ' collection');
      let documents = [];
      let collection = ESMongoSync.dbConnection.db.collection(watcher.collectionName);
      collection.count(Meteor.bindEnvironment((e, count) => {
        if (count > 0) {
          collection.find({}).forEach(Meteor.bindEnvironment(document => {
            documents.push(document);
            if (documents.length === count) {
              _.each(documents, Meteor.bindEnvironment((doc, docIndex) => {
                mainDocuments.push({
                  index: {
                    _index: watcher.index,
                    _type: watcher.type,
                    _id: doc._id
                  }
                }, doc);
                if (docIndex === documents.length - 1) {
                  checker.push(watcher.collectionName);
                  if (checker.length === newWatchers.length) {
                    ESMongoSync.options.batches.push(mainDocuments);
                    createBatches(priorityLevel + 1);
                  }
                }
              }));
            }
          }));
        } else {
          checker.push(watcher.collectionName);
          if (checker.length === newWatchers.length) {
            ESMongoSync.options.batches.push(mainDocuments);
            createBatches(priorityLevel + 1);
          }
        }
      }));
    }));
  } else {
    console.log('ESMongoSync: Batch creation complete. Processing...');
    processBatches();
  }
};

/*
 * Connect to main database
 * */
const connectDB = () => {
  MongoDriver.connect(process.env.SEARCH_MONGO_URL || ESMongoSync.options.config.mongoOplogUrl, Meteor.bindEnvironment((error, db) => {
    if (!error) {
      console.log('ESMongoSync: Connected to MONGO server successfully.');
      ESMongoSync.dbConnection.db = db;
      ESMongoSync.dbConnection.connected = true;
      createBatches();
      /*loadDocuments(ESMongoSync.options.watchedCollections, 1);*/
    } else {
      throw new Meteor.Error(400, `ESMongoSync: Connection to database: ${process.env.SEARCH_MONGO_URL} failed!`);
    }
  }));
};

/*
 * Function to tail Mongo database
 * */
const tail = (mongoUrl) => {
  /*
   * Function to reconnect after timeout when there are issues connecting to
   * Oplog.
   */
  let tailRetry = () => {
    let mongoURL = mongoUrl;
    tail(mongoUrl);
  };
  console.log(`using ${mongoUrl}`);
  ESMongoSync.Oplog = MongoOplog(mongoUrl).tail(Meteor.bindEnvironment(() => {
    if (!ESMongoSync.Oplog.stream) {
      console.log('ESMongoSync: Connection to Oplog failed!');
      console.log('ESMongoSync: Retrying...');
      Meteor.setTimeout(tailRetry, 5000);
    } else {
      console.log('ESMongoSync: Oplog tailing connection successful.');
      ESMongoSync.Oplog.on('insert', Meteor.bindEnvironment(doc => {
        const watcher = getWatcher(getCollectionName(doc.ns));
        if (watcher) {
          insert(watcher, doc.o);
        }
      }));

      ESMongoSync.Oplog.on('update', Meteor.bindEnvironment(doc => {
        const watcher = getWatcher(getCollectionName(doc.ns));
        if (watcher) {
          update(watcher, doc.o2._id, doc.o.$set);
        }
      }));

      ESMongoSync.Oplog.on('delete', Meteor.bindEnvironment(doc => {
        const watcher = getWatcher(getCollectionName(doc.ns));
        if (watcher) {
          remove(watcher, doc.o._id);
        }
      }));

      ESMongoSync.Oplog.on('error', Meteor.bindEnvironment(error => {
        console.log('ESMongoSync: ', error);
        Meteor.setTimeout(tailRetry, 5000);
      }));

      ESMongoSync.Oplog.on('end', Meteor.bindEnvironment(() => {
        console.log('ESMongoSync: Stream ended');
        Meteor.setTimeout(tailRetry, 5000);
      }));

    }
  }));
};

/*
 * Function to connect to elastic search
 * */
const connectElasticSearch = (elasticSearchUrl, callBack) => {
  ESMongoSync.EsClient = new ElasticSearch.Client({
    host: elasticSearchUrl,
    keepAlive: true
  });
  ESMongoSync.EsClient.ping({
    requestTimeout: Infinity
  }, Meteor.bindEnvironment(error => {
    if (error) {
      throw new Meteor.Error(400, `ESMongoSync: ElasticSearch cluster is down!`);
    } else {
      console.log('ESMongoSync: Connected to ElasticSearch successfully!');
      if (callBack) {
        callBack();
      }
      connectDB();
    }
  }));
};

/*
 * Function to initialize all connections
 * */
const initialize = (config) => {
  tail(config.mongoOplogUrl);
  connectElasticSearch(config.elasticSearchUrl, config.callBack);
};

/*
 * Method to initialize all option values
 * */
ESMongoSync.init = function (mongoOplogUrl, elasticSearchUrl, callBack, watchers, documentsInBatch) {
  verifyInitArgs(arguments);
  if (!verifySystemEnv(mongoOplogUrl, elasticSearchUrl)) {
    throw new Meteor.Error(400, `ESMongoSync: The following environment variables are not defined: ${unsetEnv.join(', ')}. Set and restart server.`);
  }
  ESMongoSync.options.documentsInBatch = documentsInBatch > 0 ? documentsInBatch : ESMongoSync.options.documentsInBatch;
  ESMongoSync.options.watchedCollections = watchers;
  ESMongoSync.options.config = {
    mongoOplogUrl: mongoOplogUrl || process.env['SEARCH_MONGO_URL'],
    elasticSearchUrl: elasticSearchUrl || process.env['SEARCH_ELASTIC_URL'],
    callBack: callBack
  };
  initialize(ESMongoSync.options.config);
};

/*
* Function to restart
* */
ESMongoSync.reIndex = () => {
  createBatches();
};

/*
 * Function to destroy mongoOplog
 * */
ESMongoSync.destroy = () => {
  ESMongoSync.Oplog.destroy(Meteor.bindEnvironment(() => {
    ESMongoSync.dbConnection.db.close();
    ESMongoSync.dbConnection.connected = false;
    ESMongoSync.Oplog = {};
    console.log('ESMongoSync disconnected and Destroyed!');
  }))
};

/*
 * Function to disconnect mongoOplog
 * */
ESMongoSync.disconnect = () => {
  ESMongoSync.Oplog.stop(() => {
    console.log('ESMongoSync tailing stopped!');
  });
};
<commit_msg>removed console.log and remove useless let variable<commit_after>/*
 * NPM modules
 * */
MongoOplog = Npm.require('mongo-oplog');
ElasticSearch = Npm.require('elasticsearch');
MongoDriver = Npm.require('mongodb').MongoClient;

/*
 * Define main ESMongoSync object
 * */
ESMongoSync = {
  Oplog: {},
  EsClient: {},
  dbConnection: {
    db: {},
    connected: false
  },
  options: {
    watchedCollections: [],
    batches: [],
    documentsInBatch: 100,
    config: {}
  }
};

/*
 * Function to verify env variables
 * */
const unsetEnv = [];
const getSetStatus = (env, systemEnv) => systemEnv[env] ? true : false;
const verifySystemEnv = (mongoOplogUrl, elasticSearchUrl) => {
  const processEnv = ['SEARCH_MONGO_URL', 'SEARCH_ELASTIC_URL'];
  const serverEnv = process.env;
  if (!mongoOplogUrl || !elasticSearchUrl) {
    _.each(processEnv, env => {
      if (!getSetStatus(env, serverEnv)) {
        unsetEnv.push(env);
      }
    });
    return unsetEnv.length === 0;
  } else {
    return true;
  }
};

/*
 * Function to process batch request
 * */
const processSingleBatch = (currentBatch, callBack) => {
  let currentDocuments = currentBatch.splice(0, ESMongoSync.options.documentsInBatch * 2);
  if (currentDocuments.length > 0) {
    let bulk = [];
    let currentCollectionName = '';
    _.each(currentDocuments, Meteor.bindEnvironment((document, mainIndex) => {
      if (document.index) {
        currentCollectionName = document.index._type;
      }
      transform(getWatcherByCollection(currentCollectionName), document, Meteor.bindEnvironment(doc => {
        currentDocuments[mainIndex] = doc;
        bulk.push(doc);
        if (bulk.length === currentDocuments.length) {
          ESMongoSync.EsClient.bulk({
            body: currentDocuments
          }, Meteor.bindEnvironment((error, response) => {
            if (!error && !response.errors) {
              console.log('ESMongoSync: Number of documents indexed in batch - ', bulk.length / 2);
              processSingleBatch(currentBatch, callBack);
            } else {
              console.log(error);
            }
          }));
        }
      }));
    }));
  } else {
    callBack();
  }
};

/*
 * Function to process batches
 * */
const processBatches = (currentBatchLevel) => {
  let batchLevel = currentBatchLevel || 0;
  if (batchLevel === 0) {
    console.log('ESMongoSync: Number of documents in batch - ', ESMongoSync.options.documentsInBatch);
  }
  let currentBatch = ESMongoSync.options.batches[batchLevel];
  if (currentBatch) {
    processSingleBatch(currentBatch, Meteor.bindEnvironment(() => {
      processBatches(batchLevel + 1);
    }));
  } else {
    console.log('Batch processing complete!');
  }
};

/*
 * Function to pull documents from mongoDB and send to elastic search in batches provided by user
 * */
const createBatches = (currentPriorityLevel) => {
  let priorityLevel = currentPriorityLevel || 0;
  if (priorityLevel === 0) {
    console.log('ESMongoSync: Beginning batch creation');
  }
  let newWatchers = getWatcherAtLevel(ESMongoSync.options.watchedCollections, priorityLevel);
  if (newWatchers.length > 0) {
    console.log('ESMongoSync: Processing watchers on priority level ', priorityLevel);
    let checker = [];
    let mainDocuments = [];
    _.each(newWatchers, Meteor.bindEnvironment((watcher) => {
      console.log('ESMongoSync: Processing ', watcher.collectionName, ' collection');
      let documents = [];
      let collection = ESMongoSync.dbConnection.db.collection(watcher.collectionName);
      collection.count(Meteor.bindEnvironment((e, count) => {
        if (count > 0) {
          collection.find({}).forEach(Meteor.bindEnvironment(document => {
            documents.push(document);
            if (documents.length === count) {
              _.each(documents, Meteor.bindEnvironment((doc, docIndex) => {
                mainDocuments.push({
                  index: {
                    _index: watcher.index,
                    _type: watcher.type,
                    _id: doc._id
                  }
                }, doc);
                if (docIndex === documents.length - 1) {
                  checker.push(watcher.collectionName);
                  if (checker.length === newWatchers.length) {
                    ESMongoSync.options.batches.push(mainDocuments);
                    createBatches(priorityLevel + 1);
                  }
                }
              }));
            }
          }));
        } else {
          checker.push(watcher.collectionName);
          if (checker.length === newWatchers.length) {
            ESMongoSync.options.batches.push(mainDocuments);
            createBatches(priorityLevel + 1);
          }
        }
      }));
    }));
  } else {
    console.log('ESMongoSync: Batch creation complete. Processing...');
    processBatches();
  }
};

/*
 * Connect to main database
 * */
const connectDB = () => {
  MongoDriver.connect(process.env.SEARCH_MONGO_URL || ESMongoSync.options.config.mongoOplogUrl, Meteor.bindEnvironment((error, db) => {
    if (!error) {
      console.log('ESMongoSync: Connected to MONGO server successfully.');
      ESMongoSync.dbConnection.db = db;
      ESMongoSync.dbConnection.connected = true;
      createBatches();
      /*loadDocuments(ESMongoSync.options.watchedCollections, 1);*/
    } else {
      throw new Meteor.Error(400, `ESMongoSync: Connection to database: ${process.env.SEARCH_MONGO_URL} failed!`);
    }
  }));
};

/*
 * Function to tail Mongo database
 * */
const tail = (mongoUrl) => {
  /*
   * Function to reconnect after timeout when there are issues connecting to
   * Oplog.
   */
  let tailRetry = () => {
    tail(mongoUrl);
  };
  ESMongoSync.Oplog = MongoOplog(mongoUrl).tail(Meteor.bindEnvironment(() => {
    if (!ESMongoSync.Oplog.stream) {
      console.log('ESMongoSync: Connection to Oplog failed!');
      console.log('ESMongoSync: Retrying...');
      Meteor.setTimeout(tailRetry, 5000);
    } else {
      console.log('ESMongoSync: Oplog tailing connection successful.');
      ESMongoSync.Oplog.on('insert', Meteor.bindEnvironment(doc => {
        const watcher = getWatcher(getCollectionName(doc.ns));
        if (watcher) {
          insert(watcher, doc.o);
        }
      }));

      ESMongoSync.Oplog.on('update', Meteor.bindEnvironment(doc => {
        const watcher = getWatcher(getCollectionName(doc.ns));
        if (watcher) {
          update(watcher, doc.o2._id, doc.o.$set);
        }
      }));

      ESMongoSync.Oplog.on('delete', Meteor.bindEnvironment(doc => {
        const watcher = getWatcher(getCollectionName(doc.ns));
        if (watcher) {
          remove(watcher, doc.o._id);
        }
      }));

      ESMongoSync.Oplog.on('error', Meteor.bindEnvironment(error => {
        console.log('ESMongoSync: ', error);
        Meteor.setTimeout(tailRetry, 5000);
      }));

      ESMongoSync.Oplog.on('end', Meteor.bindEnvironment(() => {
        console.log('ESMongoSync: Stream ended');
        Meteor.setTimeout(tailRetry, 5000);
      }));

    }
  }));
};

/*
 * Function to connect to elastic search
 * */
const connectElasticSearch = (elasticSearchUrl, callBack) => {
  ESMongoSync.EsClient = new ElasticSearch.Client({
    host: elasticSearchUrl,
    keepAlive: true
  });
  ESMongoSync.EsClient.ping({
    requestTimeout: Infinity
  }, Meteor.bindEnvironment(error => {
    if (error) {
      throw new Meteor.Error(400, `ESMongoSync: ElasticSearch cluster is down!`);
    } else {
      console.log('ESMongoSync: Connected to ElasticSearch successfully!');
      if (callBack) {
        callBack();
      }
      connectDB();
    }
  }));
};

/*
 * Function to initialize all connections
 * */
const initialize = (config) => {
  tail(config.mongoOplogUrl);
  connectElasticSearch(config.elasticSearchUrl, config.callBack);
};

/*
 * Method to initialize all option values
 * */
ESMongoSync.init = function (mongoOplogUrl, elasticSearchUrl, callBack, watchers, documentsInBatch) {
  verifyInitArgs(arguments);
  if (!verifySystemEnv(mongoOplogUrl, elasticSearchUrl)) {
    throw new Meteor.Error(400, `ESMongoSync: The following environment variables are not defined: ${unsetEnv.join(', ')}. Set and restart server.`);
  }
  ESMongoSync.options.documentsInBatch = documentsInBatch > 0 ? documentsInBatch : ESMongoSync.options.documentsInBatch;
  ESMongoSync.options.watchedCollections = watchers;
  ESMongoSync.options.config = {
    mongoOplogUrl: mongoOplogUrl || process.env['SEARCH_MONGO_URL'],
    elasticSearchUrl: elasticSearchUrl || process.env['SEARCH_ELASTIC_URL'],
    callBack: callBack
  };
  initialize(ESMongoSync.options.config);
};

/*
* Function to restart
* */
ESMongoSync.reIndex = () => {
  createBatches();
};

/*
 * Function to destroy mongoOplog
 * */
ESMongoSync.destroy = () => {
  ESMongoSync.Oplog.destroy(Meteor.bindEnvironment(() => {
    ESMongoSync.dbConnection.db.close();
    ESMongoSync.dbConnection.connected = false;
    ESMongoSync.Oplog = {};
    console.log('ESMongoSync disconnected and Destroyed!');
  }))
};

/*
 * Function to disconnect mongoOplog
 * */
ESMongoSync.disconnect = () => {
  ESMongoSync.Oplog.stop(() => {
    console.log('ESMongoSync tailing stopped!');
  });
};
<|endoftext|>


<commit_before>'use strict';

var sequoria = require('sequoria'),
  fs = require('fs');

var Bot = require('./bot');

var exports = module.exports = {};

var importers = {
  'command': function importCommandPlugin(bot, plugin) {
    bot.command(plugin.command, require(plugin.require));
  },
  'event': function importEventPlugin(bot, plugin) {
    bot.on(plugin.event, require(plugin.require));
  },
  'message': function importMessagePlugin(bot, plugin) {
    bot.onMessage(plugin.msgType, require(plugin.require));
  }
};

var createBot = exports.createBot = function createBot(options) {

  // perform all the options checking here before creating a Bot.
  if (!options.token) {
    sequoria.error('No token found!')
    process.exit(1);
  }

  var bot = new Bot(options);
  (options.bundles || []).forEach(bot.importBundle);
  (options.plugins || []).forEach(function(plugin) {
    var importer = importers[plugin.type];
    importer && importer(bot, plugin);
  });

  return bot;
};
<commit_msg>Add import erroring<commit_after>'use strict';

var sequoria = require('sequoria'),
  lfmt = require('lfmt'),
  fs = require('fs');

var Bot = require('./bot');

var exports = module.exports = {};

var importers = {
  'command': function importCommandPlugin(bot, plugin) {
    bot.command(plugin.command, require(plugin.require));
  },
  'event': function importEventPlugin(bot, plugin) {
    bot.on(plugin.event, require(plugin.require));
  },
  'message': function importMessagePlugin(bot, plugin) {
    bot.onMessage(plugin.msgType, require(plugin.require));
  },
  'type_error': function nonexistentPluginType(bot, plugin) {
    sequoria.error(lfmt('Plugin type {{type}} does not exist!', plugin));
  }
};

var createBot = exports.createBot = function createBot(options) {

  // perform all the options checking here before creating a Bot.
  if (!options.token) {
    sequoria.error('No token found!')
    process.exit(1);
  }

  var bot = new Bot(options);
  (options.bundles || []).forEach(bot.importBundle);
  (options.plugins || []).forEach(function(plugin) {
    var importer = importers[plugin.type] || importers.type_error;
    importer && importer(bot, plugin);
  });

  return bot;
};
<|endoftext|>


<commit_before>require('http').OutgoingMessage.prototype.hijack = function (cb) {
    var writeHead = this.writeHead,
        write = this.write,
        end = this.end,
        res = this,
        hijacking = true,
        hijackedResponse = {};

    hijackedResponse.readable = hijackedResponse.writable = true;

    hijackedResponse.write = function (chunk, encoding) {
        write.call(res, chunk, encoding);
    };

    hijackedResponse.end = function (chunk, encoding) {
        end.call(res, chunk, encoding);
    };

    hijackedResponse.__proto__ = res;

    this.writeHead = function (statusCode, headers) {
        if (statusCode) {
            this.statusCode = statusCode;
        }
        if (headers) {
            for (var headerName in headers) {
                this.setHeader(headerName, headers[headerName]);
            }
        }
        this.writeHead = writeHead;
        cb(null, hijackedResponse);
    };

    hijackedResponse.unhijack = function () {
        if (!res.headerSent) res.writeHead(res.statusCode);
        hijacking = false;
    };

    this.write = function (chunk, encoding) {
        if (!this.headerSent && this.writeHead !== writeHead) this._implicitHeader();
        if (hijacking) {
            hijackedResponse.emit('data', chunk, encoding);
        } else {
            return write.call(this, chunk, encoding);
        }
    };

    this.end = function (chunk, encoding) {
        if (chunk) {
            this.write(chunk, encoding);
        }
        if (hijacking) {
            hijackedResponse.emit('end');
        } else {
            end.call(this);
        }
    };
};
<commit_msg>Fixed hijacking of bodyless responses (such as 304s).<commit_after>require('http').OutgoingMessage.prototype.hijack = function (cb) {
    var writeHead = this.writeHead,
        write = this.write,
        end = this.end,
        res = this,
        hijacking = true,
        hijackedResponse = {};

    hijackedResponse.readable = hijackedResponse.writable = true;

    hijackedResponse.write = function (chunk, encoding) {
        write.call(res, chunk, encoding);
    };

    hijackedResponse.end = function (chunk, encoding) {
        end.call(res, chunk, encoding);
    };

    hijackedResponse.__proto__ = res;

    this.writeHead = function (statusCode, headers) {
        if (statusCode) {
            this.statusCode = statusCode;
        }
        if (headers) {
            for (var headerName in headers) {
                this.setHeader(headerName, headers[headerName]);
            }
        }
        this.writeHead = writeHead;
        cb(null, hijackedResponse);
    };

    hijackedResponse.unhijack = function () {
        if (!res.headerSent) res.writeHead(res.statusCode);
        hijacking = false;
    };

    this.write = function (chunk, encoding) {
        if (!this.headerSent && this.writeHead !== writeHead) this._implicitHeader();
        if (hijacking) {
            hijackedResponse.emit('data', chunk, encoding);
        } else {
            return write.call(this, chunk, encoding);
        }
    };

    this.end = function (chunk, encoding) {
        if (chunk) {
            this.write(chunk, encoding);
        } else if (!this.headerSent && this.writeHead !== writeHead) {
            this._implicitHeader();
        }
        if (hijacking) {
            hijackedResponse.emit('end');
        } else {
            end.call(this);
        }
    };
};
<|endoftext|>