<commit_before>// To avoid recalculation at every mouse movement tick
var PI_2 = Math.PI / 2;

/* global AFRAME */

if (typeof AFRAME === 'undefined') {
  throw new Error('Component attempted to register before AFRAME was available.');
}

/**
 * Gaze Control component for A-Frame.
 */
AFRAME.registerComponent('gaze-control', {
   dependencies: ['position', 'rotation'],

   schema: {
     enabled: { default: true }
   },

   init: function () {
     this.previousPosition = new THREE.Vector3();
     this.deltaPosition = new THREE.Vector3();

     // From setupMouseControls
     this.pitchObject = new THREE.Object3D();
     this.yawObject = new THREE.Object3D();
     this.yawObject.position.y = 10;
     this.yawObject.add(this.pitchObject);

     // From setupHMDControls
     this.dolly = new THREE.Object3D();
     this.euler = new THREE.Euler();
     this.zeroQuaternion = new THREE.Quaternion();

     this.onGazeMove = this.onGazeMove.bind(this);
   },

   update: function () {
     if (!this.data.enabled) { return; }
     this.updateOrientation();
     this.updatePosition();
   },

   play: function () {
     this.previousPosition.set(0, 0, 0);
     this.addEventListeners();
   },

   pause: function () {
     this.removeEventListeners();
   },

   tick: function (t) {
     this.update();
   },

   remove: function () {
     this.pause();
   },

   addEventListeners: function () {
     var sceneEl = this.el.sceneEl;
     var canvasEl = sceneEl.canvas;

     // listen for canvas to load.
     if (!canvasEl) {
       sceneEl.addEventListener('render-target-loaded', this.addEventListeners.bind(this));
       return;
     }

     canvasEl.addEventListener('gazemove', this.onGazeMove);
   },

   removeEventListeners: function () {
     var sceneEl = document.querySelector('a-scene');
     var canvasEl = sceneEl && sceneEl.canvas;
     if (!canvasEl) { return; }

     canvasEl.removeEventListener('gazemove', this.onGazeMove);
   },

   updateOrientation: (function () {
     var hmdEuler = new THREE.Euler();
     hmdEuler.order = 'YXZ';
     return function () {
       var pitchObject = this.pitchObject;
       var yawObject = this.yawObject;
       var hmdQuaternion = this.calculateHMDQuaternion();
       hmdEuler.setFromQuaternion(hmdQuaternion);
       this.el.setAttribute('rotation', {
         x: THREE.Math.radToDeg(hmdEuler.x) + THREE.Math.radToDeg(pitchObject.rotation.x),
         y: THREE.Math.radToDeg(hmdEuler.y) + THREE.Math.radToDeg(yawObject.rotation.y),
         z: THREE.Math.radToDeg(hmdEuler.z)
       });
     };
   })(),

   calculateHMDQuaternion: (function () {
     var hmdQuaternion = new THREE.Quaternion();
     return function () {
       var dolly = this.dolly;
       if (!this.zeroed && !dolly.quaternion.equals(this.zeroQuaternion)) {
         this.zeroOrientation();
         this.zeroed = true;
       }
       hmdQuaternion.copy(this.zeroQuaternion).multiply(dolly.quaternion);
       return hmdQuaternion;
     };
   })(),

   updatePosition: function () {
     var el = this.el;
     var deltaPosition = this.calculateDeltaPosition();
     var currentPosition = el.getAttribute('position');
     el.setAttribute('position', {
       x: currentPosition.x + deltaPosition.x,
       y: currentPosition.y + deltaPosition.y,
       z: currentPosition.z + deltaPosition.z
     });
   },

   calculateDeltaPosition: function () {
     var dolly = this.dolly;
     var deltaPosition = this.deltaPosition;
     var previousPosition = this.previousPosition;
     deltaPosition.copy(dolly.position);
     deltaPosition.sub(previousPosition);
     previousPosition.copy(dolly.position);
     return deltaPosition;
   },

   updateHMDQuaternion: (function () {
     var hmdQuaternion = new THREE.Quaternion();
     return function () {
       var dolly = this.dolly;
       this.controls.update();
       if (!this.zeroed && !dolly.quaternion.equals(this.zeroQuaternion)) {
         this.zeroOrientation();
         this.zeroed = true;
       }
       hmdQuaternion.copy(this.zeroQuaternion).multiply(dolly.quaternion);
       return hmdQuaternion;
     };
   })(),

   zeroOrientation: function () {
     var euler = new THREE.Euler();
     euler.setFromQuaternion(this.dolly.quaternion.clone().inverse());
     // Cancel out roll and pitch. We want to only reset yaw
     euler.z = 0;
     euler.x = 0;
     this.zeroQuaternion.setFromEuler(euler);
   },

   // Listener for gaze events that manipulates the scene based on gaze
   // location in window. Window is broken into 9 sectors in a 3x3 grid.
   // The center sector is the largest because the focal area consumes
   // most of the screen.
   onGazeMove: function(event) {
     // Base sector size and movements on the size of the window
     var width = window.innerWidth;
     var height = window.innerHeight;

     // Because of landscape orientation and focal area, a larger portion
     // of the height contributes to a sector size than width.
     var sector_height = height/4; // height dimension of sector
     var sector_width = width/6; // width dimension of sector

     // Speed is somewhat arbitrary but obtained based on what felt
     // comfortable in testing.
     var movement_speed = 25; // speed of panning

     // Adapted from onMouseMove()
     var pitchObject = this.pitchObject;
     var yawObject = this.yawObject;
     var previousGazeEvent = this.previousGazeEvent;
     if (!this.data.enabled) { return; }

     // Bottom Left
     if (event.detail.x > 0 && event.detail.x < sector_width && event.detail.y > 0 && event.detail.y < sector_height){
       var movementX = -movement_speed;
       var movementY = -movement_speed;
     } // Bottom Center
     else if (event.detail.x > sector_width && event.detail.x < width - sector_width && event.detail.y > 0 && event.detail.y < sector_height){
       var movementX = 0;
       var movementY = -movement_speed;
     } // Bottom Right
     else if (event.detail.x > width - sector_width && event.detail.x < width && event.detail.y > 0 && event.detail.y < sector_height){
       var movementX = movement_speed;
       var movementY = -movement_speed;
     } // Middle Left
     else if (event.detail.x > 0 && event.detail.x < sector_width && event.detail.y > sector_height && event.detail.y < height - sector_height){
       var movementX = -movement_speed;
       var movementY = 0;
     } // Middle Right
     else if (event.detail.x > width - sector_width && event.detail.x < width && event.detail.y > sector_height && event.detail.y < height - sector_height){
       var movementX = movement_speed;
       var movementY = 0;
     } // Top Left
     else if (event.detail.x > 0 && event.detail.x < sector_width && event.detail.y > height - sector_height && event.detail.y < height){
       var movementX = -movement_speed
       var movementY = movement_speed;
     } // Top Center
     else if (event.detail.x > sector_width && event.detail.x < width - sector_width && event.detail.y > height - sector_height && event.detail.y < height){
       var movementX = 0;
       var movementY = movement_speed;
     } // Top Right
     else if (event.detail.x > width - sector_width && event.detail.x < width && event.detail.y > height - sector_height && event.detail.y < height){
       var movementX = movement_speed;
       var movementY = movement_speed;
     } // User is looking at center or not at another sector
     else{
       var movementX = 0;
       var movementY = 0;
     }

     // Adapted from onMouseMove()
     this.previousGazeEvent = event;
     yawObject.rotation.y -= movementX * 0.002;
     pitchObject.rotation.x -= movementY * 0.002;
     pitchObject.rotation.x = Math.max(-PI_2, Math.min(PI_2, pitchObject.rotation.x));
   }
 });
<commit_msg>Cleaned up comments.<commit_after>// To avoid recalculation at every mouse movement tick
var PI_2 = Math.PI / 2;

/* global AFRAME */

if (typeof AFRAME === 'undefined') {
  throw new Error('Component attempted to register before AFRAME was available.');
}

/**
 * Gaze Control component for A-Frame.
 */
AFRAME.registerComponent('gaze-control', {
   dependencies: ['position', 'rotation'],

   schema: {
     enabled: { default: true }
   },

   init: function () {
     this.previousPosition = new THREE.Vector3();
     this.deltaPosition = new THREE.Vector3();

     // From setupMouseControls
     this.pitchObject = new THREE.Object3D();
     this.yawObject = new THREE.Object3D();
     this.yawObject.position.y = 10;
     this.yawObject.add(this.pitchObject);

     // From setupHMDControls
     this.dolly = new THREE.Object3D();
     this.euler = new THREE.Euler();
     this.zeroQuaternion = new THREE.Quaternion();

     this.onGazeMove = this.onGazeMove.bind(this);
   },

   update: function () {
     if (!this.data.enabled) { return; }
     this.updateOrientation();
     this.updatePosition();
   },

   play: function () {
     this.previousPosition.set(0, 0, 0);
     this.addEventListeners();
   },

   pause: function () {
     this.removeEventListeners();
   },

   tick: function (t) {
     this.update();
   },

   remove: function () {
     this.pause();
   },

   addEventListeners: function () {
     var sceneEl = this.el.sceneEl;
     var canvasEl = sceneEl.canvas;

     // listen for canvas to load.
     if (!canvasEl) {
       sceneEl.addEventListener('render-target-loaded', this.addEventListeners.bind(this));
       return;
     }

     canvasEl.addEventListener('gazemove', this.onGazeMove);
   },

   removeEventListeners: function () {
     var sceneEl = document.querySelector('a-scene');
     var canvasEl = sceneEl && sceneEl.canvas;
     if (!canvasEl) { return; }

     canvasEl.removeEventListener('gazemove', this.onGazeMove);
   },

   updateOrientation: (function () {
     var hmdEuler = new THREE.Euler();
     hmdEuler.order = 'YXZ';
     return function () {
       var pitchObject = this.pitchObject;
       var yawObject = this.yawObject;
       var hmdQuaternion = this.calculateHMDQuaternion();
       hmdEuler.setFromQuaternion(hmdQuaternion);
       this.el.setAttribute('rotation', {
         x: THREE.Math.radToDeg(hmdEuler.x) + THREE.Math.radToDeg(pitchObject.rotation.x),
         y: THREE.Math.radToDeg(hmdEuler.y) + THREE.Math.radToDeg(yawObject.rotation.y),
         z: THREE.Math.radToDeg(hmdEuler.z)
       });
     };
   })(),

   calculateHMDQuaternion: (function () {
     var hmdQuaternion = new THREE.Quaternion();
     return function () {
       var dolly = this.dolly;
       if (!this.zeroed && !dolly.quaternion.equals(this.zeroQuaternion)) {
         this.zeroOrientation();
         this.zeroed = true;
       }
       hmdQuaternion.copy(this.zeroQuaternion).multiply(dolly.quaternion);
       return hmdQuaternion;
     };
   })(),

   updatePosition: function () {
     var el = this.el;
     var deltaPosition = this.calculateDeltaPosition();
     var currentPosition = el.getAttribute('position');
     el.setAttribute('position', {
       x: currentPosition.x + deltaPosition.x,
       y: currentPosition.y + deltaPosition.y,
       z: currentPosition.z + deltaPosition.z
     });
   },

   calculateDeltaPosition: function () {
     var dolly = this.dolly;
     var deltaPosition = this.deltaPosition;
     var previousPosition = this.previousPosition;
     deltaPosition.copy(dolly.position);
     deltaPosition.sub(previousPosition);
     previousPosition.copy(dolly.position);
     return deltaPosition;
   },

   updateHMDQuaternion: (function () {
     var hmdQuaternion = new THREE.Quaternion();
     return function () {
       var dolly = this.dolly;
       this.controls.update();
       if (!this.zeroed && !dolly.quaternion.equals(this.zeroQuaternion)) {
         this.zeroOrientation();
         this.zeroed = true;
       }
       hmdQuaternion.copy(this.zeroQuaternion).multiply(dolly.quaternion);
       return hmdQuaternion;
     };
   })(),

   zeroOrientation: function () {
     var euler = new THREE.Euler();
     euler.setFromQuaternion(this.dolly.quaternion.clone().inverse());
     // Cancel out roll and pitch. We want to only reset yaw
     euler.z = 0;
     euler.x = 0;
     this.zeroQuaternion.setFromEuler(euler);
   },

   onGazeMove: function(event) {
     var width = window.innerWidth;
     var height = window.innerHeight;

     var sector_height = height/4;
     var sector_width = width/6;

     var movement_speed = 25;

     // From onMouseMove()
     var pitchObject = this.pitchObject;
     var yawObject = this.yawObject;
     var previousGazeEvent = this.previousGazeEvent;
     if (!this.data.enabled) { return; }

     if (event.detail.x > 0 && event.detail.x < sector_width && event.detail.y > 0 && event.detail.y < sector_height){
       var movementX = -movement_speed;
       var movementY = -movement_speed;
     }
     else if (event.detail.x > sector_width && event.detail.x < width - sector_width && event.detail.y > 0 && event.detail.y < sector_height){
       var movementX = 0;
       var movementY = -movement_speed;
     }
     else if (event.detail.x > width - sector_width && event.detail.x < width && event.detail.y > 0 && event.detail.y < sector_height){
       var movementX = movement_speed;
       var movementY = -movement_speed;
     }
     else if (event.detail.x > 0 && event.detail.x < sector_width && event.detail.y > sector_height && event.detail.y < height - sector_height){
       var movementX = -movement_speed;
       var movementY = 0;
     }
     else if (event.detail.x > width - sector_width && event.detail.x < width && event.detail.y > sector_height && event.detail.y < height - sector_height){
       var movementX = movement_speed;
       var movementY = 0;
     }
     else if (event.detail.x > 0 && event.detail.x < sector_width && event.detail.y > height - sector_height && event.detail.y < height){
       var movementX = -movement_speed
       var movementY = movement_speed;
     }
     else if (event.detail.x > sector_width && event.detail.x < width - sector_width && event.detail.y > height - sector_height && event.detail.y < height){
       var movementX = 0;
       var movementY = movement_speed;
     }
     else if (event.detail.x > width - sector_width && event.detail.x < width && event.detail.y > height - sector_height && event.detail.y < height){
       var movementX = movement_speed;
       var movementY = movement_speed;
     }
     else{
       var movementX = 0;
       var movementY = 0;
     }

     // From onMouseMove()
     this.previousGazeEvent = event;
     yawObject.rotation.y -= movementX * 0.002;
     pitchObject.rotation.x -= movementY * 0.002;
     pitchObject.rotation.x = Math.max(-PI_2, Math.min(PI_2, pitchObject.rotation.x));
   }
 });
