<commit_before>;
(function(mag) {

  "use strict";

  var render = {
    roots: [],
    templates: {},
    cache: {}
  }

  var unloaders = [],
    cached = [],
    pendingRequests = 0

    function callView(elementClone, module, i) {
      var args = module.getArgs(i)

      var mod = module.modules[i]
      var controller = module.controllers[i]

      // var controllerConstructor = mod.controller.$original || mod.controller
      // var controller = controllerConstructor === cached.controllerConstructor ? cached.controller : new(mod.controller || function() {})

      try {
        mod.view(controller, elementClone)
      } catch (e) {
        //THROW ?
        console.log(e)
      }
      // if (controller.onunload) unloaders.push({
      //   controller: controller,
      //   handler: controller.onunload
      // })
    }

  render.callOnload = function(module) {
    for (var i = 0, controller; controller = module.controllers[i]; i++) {
      // call once
      if (controller.onload && !controller.called) {
        controller.onload.call(null, module.elements[i])
        controller.called = 1
      }
    }
  }
  render.callConfigs = function(configs) {
    for (var i = 0, len = configs.length; i < len; i++) configs[i]()
  }
  var cache = []
  render.redraw = function(module, fill, WatchJS) {

    module = module || render.module || {}

    this.fun = (this.fun || debounce(function(id) {
      // clear existing configs
      fill.configs.splice(0, fill.configs.length)

      render.doLoop(module, fill, WatchJS)
    }))
    this.fun()
  }

  render.doLoop = function(module, fill, WatchJS) {
    for (var i = 0, root; root = render.roots[i]; i++) {
      mag.running = true

      if (module.controllers[i]) {
        if (!render.innerLoop(module, fill, i, WatchJS)) {
          //cached
        } else {
          module.deferreds[i][2]({
            _html: module.elements[i].innerHTML
          })
          //TODO: remove clones
          if (module.deferreds[i][0]) {
            var index = module.deferreds[i][1]
            delete module.elements[index],
              module.modules[index], module.controllers[index], module.promises[index], module.deferreds[index]
          }
        }
      }
    }
    fill.unclear()
  }

  render.clear = function(index, elementId, fill) {
    if (index !== -1 && cache[index]) {
      // clear events too
      fill.clear()
      //console.log('clear called on reload', elementId)
      // delete cache[index]
    }
  }
  render.innerLoop = function(module, fill, i, WatchJS) {
    var elementClone = module.elements[i]
    var args = module.getArgs(i)

    if (cache[i] && cache[i] === JSON.stringify(args[0])) {
      return false
    }
    callView(elementClone, module, i)
    // circular references will throw an exception
    // such as setting to a dom element
    cache[i] = JSON.stringify(args[0])

    render.setupWatch(WatchJS, args, fill, elementClone, i, module)

    fill.fill(elementClone, args[0])
    render.callConfigs(fill.configs)

    // call onload if present in all controllers
    render.callOnload(module)
    return true
  }
  var prevId
  //render.doWatch = function(fill, ele, i, module, frameId, prop, action, difference, oldvalue) {
  render.doWatch = function(fill, ele, i, module, changes, frameId) {

    if (frameId == prevId) return
    prevId = frameId
    mag.running = true

    var args = module.getArgs(i)

    // check if data changed
    if (cache[i] && cache[i] === JSON.stringify(args[0])) {
      return
    }
    callView(ele, module, i)
    cache[i] = JSON.stringify(args[0])

    fill.fill(ele, args[0])

    render.callConfigs(fill.configs)

    mag.running = false
  }

  render.setupWatch = function(WatchJS, args, fill, elementClone, i, module) {
    // WatchJS.watch(args[0], debounce(render.doWatch.bind(null, fill, elementClone, i, module)), 6, true)
    // return
    //this.fun = (this.fun || debounce(render.doWatch.bind(null, fill, elementClone, i, module)))

    // Which we then observe
    observeNested(args[0], function(changes) {
      // changes.forEach(function(change) {
      //console.log(change.type, change.name, change.oldValue);
      //});
      debounce(render.doWatch.bind(null, fill, elementClone, i, module, changes))()
    });
  }
  var $cancelAnimationFrame = window.cancelAnimationFrame || window.clearTimeout;
  var $requestAnimationFrame = window.requestAnimationFrame || window.setTimeout;

  var debounce = function(fn, threshhold) {
    var lastRedrawCallTime, FRAME_BUDGET = threshhold || 16,
      deferTimer
    return function() {
      if (+new Date - lastRedrawCallTime > FRAME_BUDGET || $requestAnimationFrame === window.requestAnimationFrame) {
        // hold on to it
        if (deferTimer > 0) $cancelAnimationFrame(deferTimer)
        var args = arguments
        deferTimer = $requestAnimationFrame(function() {
          lastRedrawCallTime = +new Date
          var nargs = [].slice.call(arguments).concat([].slice.call(args))
          fn.apply(this, nargs);
        }, FRAME_BUDGET)
      } else {
        lastRedrawCallTime = +new Date
        var nargs = [].slice.call(arguments).concat([].slice.call(args))
        fn.apply(this, nargs)
        deferTimer = $requestAnimationFrame(function() {
          deferTimer = null
        }, FRAME_BUDGET)
      }
    }
  }

  mag.render = render

  function observeNested(obj, callback) {
    if (obj && typeof Object.observe !== 'undefined') {
      Object.observe(obj, function(changes) {
        changes.forEach(function(change) {
          if (typeof obj[change.name] == 'object') {
            observeNested(obj[change.name], callback);
          }
        });
        callback.apply(this, arguments);
      });
    }
  }

})(window.mag || {})
<commit_msg>Update render.js<commit_after>;
(function(mag) {

  "use strict";

  var render = {
    roots: [],
    contexts: [],
    templates: {},
    cache: {}
  }

  var unloaders = [],
    cached = [],
    pendingRequests = 0

    function callView(elementClone, module, i) {
      var args = module.getArgs(i)

      var mod = module.modules[i]
      var controller = module.controllers[i]

      // var controllerConstructor = mod.controller.$original || mod.controller
      // var controller = controllerConstructor === cached.controllerConstructor ? cached.controller : new(mod.controller || function() {})
      // give it unfrozen context ?

      var context = render.contexts[i] = render.contexts[i] || {}

      try {
        mod.view(controller, elementClone, context)
      } catch (e) {
        //THROW ?
        console.log(elementClone.id, i)
        throw new Error(e)
      }
      // if (controller.onunload) unloaders.push({
      //   controller: controller,
      //   handler: controller.onunload
      // })
    }

  render.callOnload = function(module) {
    for (var i = 0, controller; controller = module.controllers[i]; i++) {
      // call once
      if (controller.onload && !controller.called) {
        controller.onload.call(null, module.elements[i])
        controller.called = 1
      }
    }
  }
  render.callConfigs = function(configs) {
    for (var i = 0, len = configs.length; i < len; i++) configs[i]()
  }
  var cache = []
  render.redraw = function(module, fill, WatchJS) {

    module = module || render.module || {}

    this.fun = (this.fun || debounce(function(id) {
      // clear existing configs
      fill.configs.splice(0, fill.configs.length)

      render.doLoop(module, fill, WatchJS)
    }))
    this.fun()
  }

  render.doLoop = function(module, fill, WatchJS) {
    for (var i = 0, root; root = render.roots[i]; i++) {
      mag.running = true

      if (module.controllers[i]) {
        if (!render.innerLoop(module, fill, i, WatchJS)) {
          //cached
        } else {
          module.deferreds[i][2]({
            _html: module.elements[i].innerHTML
          })
          //TODO: remove clones
          if (module.deferreds[i][0]) {
            var index = module.deferreds[i][1]
            delete module.elements[index],
              module.modules[index], module.controllers[index], module.promises[index], module.deferreds[index]
          }
        }
      }
    }
    fill.unclear()
  }

  render.clear = function(index, elementId, fill) {
    if (index !== -1 && cache[index]) {
      // clear events too
      fill.clear()
      //console.log('clear called on reload', elementId)
      // delete cache[index]
    }
  }
  render.innerLoop = function(module, fill, i, WatchJS) {
    var elementClone = module.elements[i]
    var args = module.getArgs(i)

    if (cache[i] && cache[i] === JSON.stringify(args[0])) {
      return false
    }
    callView(elementClone, module, i)
    // circular references will throw an exception
    // such as setting to a dom element
    cache[i] = JSON.stringify(args[0])

    render.setupWatch(WatchJS, args, fill, elementClone, i, module)

    fill.fill(elementClone, args[0])
    render.callConfigs(fill.configs)

    // call onload if present in all controllers
    render.callOnload(module)
    return true
  }
  var prevId
  //render.doWatch = function(fill, ele, i, module, frameId, prop, action, difference, oldvalue) {
  render.doWatch = function(fill, ele, i, module, changes, frameId) {

    if (frameId == prevId) return
    prevId = frameId
    mag.running = true

    var args = module.getArgs(i)

    // check if data changed
    if (cache[i] && cache[i] === JSON.stringify(args[0])) {
      return
    }
    callView(ele, module, i)
    cache[i] = JSON.stringify(args[0])

    fill.fill(ele, args[0])

    render.callConfigs(fill.configs)

    mag.running = false
  }

  render.setupWatch = function(WatchJS, args, fill, elementClone, i, module) {
    // WatchJS.watch(args[0], debounce(render.doWatch.bind(null, fill, elementClone, i, module)), 6, true)
    // return
    //this.fun = (this.fun || debounce(render.doWatch.bind(null, fill, elementClone, i, module)))

    // Which we then observe
    observeNested(args[0], function(changes) {
      // changes.forEach(function(change) {
      //console.log(change.type, change.name, change.oldValue);
      //});
      debounce(render.doWatch.bind(null, fill, elementClone, i, module, changes))()
    });
  }
  var $cancelAnimationFrame = window.cancelAnimationFrame || window.clearTimeout;
  var $requestAnimationFrame = window.requestAnimationFrame || window.setTimeout;

  var debounce = function(fn, threshhold) {
    var lastRedrawCallTime, FRAME_BUDGET = threshhold || 16,
      deferTimer
    return function() {
      if (+new Date - lastRedrawCallTime > FRAME_BUDGET || $requestAnimationFrame === window.requestAnimationFrame) {
        // hold on to it
        if (deferTimer > 0) $cancelAnimationFrame(deferTimer)
        var args = arguments
        deferTimer = $requestAnimationFrame(function() {
          lastRedrawCallTime = +new Date
          var nargs = [].slice.call(arguments).concat([].slice.call(args))
          fn.apply(this, nargs);
        }, FRAME_BUDGET)
      } else {
        lastRedrawCallTime = +new Date
        var nargs = [].slice.call(arguments).concat([].slice.call(args))
        fn.apply(this, nargs)
        deferTimer = $requestAnimationFrame(function() {
          deferTimer = null
        }, FRAME_BUDGET)
      }
    }
  }

  mag.render = render

  function observeNested(obj, callback) {
    if (obj && typeof Object.observe !== 'undefined') {
      Object.observe(obj, function(changes) {
        changes.forEach(function(change) {
          if (typeof obj[change.name] == 'object') {
            observeNested(obj[change.name], callback);
          }
        });
        callback.apply(this, arguments);
      });
    }
  }

})(window.mag || {})
<|endoftext|>


<commit_before>//@flow

import React from 'react'
import ReactDOM from 'react-dom'