<|endoftext|>


<commit_before>const fs = require('fs')
const path = require('path')
// import async from 'async'
const _ = require('lodash')
const globby = require('globby')
const chalk = require('chalk')
const v = require('voca')

module.exports = function (options, changedFile) {
  const dir = (options.args[0] || '.')
  if (options.debug) log('dir', dir)

  if (changedFile) log('changed', changedFile)

  function log (status, msg) {
    if (!options.quiet || options.verbose || options.debug) {
      status = status || ''
      msg = msg || ''

      // const toJson = (!!msg) && (msg.constructor === Object || msg.constructor === Array)
      const toJson = typeof msg !== 'string'
      msg = toJson ? '\n    ' + v.replaceAll(JSON.stringify(msg, null, '  '), '\n', '\n    ') + '\n' : msg

      if ((status + msg) === '') {
        console.log('')
      } else {
        if (v.includes(msg, '\n')) {
          console.log('/*')
          console.log('  ' + chalk.green(v.pad(status, 11)))
          console.log(msg)
          console.log('*/\n')
        } else if (status === 'changed') {
          console.log('--' + chalk.yellow(v.pad(status, 11)) + msg)
        } else {
          console.log('--' + chalk.green(v.pad(status, 11)) + msg)
        }
      }
    }
  }

  function assert (val, msg) {
    if (!val) throw new Error(msg)
  }

  function buildOne (p, f, r) {
    f = path.join(p, f)
    p = path.dirname(f)

    assert(fs.existsSync(f), 'File not found! ' + f)
    if (options.verbose) log((r ? '+++++' : 'entry'), f)

    var data = fs.readFileSync(f, 'utf8')
    var lines = data.trim().split('\n')

    for (var i = 0; i < lines.length; i++) {
      if (_.startsWith(lines[i], '\\ir')) {
        var incFile = path.join(p, lines[i].substr(4))

        assert(fs.existsSync(incFile), incFile + ' File not found from ' + f)

        if (fs.statSync(incFile).isDirectory()) {
          incFile = path.join(incFile, options.initFilename)
          assert(fs.existsSync(incFile), incFile + ' File not found from ' + f)
        }

        lines[i] = buildOne(path.dirname(incFile), path.basename(incFile), true)
      } else {
        if (!options.writeFile) console.log(lines[i])
      }
    }

    const res = lines.join('\n')

    if ((!r || (options.recursive && path.basename(f) === options.initFilename)) && options.writeFile) {
      const outFile = path.join(p, options.schemaFilename)
      fs.writeFileSync(outFile, res + '\n', 'utf8')
      if (!options.quiet) {
        log('write', outFile)
        if (options.verbose) log()
      }
    }

    return res
  }

  if (options.debug) log('options', options)

  const pattern = []

  // if (options.oneFile) {
  //   pattern.push(options.initFilename)
  // } else {
  //   pattern.push('**/' + options.initFilename)
  //   pattern.push('!./' + options.initFilename)
  // }

  pattern.push(options.initFilename)
  if (options.debug) log('pattern', pattern)

  return globby(pattern, {cwd: dir}).then(function (files) {
    if (options.debug) log('entry file(s)', files)

    log()

    const c = files.reduce(function (content, file) {
      const nextContent = buildOne(dir, file)

      return options.writeFile ? '' : content + nextContent
    }, '')

    if (!options.verbose) log()

    return c
  })
}
<commit_msg>more timing<commit_after>const fs = require('fs')
const path = require('path')
// import async from 'async'
const _ = require('lodash')
const globby = require('globby')
const chalk = require('chalk')
const v = require('voca')

module.exports = function (options, changedFile) {
  const dir = (options.args[0] || '.')
  if (options.debug) log('dir', dir)

  if (changedFile) log('changed', changedFile)

  function log (status, msg, timing = 0) {
    const timeMsg = timing ? chalk.grey(` (${timing} ms)`) : ''

    if (!options.quiet || options.verbose || options.debug) {
      status = status || ''
      msg = msg || ''

      // const toJson = (!!msg) && (msg.constructor === Object || msg.constructor === Array)
      const toJson = typeof msg !== 'string'
      msg = toJson ? '\n    ' + v.replaceAll(JSON.stringify(msg, null, '  '), '\n', '\n    ') + '\n' : msg

      if ((status + msg) === '') {
        console.log('')
      } else {
        if (v.includes(msg, '\n')) {
          console.log('/*')
          console.log('  ' + chalk.green(v.pad(status, 11)))
          console.log(msg)
          console.log(' ' + timeMsg)
          console.log('*/\n')
        } else if (status === 'changed') {
          console.log('--' + chalk.yellow(v.pad(status, 11)) + msg + timeMsg)
        } else {
          console.log('--' + chalk.green(v.pad(status, 11)) + msg + timeMsg)
        }
      }
    }
  }

  function assert (val, msg) {
    if (!val) throw new Error(msg)
  }

  function buildOne (p, f, r) {
    const start = new Date()

    f = path.join(p, f)
    p = path.dirname(f)

    assert(fs.existsSync(f), 'File not found! ' + f)
    if (options.verbose) log((r ? '+++++' : 'entry'), f)

    var data = fs.readFileSync(f, 'utf8')
    var lines = data.trim().split('\n')

    for (var i = 0; i < lines.length; i++) {
      if (_.startsWith(lines[i], '\\ir')) {
        var incFile = path.join(p, lines[i].substr(4))

        assert(fs.existsSync(incFile), incFile + ' File not found from ' + f)

        if (fs.statSync(incFile).isDirectory()) {
          incFile = path.join(incFile, options.initFilename)
          assert(fs.existsSync(incFile), incFile + ' File not found from ' + f)
        }

        lines[i] = buildOne(path.dirname(incFile), path.basename(incFile), true)
      } else {
        if (!options.writeFile) console.log(lines[i])
      }
    }

    const res = lines.join('\n')

    if ((!r || (options.recursive && path.basename(f) === options.initFilename)) && options.writeFile) {
      const outFile = path.join(p, options.schemaFilename)
      fs.writeFileSync(outFile, res + '\n', 'utf8')
      if (!options.quiet) {
        log('write', outFile, (options.timing ? new Date() - start : 0))
        if (options.verbose) log()
      }
    }

    return res
  }

  if (options.debug) log('options', options)

  const pattern = []

  // if (options.oneFile) {
  //   pattern.push(options.initFilename)
  // } else {
  //   pattern.push('**/' + options.initFilename)
  //   pattern.push('!./' + options.initFilename)
  // }

  pattern.push(options.initFilename)
  if (options.debug) log('pattern', pattern)

  return globby(pattern, {cwd: dir}).then(function (files) {
    if (options.debug) log('entry file(s)', files)

    log()

    const c = files.reduce(function (content, file) {
      const nextContent = buildOne(dir, file)

      return options.writeFile ? '' : content + nextContent
    }, '')

    if (!options.verbose) log()

    return c
  })
}
<|endoftext|>


<commit_before>/* globals module */

'use strict'

module.exports = {
  name: 'ember-frost-date-picker',

  init: function (app) {
    this.options = this.options || {}
    this.options.babel = this.options.babel || {}
    this.options.babel.optional = this.options.babel.optional || []

    if (this.options.babel.optional.indexOf('es7.decorators') === -1) {
      this.options.babel.optional.push('es7.decorators')
    }

    /* eslint-disable no-unused-expressions */
    this._super.init && this._super.init.apply(this, arguments)
    /* eslint-enable no-unused-expressions */
  },

  included: function (app) {
    this._super.included(app)
    app.import(`${app.bowerDirectory}/clockpicker-seconds/dist/jquery-clockpicker.min.js`)
  }
}
<commit_msg>add support for engines<commit_after>/* globals module */

'use strict'

module.exports = {
  name: 'ember-frost-date-picker',

  init: function (app) {
    this.options = this.options || {}
    this.options.babel = this.options.babel || {}
    this.options.babel.optional = this.options.babel.optional || []

    if (this.options.babel.optional.indexOf('es7.decorators') === -1) {
      this.options.babel.optional.push('es7.decorators')
    }

    /* eslint-disable no-unused-expressions */
    this._super.init && this._super.init.apply(this, arguments)
    /* eslint-enable no-unused-expressions */
  },

  _findHost: function () {
    var current = this
    var app

    // Keep iterating upward until we don't have a grandparent.
    // Has to do this grandparent check because at some point we hit the project.
    do {
      app = current.app || app
    } while (current.parent.parent && (current = current.parent))
    return app
  },

  included: function () {
    var app = this._findHost()

    if (!app.bowerDirectory) {
      app.import('bower_components/clockpicker-seconds/dist/jquery-clockpicker.min.js')
    } else {
      app.import(`${app.bowerDirectory}/clockpicker-seconds/dist/jquery-clockpicker.min.js`)
    }
  }
}
<|endoftext|>


<commit_before>/**
 * Core modules
 */
var fs      = require("fs");
var path    = require("path");

/**
 * 3rd Party Modules
 */
var Immutable   = require("immutable");

var _           = require("lodash");

var emitter     = require("./lib/emitter");

/**
 * Logging
 * @type {exports}
 */
var logger      = require("./lib/logger")(emitter);

/**
 * Lib
 */
var utils       = require("./lib/utils");
var yaml        = require("./lib/yaml");
var Post        = require("./lib/post");
var Page        = require("./lib/page");
var Paginator   = require("./lib/paginator");
var Partial     = require("./lib/partial");

/**
 * Global cache
 * @type {Cache}
 * @private
 */
var Cache       = require("./lib/cache");
var cache       = new Cache(populateCache);

/**
 * Get a file from cache/FS - ALL methods/plugins use this.
 */
var file              = require("./lib/file")(cache, logger);

/**
 * Template compiler
 */
var compiler          = require("./lib/plugins/handlebars")(file, logger, emitter);

/**
 * Default Data Transforms
 */
var dataTransforms    = require("./lib/plugins/dataTransforms")(cache);

/**
 * Default content Transforms
 */
var contentTransforms = require("./lib/plugins/contentTransforms")(cache);

/**
 * Merge data transforms
 */
if (compiler["dataTransforms"]) {
    dataTransforms = _.merge(dataTransforms, compiler["dataTransforms"]);
}

var defaults = Immutable.Map({
    /**
     * The location of your sites configuration file.
     */
    configFile: "./_config.yml",
    /**
     * Should posts be rendered using Markdown?
     */
    markdown: true,
    /**
     * Should code snippets be auto-highlighted?
     */
    highlight: true,
    /**
     * Should ALL code fences be auto-highlighted?
     */
    autoHighlight: false,
    /**
     * Data format for posts
     */
    dateFormat: "LL", // http://momentjs.com/docs/#/utilities/
    /**
     * Post url format, eg: /blog/:year/:month/:title
     */
    postUrlFormat: false,
    /**
     * Instead of `blog/post1.html,` you can have `blog/post1` instead
     */
    prettyUrls: true,
    /**
     * Padd content blocks to enable nicer source code
     */
    prettyMarkup: true,
    /**
     * No layouts by default.
     */
    defaultLayout: false,
    /**
     * Initial Site config
     */
    siteConfig: Immutable.Map({})
});

/**
 * Allow layouts to have layouts.
 * Recursively render layout from the inside out (allows any number of nested layouts until the current
 * one does not specify a layout)
 * @param {String} layout
 * @param {Object} data
 * @param {Function} cb
 */
function addLayout(layout, data, cb) {

    var layoutPath = utils.getLayoutPath(layout);
    var layoutFile = file.getFile(layoutPath);

    if (!layoutFile) {
        logger.warn("The layout file {red:%s} does not exist", layoutPath);
        logger.warn("Check the file exists and that you've set the {magenta:cwd} property");
        return cb(null, data.item.content);
    }

    if (layoutFile && yaml.hasFrontMatter(layoutFile.content)) {

        // nested layout
        var _data   = yaml.readFrontMatter({
            file:     layoutFile.content,
            context:  data.item,
            filePath: data.item.paths.filePath
        });

        return renderTemplate(_data.content, data, function (err, out) {

            data = compiler.addContent({
                context: data,
                content: out,
                config: data.config
            });

            addLayout(_data.front.layout, data, cb);
        });
    }

    return renderTemplate(layoutFile.content, data, cb);
}

/**
 * @param template
 * @param data
 * @param cb
 */
function renderTemplate(template, data, cb) {
    compiler.renderTemplate(template, data, cb);
}

/**
 * @param out
 * @param config
 * @param data
 * @param scope
 */
function applyContentTransforms(scope, out, data, config) {

    _.each(contentTransforms, function (plugin) {
        if (plugin.when === scope) {
            out = plugin.fn(out, data, config);
        }
    });

    return out;
}

/**
 * @param scope
 * @param item
 * @param {Immutable.Map} config
 * @param data
 * @returns {*}
 */
function applyDataTransforms(scope, item, data, config) {

    _.each(dataTransforms, function (plugin) {
        if (plugin.when === scope) {
            data = plugin.fn(item || {}, data || {}, config);
        }
    });

    return data;
}

/**
 * @param item
 * @returns {*}
 */
function getMatch(item) {

    var match;

    // Try to find an item from the cache
    if (_.isString(item)) {
        match = cache.find(item, "posts");
        if (!match) {
            match = cache.find(item, "pages");
        }
    } else {
        return item;
    }

    return match;
}

/**
 * Compile a single file
 * @param {String|Object} item
 * @param {Object} userConfig
 * @param {Function} cb
 */
function compileOne(item, userConfig, cb) {

    /**
     * Merge configs
     */
    var config = defaults.merge(userConfig);

    /**
     * Set CWD on the fly
     */
    if (config.has("cwd")) {
        file.config.cwd = config.get("cwd");
    }

    /**
     * Setup data + look for _config.yml if needed
     * @type {{site: (siteConfig|*), config: *}}
     */
    var data = {
        config: config
    };

    /**
     * Get the current item from the cache
     * @type {*}
     */
    var match = getMatch(item);

    /**
     * Don't continue if there's no match or front-matter.
     * Posts & Pages should have already been added with .addPost or .addPage
     */
    if (!match || !match.front) {
        return cb(null, item);
    }

    /**
     * Compile 1, or with pagination
     */
    if (match.front.paginate) {
        doPagination(match, data, config, cb);
    } else {
        constructItem(match, data, config, function (err, item) {
            if (err) {
                return cb(err);
            } else {
                cb(null, item);
            }
        });
    }
}

/**
 * @param cb
 * @param config
 * @param items
 */
function compileMany(items, config, cb) {

    var compiled = [];
    var count    = 0;

    items.forEach(function (post) {
        compileOne(post, config, function (err, out) {
            if (err) {
                cb(err);
            }
            count += 1;
            if (Array.isArray(out)) {
                compiled.concat(out);
            } else {
                compiled.push(out);
            }
            if (count === items.length) {
                cb(null, compiled);
            }
        });
    });
}

/**
 * Convenience method to compile all posts & pages in cache
 * @param config
 * @param cb
 */
function compileAll(config, cb) {
    var items = cache.posts().concat(cache.pages());
    return compileMany(items, config, cb);
}

/**
 * Convenience method to compile all posts in the cache
 * @param config
 * @param cb
 */
function compilePosts(config, cb) {
    return compileMany(cache.posts(), config, cb);
}

/**
 * Convenience method to compile all pages in the cache
 * @param config
 * @param cb
 */
function compilePages(config, cb) {
    return compileMany(cache.pages(), config, cb);
}

/**
 * @param {Post|Page} item
 * @param {Object} data
 * @param {Object} config
 * @param {Function} cb
 */
function doPagination(item, data, config, cb) {

    var meta           = utils.splitMeta(item.front.paginate);
    var collection     = cache.getCollection(meta[0]);

    var paginator      = new Paginator(collection, item, meta[1], config);
    var paginatorPages = paginator.pages();

    var compiledItems  = [];

    paginatorPages.forEach(function (item, i) {

        data.paged = paginator.getMetaData(item, data.config, i);

        constructItem(item.page, data, config, function (err, item) {
            if (err) {
                return cb(err);
            } else {
                compiledItems.push(item);
                if (compiledItems.length === paginatorPages.length) {
                    cb(null, compiledItems);
                }
            }
        });
    });
}

/**
 * @param {Post|Page} item
 * @param {Object} data
 * @param {Immutable.Map} config
 * @param {Function} cb
 */
function constructItem(item, data, config, cb) {

    data = applyDataTransforms("before item parsed", item, data, config);

    renderTemplate(
        applyContentTransforms("before item parsed", item.content, data, config),
        data,
        handleSuccess.bind(null, item, data, config, cb));
}

/**
 * @param err
 * @param out
 * @param data
 * @param item
 * @param config
 * @param cb
 * @returns {*}
 */
function handleSuccess(item, data, config, cb, err, out) {

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

    var fullContent = applyContentTransforms("before item render", out, data, config);

    // Just write the body content without parsing (already done);
    data = compiler.addContent({
        content: fullContent,
        context: data,
        config:  config
    });

    var layout = getLayoutName(data.page.front.layout, config);

    if (layout) {
        return appendLayout(layout, item, data, cb);
    }

    item.compiled = fullContent;

    return cb(null, item);
}

/**
 * @param layout
 * @param {Immutable.Map} config
 * @returns {*}
 */
function getLayoutName(layout, config) {
    if (_.isUndefined(layout)) {
        if (config.get("defaultLayout") !== false) {
            return config.get("defaultLayout");
        }
    }
    return layout;
}

/**
 * @param layout
 * @param item
 * @param data
 * @param cb
 */
function appendLayout(layout, item, data, cb) {
    addLayout(layout, data, function (err, out) {
        if (err) {
            cb(err);
        } else {
            item.compiled = out;
            cb(null, item);
        }
    });
}

/**
 * @param {String} key
 * @param {String} value
 * @param {String} [type]
 * @returns {*}
 */
function populateCache(key, value, type) {

    var url = require("./lib/url");
    type = type || "partial";

    var partial;

    if (type === "data") {
        return cache.addData(key, value);
    }

    if (partial = cache.find(url.makeShortKey(key, file.config.cwd), "partials")){
        partial.content = value;
    } else {
        partial = new Partial(key, value, file);
        cache.addPartial(partial);
    }

    return cache;
}

/**
 * Allow api users to retrieve the cache.
 * @returns {{partials: {}, posts: Array, pages: Array}}
 */
function getCache() {
    return cache;
}

/**
 * @param key
 * @param string
 * @param [userConfig]
 */
function addPost(key, string, userConfig) {

    var config = getConfig(userConfig);

    var post;

    /**
     * Update a cached post
     */
    if (post = cache.find(key, "posts")) {
        post.addData(key, string);
        utils.prepareFrontVars({
            items:    post,
            config:   config,
            override: true,
            blacklist: ["categories"]
        });
        return post;
    }

    /**
     * Create a new post.
     * @type {Post}
     */
    post = new Post(key, string, config);

    var filtered = applyDataTransforms("before item added", post, {}, config);

    if (filtered) {
        cache.addPost(filtered);
        return filtered;
    }

    return post;
}

function getConfig (userConfig) {

    var config = Immutable.Map(userConfig || {});

    if (!config.cwd) {
        return config.set("cwd", file.config.cwd);
    }

    return config;
}

/**
 * @param key
 * @param string
 * @param [userConfig]
 */
function addPage(key, string, userConfig) {

    var config = getConfig(userConfig);
    var page;

    if (page = cache.find(key, "pages")) {
        logger.debug("Updating page: {yellow:%s}", page.key);
        page.addData(key, string);
        utils.prepareFrontVars({
            items: page,
            config: config,
            override: true
        });
        return page;
    }

    page = new Page(key, string, config);

    logger.debug("Adding page {yellow:%s} as {cyan:%s}", page.key, page.url);
    cache.addPage(page);

    return page;
}

/**
 *
 */
function registerTransform (fn) {
    transforms.push(fn);
}

/*-------------/
 *  Public API
 *------------*/

/**
 * Cache/Log/Utils
 * @type {*|exports}
 */
module.exports.logger = logger;
module.exports.utils = utils;
module.exports.clearCache = function () {
    logger.debug("Clearing all caches, (posts, pages, includes, partials)");
    emitter.removeAllListeners();
    file.reset();
    cache.reset();
};

/**
 * @param {String} cwd
 */
module.exports.setCwd = function (cwd) {
    file.config.cwd = cwd;
};

/**
 * Default configurations
 */
module.exports.defaults = defaults;

/**
 * Populate the cache
 */
module.exports.populateCache        = populateCache;
module.exports.compileOne           = compileOne;
module.exports.compilePosts         = compilePosts;
module.exports.compilePages         = compilePages;
module.exports.compileAll           = compileAll;
module.exports.compileMany          = compileMany;
module.exports.getCache             = getCache;
module.exports.addPost              = addPost;
module.exports.addPage              = addPage;
module.exports.registerTransform    = registerTransform;
module.exports.emitter              = emitter;
module.exports.file                 = file;