import Debug from './components/Debug'
import Nav from './components/Nav'
import Footer from './components/Footer'
import NotFound from './components/NotFound'
import TldrPage from './components/TldrPage'
import Welcome from './components/Welcome'

import type { History } from 'history'
import type { State } from './Tldr'

let navigate = (history: History) => (path: string) =>
  history.push({...history.getCurrentLocation(),
               pathname: `/${path.toLowerCase().trim().replace(' ','-')}`})

const Oops = () => (

 Holy! Page not found!

 Something has gone terribly wrong.

)

const Loading = () => (

 Loading...

)

export default (props: State) => {
  let {found, page, params: {debug, command, history}} = props
  try {
    ReactDOM.render((

        { !command.name && <Welcome /> }
        { command.name && found === undefined && <Loading /> }
        { command.name && found === false     && <NotFound /> }
        { found && page && !page.error && <TldrPage {...page} /> }
        { found && page &&  page.error && <Oops /> }
        { debug && <Debug {...props} /> }

    ), document.getElementById('tldr'))
  } catch (e) {
    console.log(e)
  }
}
<commit_msg>Glue the whole thing together<commit_after>//@flow

import React from 'react'
import ReactDOM from 'react-dom'

import Debug from './components/Debug'
import Nav from './components/Nav'
import Footer from './components/Footer'
import NotFound from './components/NotFound'
import TldrPage from './components/TldrPage'
import Welcome from './components/Welcome'

import type { History } from 'history'
import type { State } from './Tldr'

let navigate = (history: History) => (path: string) =>
  history.push({...history.getCurrentLocation(),
               pathname: `/${path.toLowerCase().trim().replace(' ','-')}`})

const Oops = () => (

 Holy! Page not found!

 Something has gone terribly wrong.

)

const Loading = () => (

 Loading...

)

export default (props: State) => {
  let {found, page, params: {_, debug, command, history}} = props
  try {
    ReactDOM.render((

        { !command.name && <Welcome /> }
        { command.name && found === undefined && <Loading /> }
        { command.name && found === false     && <NotFound /> }
        { found && page && !page.error && <TldrPage {...page} /> }
        { found && page &&  page.error && <Oops /> }
        { debug && <Debug {...props} /> }

    ), document.getElementById('tldr'))
  } catch (e) {
    console.log(e)
  }
}
<|endoftext|>


<commit_before>import find from 'lodash/find'
import merge from 'lodash/merge'
import each from 'lodash/each'

import events from './store/module/events'

/**
 * Includes language in the route
 * @param  {Object} route
 * @return {Object}
 */
export const localize = (route, urlPrefix) => {
  let originalRouteParams = route.params || {}

  /**
   * It's not possible to push/replace a route with the readonly property `path`
   * so it's necessary to copy the route in a new object first and then delete
   * the property
   */
  let routeCopy = { ...route }
  delete routeCopy.path

  return merge(routeCopy, {
    params: {
      ...originalRouteParams,
      lang: urlPrefix
    }
  })
}

/**
 * Update URL prefix
 * @param  {VueRouter} router
 * @param  {String} urlPrefix
 */
export const updateURLPrefix = (router, urlPrefix) => {
  const { currentRoute } = router

  if (router && currentRoute) {
    router.replace(localize(currentRoute, urlPrefix))
  }
}

const detectedURLPrefixExists = (urlPrefix, languages) => {
  return find(languages, { urlPrefix })
}

/**
 * Applies specific functionalities to handle language redirects and URL prefixing.
 * The application will be able to add the language urlPrefix property in its URL and
 * change the application language based on that specific parameter.
 * If that prefix is not valid or it doesn't exist, the application will fallback
 * to the default language.
 * VueRouter instance is required to unlock this feature.
 */
export const registerRouter = (router, store) => {
  if (!router) {
    return
  }

  let initialUrlPrefix = store.getters.currentLanguage.urlPrefix
  const currentUrlPrefix = router.currentRoute.params.lang
  const detectedURLPrefix = detectedURLPrefixExists(currentUrlPrefix, store.getters.languages)

  /**
   * Sometimes there's no way that we have and end-point where we receive the default code
   * every time the application changes it, so we can enable the trustURL property to always
   * trust the URL parameter and dispatch again the language mutation.
   */
  if (detectedURLPrefix && store.getters.trustURL) {
    initialUrlPrefix = detectedURLPrefix.urlPrefix
    store.dispatch(events.SET_LANGUAGE, initialUrlPrefix)
  }

  // First time the router is registered, the route needs to be synced with the current language
  updateURLPrefix(router, initialUrlPrefix)

  router.beforeEach((to, from, next) => {
    const { availableLanguages, currentLanguage, forceTranslation, languages } = store.getters
    const urlPrefix = to.params.lang
    const languageList = forceTranslation ? languages : availableLanguages
    const urlLanguage = find(languageList, { urlPrefix })
    /**
     * In case the language is not provided or doesn't exists,
     * the default language will be used.
     * This will only be fired on landing, because most of the time
     * the URL doesn't contain a language prefix or the user typed
     * a different language on purpose and we need to check it.
     */
    if (!urlLanguage || !from.name) {
      return next(localize(to, currentLanguage.urlPrefix))
    }

    /**
     * Check if the detected language in the URL is also the current
     * translated language, otherwise it needs to be updated.
     * Browser language has prioriry over the store state
     */
    const isDiff = urlLanguage && urlLanguage.urlPrefix !== currentLanguage.urlPrefix

    if (isDiff) {
      return store.dispatch(events.SET_LANGUAGE, urlLanguage.code).then(() => next())
    }

    next()
  })
}

/**
 * Route parser takes the current routes object before is injected in the VueRouter instance
 * and it returns the necessary tree structure to enable language prefixing
 * @param  {Array<Object>} routes
 * @param  {String} [defaultCode='en'] - language redirect
 * @return {Array<Object>}
 */
export const routeParser = (routes, defaultCode = 'en') => {
  each(routes, route => {
    const { path } = route
    route.path = `/:lang${path}`
  })

  return [
    ...routes,
    {
      path: '/*',
      name: 'redirect',
      redirect: {
        path: `/${defaultCode}`
      }
    }
  ]
}

export default function (Vue, router, store) {
  Vue.prototype.$localize = (route) => {
    return localize(route, store.getters.currentLanguage.urlPrefix)
  }
}
<commit_msg>fix(localize): add path to the new route<commit_after>import find from 'lodash/find'
import merge from 'lodash/merge'
import each from 'lodash/each'

import events from './store/module/events'

/**
 * Includes language in the route
 * @param  {Object} route
 * @return {Object}
 */
export const localize = (route, urlPrefix) => {
  let originalRouteParams = route.params || {}

  let routeCopy = { ...route }

  // Fixes issue #12
  // https://github.com/MatteoGabriele/vue-i18n-manager/issues/12
  const path = routeCopy.path

  delete routeCopy.path

  return merge(routeCopy, {
    path,
    params: {
      ...originalRouteParams,
      lang: urlPrefix
    }
  })
}

/**
 * Update URL prefix
 * @param  {VueRouter} router
 * @param  {String} urlPrefix
 */
export const updateURLPrefix = (router, urlPrefix) => {
  const { currentRoute } = router

  if (router && currentRoute) {
    router.replace(localize(currentRoute, urlPrefix))
  }
}

const detectedURLPrefixExists = (urlPrefix, languages) => {
  return find(languages, { urlPrefix })
}

/**
 * Applies specific functionalities to handle language redirects and URL prefixing.
 * The application will be able to add the language urlPrefix property in its URL and
 * change the application language based on that specific parameter.
 * If that prefix is not valid or it doesn't exist, the application will fallback
 * to the default language.
 * VueRouter instance is required to unlock this feature.
 */
export const registerRouter = (router, store) => {
  if (!router) {
    return
  }

  let initialUrlPrefix = store.getters.currentLanguage.urlPrefix
  const currentUrlPrefix = router.currentRoute.params.lang
  const detectedURLPrefix = detectedURLPrefixExists(currentUrlPrefix, store.getters.languages)

  /**
   * Sometimes there's no way that we have and end-point where we receive the default code
   * every time the application changes it, so we can enable the trustURL property to always
   * trust the URL parameter and dispatch again the language mutation.
   */
  if (detectedURLPrefix && store.getters.trustURL) {
    initialUrlPrefix = detectedURLPrefix.urlPrefix
    store.dispatch(events.SET_LANGUAGE, initialUrlPrefix)
  }

  // First time the router is registered, the route needs to be synced with the current language
  updateURLPrefix(router, initialUrlPrefix)

  router.beforeEach((to, from, next) => {
    const { availableLanguages, currentLanguage, forceTranslation, languages } = store.getters
    const urlPrefix = to.params.lang
    const languageList = forceTranslation ? languages : availableLanguages
    const urlLanguage = find(languageList, { urlPrefix })
    /**
     * In case the language is not provided or doesn't exists,
     * the default language will be used.
     * This will only be fired on landing, because most of the time
     * the URL doesn't contain a language prefix or the user typed
     * a different language on purpose and we need to check it.
     */
    if (!urlLanguage || !from.name) {
      return next(localize(to, currentLanguage.urlPrefix))
    }

    /**
     * Check if the detected language in the URL is also the current
     * translated language, otherwise it needs to be updated.
     * Browser language has prioriry over the store state
     */
    const isDiff = urlLanguage && urlLanguage.urlPrefix !== currentLanguage.urlPrefix

    if (isDiff) {
      return store.dispatch(events.SET_LANGUAGE, urlLanguage.code).then(() => next())
    }

    next()
  })
}

/**
 * Route parser takes the current routes object before is injected in the VueRouter instance
 * and it returns the necessary tree structure to enable language prefixing
 * @param  {Array<Object>} routes
 * @param  {String} [defaultCode='en'] - language redirect
 * @return {Array<Object>}
 */
export const routeParser = (routes, defaultCode = 'en') => {
  each(routes, route => {
    const { path } = route
    route.path = `/:lang${path}`
  })

  return [
    ...routes,
    {
      path: '/*',
      name: 'redirect',
      redirect: {
        path: `/${defaultCode}`
      }
    }
  ]
}

export default function (Vue, router, store) {
  Vue.prototype.$localize = (route) => {
    return localize(route, store.getters.currentLanguage.urlPrefix)
  }
}
<|endoftext|>


<commit_before>var router = require('express').Router()
  , ArduinoCompiler = require('./make')
  , ProjectManager = require('borgnix-project-manager/lib/project-manager')
  , path = require('path')
  // , boards = require('./lib/board')
  , fs = require('fs-extra')
  , walk = require('walk')
  , unzip = require('unzip')
  , _ = require('underscore')

var compiler, pm, boards = require('../data/boards.json')

router.post('/compile', async function(req, res) {
  // console.log(req.body)
  var info = {
    owner: req.session.user.uid
  , type: req.body.type
  , name: req.body.name
  }
  try {
    var sketch = await pm.findProject(info)
    compiler.compile(sketch, req.body.board, function(err, stdout, stderr) {
      var memoryUsage = stdout.slice(stdout.lastIndexOf('AVR Memory Usage'))
      res.json({
        status: err ? 1 : 0
      , content: {
          error: err
        , stdout: memoryUsage
        , stderr: stderr
        }
      })
    })
  } catch (e) {
    res.json({status: 1, content: e.toString()})
  }
})