/**
 * @type {getFile}
 * @private
 */
module.exports._getFile = file.getFile;
module.exports.stream   = require("./plugins/stream");
<commit_msg>Remove configFile option - this to be resolved in facades<commit_after>/**
 * Core modules
 */
var fs      = require("fs");
var path    = require("path");

/**
 * 3rd Party Modules
 */
var Immutable   = require("immutable");

var _           = require("lodash");

var emitter     = require("./lib/emitter");

/**
 * Logging
 * @type {exports}
 */
var logger      = require("./lib/logger")(emitter);

/**
 * Lib
 */
var utils       = require("./lib/utils");
var yaml        = require("./lib/yaml");
var Post        = require("./lib/post");
var Page        = require("./lib/page");
var Paginator   = require("./lib/paginator");
var Partial     = require("./lib/partial");

/**
 * Global cache
 * @type {Cache}
 * @private
 */
var Cache       = require("./lib/cache");
var cache       = new Cache(populateCache);

/**
 * Get a file from cache/FS - ALL methods/plugins use this.
 */
var file              = require("./lib/file")(cache, logger);

/**
 * Template compiler
 */
var compiler          = require("./lib/plugins/handlebars")(file, logger, emitter);

/**
 * Default Data Transforms
 */
var dataTransforms    = require("./lib/plugins/dataTransforms")(cache);

/**
 * Default content Transforms
 */
var contentTransforms = require("./lib/plugins/contentTransforms")(cache);

/**
 * Merge data transforms
 */
if (compiler["dataTransforms"]) {
    dataTransforms = _.merge(dataTransforms, compiler["dataTransforms"]);
}

var defaults = Immutable.Map({
    /**
     * Should posts be rendered using Markdown?
     */
    markdown: true,
    /**
     * Should code snippets be auto-highlighted?
     */
    highlight: true,
    /**
     * Should ALL code fences be auto-highlighted?
     */
    autoHighlight: false,
    /**
     * Data format for posts
     */
    dateFormat: "LL", // http://momentjs.com/docs/#/utilities/
    /**
     * Post url format, eg: /blog/:year/:month/:title
     */
    postUrlFormat: false,
    /**
     * Instead of `blog/post1.html,` you can have `blog/post1` instead
     */
    prettyUrls: true,
    /**
     * Padd content blocks to enable nicer source code
     */
    prettyMarkup: true,
    /**
     * No layouts by default.
     */
    defaultLayout: false,
    /**
     * Initial Site config
     */
    siteConfig: Immutable.Map({})
});

/**
 * Allow layouts to have layouts.
 * Recursively render layout from the inside out (allows any number of nested layouts until the current
 * one does not specify a layout)
 * @param {String} layout
 * @param {Object} data
 * @param {Function} cb
 */
function addLayout(layout, data, cb) {

    var layoutPath = utils.getLayoutPath(layout);
    var layoutFile = file.getFile(layoutPath);

    if (!layoutFile) {
        logger.warn("The layout file {red:%s} does not exist", layoutPath);
        logger.warn("Check the file exists and that you've set the {magenta:cwd} property");
        return cb(null, data.item.content);
    }

    if (layoutFile && yaml.hasFrontMatter(layoutFile.content)) {

        // nested layout
        var _data   = yaml.readFrontMatter({
            file:     layoutFile.content,
            context:  data.item,
            filePath: data.item.paths.filePath
        });

        return renderTemplate(_data.content, data, function (err, out) {

            data = compiler.addContent({
                context: data,
                content: out,
                config: data.config
            });

            addLayout(_data.front.layout, data, cb);
        });
    }

    return renderTemplate(layoutFile.content, data, cb);
}

/**
 * @param template
 * @param data
 * @param cb
 */
function renderTemplate(template, data, cb) {
    compiler.renderTemplate(template, data, cb);
}

/**
 * @param out
 * @param config
 * @param data
 * @param scope
 */
function applyContentTransforms(scope, out, data, config) {

    _.each(contentTransforms, function (plugin) {
        if (plugin.when === scope) {
            out = plugin.fn(out, data, config);
        }
    });

    return out;
}

/**
 * @param scope
 * @param item
 * @param {Immutable.Map} config
 * @param data
 * @returns {*}
 */
function applyDataTransforms(scope, item, data, config) {

    _.each(dataTransforms, function (plugin) {
        if (plugin.when === scope) {
            data = plugin.fn(item || {}, data || {}, config);
        }
    });

    return data;
}

/**
 * @param item
 * @returns {*}
 */
function getMatch(item) {

    var match;

    // Try to find an item from the cache
    if (_.isString(item)) {
        match = cache.find(item, "posts");
        if (!match) {
            match = cache.find(item, "pages");
        }
    } else {
        return item;
    }

    return match;
}

/**
 * Compile a single file
 * @param {String|Object} item
 * @param {Object} userConfig
 * @param {Function} cb
 */
function compileOne(item, userConfig, cb) {

    /**
     * Merge configs
     */
    var config = defaults.merge(userConfig);

    /**
     * Set CWD on the fly
     */
    if (config.has("cwd")) {
        file.config.cwd = config.get("cwd");
    }

    /**
     * Setup data + look for _config.yml if needed
     * @type {{site: (siteConfig|*), config: *}}
     */
    var data = {
        config: config
    };

    /**
     * Get the current item from the cache
     * @type {*}
     */
    var match = getMatch(item);

    /**
     * Don't continue if there's no match or front-matter.
     * Posts & Pages should have already been added with .addPost or .addPage
     */
    if (!match || !match.front) {
        return cb(null, item);
    }

    /**
     * Compile 1, or with pagination
     */
    if (match.front.paginate) {
        doPagination(match, data, config, cb);
    } else {
        constructItem(match, data, config, function (err, item) {
            if (err) {
                return cb(err);
            } else {
                cb(null, item);
            }
        });
    }
}

/**
 * @param cb
 * @param config
 * @param items
 */
function compileMany(items, config, cb) {

    var compiled = [];
    var count    = 0;

    items.forEach(function (post) {
        compileOne(post, config, function (err, out) {
            if (err) {
                cb(err);
            }
            count += 1;
            if (Array.isArray(out)) {
                compiled.concat(out);
            } else {
                compiled.push(out);
            }
            if (count === items.length) {
                cb(null, compiled);
            }
        });
    });
}

/**
 * Convenience method to compile all posts & pages in cache
 * @param config
 * @param cb
 */
function compileAll(config, cb) {
    var items = cache.posts().concat(cache.pages());
    return compileMany(items, config, cb);
}

/**
 * Convenience method to compile all posts in the cache
 * @param config
 * @param cb
 */
function compilePosts(config, cb) {
    return compileMany(cache.posts(), config, cb);
}

/**
 * Convenience method to compile all pages in the cache
 * @param config
 * @param cb
 */
function compilePages(config, cb) {
    return compileMany(cache.pages(), config, cb);
}

/**
 * @param {Post|Page} item
 * @param {Object} data
 * @param {Object} config
 * @param {Function} cb
 */
function doPagination(item, data, config, cb) {

    var meta           = utils.splitMeta(item.front.paginate);
    var collection     = cache.getCollection(meta[0]);

    var paginator      = new Paginator(collection, item, meta[1], config);
    var paginatorPages = paginator.pages();

    var compiledItems  = [];

    paginatorPages.forEach(function (item, i) {

        data.paged = paginator.getMetaData(item, data.config, i);

        constructItem(item.page, data, config, function (err, item) {
            if (err) {
                return cb(err);
            } else {
                compiledItems.push(item);
                if (compiledItems.length === paginatorPages.length) {
                    cb(null, compiledItems);
                }
            }
        });
    });
}

/**
 * @param {Post|Page} item
 * @param {Object} data
 * @param {Immutable.Map} config
 * @param {Function} cb
 */
function constructItem(item, data, config, cb) {

    data = applyDataTransforms("before item parsed", item, data, config);

    renderTemplate(
        applyContentTransforms("before item parsed", item.content, data, config),
        data,
        handleSuccess.bind(null, item, data, config, cb));
}

/**
 * @param err
 * @param out
 * @param data
 * @param item
 * @param config
 * @param cb
 * @returns {*}
 */
function handleSuccess(item, data, config, cb, err, out) {

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

    var fullContent = applyContentTransforms("before item render", out, data, config);

    // Just write the body content without parsing (already done);
    data = compiler.addContent({
        content: fullContent,
        context: data,
        config:  config
    });

    var layout = getLayoutName(data.page.front.layout, config);

    if (layout) {
        return appendLayout(layout, item, data, cb);
    }

    item.compiled = fullContent;

    return cb(null, item);
}

/**
 * @param layout
 * @param {Immutable.Map} config
 * @returns {*}
 */
function getLayoutName(layout, config) {
    if (_.isUndefined(layout)) {
        if (config.get("defaultLayout") !== false) {
            return config.get("defaultLayout");
        }
    }
    return layout;
}

/**
 * @param layout
 * @param item
 * @param data
 * @param cb
 */
function appendLayout(layout, item, data, cb) {
    addLayout(layout, data, function (err, out) {
        if (err) {
            cb(err);
        } else {
            item.compiled = out;
            cb(null, item);
        }
    });
}

/**
 * @param {String} key
 * @param {String} value
 * @param {String} [type]
 * @returns {*}
 */
function populateCache(key, value, type) {

    var url = require("./lib/url");
    type = type || "partial";

    var partial;

    if (type === "data") {
        return cache.addData(key, value);
    }

    if (partial = cache.find(url.makeShortKey(key, file.config.cwd), "partials")){
        partial.content = value;
    } else {
        partial = new Partial(key, value, file);
        cache.addPartial(partial);
    }

    return cache;
}

/**
 * Allow api users to retrieve the cache.
 * @returns {{partials: {}, posts: Array, pages: Array}}
 */
function getCache() {
    return cache;
}

/**
 * @param key
 * @param string
 * @param [userConfig]
 */
function addPost(key, string, userConfig) {

    var config = getConfig(userConfig);

    var post;

    /**
     * Update a cached post
     */
    if (post = cache.find(key, "posts")) {
        post.addData(key, string);
        utils.prepareFrontVars({
            items:    post,
            config:   config,
            override: true,
            blacklist: ["categories"]
        });
        return post;
    }

    /**
     * Create a new post.
     * @type {Post}
     */
    post = new Post(key, string, config);

    var filtered = applyDataTransforms("before item added", post, {}, config);

    if (filtered) {
        cache.addPost(filtered);
        return filtered;
    }

    return post;
}

function getConfig (userConfig) {

    var config = Immutable.Map(userConfig || {});

    if (!config.cwd) {
        return config.set("cwd", file.config.cwd);
    }

    return config;
}

/**
 * @param key
 * @param string
 * @param [userConfig]
 */
function addPage(key, string, userConfig) {

    var config = getConfig(userConfig);
    var page;

    if (page = cache.find(key, "pages")) {
        logger.debug("Updating page: {yellow:%s}", page.key);
        page.addData(key, string);
        utils.prepareFrontVars({
            items: page,
            config: config,
            override: true
        });
        return page;
    }

    page = new Page(key, string, config);

    logger.debug("Adding page {yellow:%s} as {cyan:%s}", page.key, page.url);
    cache.addPage(page);

    return page;
}

/**
 *
 */
function registerTransform (fn) {
    transforms.push(fn);
}

/*-------------/
 *  Public API
 *------------*/

/**
 * Cache/Log/Utils
 * @type {*|exports}
 */
module.exports.logger = logger;
module.exports.utils = utils;
module.exports.clearCache = function () {
    logger.debug("Clearing all caches, (posts, pages, includes, partials)");
    emitter.removeAllListeners();
    file.reset();
    cache.reset();
};

/**
 * @param {String} cwd
 */
module.exports.setCwd = function (cwd) {
    file.config.cwd = cwd;
};

/**
 * Default configurations
 */
module.exports.defaults = defaults;

/**
 * Populate the cache
 */
module.exports.populateCache        = populateCache;
module.exports.compileOne           = compileOne;
module.exports.compilePosts         = compilePosts;
module.exports.compilePages         = compilePages;
module.exports.compileAll           = compileAll;
module.exports.compileMany          = compileMany;
module.exports.getCache             = getCache;
module.exports.addPost              = addPost;
module.exports.addPage              = addPage;
module.exports.registerTransform    = registerTransform;
module.exports.emitter              = emitter;
module.exports.file                 = file;

/**
 * @type {getFile}
 * @private
 */
module.exports._getFile = file.getFile;
module.exports.stream   = require("./plugins/stream");
<|endoftext|>


<commit_before>"use strict";
var string = require("string");
var assign = require("lodash.assign");
var defaults = {
  includeLevel: [ 1, 2 ],
  containerClass: "table-of-contents",
  slugify: function(str) {
    return string(str).slugify().toString();
  },
  markerPattern: /^\[\[toc\]\]/im,
  listType: "ul",
  format: undefined
};

module.exports = function(md, options) {
  var options = assign({}, defaults, options);
  var tocRegexp = options.markerPattern;
  var gstate;

  function toc(state, silent) {
    var token;
    var match;

    // Reject if the token does not start with [
    if (state.src.charCodeAt(state.pos) !== 0x5B /* [ */ ) {
      return false;
    }
    // Don't run any pairs in validation mode
    if (silent) {
      return false;
    }

    // Detect TOC markdown
    match = tocRegexp.exec(state.src);
    match = !match ? [] : match.filter(function(m) { return m; });
    if (match.length < 1) {
      return false;
    }

    // Build content
    token = state.push("toc_open", "toc", 1);
    token.markup = "[[toc]]";
    token = state.push("toc_body", "", 0);
    token = state.push("toc_close", "toc", -1);

    // Update pos so the parser can continue
    var newline = state.src.indexOf("\n");
    if (newline !== -1) {
      state.pos = state.pos + newline;
    } else {
      state.pos = state.pos + state.posMax + 1;
    }

    return true;
  }

  md.renderer.rules.toc_open = function(tokens, index) {
    return '
';
  };

  md.renderer.rules.toc_close = function(tokens, index) {
    return "
";
  };

  md.renderer.rules.toc_body = function(tokens, index) {
    return renderChildsTokens(0, gstate.tokens)[1];
  };

  function renderChildsTokens(pos, tokens) {
    var headings = [],
        buffer = '',
        currentLevel,
        subHeadings,
        size = tokens.length,
        i = pos;
    while(i < size) {
      var token = tokens[i];
      var heading = tokens[i - 1];
      var level = parseInt(token.tag.substr(1, 1));
      if (token.type !== "heading_close" || options.includeLevel.indexOf(level) == -1 || heading.type !== "inline") {
        i++; continue; // Skip if not matching criteria
      }
      if (!currentLevel) {
        currentLevel = level;// We init with the first found level
      } else {
        if (level > currentLevel) {
          subHeadings = renderChildsTokens(i, tokens);
          buffer += subHeadings[1];
          i = subHeadings[0];
          continue;
        }
        if (level < currentLevel) {
          // Finishing the sub headings
          buffer += "
";
          headings.push(buffer);
          return [i, "<" + options.listType + ">" + headings.join("") + "</" + options.listType + ">"];
        }
        if (level == currentLevel) {
          // Finishing the sub headings
          buffer += "
";
          headings.push(buffer);
        }
      }
      buffer = "
";
      buffer += typeof options.format === "function" ? options.format(heading.content) : heading.content;
      buffer += "";
      i++;
    }
    buffer += "
";
    headings.push(buffer);
    return [i, "<" + options.listType + ">" + headings.join("") + "</" + options.listType + ">"];
  }

  // Catch all the tokens for iteration later
  md.core.ruler.push("grab_state", function(state) {
    gstate = state;
  });

  // Insert TOC
  md.inline.ruler.after("emphasis", "toc", toc);
};
<commit_msg>Fix "Cannot read property 'substr' of null"<commit_after>"use strict";
var string = require("string");
var assign = require("lodash.assign");
var defaults = {
  includeLevel: [ 1, 2 ],
  containerClass: "table-of-contents",
  slugify: function(str) {
    return string(str).slugify().toString();
  },
  markerPattern: /^\[\[toc\]\]/im,
  listType: "ul",
  format: undefined
};

module.exports = function(md, options) {
  var options = assign({}, defaults, options);
  var tocRegexp = options.markerPattern;
  var gstate;

  function toc(state, silent) {
    var token;
    var match;

    // Reject if the token does not start with [
    if (state.src.charCodeAt(state.pos) !== 0x5B /* [ */ ) {
      return false;
    }
    // Don't run any pairs in validation mode
    if (silent) {
      return false;
    }

    // Detect TOC markdown
    match = tocRegexp.exec(state.src);
    match = !match ? [] : match.filter(function(m) { return m; });
    if (match.length < 1) {
      return false;
    }

    // Build content
    token = state.push("toc_open", "toc", 1);
    token.markup = "[[toc]]";
    token = state.push("toc_body", "", 0);
    token = state.push("toc_close", "toc", -1);

    // Update pos so the parser can continue
    var newline = state.src.indexOf("\n");
    if (newline !== -1) {
      state.pos = state.pos + newline;
    } else {
      state.pos = state.pos + state.posMax + 1;
    }

    return true;
  }

  md.renderer.rules.toc_open = function(tokens, index) {
    return '
';
  };

  md.renderer.rules.toc_close = function(tokens, index) {
    return "
";
  };

  md.renderer.rules.toc_body = function(tokens, index) {
    return renderChildsTokens(0, gstate.tokens)[1];
  };

  function renderChildsTokens(pos, tokens) {
    var headings = [],
        buffer = '',
        currentLevel,
        subHeadings,
        size = tokens.length,
        i = pos;
    while(i < size) {
      var token = tokens[i];
      var heading = tokens[i - 1];
      var level = token.tag && parseInt(token.tag.substr(1, 1));
      if (token.type !== "heading_close" || options.includeLevel.indexOf(level) == -1 || heading.type !== "inline") {
        i++; continue; // Skip if not matching criteria
      }
      if (!currentLevel) {
        currentLevel = level;// We init with the first found level
      } else {
        if (level > currentLevel) {
          subHeadings = renderChildsTokens(i, tokens);
          buffer += subHeadings[1];
          i = subHeadings[0];
          continue;
        }
        if (level < currentLevel) {
          // Finishing the sub headings
          buffer += "
";
          headings.push(buffer);
          return [i, "<" + options.listType + ">" + headings.join("") + "</" + options.listType + ">"];
        }
        if (level == currentLevel) {
          // Finishing the sub headings
          buffer += "
";
          headings.push(buffer);
        }
      }
      buffer = "
";
      buffer += typeof options.format === "function" ? options.format(heading.content) : heading.content;
      buffer += "";
      i++;
    }
    buffer += "
";
    headings.push(buffer);
    return [i, "<" + options.listType + ">" + headings.join("") + "</" + options.listType + ">"];
  }

  // Catch all the tokens for iteration later
  md.core.ruler.push("grab_state", function(state) {
    gstate = state;
  });

  // Insert TOC
  md.inline.ruler.after("emphasis", "toc", toc);
};
<|endoftext|>


<commit_before>var express = require('express');
var app     = express();
var pak     = require('./package.json')
var Client  = require('node-rest-client').Client
var client  = new Client();
var year    = new Date().getFullYear();
var envic   = require('envic')

var shortIt = {
	company:    process.env.COMPANY       || process.env.NAME || process.env.APPNAME || pak.name,
	domain:     process.env.DOMAIN        || process.env.NAME || process.env.APPNAME || pak.name,
	name:       process.env.APPNAME       || pak.name,
	version:    process.env.APPVERSION    || pak.version,
	url:        process.env.URL           || 'https://github.com/yieme/shortit',
	year:       process.env.YEAR          || (year > 2015) ? '2015-' + year : year,
	logoUrl:    process.env.LOGO_URL      || 'logo.png',
	faviconUrl: process.env.FAVICON_URL   || 'favicon.png',
	nopowered:  process.env.NO_POWERED_BY || false,
	headCode:   process.env.HEADCODE      || '',
	bodyCode:   process.env.BODYCODE      || '',
	header1:    process.env.HEADERNAM     || false,
	value1:     process.env.HEADERVAL     || false,
	header2:    process.env.HEADERNAM2    || false,
	value2:     process.env.HEADERVAL2    || false,
	server:     process.env.SERVER        || false
};

shortIt.nameVersion = shortIt.name + '/' + shortIt.version
console.log('')
console.log('- - - - - - - - - - - - - - - -')
console.log(shortIt.nameVersion,'begin')

var conPassThru    = process.env.CONSOLE_PASSTHRU // console pass-thru
var logPassThru    = process.env.LOG_PASSTHRU
var passThruReturn = process.env.PASSTHRU_MESSAGE || '{ok:1}'
var passThruMaxLen = (process.env.PASSTHRU_MAXLEN) ? parseInt(process.env.PASSTHRU_MAXLEN) : 255 // maximum length of pass-thru string
var footerLinks = '';
var buttonLinks = '';
var shorts  = require('./shorts.json');
var fs      = require('fs')
var gaTxt   = fs.readFileSync('./templates/ga.js', 'utf8')
var gaid    = process.env.GA_ID
console.log('gaid:', gaid,'-',process.env.GA_ID)
if (gaid) {
	gaTxt = gaTxt.replace('$GAID', gaid)
}
var shortsDataUrl = process.env.DATA_URL;
app.set('port', (process.env.PORT || 5000));
var template      = '

$msg';
var home          = '$company uses the $domain domain as part of a service to protect users from harmful activity, to provide value for the developer ecosystem, and as a quality signal for surfacing interesting events.';
var msg404        = 'Sorry, page not found';
var lastUpdate    = 0;
var started       = +new Date();
var refreshWait   = 5000; // 5 seconds between refresh requests
var reloadFrequency = process.env.RELOAD || 24*60*60*1000; /// daily default
var stats         = {};
//var Logger        = require('le_node');
var winston    = require('winston')
var logentriesConfig = {
	token:      process.env.LOGENTRIES,
	bufferSize: process.env.LOGENTRIES_BUFFER || 100,
	secure:     1,
	'console':  1
};
var logger      = new winston.Logger()
logger.add(winston.transports.Console)
if (logentriesConfig.token) {
	console.log('Log transport: LogEntries')
	var Logentries = require('winston-logentries')
	logger.add(new winston.transports.Logentries(logentriesConfig))
}
var logUrl = envic('LOG_URL')
if (logUrl) {
	console.log('Log transport: Http', logUrl.host)
	logger.add( winston.transports.Http, logUrl )
}
var log = {
	info:    (logentriesConfig.token) ? function(m) { logger.log('info',    m)} : console.log,
	warning: (logentriesConfig.token) ? function(m) { logger.log('warning', m)} : console.warn,
	error:   (logentriesConfig.token) ? function(m) { logger.log('error',   m)} : console.error
}

var logFirebase = envic('LOG_FIREBASE')
var firelogRef
if (logFirebase) {
	console.log('Log transport: Http', logFirebase.url)
	var Firebase = require('firebase');
	var firelogRef = new Firebase(logFirebase.url);
	firelogRef.auth(logFirebase.token, function(error, result) {
	  if (error) {
	    console.log("Firebase Authentication Failed!", error);
			firelogRef = undefined
	  } else {
	    console.log("Firebase Authenticated successfully with payload:", result.auth);
	    console.log("Firebase Auth expires at:", new Date(result.expires * 1000));
	  }
	})
}