router.get('/boards', function(req, res) {
  // res.json(Object.keys(boards.data()))
  res.json(boards)
})

router.get('/hex/:filename', async function(req, res) {
  var info = {
    owner: req.session.user.uid
  , type: req.body.type
  , name: req.body.name
  }
  try {
    var sketch = await pm.findProject(info)
      , hexFile = path.join(
          sketch.dir
        , 'build-' + (req.query.board || 'uno')
        , req.params.filename
        )
    if (fs.existsSync(hexFile)) {
      res.sendFile(hexFile)
    } else {
      res.json({status: 1, content: 'Hex Not Found'})
    }
  } catch (e) {
    res.json({status: 1, content: 'Hex Not Found'})
  }
})

router.post('/upload-zip-lib', function(req, res) {
  _.map(req.files, function(file, key) {
    // console.log(file)
    if (file.extension !== 'zip') return null
    var outPath = path.join(
      pm.root, req.session.user.uid
    , 'arduino/libraries'
    , path.basename(file.originalname, '.zip')
    )
    fs.createReadStream(file.path).pipe(unzip.Extract({
      path: outPath
    }))
  })
  res.json({
    status: 0
  })
})

router.get('/libs', function(req, res) {
  var userLibPath = path.join( pm.root, req.session.user.uid
                             , 'arduino/libraries')
    , ideLibPath = path.join(compiler.arduinoDir, 'libraries')
    , avrLibPath = path.join( compiler.arduinoDir
                            , 'hardware/arduino/avr/libraries')

  try {
    var userLibs = getLibs(userLibPath, 'user')
    var ideLibs = getLibs(ideLibPath, 'ide')
    var avrLibs = getLibs(avrLibPath, 'ide')
    res.json({
      status: 0,
      content: {
        userLibs: userLibs,
        ideLibs: ideLibs.concat(avrLibs)
      }
    })
  } catch (e) {
    res.json({
      status: 1,
      content: e
    })
  }
})

function getLibs(libPath, type) {

  var libs = []
  fs.readdirSync(libPath).map(function(file) {
    var fullPath = path.join(libPath, file)
    var stat = fs.lstatSync(fullPath)

    var lib = {
      name: file,
      headers: []
    }
    if (type === 'ide') {
      lib.type = 'ide'
    } else if (stat.isSymbolicLink()) {
      lib.type = 'public'
    } else if (stat.isDirectory()) {
      lib.type = 'private'
    } else {
      return null
    }

    var opt = {
      followLinks: true,
      listeners: {
        file: function(root, stat, next) {
          // console.log(path.extname(stat.name), root)
          if (path.relative(fullPath, root).indexOf('example') != -1)
            return next()
          if (path.extname(stat.name) === '.h') {
            var header = path.join(path.relative(fullPath, root), stat.name)
            if (header.indexOf('src/') === 0)
              header = header.slice(4)
            if (header.indexOf('extras/') === 0)
              return next()
            lib.headers.push(header)
          }
          next()
        },
        error: function() {
          console.error('walking error')
          throw new Error('walking error')
        },
        end: function() {
          libs.push(lib)
        }
      }
    }
    var walker = walk.walkSync(fullPath, opt)

  })
  return libs
}

module.exports = function(config) {
  var opt = {}
  if (config.projectRoot)
    opt.root = config.projectRoot
  else
    throw new Error('config.projectRoot is missing')

  if (config.arduinoLibs)
    opt.arduinoLibs = config.arduinoLibs
  else
    throw new Error('config.arduinoLibs is missing')

  pm = new ProjectManager({
    projectDir: config.projectRoot
  , tplDir: path.join(__dirname, '../project-tpl')
  , store: config.store
  })

  compiler = new ArduinoCompiler(config)

  return router
}
<commit_msg>add debug<commit_after>var router = require('express').Router()
  , ArduinoCompiler = require('./make')
  , ProjectManager = require('borgnix-project-manager/lib/project-manager')
  , path = require('path')
  // , boards = require('./lib/board')
  , fs = require('fs-extra')
  , walk = require('walk')
  , unzip = require('unzip')
  , _ = require('underscore')

var compiler, pm, boards = require('../data/boards.json')

router.post('/compile', async function(req, res) {
  // console.log(req.body)
  var info = {
    owner: req.session.user.uid
  , type: req.body.type
  , name: req.body.name
  }
  try {
    var sketch = await pm.findProject(info)
    compiler.compile(sketch, req.body.board, function(err, stdout, stderr) {
      var memoryUsage = stdout.slice(stdout.lastIndexOf('AVR Memory Usage'))
      res.json({
        status: err ? 1 : 0
      , content: {
          error: err
        , stdout: memoryUsage
        , stderr: stderr
        }
      })
    })
  } catch (e) {
    res.json({status: 1, content: e.toString()})
  }
})

router.get('/boards', function(req, res) {
  // res.json(Object.keys(boards.data()))
  res.json(boards)
})

router.get('/hex/:filename', async function(req, res) {
  var info = {
    owner: req.session.user.uid
  , type: req.body.type
  , name: req.body.name
  }
  try {
    var sketch = await pm.findProject(info)
      , hexFile = path.join(
          sketch.dir
        , 'build-' + (req.query.board || 'uno')
        , req.params.filename
        )
    if (fs.existsSync(hexFile)) {
      res.sendFile(hexFile)
    } else {
      res.json({status: 1, content: 'Hex Not Found'})
    }
  } catch (e) {
    res.json({status: 1, content: 'Hex Not Found'})
  }
})

router.post('/upload-zip-lib', function(req, res) {
  _.map(req.files, function(file, key) {
    // console.log(file)
    if (file.extension !== 'zip') return null
    var outPath = path.join(
      pm.root, req.session.user.uid
    , 'arduino/libraries'
    , path.basename(file.originalname, '.zip')
    )
    fs.createReadStream(file.path).pipe(unzip.Extract({
      path: outPath
    }))
  })
  res.json({
    status: 0
  })
})

router.get('/libs', function(req, res) {
  var userLibPath = path.join( pm.root, req.session.user.uid
                             , 'arduino/libraries')
  console.log(userLibPath)
  var ideLibPath = path.join(compiler.arduinoDir, 'libraries')
  console.log(ideLibPath)
  var avrLibPath = path.join( compiler.arduinoDir
                            , 'hardware/arduino/avr/libraries')
  console.log(avrLibPath)

  try {
    var userLibs = getLibs(userLibPath, 'user')
    var ideLibs = getLibs(ideLibPath, 'ide')
    var avrLibs = getLibs(avrLibPath, 'ide')
    res.json({
      status: 0,
      content: {
        userLibs: userLibs,
        ideLibs: ideLibs.concat(avrLibs)
      }
    })
  } catch (e) {
    res.json({
      status: 1,
      content: e
    })
  }
})

function getLibs(libPath, type) {

  var libs = []
  fs.readdirSync(libPath).map(function(file) {
    var fullPath = path.join(libPath, file)
    var stat = fs.lstatSync(fullPath)

    var lib = {
      name: file,
      headers: []
    }
    if (type === 'ide') {
      lib.type = 'ide'
    } else if (stat.isSymbolicLink()) {
      lib.type = 'public'
    } else if (stat.isDirectory()) {
      lib.type = 'private'
    } else {
      return null
    }

    var opt = {
      followLinks: true,
      listeners: {
        file: function(root, stat, next) {
          // console.log(path.extname(stat.name), root)
          if (path.relative(fullPath, root).indexOf('example') != -1)
            return next()
          if (path.extname(stat.name) === '.h') {
            var header = path.join(path.relative(fullPath, root), stat.name)
            if (header.indexOf('src/') === 0)
              header = header.slice(4)
            if (header.indexOf('extras/') === 0)
              return next()
            lib.headers.push(header)
          }
          next()
        },
        error: function() {
          console.error('walking error')
          throw new Error('walking error')
        },
        end: function() {
          libs.push(lib)
        }
      }
    }
    var walker = walk.walkSync(fullPath, opt)

  })
  return libs
}

module.exports = function(config) {
  var opt = {}
  if (config.projectRoot)
    opt.root = config.projectRoot
  else
    throw new Error('config.projectRoot is missing')

  if (config.arduinoLibs)
    opt.arduinoLibs = config.arduinoLibs
  else
    throw new Error('config.arduinoLibs is missing')

  pm = new ProjectManager({
    projectDir: config.projectRoot
  , tplDir: path.join(__dirname, '../project-tpl')
  , store: config.store
  })

  compiler = new ArduinoCompiler(config)

  return router
}
<|endoftext|>


<commit_before>module.exports = [
  {
    method: 'GET',
    path: '/',
    handler: (request, reply) => {
      var data = {
        isWelcome: true,
        next: '/avatar'
      };
      reply.view('welcome', data);
    }
  },
  {
    method: 'GET',
    path: '/avatar',
    handler: (request, reply) => {
      var data = {
        isAvatar: true,
        prev: '/',
        next: '/introduction'
       };
      reply.view('choose-an-avatar', data);
    }
  },
  {
    method: 'GET',
    path: '/introduction',
    handler: (request, reply) => {
      var data =  {
        prev: '/avatar',
        next: '/eating'
      };
      reply.view('introduction', data);
    }
  },
  {
    method: 'GET',
    path: '/eating',
    handler: (request, reply) => {
      var data =  {
        prev: '/introduction',
        next: '/feelings'
      };
      reply.view('eating', data);
    }
  },
  {
    method: 'GET',
    path: '/feelings',
    handler: (request, reply) => {
      var data =  {
        prev: '/eating',
        next: '/personality'
      };
      reply.view('feelings', data);
    }
  },
  {
    method: 'GET',
    path: '/personality',
    handler: (request, reply) => {
      var data =  {
        prev: '/feelings',
        next: '/hobbies'
      };
      reply.view('personality', data);
    }
  },
  {
    method: 'GET',
    path: '/hobbies',
    handler: (request, reply) => {
      var data =  {
        prev: '/personality',
        next: '/sleep'
      };
      reply.view('hobbies', data);
    }
  },
  {
    method: 'GET',
    path: '/sleep',
    handler: (request, reply) => {
      var data =  {
        prev: '/hobbies',
        next: '/friends'
      };
      reply.view('sleep', data);
    }
  },
  {
    method: 'GET',
    path: '/friends',
    handler: (request, reply) => {
      var data =  {
        prev: '/sleep',
        next: '/school'
      };
      reply.view('friends', data);
    }
  },
  {
    method: 'GET',
    path: '/school',
    handler: (request, reply) => {
      var data =  {
        prev: '/fiends',
        next: '/finished'
      };
      reply.view('school', data);
    }
  },
  {
    method: 'GET',
    path: '/finished',
    handler: (request, reply) => {
      var data =  {
        isEnd: true,
        prev: '/school'
      };
      reply.view('finished', data);
    }
  },
  {
    method: 'GET',
    path: '/{file*}',
    handler: {
      directory: {
        path: 'public'
      }
    }
  },
  {
    method: 'GET',
    path: '/public/jquery.min.js',
    handler: {
      file: {
        path: 'node_modules/jquery/dist/jquery.min.js'
      }
    }
  },
  {
    method: 'GET',
    path: '/public/materialize/{file*}',
    handler: {
      directory: {
        path: 'node_modules/materialize-css/dist'
      }
    }
  }
];
<commit_msg>Fix routing for school page<commit_after>module.exports = [
  {
    method: 'GET',
    path: '/',
    handler: (request, reply) => {
      var data = {
        isWelcome: true,
        next: '/avatar'
      };
      reply.view('welcome', data);
    }
  },
  {
    method: 'GET',
    path: '/avatar',
    handler: (request, reply) => {
      var data = {
        isAvatar: true,
        prev: '/',
        next: '/introduction'
       };
      reply.view('choose-an-avatar', data);
    }
  },
  {
    method: 'GET',
    path: '/introduction',
    handler: (request, reply) => {
      var data =  {
        prev: '/avatar',
        next: '/eating'
      };
      reply.view('introduction', data);
    }
  },
  {
    method: 'GET',
    path: '/eating',
    handler: (request, reply) => {
      var data =  {
        prev: '/introduction',
        next: '/feelings'
      };
      reply.view('eating', data);
    }
  },
  {
    method: 'GET',
    path: '/feelings',
    handler: (request, reply) => {
      var data =  {
        prev: '/eating',
        next: '/personality'
      };
      reply.view('feelings', data);
    }
  },
  {
    method: 'GET',
    path: '/personality',
    handler: (request, reply) => {
      var data =  {
        prev: '/feelings',
        next: '/hobbies'
      };
      reply.view('personality', data);
    }
  },
  {
    method: 'GET',
    path: '/hobbies',
    handler: (request, reply) => {
      var data =  {
        prev: '/personality',
        next: '/sleep'
      };
      reply.view('hobbies', data);
    }
  },
  {
    method: 'GET',
    path: '/sleep',
    handler: (request, reply) => {
      var data =  {
        prev: '/hobbies',
        next: '/friends'
      };
      reply.view('sleep', data);
    }
  },
  {
    method: 'GET',
    path: '/friends',
    handler: (request, reply) => {
      var data =  {
        prev: '/sleep',
        next: '/school'
      };
      reply.view('friends', data);
    }
  },
  {
    method: 'GET',
    path: '/school',
    handler: (request, reply) => {
      var data =  {
        prev: '/friends',
        next: '/finished'
      };
      reply.view('school', data);
    }
  },
  {
    method: 'GET',
    path: '/finished',
    handler: (request, reply) => {
      var data =  {
        isEnd: true,
        prev: '/school'
      };
      reply.view('finished', data);
    }
  },
  {
    method: 'GET',
    path: '/{file*}',
    handler: {
      directory: {
        path: 'public'
      }
    }
  },
  {
    method: 'GET',
    path: '/public/jquery.min.js',
    handler: {
      file: {
        path: 'node_modules/jquery/dist/jquery.min.js'
      }
    }
  },
  {
    method: 'GET',
    path: '/public/materialize/{file*}',
    handler: {
      directory: {
        path: 'node_modules/materialize-css/dist'
      }
    }
  }
];
<|endoftext|>