var favicon_png   = '';
var logo_png      = '';

app.use(function customHeaders( req, res, next ){
  // Switch off the default 'X-Powered-By: Express' header
	if (shortIt.nopowered) {
		app.disable( 'x-powered-by' );
	} else {
  	res.setHeader( 'X-Powered-By', shortIt.nameVersion);
	}
	if (shortIt.server)  res.setHeader('Server', shortIt.server)
	if (shortIt.header1) res.setHeader(shortIt.header1, shortIt.value1)
	if (shortIt.header2) res.setHeader(shortIt.header2, shortIt.value2)
  next()
})

function bump(area) {
	var now   = new Date();
	var year  = now.getFullYear();
	var month = now.getMonth() + 1;
	month     = (month<=9) ? '0' + month : ''+ month;
	var day   = now.getDate();
	day       = (day <= 9) ? '0' + day : '' + day;
	var stat  = stats[area] || {};
	stat.tdd = stat.tdd || 0;
	stat.tdd++;
	stat[year]     = stat[year]     || {};
	stat[year].ytd = stat[year].ytd || 0;
	stat[year].ytd++;
	stat[year][month]      = stat[year][month]      || {};
	stat[year][month].mtd  = stat[year][month].mtd  || 0;
	stat[year][month].mtd++;
	stat[year][month][day] = stat[year][month][day] || 0;
	stat[year][month][day]++;
	stats[area] = stat;
}

function duration(val) {
	val = Math.round(val / 1000);
	if (val <= 59) return val + 's';
	val = Math.round(val / 60);
	if (val <= 59) return val + 'm';
	val = Math.round(val / 60);
	if (val <= 23) return val + 'h';
	val = Math.round(val / 24);
	return val + 'd';
}

function getShorts() {
	var now       = +new Date();
	var timeDelta = now - lastUpdate;
	if (timeDelta > refreshWait) {
		lastUpdate  = now;
		if (shortsDataUrl) {
			client.get(shortsDataUrl, function(data, response){
				log.info(shortsDataUrl +   ' loaded at: ' + new Date().toString());
				var parsed = JSON.parse(data);
				shorts     = parsed;
			});
		} else {
			log.error('DATA_URL not defined');
		}
	}
}

function sendJson(res, obj) {
	res.type('json');
	obj = obj || {};
	var json = JSON.stringify(obj, null, 2);
	res.send(json);
}

function notFound(res, short) {
	bump('_404');
	log.warning('/' + short + ' Not Found');
	if (shorts._404) return doShort('_404', res);
	render(res, '_404', msg404.replace('$short', short));
	res.status(404);
}

function doShort(short, res) {
	var url   = shorts[short];
	if (url) {
		url = url.url || url; // support firebase short: { id: short, url: url } formatted data
		res.redirect(302, url);
		log.info(short + ': ' + url);
		bump(short);
	} else {
		notFound(res, short);
	}
}

function render(res, name, $msg) {
	var result = template.replace('$msg', $msg);
	for(var max=10; max>0 && result.indexOf('$') >= 0; max--) {
		result = result
			.replace('$company',     shortIt.company)
			.replace('$url',         shortIt.url)
			.replace('$domain',      shortIt.domain)
			.replace('$year',        shortIt.year)
			.replace('$logoUrl',     shortIt.logoUrl)
			.replace('$faviconUrl',  shortIt.faviconUrl)
			.replace('$packageName', shortIt.name)
			.replace('$packageVer',  shortIt.version)
			.replace('$headCode',    shortIt.headCode)
			.replace('$bodyCode',    shortIt.bodyCode)
			.replace('$buttonLinks', buttonLinks)
			.replace('$footerLinks', footerLinks)
		;
	}
	res.send(result);
	bump(name);
	log.info('/' + name);
}

function renderPng(res, name, img) {
	res.type('png');
	res.send(img);
	name = name + '.png';
	bump(name);
	log.info('/' + name);
}

app.get('/favicon.png', function (req, res) {
	renderPng(res, 'favicon', favicon);
});

app.get('/logo.png', function (req, res) {
	renderPng(res, 'logo', logo);
});

app.get('/', function (req, res) {
	if (shorts._home) return doShort('_home', res);
	render(res, '_home', process.env.MESSAGE || home);
});

app.get('/_reload', function (req, res) {
	render(res, '_reload', 'Reload done.');
	getShorts();
});

app.get('/_stats', function (req, res) {
	bump('_stats');
	stats._running = duration(+new Date() - started);
	stats._updated = duration(+new Date() - lastUpdate);
	sendJson(res, stats);
	log.info('/_stats ' + JSON.stringify(stats));
});

app.get('/_stats/:short', function (req, res) {
	bump('_stats/*');
	sendJson(res, stats[req.params.short]);
	log.info('/_stats/' + req.params.short);
});

String.prototype.replaceIgnoreCase = function(strReplace, strWith) {
    var reg = new RegExp(strReplace, 'i'); // i=ignore case, g=global (ie all)
    return this.replace(reg, strWith);
};

if (conPassThru) { // console pass-thru
	app.get(conPassThru, function (req, res) {
		data = req.originalUrl.replaceIgnoreCase(conPassThru, '')
		if (data.substr(0,1) == '/') data = data.replace('/', '')
		if (data.substr(0,1) == '?') data = data.replace('?', '')
		if (passThruMaxLen && data.length > passThruMaxLen) {
			data = data.substr(0, passThruMaxLen)
		}
		console.log('data', data);
		res.send(passThruReturn)
	});
}

if (logPassThru) {
	app.get(logPassThru, function (req, res) {
		data = req.originalUrl.replaceIgnoreCase(logPassThru, '')
		if (data.substr(0,1) == '/') data = data.replace('/', '')
		if (data.substr(0,1) == '?') data = data.replace('?', '')
		if (passThruMaxLen && data.length > passThruMaxLen) {
			data = data.substr(0, passThruMaxLen)
		}
		log.info(data);
		if (firelogRef) {
			firelogRef.push(data)
		}
		res.send(passThruReturn)
	});
}

app.get('/:short', function (req, res) {
	doShort(req.params.short, res);
});

var server = app.listen(app.get('port'), function () {
  var host = server.address().address;
  var port = server.address().port;
  log.info(shortIt.nameVersion + ' listening on: ' + host + ' port: ' + port + ' at: ' + new Date().toString());
	if (!process.env.COMPANY) {
		log.warning('COMPANY not defined');
	}
	if (!process.env.DOMAIN) {
		log.warning('DOMAIN not defined');
	}
	if (!process.env.URL) {
		log.warning('URL not defined');
	}
});

function loadFile(path, cb) {
	fs.readFile('./' + path, 'utf8', function (err, data) {
	  if (data && !err) {
			log.info('Loaded ' + path);
		} else {
			log.warning('Unable to load ' + path);
		}
		data = data.replace('$analytics', (gaid) ? gaTxt : '')
		cb(data);
	});
}

function loadTemplate(name, cb) {
	loadFile('./templates/' + name + '.html', cb);
}

function loadPng(path, cb) {
	fs.readFile('./' + path, function (err, data) {
	  if (data && !err) {
			log.info('Loaded ' + path);
		} else {
			log.warning('Unable to load ' + path);
		}
		cb(data);
	});
}

loadTemplate('index', function(data) {
	template = data || '';
});
loadTemplate('home', function(data) {
	home = data || '';
});
loadTemplate('404', function(data) {
	msg404 = data || '';
});
loadTemplate('footerLink', function(data) {
	data = data || '';
	for (var i=1; i<=9; i++) {
		if (process.env['FOOTER'+i]) {
			footerLinks += data
				.replace('$url',  process.env[ 'FOOTER_URL' + i ])
				.replace('$text', process.env[ 'FOOTER'     + i ])
			;
		}
	}
});
loadTemplate('buttonLink', function(data) {
	data = data || '';
	for (var i=1; i<=9; i++) {
		if (process.env['BUTTON'+i]) {
			buttonLinks += data
				.replace('$url',  process.env[ 'BUTTON_URL' + i ])
				.replace('$text', process.env[ 'BUTTON'     + i ])
			;
		}
	}
});
loadPng('favicon.png', function(data) {
	favicon = data || null;
});
loadPng('logo.png', function(data) {
	logo = data || null;
});

getShorts();
setInterval(getShorts, reloadFrequency);
<commit_msg>analytics fix<commit_after>var express = require('express');
var app     = express();
var pak     = require('./package.json')
var Client  = require('node-rest-client').Client
var client  = new Client();
var year    = new Date().getFullYear();
var envic   = require('envic')

var shortIt = {
	company:    process.env.COMPANY       || process.env.NAME || process.env.APPNAME || pak.name,
	domain:     process.env.DOMAIN        || process.env.NAME || process.env.APPNAME || pak.name,
	name:       process.env.APPNAME       || pak.name,
	version:    process.env.APPVERSION    || pak.version,
	url:        process.env.URL           || 'https://github.com/yieme/shortit',
	year:       process.env.YEAR          || (year > 2015) ? '2015-' + year : year,
	logoUrl:    process.env.LOGO_URL      || 'logo.png',
	faviconUrl: process.env.FAVICON_URL   || 'favicon.png',
	nopowered:  process.env.NO_POWERED_BY || false,
	headCode:   process.env.HEADCODE      || '',
	bodyCode:   process.env.BODYCODE      || '',
	header1:    process.env.HEADERNAM     || false,
	value1:     process.env.HEADERVAL     || false,
	header2:    process.env.HEADERNAM2    || false,
	value2:     process.env.HEADERVAL2    || false,
	server:     process.env.SERVER        || false
};

shortIt.nameVersion = shortIt.name + '/' + shortIt.version
console.log('')
console.log('- - - - - - - - - - - - - - - -')
console.log(shortIt.nameVersion,'begin')

var conPassThru    = process.env.CONSOLE_PASSTHRU // console pass-thru
var logPassThru    = process.env.LOG_PASSTHRU
var passThruReturn = process.env.PASSTHRU_MESSAGE || '{ok:1}'
var passThruMaxLen = (process.env.PASSTHRU_MAXLEN) ? parseInt(process.env.PASSTHRU_MAXLEN) : 255 // maximum length of pass-thru string
var footerLinks = '';
var buttonLinks = '';
var shorts  = require('./shorts.json');
var fs      = require('fs')
var gaTxt   = fs.readFileSync('./templates/ga.js', 'utf8')
var gaid    = process.env.GA_ID
if (gaid) {
	gaTxt = gaTxt.replace('$GAID', gaid)
}
var shortsDataUrl = process.env.DATA_URL;
app.set('port', (process.env.PORT || 5000));
var template      = '

$msg';
var home          = '$company uses the $domain domain as part of a service to protect users from harmful activity, to provide value for the developer ecosystem, and as a quality signal for surfacing interesting events.';
var msg404        = 'Sorry, page not found';
var lastUpdate    = 0;
var started       = +new Date();
var refreshWait   = 5000; // 5 seconds between refresh requests
var reloadFrequency = process.env.RELOAD || 24*60*60*1000; /// daily default
var stats         = {};
//var Logger        = require('le_node');
var winston    = require('winston')
var logentriesConfig = {
	token:      process.env.LOGENTRIES,
	bufferSize: process.env.LOGENTRIES_BUFFER || 100,
	secure:     1,
	'console':  1
};
var logger      = new winston.Logger()
logger.add(winston.transports.Console)
if (logentriesConfig.token) {
	console.log('Log transport: LogEntries')
	var Logentries = require('winston-logentries')
	logger.add(new winston.transports.Logentries(logentriesConfig))
}
var logUrl = envic('LOG_URL')
if (logUrl) {
	console.log('Log transport: Http', logUrl.host)
	logger.add( winston.transports.Http, logUrl )
}
var log = {
	info:    (logentriesConfig.token) ? function(m) { logger.log('info',    m)} : console.log,
	warning: (logentriesConfig.token) ? function(m) { logger.log('warning', m)} : console.warn,
	error:   (logentriesConfig.token) ? function(m) { logger.log('error',   m)} : console.error
}

var logFirebase = envic('LOG_FIREBASE')
var firelogRef
if (logFirebase) {
	console.log('Log transport: Http', logFirebase.url)
	var Firebase = require('firebase');
	var firelogRef = new Firebase(logFirebase.url);
	firelogRef.auth(logFirebase.token, function(error, result) {
	  if (error) {
	    console.log("Firebase Authentication Failed!", error);
			firelogRef = undefined
	  } else {
	    console.log("Firebase Authenticated successfully with payload:", result.auth);
	    console.log("Firebase Auth expires at:", new Date(result.expires * 1000));
	  }
	})
}

var favicon_png   = '';
var logo_png      = '';

app.use(function customHeaders( req, res, next ){
  // Switch off the default 'X-Powered-By: Express' header
	if (shortIt.nopowered) {
		app.disable( 'x-powered-by' );
	} else {
  	res.setHeader( 'X-Powered-By', shortIt.nameVersion);
	}
	if (shortIt.server)  res.setHeader('Server', shortIt.server)
	if (shortIt.header1) res.setHeader(shortIt.header1, shortIt.value1)
	if (shortIt.header2) res.setHeader(shortIt.header2, shortIt.value2)
  next()
})

function bump(area) {
	var now   = new Date();
	var year  = now.getFullYear();
	var month = now.getMonth() + 1;
	month     = (month<=9) ? '0' + month : ''+ month;
	var day   = now.getDate();
	day       = (day <= 9) ? '0' + day : '' + day;
	var stat  = stats[area] || {};
	stat.tdd = stat.tdd || 0;
	stat.tdd++;
	stat[year]     = stat[year]     || {};
	stat[year].ytd = stat[year].ytd || 0;
	stat[year].ytd++;
	stat[year][month]      = stat[year][month]      || {};
	stat[year][month].mtd  = stat[year][month].mtd  || 0;
	stat[year][month].mtd++;
	stat[year][month][day] = stat[year][month][day] || 0;
	stat[year][month][day]++;
	stats[area] = stat;
}

function duration(val) {
	val = Math.round(val / 1000);
	if (val <= 59) return val + 's';
	val = Math.round(val / 60);
	if (val <= 59) return val + 'm';
	val = Math.round(val / 60);
	if (val <= 23) return val + 'h';
	val = Math.round(val / 24);
	return val + 'd';
}

function getShorts() {
	var now       = +new Date();
	var timeDelta = now - lastUpdate;
	if (timeDelta > refreshWait) {
		lastUpdate  = now;
		if (shortsDataUrl) {
			client.get(shortsDataUrl, function(data, response){
				log.info(shortsDataUrl +   ' loaded at: ' + new Date().toString());
				var parsed = JSON.parse(data);
				shorts     = parsed;
			});
		} else {
			log.error('DATA_URL not defined');
		}
	}
}

function sendJson(res, obj) {
	res.type('json');
	obj = obj || {};
	var json = JSON.stringify(obj, null, 2);
	res.send(json);
}

function notFound(res, short) {
	bump('_404');
	log.warning('/' + short + ' Not Found');
	if (shorts._404) return doShort('_404', res);
	render(res, '_404', msg404.replace('$short', short));
	res.status(404);
}

function doShort(short, res) {
	var url   = shorts[short];
	if (url) {
		url = url.url || url; // support firebase short: { id: short, url: url } formatted data
		res.redirect(302, url);
		log.info(short + ': ' + url);
		bump(short);
	} else {
		notFound(res, short);
	}
}

function render(res, name, $msg) {
	var result = template.replace('$msg', $msg);
	for(var max=10; max>0 && result.indexOf('$') >= 0; max--) {
		result = result
			.replace('$company',     shortIt.company)
			.replace('$url',         shortIt.url)
			.replace('$domain',      shortIt.domain)
			.replace('$year',        shortIt.year)
			.replace('$logoUrl',     shortIt.logoUrl)
			.replace('$faviconUrl',  shortIt.faviconUrl)
			.replace('$packageName', shortIt.name)
			.replace('$packageVer',  shortIt.version)
			.replace('$headCode',    shortIt.headCode)
			.replace('$bodyCode',    shortIt.bodyCode)
			.replace('$buttonLinks', buttonLinks)
			.replace('$footerLinks', footerLinks)
		;
	}
	res.send(result);
	bump(name);
	log.info('/' + name);
}

function renderPng(res, name, img) {
	res.type('png');
	res.send(img);
	name = name + '.png';
	bump(name);
	log.info('/' + name);
}

app.get('/favicon.png', function (req, res) {
	renderPng(res, 'favicon', favicon);
});

app.get('/logo.png', function (req, res) {
	renderPng(res, 'logo', logo);
});

app.get('/', function (req, res) {
	if (shorts._home) return doShort('_home', res);
	render(res, '_home', process.env.MESSAGE || home);
});

app.get('/_reload', function (req, res) {
	render(res, '_reload', 'Reload done.');
	getShorts();
});

app.get('/_stats', function (req, res) {
	bump('_stats');
	stats._running = duration(+new Date() - started);
	stats._updated = duration(+new Date() - lastUpdate);
	sendJson(res, stats);
	log.info('/_stats ' + JSON.stringify(stats));
});

app.get('/_stats/:short', function (req, res) {
	bump('_stats/*');
	sendJson(res, stats[req.params.short]);
	log.info('/_stats/' + req.params.short);
});

String.prototype.replaceIgnoreCase = function(strReplace, strWith) {
    var reg = new RegExp(strReplace, 'i'); // i=ignore case, g=global (ie all)
    return this.replace(reg, strWith);
};

if (conPassThru) { // console pass-thru
	app.get(conPassThru, function (req, res) {
		data = req.originalUrl.replaceIgnoreCase(conPassThru, '')
		if (data.substr(0,1) == '/') data = data.replace('/', '')
		if (data.substr(0,1) == '?') data = data.replace('?', '')
		if (passThruMaxLen && data.length > passThruMaxLen) {
			data = data.substr(0, passThruMaxLen)
		}
		console.log('data', data);
		res.send(passThruReturn)
	});
}

if (logPassThru) {
	app.get(logPassThru, function (req, res) {
		data = req.originalUrl.replaceIgnoreCase(logPassThru, '')
		if (data.substr(0,1) == '/') data = data.replace('/', '')
		if (data.substr(0,1) == '?') data = data.replace('?', '')
		if (passThruMaxLen && data.length > passThruMaxLen) {
			data = data.substr(0, passThruMaxLen)
		}
		log.info(data);
		if (firelogRef) {
			firelogRef.push(data)
		}
		res.send(passThruReturn)
	});
}

app.get('/:short', function (req, res) {
	doShort(req.params.short, res);
});

var server = app.listen(app.get('port'), function () {
  var host = server.address().address;
  var port = server.address().port;
  log.info(shortIt.nameVersion + ' listening on: ' + host + ' port: ' + port + ' at: ' + new Date().toString());
	if (!process.env.COMPANY) {
		log.warning('COMPANY not defined');
	}
	if (!process.env.DOMAIN) {
		log.warning('DOMAIN not defined');
	}
	if (!process.env.URL) {
		log.warning('URL not defined');
	}
});

function loadFile(path, cb) {
	fs.readFile('./' + path, 'utf8', function (err, data) {
	  if (data && !err) {
			log.info('Loaded ' + path);
		} else {
			log.warning('Unable to load ' + path);
		}
		data = data.replace('$analytics', (gaid) ? gaTxt : '')
		cb(data);
	});
}

function loadTemplate(name, cb) {
	loadFile('./templates/' + name + '.html', cb);
}

function loadPng(path, cb) {
	fs.readFile('./' + path, function (err, data) {
	  if (data && !err) {
			log.info('Loaded ' + path);
		} else {
			log.warning('Unable to load ' + path);
		}
		cb(data);
	});
}

loadTemplate('index', function(data) {
	template = data || '';
});
loadTemplate('home', function(data) {
	home = data || '';
});
loadTemplate('404', function(data) {
	msg404 = data || '';
});
loadTemplate('footerLink', function(data) {
	data = data || '';
	for (var i=1; i<=9; i++) {
		if (process.env['FOOTER'+i]) {
			footerLinks += data
				.replace('$url',  process.env[ 'FOOTER_URL' + i ])
				.replace('$text', process.env[ 'FOOTER'     + i ])
			;
		}
	}
});
loadTemplate('buttonLink', function(data) {
	data = data || '';
	for (var i=1; i<=9; i++) {
		if (process.env['BUTTON'+i]) {
			buttonLinks += data
				.replace('$url',  process.env[ 'BUTTON_URL' + i ])
				.replace('$text', process.env[ 'BUTTON'     + i ])
			;
		}
	}
});
loadPng('favicon.png', function(data) {
	favicon = data || null;
});
loadPng('logo.png', function(data) {
	logo = data || null;
});

getShorts();
setInterval(getShorts, reloadFrequency);
<|endoftext|>


<commit_before>var sqlite3 = require('sqlite3').verbose();
var fs = require('fs');
var request = require('request');
var moment = require('moment');
var cron = require('node-cron');
var exec = require('child_process').exec;
var async = require('async');
/*

THE CODE IS SOOOO DIRTY, BUT I NEED THE DATA NOT CLEAN CODE
*/

/*
- Diseñar BD
- LLamada api
- guardar datos
- hacerlo npm task para que se ejecute periodicamente
- tests
*/
//var start = Date.now();

var db = new sqlite3.Database('gas_prices.db');
var today = new moment().format("DD/MM/YYYY");
async.waterfall([
	createDbPrices,
	createDb,
	function (callback) {
		var alreadyChecked = false;
		db.each("SELECT date as dd FROM gas_last WHERE num = 1", function (err, row) {
			if (err) throw err;
			if (row == undefined) return;
			alreadyChecked = (row['dd'] == today)
		}, function () {
			if (alreadyChecked)
				callback('Already Checked ');
			else
				callback(null);
		});
	},
	requestGasData,
], function (err, result) {
	if (err) {
		sendMail(err + today);
		process.exit(1);
		//throw err;
	} else {
		console.log(result);
		sendMail(result + today);
	}
});
/*cron.schedule('* * * * *', function () {
	createDb(db);
	requestGasData(db);
});*/