<commit_before>import App         from './containers/App';
import HomePage    from './containers/HomePage';
import WelcomePage from './containers/WelcomePage';

export default function getRoutes(store) {

  return {
    component: App,
    onEnter: App.onEnter(store),

    childRoutes: [
      {
        path: '/',
        component: HomePage,
        onEnter: HomePage.onEnter(store)
      },

      {
        path: '/welcome',
        component: WelcomePage
      }
    ]
  };
}
<commit_msg>a nice way displaying routes<commit_after>import React   from 'react';
import {Route} from 'react-router';

import App         from './containers/App';
import HomePage    from './containers/HomePage';
import WelcomePage from './containers/WelcomePage';

export default function getRoutes(store) {

  return (
    <Route component={App} onEnter={App.onEnter(store)}>
      <Route path='/'       component={HomePage} onEnter={HomePage.onEnter(store)}/>
      <Route path='welcome' component={WelcomePage}/>
    </Route>
  );
}
<|endoftext|>


<commit_before>import Home from 'components/Home/home';
import User from 'components/User/user';
import Login from 'components/Login/login';
import NotFound from 'components/NotFound/notFound';

import auth from 'helpers/auth';

import { PubSub } from 'src/main';

// wait until auth is up and running
function authGate(to, from, next){
  // start by showing ye olde loader
  PubSub.$emit('toggleLoader', true);
  // check auth module state
  if (auth.state.initialized) {
    routeGuard(to, from, next);
  } else {
    // we need to wait until it gets its act together before we move on
    PubSub.$once('authStateChanged', function(){
      routeGuard(to, from, next);
    });
  }
}

// restricts access for unauthd users, handles redirects
function routeGuard(to, from, next) {
  console.log('guard');
  if (to.matched.some(record => record.meta.requiresAuth)) {
    // this route requires auth, check if logged in
    // if not, redirect to login page.
    if (!auth.state.loggedIn) {
      next({
        path: '/login'
      });
      PubSub.$emit('toggleLoader', false);
    } else {
      next();
      PubSub.$emit('toggleLoader', false);
    }
  } else {
    next();
    PubSub.$emit('toggleLoader', false);
  }
}

// handles /login stuff
function handleAuth(to, from, next) {
  if (!auth.state.loggedIn) {
    auth.checkRedirect(next, next);
  } else {
    // if already logged in go to user page instead
    next({
      path: '/user'
    });
  }
}

const routes = [
  {
    path: '/',
    component: Home,
    meta: { requiresAuth: true }
  },
  {
    path: '/login',
    component: Login,
    beforeEnter: handleAuth,
  },
  {
    path: '/user',
    component: User,
    meta: { requiresAuth: true }
  },
  {
    path: '*',
    component: NotFound
  }
];

export { routes, authGate };
<commit_msg>routeGuard cleanup<commit_after>import Home from 'components/Home/home';
import User from 'components/User/user';
import Login from 'components/Login/login';
import NotFound from 'components/NotFound/notFound';

import auth from 'helpers/auth';

import { PubSub } from 'src/main';

// wait until auth is up and running
function authGate(to, from, next){
  // start by showing ye olde loader
  PubSub.$emit('toggleLoader', true);
  // check auth module state
  if (auth.state.initialized) {
    routeGuard(to, from, next);
  } else {
    // we need to wait until it gets its act together before we move on
    PubSub.$once('authStateChanged', function(){
      routeGuard(to, from, next);
    });
  }
}

// restricts access for unauthd users
function routeGuard(to, from, next) {
  // check if route requires authorization, and if user is authd
  if (to.matched.some(record => record.meta.requiresAuth) && !auth.state.loggedIn) {
    // yep and nope, redirect to login
    next({
      path: '/login'
    });
    PubSub.$emit('toggleLoader', false);
  } else {
    // can proceed
    next();
    PubSub.$emit('toggleLoader', false);
  }
}

// handles /login stuff
function handleAuth(to, from, next) {
  if (!auth.state.loggedIn) {
    auth.checkRedirect(next, next);
  } else {
    // if already logged in go to user page instead
    next({
      path: '/user'
    });
  }
}

const routes = [
  {
    path: '/',
    component: Home,
    meta: { requiresAuth: true }
  },
  {
    path: '/login',
    component: Login,
    beforeEnter: handleAuth,
  },
  {
    path: '/user',
    component: User,
    meta: { requiresAuth: true }
  },
  {
    path: '*',
    component: NotFound
  }
];

export { routes, authGate };
<|endoftext|>


<commit_before>'use strict'

const bot = require('./lib/bot')
const Logger = require('./lib/logger')

class Routes {

  static makeRoutes(app) {

    const get = (req, res)  => {
      return bot._verify(req, res)
    }

    const post = (req, res)  => {
      Logger.log('info', JSON.stringify(req.body))
      bot._handleMessage(req.body)
      res.send('ok')
    }

    app.get('/', get)
    app.post('/', post)
  }
}

module.exports = Routes
<commit_msg>update comments<commit_after>'use strict'

const bot = require('./lib/bot')
const Logger = require('./lib/logger')

class Routes {

  static makeRoutes(app) {

    const get = (req, res)  => {
      return bot._verify(req, res)
    }

    const post = (req, res)  => {
      Logger.log('info', JSON.stringify(req.body))
      bot._handleMessage(req.body)

      // Facebook requires an immediate 200 OK response
      res.send('ok')
    }

    app.get('/', get)
    app.post('/', post)
  }
}

module.exports = Routes
<|endoftext|>


<commit_before>var Emitter = require('events').EventEmitter;
var util = require('util');
var spawn = require('child_process').spawn;
var exec = require('child_process').exec;
var fs = require('fs-extra');
var path = require('path');
var uuid = require('node-uuid').v1;
var readline = require('readline');
var chalk = require('chalk');
var _ = require('underscore');

// Will parse the log file.
// type [1] [TYPE]
// date [2] and time [3] (1234/12/12 hh:mm:ss)
// message [4] ...
var regexLog = /^\[([^\]]*)\]\(([^\)]*) ([^\)]*)\):([^\n]*)/gm;

function Runner () {
    Emitter.call(this);
    this.initialize();
}

// Extend Event.Emitter.
util.inherits(Runner, Emitter);

Runner.prototype.initialize = function () {
    this.uuid = uuid();

    this.folder = path.join(__dirname, './bots/files/', this.uuid);
    this.captures = path.join(this.folder, 'captures');
    this.download = path.join(this.folder, 'download');
    this.log = path.join(this.folder, 'log.txt');
    this.cookie = path.join(this.folder, 'cookies.txt');

    this.cancelled = false;
    this.children = {};

    this.createFiles();
};

Runner.prototype.createFiles = function createFiles () {
    // Create its captures folder.
    fs.mkdirsSync(this.captures);
    // Create its download folder
    fs.mkdirsSync(this.download);
    // Create the log file.
    fs.closeSync(fs.openSync(this.log, 'w'));
    // Create the cookie file.
    fs.closeSync(fs.openSync(this.cookie, 'w'));
};

Runner.prototype.bindings = function bindings () {
    // To avoid multiple watchers we unbind before.
    this.unbindings();
    // Listen for the agent's files.
    this.watcher = fs.watch(this.folder, function (evt, filename) {
        // If it's a new log.
        if (filename === 'log.txt' && (evt === 'rename' || evt === 'change')) {
            this.parseLog(path.join(this.folder, filename));
        }
    }.bind(this));
};

Runner.prototype.unbindings = function unbindings () {
    if (this.watcher) {
        this.watcher.close();
    }
};

Runner.prototype.createReport = function createReport () {
    this.report = {};

    this.report.timing = {};
    // Total time of everything
    this.report.timing.total = _.reduce(this.tasks, function (memo, task) {
        return memo + task.test.duration;
    }, 0);
    // The longest task
    this.report.timing.slowest = _.max(this.tasks, function (task) {
        return task.test.duration;
    });
    // The fastest task
    this.report.timing.fastest = _.min(this.tasks, function (task) {
        return task.test.duration;
    });
    // All the tasks that are above the median
    this.report.timing.above = _.filter(this.tasks, function (task) {
        return task.test.duration >
            (this.report.timing.slowest.test.duration / 2);
    }.bind(this));

    // All the errors
    this.report.errors = {
        byTask: {},
        byError: {}
    };

    // Different indexation
    _.each(this.tasks, function (task) {
        if (task.errors.length) {
            this.report.errors.byTask[task.test.it || task.test.type] =
                task.errors;
        }

        _.each(task.errors, function (error) {
            this.report.errors.byError[error.message] =
                this.report.errors.byError[error.message] || [];
            this.report.errors.byError[error.message].error = error;
            this.report.errors.byError[error.message].push(task);
        }.bind(this));
    }.bind(this));

    this.report.tasks = this.tasks;

    return this.report;
};

// Throttle the call.
Runner.prototype.parseLog = function parseLog (logFile) {
    clearTimeout(this.timeoutParse);
    this.timeoutParse = setTimeout(
        this.doParseLog.bind(this, logFile),
    10);
};

Runner.prototype.doParseLog = function doParseLog (logFile) {
    var reader = readline.createInterface({
        input: fs.createReadStream(logFile),
        terminal: false
    });

    reader.on('line', function (line) {
        this.parseLine(line);
    }.bind(this));
};

Runner.prototype.parseLine = function parseLine (line) {
    var result, logObject, key;
    while (result = regexLog.exec(line)) {
        logObject = {
            type: result[1],
            date: result[2],
            time: result[3],
            message: result[4]
        };
        this.handleLog(logObject);
    }
};

Runner.prototype.handleLog = function handleLog (logObject) {
    var key = logObject.type + logObject.date + logObject.time;
    // If we already have it we don't need to do anything.
    if (this.logs[key]) {
        return;
    }
    // Try to get an object out of its message.
    try {
        // Remove escaped characters.
        logObject.message = logObject.message
            .replace(/\\\\\//g, '\/')
            .replace(/\\\\"/g, '\"')
            .replace(/\\"/g, '\"');
        logObject.message = JSON.parse(logObject.message);
    } catch (e) {
        // Not and object.
    }
    this.logs[key] = logObject;

    switch (this.logs[key].type) {
        case 'TASK.START':
            this.pending(logObject);
            break;
        case 'TASK.FAIL':
            this.fail(logObject);
            this.test(logObject);
            break;
        case 'TASK.ERROR':
            this.error(logObject);
            break;
        case 'TASK.END':
            this.test(logObject);
            break;
        default:
            console.log(chalk.bgRed('Log not taken into account'));
            console.log(logObject);
            break;
    }
};

// Run all the tasks.
Runner.prototype.run = function run (files) {
    if (this.started) {
        return;
    }
    this.bindings();
    this.clear();
    this.started = true;
    this.files = files;
    this.emit('begin', this.files);
    this.runTask();
};

// Clear sored data.
Runner.prototype.clear = function clear () {
    this.logs = {};
    this.tasks = {};
    this.currentFile = -1;
    this.started = false;
};

// Kill all subprocesses
Runner.prototype.killAll = function killAll () {
    this.cancelled = true;
    for (var i in this.children) {
        if (this.children.hasOwnProperty(i)) {
            this.killChild(i);
        }
    }
};

// Kill a specific subprocesses
Runner.prototype.killChild = function killChild (uuid) {
    if (!this.children[uuid]) {
        return;
    }

    var child = this.children[uuid].child;

    if (typeof child.disconnect === 'function') {
        child.disconnect();
    }

    if (typeof child.kill === 'function') {
        //Child process can't be killed if it has a subprocess still running
        //So, PhantomJs has to be killed first in order to kill CasperJs
        var isWin = /^win/.test(process.platform);
        var killCommand = 'kill -9 ' + child.PhantomPID;

        if (isWin) {
            killCommand = 'taskkill /PID ' + child.PhantomPID + ' /F';
        }

        //Kill PhantomJs using a kill command depending on the platform
        exec(killCommand, function (error, stdout, stderr) {
            if (error !== null) {
                console.log(
                    chalk.bgRed(' -[ ERROR ]- Cannot end PhantomJs: '),
                    error
                );
                return;
            }
            //Kill CasperJs if PhantomJs has been successfully killed
            child.kill('SIGTERM');
        });
    }

    //Clean the child process if it has been successfully killed
    if (child.killed) {
        this.cleanChild(uuid);
    }
};

// Clean instance of child
Runner.prototype.cleanChild = function cleanChild (uuid) {
    delete this.children[uuid];
};

// Run the next task.
Runner.prototype.runTask = function runTask () {
    this.currentFile += 1;
    var file = this.files[this.currentFile];
    if (file) {
        // When the runner ends its suite.
        // Clean the previous child and do the next one.
        this.once('end', function (child, code, signal) {
            if (child) {
                this.cleanChild(child.uuid);
            }
            // Do the next one.
            this.runTask();
        }.bind(this));

        this.start(file.tasks);
    } else {
        this.finish();
    }
};

// Update the stored task to be sure to have all updated infos.
Runner.prototype.updateTest = function (test) {
    this.tasks[test.logId].test = _.extend(
        this.tasks[test.logId].test,
        test
    );
};

// When a new suite begins
Runner.prototype.start = function start (tasks) {
    this.emit('start', tasks);
    if (this.cancelled) {
        this.end(null, null, 'SIGTERM');
        return;
    }
    this.spawn(tasks);
};

// When a suite ends
Runner.prototype.end = function end (child, code, signal) {
    this.emit('end', child, code, signal);
};

// When everything is done.
Runner.prototype.finish = function finish () {
    this.started = false;
    this.cancelled = false;
    this.emit('finish', this.createReport());
    this.unbindings();
};

// A task is pending.
Runner.prototype.pending = function pending (log) {
    var test = log.message;
    if (!this.tasks[test.logId]) {
        this.tasks[test.logId] = {
            errors: [],
            failed: false,
            logs: []
        };
    }
    this.tasks[test.logId].test = test;
    this.tasks[test.logId].logs.push(log);
    this.emit('pending', this.tasks[test.logId].test);
};

// A task got an error
Runner.prototype.error = function error (log) {
    var test = log.message;
    if (!this.tasks[test.logId]) {
        this.pending(log);
    } else {
        this.tasks[test.logId].logs.push(log);
    }
    var error = {
        message: test.error,
        details: test.details,
        type: test.type
    };
    // Ignore 'Operation Cancelled' type of error.
    if (/Operation canceled/.test(test.error)) {
        return;
    }
    this.tasks[test.logId].errors.push(error);
    this.emit('error', error);
};

// A task failed
Runner.prototype.fail = function fail (log) {
    var test = log.message;
    if (!this.tasks[test.logId]) {
        this.pending(log);
    } else {
        this.tasks[test.logId].logs.push(log);
    }
    this.updateTest(test);
    this.tasks[test.logId].failed = true;
    var lastError = this.tasks[test.logId].errors.slice(-1)[0];
    this.emit(
        'fail',
        this.tasks[test.logId].test,
        lastError ? lastError.message : null
    );
};

// A task succeeded
Runner.prototype.test = function test (log) {
    var test = log.message;
    if (!this.tasks[test.logId]) {
        this.pending(log);
    } else {
        this.tasks[test.logId].logs.push(log);
    }
    this.updateTest(test);
    this.emit('test', this.tasks[test.logId].test);

    // If it hasn't failed yet, it's succeeded
    if (!this.tasks[test.logId].failed) {
        this.emit('pass', this.tasks[test.logId].test);
    }
};

// Spawn the casper
Runner.prototype.spawn = function spawnChild (tasks) {
    // Spawn the child.
    var child = spawn(
        path.join(__dirname, '../node_modules/casperjs/bin/casperjs'),
        [
            path.join(__dirname, './bots/worker.js'),
            '--tasks=' + tasks,
            '--cwd=' + this.folder,
            '--cookies-file=' + this.cookie,
            '--web-security=no',
            '--ssl-protocol=any',
            '--ignore-ssl-errors=yes',
            '--log-file=' + this.log
        ],
        {
            env: process.env
        }
    );
    child.uuid = this.uuid + '-' + child.pid;

    this.children[child.uuid] = {
        id: child.uuid,
        name: child.pid.toString(),
        child: child,
        logFile: this.log
    };
    this.bindChild(child);
};

// Clean agent's files.
Runner.prototype.clean = function clean () {
    fs.removeSync(this.folder);
};

// Bind the casper.
Runner.prototype.bindChild = function bindChild (child) {

    child.on('close', this.end.bind(this, child));

    child.stdout.on('data', function (data) {
        var output = data.toString();

        //PhantomJS PID is passed as 'PhantomJS PID: PID'
        //Extract PhantomJS's PID once received
        //Otherwise, console.log the output message
        if (output.indexOf('PhantomJS PID: ') > -1) {
            child.PhantomPID = parseInt(output.split(': ')[1]);
        } else {
            console.log(chalk.blue(' -[ child ]- '), output);
        }
    });

    child.stderr.on('data', function (data) {
        console.log(chalk.bgRed(' -[ ERROR ]- '), data.toString());
    });
};

module.exports = new Runner();
<commit_msg>chore(runner): add log<commit_after>var Emitter = require('events').EventEmitter;
var util = require('util');
var spawn = require('child_process').spawn;
var exec = require('child_process').exec;
var fs = require('fs-extra');
var path = require('path');
var uuid = require('node-uuid').v1;
var readline = require('readline');
var chalk = require('chalk');
var _ = require('underscore');

// Will parse the log file.
// type [1] [TYPE]
// date [2] and time [3] (1234/12/12 hh:mm:ss)
// message [4] ...
var regexLog = /^\[([^\]]*)\]\(([^\)]*) ([^\)]*)\):([^\n]*)/gm;

function Runner () {
    Emitter.call(this);
    this.initialize();
}

// Extend Event.Emitter.
util.inherits(Runner, Emitter);

Runner.prototype.initialize = function () {
    this.uuid = uuid();

    this.folder = path.join(__dirname, './bots/files/', this.uuid);
    this.captures = path.join(this.folder, 'captures');
    this.download = path.join(this.folder, 'download');
    this.log = path.join(this.folder, 'log.txt');
    this.cookie = path.join(this.folder, 'cookies.txt');

    this.cancelled = false;
    this.children = {};

    this.createFiles();
};

Runner.prototype.createFiles = function createFiles () {
    // Create its captures folder.
    fs.mkdirsSync(this.captures);
    // Create its download folder
    fs.mkdirsSync(this.download);
    // Create the log file.
    fs.closeSync(fs.openSync(this.log, 'w'));
    // Create the cookie file.
    fs.closeSync(fs.openSync(this.cookie, 'w'));
};

Runner.prototype.bindings = function bindings () {
    // To avoid multiple watchers we unbind before.
    this.unbindings();
    // Listen for the agent's files.
    this.watcher = fs.watch(this.folder, function (evt, filename) {
        // If it's a new log.
        if (filename === 'log.txt' && (evt === 'rename' || evt === 'change')) {
            this.parseLog(path.join(this.folder, filename));
        }
    }.bind(this));
};

Runner.prototype.unbindings = function unbindings () {
    if (this.watcher) {
        this.watcher.close();
    }
};

Runner.prototype.createReport = function createReport () {
    this.report = {};

    this.report.timing = {};
    // Total time of everything
    this.report.timing.total = _.reduce(this.tasks, function (memo, task) {
        return memo + task.test.duration;
    }, 0);
    // The longest task
    this.report.timing.slowest = _.max(this.tasks, function (task) {
        return task.test.duration;
    });
    // The fastest task
    this.report.timing.fastest = _.min(this.tasks, function (task) {
        return task.test.duration;
    });
    // All the tasks that are above the median
    this.report.timing.above = _.filter(this.tasks, function (task) {
        return task.test.duration >
            (this.report.timing.slowest.test.duration / 2);
    }.bind(this));

    // All the errors
    this.report.errors = {
        byTask: {},
        byError: {}
    };

    // Different indexation
    _.each(this.tasks, function (task) {
        if (task.errors.length) {
            this.report.errors.byTask[task.test.it || task.test.type] =
                task.errors;
        }

        _.each(task.errors, function (error) {
            this.report.errors.byError[error.message] =
                this.report.errors.byError[error.message] || [];
            this.report.errors.byError[error.message].error = error;
            this.report.errors.byError[error.message].push(task);
        }.bind(this));
    }.bind(this));

    this.report.tasks = this.tasks;

    return this.report;
};