function requestGasData(callback) {
	var options = {
		url: 'https://sedeaplicaciones.minetur.gob.es/ServiciosRESTCarburantes/PreciosCarburantes/EstacionesTerrestres/',
		method: 'GET',
		headers: {
			'Accept': 'application/json, text/plain, */*'
		}
	};
	request(options, function (error, response, body) {
		if (!error && response.statusCode == 200) {
			var gasData = cleanUpResponse(JSON.parse(body));
			if (gasData.ListaEESSPrecio.length <= 0) {
				console.log("ERROR.");
				return;
			}
			var todayDate = new moment(gasData['Fecha'], 'DD/MM/YYYY').unix();
			insertDataToDb(db, gasData.ListaEESSPrecio, todayDate);
			console.log('Number of Fuel Stations parsed: ' + gasData.ListaEESSPrecio.length);
			responseToFile(gasData);
			db.close(function () {
				//console.log("Total time: " + (Date.now() - start) + "ms");
				allCompleted(callback);
			});
		} else {
			//sendMail('ERROR (L46): ' + gasData['Fecha']);
			callback('ERROR request ');
		}
	});
}
function insertDataToDb(db, rows, todayDate) {
	db.serialize(function () {
		rowsSinceLastCommit = 0;
		var stmt;
		rows.forEach(function callback(row, index, array) {
			if (rowsSinceLastCommit == 0) {
				db.run("begin transaction");
				stmt = db.prepare(`INSERT OR IGNORE INTO gas_data(
		'c_p', 'address', 'city', 'latitude', 'longitude', 'diesel_price', 'new_diesel_price',
		'province', 'ideess', 'idmunicipio', 'idprovincia', 'idccaa', 'date') VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)`);
			}
			stmt.run(
				row['C.P.'],
				row['Dirección'],
				row['Localidad'],
				row['Latitud'] == null ? null : parseFloat(row['Latitud'].replace(',', '.').replace(' ', '')),
				row['Longitud (WGS84)'] == null ? null : parseFloat(row['Longitud (WGS84)'].replace(',', '.').replace(' ', '')),
				row['Precio Gasoleo A'] == null ? null : parseFloat(row['Precio Gasoleo A'].replace(',', '.').replace(' ', '')),
				row['Precio Nuevo Gasoleo A'] == null ? null : parseFloat(row['Precio Nuevo Gasoleo A'].replace(',', '.').replace(' ', '')),
				row['Provincia'],
				row['IDEESS'],
				row['IDMunicipio'],
				row['IDProvincia'],
				row['IDCCAA'],
				todayDate);
			rowsSinceLastCommit++;
			if (rowsSinceLastCommit >= 1200) {
				db.run("commit");
				rowsSinceLastCommit = 0;
			}
		});
		if (rowsSinceLastCommit > 0)
			db.run("commit");
		/*db.each("SELECT rowid AS id, info FROM lorem", function (err, row) {
			console.log(row.id + ": " + row.info);
		});*/
	});
}
function createDbPrices(callback) {
	db.run("CREATE TABLE IF NOT EXISTS  `gas_data` ("
		+ "`c_p`	TEXT,"
		+ "`address`	TEXT,"
		+ "`city`	TEXT,"
		+ "`latitude`	REAL,"
		+ "`longitude`	REAL,"
		+ "`diesel_price`	REAL,"
		+ "`new_diesel_price`	REAL,"
		+ "`province`	TEXT,"
		+ "`ideess`	INTEGER,"
		+ "`idmunicipio`	INTEGER,"
		+ "`idprovincia`	INTEGER,"
		+ "`idccaa`	INTEGER,"
		+ "`date`	INTEGER NOT NULL,"
		+ "PRIMARY KEY(`ideess`,`date`));", callback);
}
function createDb(callback) {
	db.run("CREATE TABLE IF NOT EXISTS  `gas_last` ("
		+ "`num`	INTEGER,"
		+ "`date`	TEXT,"
		+ "PRIMARY KEY(`num`));", callback);

}

function responseToFile(response) {
	fs.writeFile('last_data.json', JSON.stringify(response, null, 4));
}

function cleanUpResponse(response) {
	var pricesData = response.ListaEESSPrecio.filter(function (ele) {
		return (ele != null && ele != 1);
	});
	response.ListaEESSPrecio = pricesData;
	return response;
}

function sendMail(body) {
	exec('echo ' + body + ' | mailx -s "GAS_PRICES" gonzalo.hernandez.1293@gmail.com', function (error, stdout, stderr) { });
}

function allCompleted(callback) {
	db.serialize(function () {
		var stmt = db.prepare("INSERT INTO gas_last VALUES (?,?)");
		stmt.run(1, today);
		stmt.finalize();
	});
	callback(null, 'OK ');
}
<commit_msg>Fixed some callbacks at the end that did not get executed<commit_after>var sqlite3 = require('sqlite3').verbose();
var fs = require('fs');
var request = require('request');
var moment = require('moment');
var cron = require('node-cron');
var exec = require('child_process').exec;
var async = require('async');
/*

THE CODE IS SOOOO DIRTY, BUT I NEED THE DATA NOT CLEAN CODE
*/

/*
- Diseñar BD
- LLamada api
- guardar datos
- hacerlo npm task para que se ejecute periodicamente
- tests
- db.serialize seems to be useless, so trash it
*/
//var start = Date.now();
var db_location = '/home/gonzalo/gas-prices-spain/gas_prices.db';
var db = new sqlite3.Database(db_location);
var today = new moment().format("DD/MM/YYYY");
async.waterfall([
	createDbPrices,
	createDb,
	function (callback) {
		var alreadyChecked = false;
		db.each("SELECT date as dd FROM gas_last WHERE num = 1", function (err, row) {
			if (err) throw err;
			if (row == undefined) return;
			alreadyChecked = (row['dd'] == today);
			//console.log(alreadyChecked + ' '+ row['dd']);
		}, function () {
			if (alreadyChecked)
				callback('ALREADY_CHECKED');
			else
				callback(null);
		});
	},
	requestGasData,
], function (err, result) {
	if (err) {
		if(err == 'ALREADY_CHECKED'){// This is fine, not an error
			console.log("Already checked today");
			process.exit();
		}

		sendMail(err+' '+ today, function(){ db.close(); process.exit(1);});
		console.log("Finished with Errors");
		//throw err;
	} else {
		console.log(result);
		sendMail(result+' '+ today, function(){ db.close(); process.exit();});
	}
});

/*cron.schedule('* * * * *', function () {
	createDb(db);
	requestGasData(db);
});*/

/***************************** MY FUNCTIONS ****************************/
function requestGasData(callback) {
	var options = {
		url: 'https://sedeaplicaciones.minetur.gob.es/ServiciosRESTCarburantes/PreciosCarburantes/EstacionesTerrestres/',
		method: 'GET',
		headers: {
			'Accept': 'application/json, text/plain, */*'
		}
	};
	request(options, function (error, response, body) {
		if (!error && response.statusCode == 200) {
			var gasData = cleanUpResponse(JSON.parse(body));
			if (gasData.ListaEESSPrecio.length <= 0) {
				callback('SERVICE_NOT_AVAILABLE');
				return;
			}
			var todayDate = new moment(gasData['Fecha'], 'DD/MM/YYYY').unix();
			insertDataToDb(db, gasData.ListaEESSPrecio, todayDate);
			console.log('Number of Fuel Stations parsed: ' + gasData.ListaEESSPrecio.length);
			responseToFile(gasData);
			db.close(function () {
				//console.log("Total time: " + (Date.now() - start) + "ms");
				allCompleted(callback);
			});
		} else {
			//sendMail('ERROR (L46): ' + gasData['Fecha']);
			callback('ERROR_IN_REQUEST');
		}
	});
}
function insertDataToDb(db, rows, todayDate) {
	db.serialize(function () {
		rowsSinceLastCommit = 0;
		var stmt;
		rows.forEach(function callback(row, index, array) {
			if (rowsSinceLastCommit == 0) {
				db.run("begin transaction");
				stmt = db.prepare(`INSERT OR IGNORE INTO gas_data(
		'c_p', 'address', 'city', 'latitude', 'longitude', 'diesel_price', 'new_diesel_price',
		'province', 'ideess', 'idmunicipio', 'idprovincia', 'idccaa', 'date') VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)`);
			}
			stmt.run(
				row['C.P.'],
				row['Dirección'],
				row['Localidad'],
				row['Latitud'] == null ? null : parseFloat(row['Latitud'].replace(',', '.').replace(' ', '')),
				row['Longitud (WGS84)'] == null ? null : parseFloat(row['Longitud (WGS84)'].replace(',', '.').replace(' ', '')),
				row['Precio Gasoleo A'] == null ? null : parseFloat(row['Precio Gasoleo A'].replace(',', '.').replace(' ', '')),
				row['Precio Nuevo Gasoleo A'] == null ? null : parseFloat(row['Precio Nuevo Gasoleo A'].replace(',', '.').replace(' ', '')),
				row['Provincia'],
				row['IDEESS'],
				row['IDMunicipio'],
				row['IDProvincia'],
				row['IDCCAA'],
				todayDate);
			rowsSinceLastCommit++;
			if (rowsSinceLastCommit >= 1200) {
				db.run("commit");
				rowsSinceLastCommit = 0;
			}
		});
		if (rowsSinceLastCommit > 0)
			db.run("commit");
		/*db.each("SELECT rowid AS id, info FROM lorem", function (err, row) {
			console.log(row.id + ": " + row.info);
		});*/
	});
}
function createDbPrices(callback) {
	db.run("CREATE TABLE IF NOT EXISTS  `gas_data` ("
		+ "`c_p`	TEXT,"
		+ "`address`	TEXT,"
		+ "`city`	TEXT,"
		+ "`latitude`	REAL,"
		+ "`longitude`	REAL,"
		+ "`diesel_price`	REAL,"
		+ "`new_diesel_price`	REAL,"
		+ "`province`	TEXT,"
		+ "`ideess`	INTEGER,"
		+ "`idmunicipio`	INTEGER,"
		+ "`idprovincia`	INTEGER,"
		+ "`idccaa`	INTEGER,"
		+ "`date`	INTEGER NOT NULL,"
		+ "PRIMARY KEY(`ideess`,`date`));", callback);
}
function createDb(callback) {
	db.run("CREATE TABLE IF NOT EXISTS  `gas_last` ("
		+ "`num`	INTEGER,"
		+ "`date`	TEXT,"
		+ "PRIMARY KEY(`num`));", callback);

}

function responseToFile(response) {
	fs.writeFile('last_data.json', JSON.stringify(response, null, 4));
}

function cleanUpResponse(response) {
	var pricesData = response.ListaEESSPrecio.filter(function (ele) {
		return (ele != null && ele != 1);
	});
	response.ListaEESSPrecio = pricesData;
	return response;
}

function sendMail(body, callback) {
	exec('echo ' + body + ' | mailx -s "GAS_PRICES" gonzalo.hernandez.1293@gmail.com', function (error, stdout, stderr) {
		if(callback)
			callback();
	});
}

function allCompleted(callback) {
	db.serialize(function () {
		var stmt = db.prepare("INSERT OR REPLACE INTO gas_last VALUES (1,?)");
		stmt.run(today, function(){ callback(null, 'OK'); } );
	});
}
<|endoftext|>


<commit_before>var five = require("johnny-five"),
    board = new five.Board({port: "COM13"});

board.on("ready", function() {
  // Create an Led on pin 13
  var led = new five.Led(2);

  // Create a new `motion` hardware instance.
  var motion = new five.IR.Motion(7);

  // "calibrated" occurs once, at the beginning of a session,
  motion.on("calibrated", function() {
    console.log("calibrated");
  });

  // "motionstart" events are fired when the "calibrated"
  // proximal area is disrupted, generally by some form of movement
  motion.on("motionstart", function() {
    console.log("on");
    led.on();
  });

  // "motionend" events are fired following a "motionstart" event
  // when no movement has occurred in X ms
  motion.on("motionend", function() {
    console.log("off");
    led.off();
  });

});

navigator.getUserMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);

if (navigator.getUserMedia) {
  navigator.getUserMedia(

    // constraints
    {
      video: true,
      audio: true
    },

    // successCallback
    function(localMediaStream) {
      var video = document.querySelector('video');
      video.src = window.URL.createObjectURL(localMediaStream);
      // Do something with the video here, e.g. video.play()
    },

    // errorCallback
    function(err) {
      console.log("The following error occured: " + err);
    });
} else {
  console.log("getUserMedia not supported");
}
<commit_msg>remove unused code<commit_after>var five = require("johnny-five");
var board = new five.Board({});

board.on("ready", function() {
  // Create an Led on pin 13
  var led = new five.Led(2);

  // Create a new `motion` hardware instance.
  var motion = new five.IR.Motion(7);

  // "calibrated" occurs once, at the beginning of a session,
  motion.on("calibrated", function() {
    console.log("calibrated");
  });

  // "motionstart" events are fired when the "calibrated"
  // proximal area is disrupted, generally by some form of movement
  motion.on("motionstart", function() {
    console.log("on");
    led.on();
  });

  // "motionend" events are fired following a "motionstart" event
  // when no movement has occurred in X ms
  motion.on("motionend", function() {
    console.log("off");
    led.off();

  });

});
<|endoftext|>