// Throttle the call.
Runner.prototype.parseLog = function parseLog (logFile) {
    clearTimeout(this.timeoutParse);
    this.timeoutParse = setTimeout(
        this.doParseLog.bind(this, logFile),
    10);
};

Runner.prototype.doParseLog = function doParseLog (logFile) {
    var reader = readline.createInterface({
        input: fs.createReadStream(logFile),
        terminal: false
    });

    reader.on('line', function (line) {
        this.parseLine(line);
    }.bind(this));
};

Runner.prototype.parseLine = function parseLine (line) {
    var result, logObject, key;
    while (result = regexLog.exec(line)) {
        logObject = {
            type: result[1],
            date: result[2],
            time: result[3],
            message: result[4]
        };
        this.handleLog(logObject);
    }
};

Runner.prototype.handleLog = function handleLog (logObject) {
    var key = logObject.type + logObject.date + logObject.time;
    // If we already have it we don't need to do anything.
    if (this.logs[key]) {
        return;
    }
    // Try to get an object out of its message.
    try {
        // Remove escaped characters.
        logObject.message = logObject.message
            .replace(/\\\\\//g, '\/')
            .replace(/\\\\"/g, '\"')
            .replace(/\\"/g, '\"');
        logObject.message = JSON.parse(logObject.message);
    } catch (e) {
        // Not and object.
    }
    this.logs[key] = logObject;

    switch (this.logs[key].type) {
        case 'TASK.START':
            this.pending(logObject);
            break;
        case 'TASK.FAIL':
            this.fail(logObject);
            this.test(logObject);
            break;
        case 'TASK.ERROR':
            this.error(logObject);
            break;
        case 'TASK.END':
            this.test(logObject);
            break;
        default:
            console.log(chalk.bgRed('Log not taken into account'));
            console.log(logObject);
            break;
    }
};

// Run all the tasks.
Runner.prototype.run = function run (files) {
    if (this.started) {
        return;
    }
    this.bindings();
    this.clear();
    this.started = true;
    this.files = files;
    this.emit('begin', this.files);
    this.runTask();
};

// Clear sored data.
Runner.prototype.clear = function clear () {
    this.logs = {};
    this.tasks = {};
    this.currentFile = -1;
    this.started = false;
};

// Kill all subprocesses
Runner.prototype.killAll = function killAll () {
    this.cancelled = true;
    for (var i in this.children) {
        if (this.children.hasOwnProperty(i)) {
            this.killChild(i);
        }
    }
};

// Kill a specific subprocesses
Runner.prototype.killChild = function killChild (uuid) {
    if (!this.children[uuid]) {
        return;
    }

    var child = this.children[uuid].child;

    if (typeof child.disconnect === 'function') {
        child.disconnect();
    }

    if (typeof child.kill === 'function') {
        //Child process can't be killed if it has a subprocess still running
        //So, PhantomJs has to be killed first in order to kill CasperJs
        var isWin = /^win/.test(process.platform);
        var killCommand = 'kill -9 ' + child.PhantomPID;

        if (isWin) {
            killCommand = 'taskkill /PID ' + child.PhantomPID + ' /F';
        }

        //Kill PhantomJs using a kill command depending on the platform
        exec(killCommand, function (error, stdout, stderr) {
            if (error !== null) {
                console.log(
                    chalk.bgRed(' -[ ERROR ]- Cannot end PhantomJs: '),
                    error
                );
                return;
            }
            //Kill CasperJs if PhantomJs has been successfully killed
            child.kill('SIGTERM');
        });
    }

    //Clean the child process if it has been successfully killed
    if (child.killed) {
        this.cleanChild(uuid);
    }
};

// Clean instance of child
Runner.prototype.cleanChild = function cleanChild (uuid) {
    delete this.children[uuid];
};

// Run the next task.
Runner.prototype.runTask = function runTask () {
    this.currentFile += 1;
    var file = this.files[this.currentFile];
    if (file) {
        // When the runner ends its suite.
        // Clean the previous child and do the next one.
        this.once('end', function (child, code, signal) {
            if (child) {
                this.cleanChild(child.uuid);
            }
            // Do the next one.
            this.runTask();
        }.bind(this));

        this.start(file.tasks);
    } else {
        this.finish();
    }
};

// Update the stored task to be sure to have all updated infos.
Runner.prototype.updateTest = function (test) {
    this.tasks[test.logId].test = _.extend(
        this.tasks[test.logId].test,
        test
    );
};

// When a new suite begins
Runner.prototype.start = function start (tasks) {
    this.emit('start', tasks);
    if (this.cancelled) {
        this.end(null, null, 'SIGTERM');
        return;
    }
    this.spawn(tasks);
};

// When a suite ends
Runner.prototype.end = function end (child, code, signal) {
    this.emit('end', child, code, signal);
};

// When everything is done.
Runner.prototype.finish = function finish () {
    this.started = false;
    this.cancelled = false;
    this.emit('finish', this.createReport());
    this.unbindings();
};

// A task is pending.
Runner.prototype.pending = function pending (log) {
    var test = log.message;
    if (!this.tasks[test.logId]) {
        this.tasks[test.logId] = {
            errors: [],
            failed: false,
            logs: []
        };
    }
    this.tasks[test.logId].test = test;
    this.tasks[test.logId].logs.push(log);
    this.emit('pending', this.tasks[test.logId].test);
};

// A task got an error
Runner.prototype.error = function error (log) {
    var test = log.message;
    if (!this.tasks[test.logId]) {
        this.pending(log);
    } else {
        this.tasks[test.logId].logs.push(log);
    }
    var error = {
        message: test.error,
        details: test.details,
        type: test.type
    };
    // Ignore 'Operation Cancelled' type of error.
    if (/Operation canceled/.test(test.error)) {
        return;
    }
    this.tasks[test.logId].errors.push(error);
    this.emit('error', error);
};

// A task failed
Runner.prototype.fail = function fail (log) {
    var test = log.message;
    if (!this.tasks[test.logId]) {
        this.pending(log);
    } else {
        this.tasks[test.logId].logs.push(log);
    }
    this.updateTest(test);
    this.tasks[test.logId].failed = true;
    var lastError = this.tasks[test.logId].errors.slice(-1)[0];
    this.emit(
        'fail',
        this.tasks[test.logId].test,
        lastError ? lastError.message : null
    );
};

// A task succeeded
Runner.prototype.test = function test (log) {
    var test = log.message;
    if (!this.tasks[test.logId]) {
        this.pending(log);
    } else {
        this.tasks[test.logId].logs.push(log);
    }
    this.updateTest(test);
    this.emit('test', this.tasks[test.logId].test);

    // If it hasn't failed yet, it's succeeded
    if (!this.tasks[test.logId].failed) {
        this.emit('pass', this.tasks[test.logId].test);
    }
};

// Spawn the casper
Runner.prototype.spawn = function spawnChild (tasks) {
    // Spawn the child.
    var child = spawn(
        path.join(__dirname, '../node_modules/casperjs/bin/casperjs'),
        [
            path.join(__dirname, './bots/worker.js'),
            '--tasks=' + tasks,
            '--cwd=' + this.folder,
            '--cookies-file=' + this.cookie,
            '--web-security=no',
            '--ssl-protocol=any',
            '--ignore-ssl-errors=yes',
            '--log-file=' + this.log
        ],
        {
            env: process.env
        }
    );
    child.uuid = this.uuid + '-' + child.pid;
    console.log('Spawn ' + child.uuid + ':' + child.pid);
    this.children[child.uuid] = {
        id: child.uuid,
        name: child.pid.toString(),
        child: child,
        logFile: this.log
    };
    this.bindChild(child);
};

// Clean agent's files.
Runner.prototype.clean = function clean () {
    fs.removeSync(this.folder);
};

// Bind the casper.
Runner.prototype.bindChild = function bindChild (child) {

    child.on('close', this.end.bind(this, child));

    child.stdout.on('data', function (data) {
        var output = data.toString();

        //PhantomJS PID is passed as 'PhantomJS PID: PID'
        //Extract PhantomJS's PID once received
        //Otherwise, console.log the output message
        if (output.indexOf('PhantomJS PID: ') > -1) {
            child.PhantomPID = parseInt(output.split(': ')[1]);
        } else {
            console.log(chalk.blue(' -[ child ]- '), output);
        }
    });

    child.stderr.on('data', function (data) {
        console.log(chalk.bgRed(' -[ ERROR ]- '), data.toString());
    });
};

module.exports = new Runner();
<|endoftext|>


<commit_before>// Api handles the searching of queries and keeping track of query id and sequence
export class Api {

  // constructor takes sajari project and collection details, and an optional address as an override
  constructor(project, collection, address) {
    this.p = project;
    this.c = collection;
    this.a = address || 'https://apid.sajari.com:9200/search-v10/';
  }

  // search takes a query, success and error callbacks
  search(query, callback) {
    // create a new XMLHttpRequest for the search
    const request = new XMLHttpRequest();

    // specify POST, the address, and async is true
    request.open('POST', this.a, true);
    request.setRequestHeader('Accept', 'application/json');

    request.onreadystatechange = () => {
      // if the request is not done, do nothing
      if (request.readyState !== 4) {
        return;
      }

      if (request.status === 200) {
        callback(null, JSON.parse(request.responseText));
      } else {
        callback(request.responseText, null);
      }
    };

    // Add project, collection, query sequence, and query id to the query and send it
    request.send(JSON.stringify({
      request: query.q,
      project: this.p,
      collection: this.c,
      // eslint-disable-next-line no-param-reassign
      sequence: query.s++, // Increment query sequence
      id: query.i,
    }));

    return request;
  }
}

/* Body */

export function body(text, weight) {
  return { text, weight: weight || 1 };
}

/* Aggregate */

export const METRIC_TYPE_MAX = 'MAX';
export const METRIC_TYPE_MIN = 'MIN';
export const METRIC_TYPE_AVG = 'AVG';
export const METRIC_TYPE_SUM = 'SUM';

export function metricAggregate(name, field, type) {
  return [name, { metric: { field, type } }];
}

export function countAggregate(name, field) {
  return [name, { count: { field } }];
}

export function bucket(name, filter) {
  return { name, filter };
}

export function bucketAggregate(name, buckets) {
  return [name, { bucket: { buckets } }];
}

/* Filters */

export const FILTER_OP_EQ = 'EQUAL_TO';
export const FILTER_OP_NOT_EQ = 'DOES_NOT_EQUAL';
export const FILTER_OP_GT = 'GREATER_THAN';
export const FILTER_OP_GT_EQ = 'GREATER_THAN_OR_EQUAL_TO';
export const FILTER_OP_LT = 'LESS_THAN';
export const FILTER_OP_LT_EQ = 'LESS_THAN_OR_EQUAL_TO';
export const FILTER_OP_CONTAIN = 'CONTAINS';
export const FILTER_OP_NOT_CONTAIN = 'DOES_NOT_CONTAINS';
export const FILTER_OP_SUFFIX = 'ENDS_WITH';
export const FILTER_OP_PREFIX = 'STARTS_WITH';

export function fieldFilter(field, value, operator) {
  // eslint-disable-next-line no-use-before-define
  return { field: { field, value: encode(String(value)), operator } };
}

/* Filter Combinators */

export const COMB_FILTER_OP_ALL = 'ALL';
export const COMB_FILTER_OP_ANY = 'ANY';
export const COMB_FILTER_OP_ONE = 'ONE';
export const COMB_FILTER_OP_NONE = 'NONE';

export function combinatorFilter(filters, operator) {
  return { combinator: { filters, operator } };
}

/* Index Boosts */

export function fieldIndexBoost(field, value) {
  return { field: { field, value } };
}

export function scoreIndexBoost(threshold) {
  return { score: { threshold } };
}

/* Meta Boosts */

export function filterMetaBoost(filter, value) {
  return { filter: { filter, value } };
}

// eslint-disable-next-line camelcase
export function additiveMetaBoost(meta_boost, value) {
  return { add: { meta_boost, value } };
}

export const GEO_META_BOOST_REGION_INSIDE = 'INSIDE';
export const GEO_META_BOOST_REGION_OUTSIDE = 'OUTSIDE';

// eslint-disable-next-line camelcase
export function geoMetaBoost(field_lat, field_lng, lat, lng, radius, value, region) {
  return { geo: { field_lat, field_lng, lat, lng, radius, value, region } };
}

export function pointValue(point, value) {
  return { point, value };
}

export function intervalMetaBoost(field, points) {
  return { interval: { field, points } };
}

export function distanceMetaBoost(min, max, ref, field, value) {
  return { distance: { min, max, ref, field, value } };
}

export function elementMetaBoost(field, elts) {
  return { element: { field, elts } };
}

export function textMetaBoost(field, text) {
  return { text: { field, text } };
}

/* Sort */

export const SORT_ASCENDING = 'ASC';
export const SORT_DESCENDING = 'DESC';

export function sort(field, order) {
  return { field, order };
}

export function transform(identifier) {
  return { identifier };
}

/* Query */

export class Query {

  // Constructor sets some sane defaults
  constructor() {
    this.resetID();
    this.q = {
      page: 1,
      max_results: 10,
    };
  }

  resetID() {
    this.i = '';
    this.s = 0;

    // Generate a random id for the query
    for (let i = 0; i < 16; i++) {
      this.i += 'abcdefghijklmnopqrstuvwxyz0123456789'.charAt(Math.floor(Math.random() * 36));
    }
  }

  // Max results is a number
  resultsPerPage(max) {
    this.q.max_results = max;
  }

  // Page is a number
  page(page) {
    this.q.page = page;
  }

  // Body is a list of Body objects
  // eslint-disable-next-line no-shadow
  body(body) {
    this.q.body = body;
  }

  // Fields is a list of strings
  fields(fields) {
    this.q.fields = fields;
  }

  // Filter is a single Filter object
  filter(filter) {
    this.q.filter = filter;
  }

  // Meta boosts is a list of MetaBoost objects
  metaBoosts(boosts) {
    this.q.meta_boosts = boosts;
  }

  // Index boosts is a list of IndexBoost objectss
  indexBoosts(boosts) {
    this.q.index_boosts = boosts;
  }

  // Aggregates is a list of Aggregate Objects
  aggregates(aggregates) {
    const newAggregates = {};
    for (let i = 0; i < aggregates.length; i++) {
      newAggregates[aggregates[i][0]] = aggregates[i][1];
    }
    this.q.aggregates = newAggregates;
  }

  sort(sorts) {
    this.q.sort = sorts;
  }

  // Transforms is a list of strings
  transforms(transforms) {
    this.q.transforms = transforms;
  }
}

/* Base64 encoding */

const b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';

/* eslint-disable */
function _utf8_encode(string) {
  string = string.replace(/\r\n/g,'\n');
  var utftext = '';

  for (var n = 0; n < string.length; n++) {
    var c = string.charCodeAt(n);

    if (c < 128) {
      utftext += String.fromCharCode(c);
    } else if((c > 127) && (c < 2048)) {
      utftext += String.fromCharCode((c >> 6) | 192);
      utftext += String.fromCharCode((c & 63) | 128);
    } else {
      utftext += String.fromCharCode((c >> 12) | 224);
      utftext += String.fromCharCode(((c >> 6) & 63) | 128);
      utftext += String.fromCharCode((c & 63) | 128);
    }
  }

  return utftext;
}

function encode(input) {
  let output = '';
  let chr1, chr2, chr3, enc1, enc2, enc3, enc4;
  let i = 0;

  input = _utf8_encode(input);

  while (i < input.length) {
    chr1 = input.charCodeAt(i++);
    chr2 = input.charCodeAt(i++);
    chr3 = input.charCodeAt(i++);

    enc1 = chr1 >> 2;
    enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
    enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
    enc4 = chr3 & 63;

    if (isNaN(chr2)) {
      enc3 = enc4 = 64;
    } else if (isNaN(chr3)) {
      enc4 = 64;
    }

    output = output + b64.charAt(enc1) + b64.charAt(enc2) + b64.charAt(enc3) + b64.charAt(enc4);
  }

  return output;
}
<commit_msg>Updating proto<commit_after>// Api handles the searching of queries and keeping track of query id and sequence
export class Api {

  // constructor takes sajari project and collection details, and an optional address as an override
  constructor(project, collection, address) {
    this.p = project;
    this.c = collection;
    this.a = address || 'https://apid.sajari.com:9200/search-v10/';
  }

  // search takes a query, success and error callbacks
  search(query, callback) {
    // create a new XMLHttpRequest for the search
    const request = new XMLHttpRequest();

    // specify POST, the address, and async is true
    request.open('POST', this.a, true);
    request.setRequestHeader('Accept', 'application/json');

    request.onreadystatechange = () => {
      // if the request is not done, do nothing
      if (request.readyState !== 4) {
        return;
      }

      if (request.status === 200) {
        callback(null, JSON.parse(request.responseText));
      } else {
        callback(request.responseText, null);
      }
    };

    // Add project, collection, query sequence, and query id to the query and send it
    request.send(JSON.stringify({
      request: query.q,
      project: this.p,
      collection: this.c,
      // eslint-disable-next-line no-param-reassign
      sequence: query.s++, // Increment query sequence
      id: query.i,
    }));

    return request;
  }
}

/* Body */

export function body(text, weight) {
  return { text, weight: weight || 1 };
}

/* Aggregate */

export const METRIC_TYPE_MAX = 'MAX';
export const METRIC_TYPE_MIN = 'MIN';
export const METRIC_TYPE_AVG = 'AVG';
export const METRIC_TYPE_SUM = 'SUM';

export function metricAggregate(name, field, type) {
  return [name, { metric: { field, type } }];
}

export function countAggregate(name, field) {
  return [name, { count: { field } }];
}

export function bucket(name, filter) {
  return { name, filter };
}

export function bucketAggregate(name, buckets) {
  return [name, { bucket: { buckets } }];
}

/* Filters */

export const FILTER_OP_EQ = 'EQUAL_TO';
export const FILTER_OP_NOT_EQ = 'DOES_NOT_EQUAL';
export const FILTER_OP_GT = 'GREATER_THAN';
export const FILTER_OP_GT_EQ = 'GREATER_THAN_OR_EQUAL_TO';
export const FILTER_OP_LT = 'LESS_THAN';
export const FILTER_OP_LT_EQ = 'LESS_THAN_OR_EQUAL_TO';
export const FILTER_OP_CONTAINS = 'CONTAINS';
export const FILTER_OP_NOT_CONTAIN = 'DOES_NOT_CONTAIN';
export const FILTER_OP_SUFFIX = 'HAS_SUFFIX';
export const FILTER_OP_PREFIX = 'HAS_PREFX';

export function fieldFilter(field, value, operator) {
  // eslint-disable-next-line no-use-before-define
  return { field: { field, value: encode(String(value)), operator } };
}

/* Filter Combinators */

export const COMB_FILTER_OP_ALL = 'ALL';
export const COMB_FILTER_OP_ANY = 'ANY';
export const COMB_FILTER_OP_ONE = 'ONE';
export const COMB_FILTER_OP_NONE = 'NONE';

export function combinatorFilter(filters, operator) {
  return { combinator: { filters, operator } };
}

/* Index Boosts */

export function fieldInstanceBoost(field, value) {
  return { field: { field, value } };
}

export function scoreInstanceBoost(threshold) {
  return { score: { threshold } };
}

/* Meta Boosts */

export function filterFieldBoost(filter, value) {
  return { filter: { filter, value } };
}

// eslint-disable-next-line camelcase
export function additiveFieldBoost(field_boost, value) {
  return { add: { field_boost, value } };
}

export const GEO_META_BOOST_REGION_INSIDE = 'INSIDE';
export const GEO_META_BOOST_REGION_OUTSIDE = 'OUTSIDE';

// eslint-disable-next-line camelcase
export function geoMetaBoost(field_lat, field_lng, lat, lng, radius, value, region) {
  return { geo: { field_lat, field_lng, lat, lng, radius, value, region } };
}

export function pointValue(point, value) {
  return { point, value };
}

export function intervalFieldBoost(field, points) {
  return { interval: { field, points } };
}

export function distanceFieldBoost(min, max, ref, field, value) {
  return { distance: { min, max, ref, field, value } };
}

export function elementFieldBoost(field, elts) {
  return { element: { field, elts } };
}

export function textFieldBoost(field, text) {
  return { text: { field, text } };
}

/* Sort */

export const SORT_ASCENDING = 'ASC';
export const SORT_DESCENDING = 'DESC';

export function sort(field, order) {
  return { field, order };
}

export function transform(identifier) {
  return { identifier };
}

/* Query */

export class Query {

  // Constructor sets some sane defaults
  constructor() {
    this.resetID();
    this.q = {
      page: 1,
      max_results: 10,
    };
  }

  resetID() {
    this.i = '';
    this.s = 0;

    // Generate a random id for the query
    for (let i = 0; i < 16; i++) {
      this.i += 'abcdefghijklmnopqrstuvwxyz0123456789'.charAt(Math.floor(Math.random() * 36));
    }
  }

  // Results per page is a number
  resultsPerPage(results) {
    this.q.results_per_page = results;
  }

  // Page is a number
  page(page) {
    this.q.page = page;
  }

  // Body is a list of Body objects
  // eslint-disable-next-line no-shadow
  body(body) {
    this.q.body = body;
  }

  // Fields is a list of strings
  fields(fields) {
    this.q.fields = fields;
  }

  // Filter is a single Filter object
  filter(filter) {
    this.q.filter = filter;
  }

  // Field boosts is a list of FieldBoost objects
  fieldBoosts(boosts) {
    this.q.field_boosts = boosts;
  }

  // Instance boosts is a list of InstancBoost objectss
  instanceBoosts(boosts) {
    this.q.instance_boosts = boosts;
  }

  // Aggregates is a list of Aggregate Objects
  aggregates(aggregates) {
    const newAggregates = {};
    for (let i = 0; i < aggregates.length; i++) {
      newAggregates[aggregates[i][0]] = aggregates[i][1];
    }
    this.q.aggregates = newAggregates;
  }

  sort(sorts) {
    this.q.sort = sorts;
  }

  // Transforms is a list of strings
  transforms(transforms) {
    this.q.transforms = transforms;
  }
}

/* Base64 encoding */

const b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';

/* eslint-disable */
function _utf8_encode(string) {
  string = string.replace(/\r\n/g,'\n');
  var utftext = '';

  for (var n = 0; n < string.length; n++) {
    var c = string.charCodeAt(n);

    if (c < 128) {
      utftext += String.fromCharCode(c);
    } else if((c > 127) && (c < 2048)) {
      utftext += String.fromCharCode((c >> 6) | 192);
      utftext += String.fromCharCode((c & 63) | 128);
    } else {
      utftext += String.fromCharCode((c >> 12) | 224);
      utftext += String.fromCharCode(((c >> 6) & 63) | 128);
      utftext += String.fromCharCode((c & 63) | 128);
    }
  }

  return utftext;
}

function encode(input) {
  let output = '';
  let chr1, chr2, chr3, enc1, enc2, enc3, enc4;
  let i = 0;

  input = _utf8_encode(input);

  while (i < input.length) {
    chr1 = input.charCodeAt(i++);
    chr2 = input.charCodeAt(i++);
    chr3 = input.charCodeAt(i++);

    enc1 = chr1 >> 2;
    enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
    enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
    enc4 = chr3 & 63;

    if (isNaN(chr2)) {
      enc3 = enc4 = 64;
    } else if (isNaN(chr3)) {
      enc4 = 64;
    }

    output = output + b64.charAt(enc1) + b64.charAt(enc2) + b64.charAt(enc3) + b64.charAt(enc4);
  }

  return output;
}
<|endoftext|>


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

var mjAPI = require('MathJax-node/lib/mj-single.js');
var url = require('url');
var unescape = require('querystring').unescape;
var fs = require('fs');
var path = require('path');
var crypto = require('crypto');

var argv = require('yargs')
  .demand(1).strict()
  .usage('Usage: mathserver [options] <port>', {
    host: {
      default: '127.0.0.1',
      describe: 'address to listen on'
    },
    no_optimize: {
      boolean: true,
      describe: 'disable optimization of svg'
    },
    font: {
      default: 'TeX',
      describe: 'web font to use'
    },
    inline_svg: {
      default: '/math.svg',
      describe: 'inline math svg path'
    },
    display_svg: {
      default: '/display_math.svg',
      describe: 'display math svg path'
    },
    inline_png: {
      default: '/math.png',
      describe: 'inline math png path'
    },
    display_png: {
      default: '/display_math.png',
      describe: 'display math png path'
    },
    cache: {
      default: 'cache',
      describe: 'cache directory'
    },
    nginx: {
      default: null,
      describe: 'nginx X-Accel-Redirect internal location for cache directory'
    }
  })
  .argv;

mjAPI.config({MathJax: {SVG: {font: argv.font === 'STIX' ? 'STIX-Web' : argv.font}}});
mjAPI.start();

if (!argv.no_optimize) {
  try {
    var SVGO = require('svgo');
    var svgo = new SVGO();
  } catch (e) {
    var svgo = undefined;
    console.log("Can't find svgo, can't optimize svgs");
  }
} else
  var svgo = undefined;

var cache_dir = argv.cache;
var x_accel = argv.nginx;
var urlmap = {};
urlmap[argv.inline_svg] = {
  format: 'inline-TeX', cache: 'inline', type: 'svg',
  content_type: 'image/svg+xml; charset=utf-8'
};
urlmap[argv.display_svg] = {
  format: 'TeX', cache: 'display', type: 'svg',
  content_type: 'image/svg+xml; charset=utf-8',
};

try {
  var rsvg = require('rsvg').Rsvg;
  urlmap[argv.inline_png] = {
    format: 'inline-TeX', cache: 'inline', type: 'png',
    content_type: 'image/png'
  };
  urlmap[argv.display_png] = {
    format: 'TeX', cache: 'display', type: 'png',
    content_type: 'image/png',
  };
} catch (e) {
  var rsvg = undefined;
  console.log("Can't rasterize without rsvg")
}

function save(file, data) {
  var temp = file + '.tmp';
  fs.writeFile(temp, data, function (err) {
    if (err) console.log(err);
    fs.rename(temp, file, function (err) {
      if (err) console.log(err);
    });
  });
}

function render_png(data) {
  var svg = new rsvg(data);
  return svg.render({
    format: 'png', width: svg.width * 1.5, height: svg.height * 1.5
  });
}

require('http').createServer(function (req, res) {
  var pathname = url.parse(req.url).pathname;
  var query = req.url.indexOf('?');
  if (!(pathname in urlmap) || query === -1) {
    res.writeHead(404, {'Content-Type': 'text/plain'});
    res.end('404 Not Found');
    return;
  }
  var config = urlmap[pathname];
  var math = unescape(req.url.substr(query+1));
  var hash = crypto.createHash('md5').update(math).digest('hex');
  var key = config.cache + '_' + hash;
  var prefix = path.join(cache_dir, config.cache + '_' + hash);
  var cache = prefix + '.' + config.type;
  fs.exists(cache, function (exists) {
    if (exists) {
      if (x_accel === null) {
        fs.readFile(cache, function (err, data) {
          if (err) {
            console.log(err);
            res.writeHead(500, {'Content-Type': 'text/plain'});
            res.end(err.toString());
          } else {
            res.writeHead(200, {'Content-Type': config.content_type});
            res.end(data);
          }
        });
      } else {
        res.writeHead(200, {
          'Content-Type': config.content_type,
          'X-Accel-Redirect': x_accel + key + '.' + config.type
        });
        res.end();
      }
      return;
    }
    mjAPI.typeset({
      math: math,
      format: config.format,
      svg: true,
    }, function (data) {
      if (data.errors) {
        res.writeHead(400, {'Content-Type': 'text/plain'});
        res.end(data.errors.toString());
      } else {
        res.writeHead(200, {'Content-Type': config.content_type});
        if (typeof svgo !== 'undefined') {
          svgo.optimize(data.svg, function (result) {
            if (config.type == 'svg')
              res.end(result.data);
            save(prefix + '.svg', result.data);
          });
        } else {
          if (config.type == 'svg')
            res.end(data.svg);
          save(prefix + '.svg', data.svg);
        }
        var png = render_png(data.svg);
        if (config.type == 'png')
          res.end(png.data);
        save(prefix + '.png', png.data);
      }
    });
  });
}).listen(parseInt(argv._[0]), argv.host);<commit_msg>Attempt to switch to svg2png.<commit_after>#!/usr/bin/env node

var mjAPI = require('MathJax-node/lib/mj-single.js');
var url = require('url');
var unescape = require('querystring').unescape;
var fs = require('fs');
var path = require('path');
var crypto = require('crypto');

var argv = require('yargs')
  .demand(1).strict()
  .usage('Usage: mathserver [options] <port>', {
    host: {
      default: '127.0.0.1',
      describe: 'address to listen on'
    },
    no_optimize: {
      boolean: true,
      describe: 'disable optimization of svg'
    },
    font: {
      default: 'TeX',
      describe: 'web font to use'
    },
    inline_svg: {
      default: '/math.svg',
      describe: 'inline math svg path'
    },
    display_svg: {
      default: '/display_math.svg',
      describe: 'display math svg path'
    },
    inline_png: {
      default: '/math.png',
      describe: 'inline math png path'
    },
    display_png: {
      default: '/display_math.png',
      describe: 'display math png path'
    },
    cache: {
      default: 'cache',
      describe: 'cache directory'
    },
    nginx: {
      default: null,
      describe: 'nginx X-Accel-Redirect internal location for cache directory'
    }
  })
  .argv;

mjAPI.config({MathJax: {SVG: {font: argv.font === 'STIX' ? 'STIX-Web' : argv.font}}});
mjAPI.start();

if (!argv.no_optimize) {
  try {
    var SVGO = require('svgo');
    var svgo = new SVGO();
  } catch (e) {
    var svgo = undefined;
    console.log("Can't find svgo, can't optimize svgs");
  }
} else
  var svgo = undefined;

var cache_dir = argv.cache;
var x_accel = argv.nginx;
var urlmap = {};
urlmap[argv.inline_svg] = {
  format: 'inline-TeX', cache: 'inline', type: 'svg',
  content_type: 'image/svg+xml; charset=utf-8'
};
urlmap[argv.display_svg] = {
  format: 'TeX', cache: 'display', type: 'svg',
  content_type: 'image/svg+xml; charset=utf-8',
};

try {
  var svg2png = require('svg2png');
  urlmap[argv.inline_png] = {
    format: 'inline-TeX', cache: 'inline', type: 'png',
    content_type: 'image/png'
  };
  urlmap[argv.display_png] = {
    format: 'TeX', cache: 'display', type: 'png',
    content_type: 'image/png',
  };
} catch (e) {
  var svg2png = undefined;
  console.log("Can't rasterize without svg2png")
}

function save(file, data) {
  var temp = file + '.tmp';
  fs.writeFile(temp, data, function (err) {
    if (err) console.log(err);
    fs.rename(temp, file, function (err) {
      if (err) console.log(err);
    });
  });
}

function render_png(data, callback) {
  svg2png(data, {width: svg.width * 1.5, height: svg.height * 1.5}).then(callback);
}

require('http').createServer(function (req, res) {
  var pathname = url.parse(req.url).pathname;
  var query = req.url.indexOf('?');
  if (!(pathname in urlmap) || query === -1) {
    res.writeHead(404, {'Content-Type': 'text/plain'});
    res.end('404 Not Found');
    return;
  }
  var config = urlmap[pathname];
  var math = unescape(req.url.substr(query+1));
  var hash = crypto.createHash('md5').update(math).digest('hex');
  var key = config.cache + '_' + hash;
  var prefix = path.join(cache_dir, config.cache + '_' + hash);
  var cache = prefix + '.' + config.type;
  fs.exists(cache, function (exists) {
    if (exists) {
      if (x_accel === null) {
        fs.readFile(cache, function (err, data) {
          if (err) {
            console.log(err);
            res.writeHead(500, {'Content-Type': 'text/plain'});
            res.end(err.toString());
          } else {
            res.writeHead(200, {'Content-Type': config.content_type});
            res.end(data);
          }
        });
      } else {
        res.writeHead(200, {
          'Content-Type': config.content_type,
          'X-Accel-Redirect': x_accel + key + '.' + config.type
        });
        res.end();
      }
      return;
    }
    mjAPI.typeset({
      math: math,
      format: config.format,
      svg: true,
    }, function (data) {
      if (data.errors) {
        res.writeHead(400, {'Content-Type': 'text/plain'});
        res.end(data.errors.toString());
      } else {
        res.writeHead(200, {'Content-Type': config.content_type});
        if (typeof svgo !== 'undefined') {
          svgo.optimize(data.svg, function (result) {
            if (config.type == 'svg')
              res.end(result.data);
            save(prefix + '.svg', result.data);
          });
        } else {
          if (config.type == 'svg')
            res.end(data.svg);
          save(prefix + '.svg', data.svg);
        }
        render_png(data.svg, function (buffer) {
          if (config.type == 'png')
            res.end(buffer);
          save(prefix + '.png', buffer);
        });
      }
    });
  });
}).listen(parseInt(argv._[0]), argv.host);<|endoftext|>