<commit_before>// Meteor Generate
// Copyright(c) 2014 Adam Brodzinski <adambrodzinski@gmail.com>
// MIT Licensed

/*global templatePath, puts */
var fs = require('fs-extra'),
    router = require('./router.js');

module.exports = {
  initSource: templatePath + 'init/',

  // Public: Copy the boilerplate in the templates init folder to
  // the user's root project folder. Creates a router and client
  // folder. The project name is used for removing original boilerplate.
  //
  // Examples:
  // require('./init').init('myProjectName');
  //
  // projectName - the {String} name of the user's meteor project
  //
  init: function(projectName) {
    var self = this;
    this.projectName = projectName;
    this.projDir = './' + projectName + '/';
    this.packages = this.projDir + '.meteor/packages';

    this._runCommand('meteor create ' + projectName, function() {

      router.create(self.projDir);
      self._copyTemplate();
      self._removeOriginalMeteorFiles(projectName);
      self._removeUnwantedPackages();

      // add packages to .meteor/packages file
      fs.appendFileSync(self.projDir + '.meteor/packages', 'iron-router\n');
      fs.appendFileSync(self.projDir + '.meteor/packages', 'browser-policy\n');
      puts("    Added Package: iron-router");
      puts("    Added Package: browser-policy");

      console.log('\n-------------------------------------------');
      console.log('  type cd %s to navigate to project', projectName);
      console.log('  then run `mrt update` to install Iron Router');
      console.log('-------------------------------------------\n');
    });
  },

  // Private: Copy the boilerplate from templates directory and place it
  // in the user's project root directory. Remove .gitkeep when done
  //
  _copyTemplate: function() {
    fs.copySync(this.initSource, this.projDir);
    fs.removeSync(this.projDir + 'client/.gitkeep');
    fs.removeSync(this.projDir + 'server/.gitkeep');

    console.log('    Created: .jshintrc');
    console.log('    Created: .jshintignore');
    console.log('    Created: smart.json');
    console.log('    Created: makefile');
  },

  // Private: Removes the original foo.html, foo.js, and foo.css files
  // that Meteor creates after a `meteor create foo` command
  //
  _removeOriginalMeteorFiles: function() {
    fs.removeSync(this.projDir + this.projectName + '.js');
    fs.removeSync(this.projDir + this.projectName + '.html');
    fs.removeSync(this.projDir + this.projectName + '.css');
    puts('    Removed: original boilerplate');
  },

  // Private: Removes packages that are not wanted for a production app
  //
  _removeUnwantedPackages: function() {
    this._removePackage('insecure');
    this._removePackage('autopublish');
    puts("Updating Packages");
    puts("    Removed Package: insecure");
    puts("    Removed Package: autopublish");
  },

  // Private: Run a command on the command line.
  //
  // command - the {String} command to run
  // callback - a {Function} to call when complete
  //
  _runCommand: function(command, callback) {
    var exec = require('child_process').exec;

    exec(command, function (err) {
      if (err) console.log('exec error: ' + err);
      callback.call(this);
    });
  },

  // Private: Look at packages file and remove package if present. Stream
  // packages file, replace, then overwrite original file.
  //
  // packageName - The {String} name of the package
  //
  _removePackage: function(packageName) {
    var oldPackages, newPackages;

    oldPackages = fs.readFileSync(this.packages, {encoding: 'utf-8'});
    newPackages = oldPackages.replace(packageName + '\n', '');
    fs.writeFileSync(this.packages, newPackages);
  }

};

<commit_msg>rename to puts<commit_after>// Meteor Generate
// Copyright(c) 2014 Adam Brodzinski <adambrodzinski@gmail.com>
// MIT Licensed

/*global templatePath, puts */
var fs = require('fs-extra'),
    router = require('./router.js');

module.exports = {
  initSource: templatePath + 'init/',

  // Public: Copy the boilerplate in the templates init folder to
  // the user's root project folder. Creates a router and client
  // folder. The project name is used for removing original boilerplate.
  //
  // Examples:
  // require('./init').init('myProjectName');
  //
  // projectName - the {String} name of the user's meteor project
  //
  init: function(projectName) {
    var self = this;
    this.projectName = projectName;
    this.projDir = './' + projectName + '/';
    this.packages = this.projDir + '.meteor/packages';

    this._runCommand('meteor create ' + projectName, function() {

      router.create(self.projDir);
      self._copyTemplate();
      self._removeOriginalMeteorFiles(projectName);
      self._removeUnwantedPackages();

      // add packages to .meteor/packages file
      fs.appendFileSync(self.projDir + '.meteor/packages', 'iron-router\n');
      fs.appendFileSync(self.projDir + '.meteor/packages', 'browser-policy\n');
      puts("    Added Package: iron-router");
      puts("    Added Package: browser-policy");

      puts('\n-------------------------------------------');
      puts('  type cd %s to navigate to project', projectName);
      puts('  then run `mrt update` to install Iron Router');
      puts('-------------------------------------------\n');
    });
  },

  // Private: Copy the boilerplate from templates directory and place it
  // in the user's project root directory. Remove .gitkeep when done
  //
  _copyTemplate: function() {
    fs.copySync(this.initSource, this.projDir);
    fs.removeSync(this.projDir + 'client/.gitkeep');
    fs.removeSync(this.projDir + 'server/.gitkeep');

    puts('    Created: .jshintrc');
    puts('    Created: .jshintignore');
    puts('    Created: smart.json');
    puts('    Created: makefile');
  },

  // Private: Removes the original foo.html, foo.js, and foo.css files
  // that Meteor creates after a `meteor create foo` command
  //
  _removeOriginalMeteorFiles: function() {
    fs.removeSync(this.projDir + this.projectName + '.js');
    fs.removeSync(this.projDir + this.projectName + '.html');
    fs.removeSync(this.projDir + this.projectName + '.css');
    puts('    Removed: original boilerplate');
  },

  // Private: Removes packages that are not wanted for a production app
  //
  _removeUnwantedPackages: function() {
    this._removePackage('insecure');
    this._removePackage('autopublish');
    puts("Updating Packages");
    puts("    Removed Package: insecure");
    puts("    Removed Package: autopublish");
  },

  // Private: Run a command on the command line.
  //
  // command - the {String} command to run
  // callback - a {Function} to call when complete
  //
  _runCommand: function(command, callback) {
    var exec = require('child_process').exec;

    exec(command, function (err) {
      if (err) puts('exec error: ' + err);
      callback.call(this);
    });
  },

  // Private: Look at packages file and remove package if present. Stream
  // packages file, replace, then overwrite original file.
  //
  // packageName - The {String} name of the package
  //
  _removePackage: function(packageName) {
    var oldPackages, newPackages;

    oldPackages = fs.readFileSync(this.packages, {encoding: 'utf-8'});
    newPackages = oldPackages.replace(packageName + '\n', '');
    fs.writeFileSync(this.packages, newPackages);
  }

};

<|endoftext|>


<commit_before>
// initialize a package.json file

module.exports = init

var read = require("read")
  , path = require("path")
  , readJson = require("./utils/read-json.js")
  , fs = require("graceful-fs")
  , promiseChain = require("./utils/promise-chain.js")
  , exec = require("./utils/exec.js")
  , semver = require("semver")
  , log = require("./utils/log.js")
  , npm = require("./npm.js")
  , output = require("./utils/output.js")

init.usage = "npm init [folder]"

function init (args, cb) {
  var folder = args[0] || "."
    , ll = npm.config.get("loglevel")
  npm.config.set("loglevel", "paused")
  if (folder.charAt(0) !== "/") folder = path.join(process.cwd(), folder)

  readJson(path.join(folder, "package.json"), function (er, data) {
    if (er) data = {}

    data.author = data.author ||
      { name: npm.config.get("init.author.name")
      , email: npm.config.get("init.author.email")
      , url: npm.config.get("init.author.url") }

    init_(data, folder, function (er) {
      npm.config.set("loglevel", ll)
      if (!er) log(path.resolve(folder, "package.json"), "written")
      cb(er)
    })
  })
}

function init_ (data, folder, cb) {
  var nv = npm.config.get("node-version")
    , p = semver.parse(nv)
    , eng = ""

  if (!p[5]) eng = "~" + nv
  else eng = "~" + [p[1], p[2], p[3]].join(".") + " || " + nv

  // node version 0.n is api-compatible with 0.(n+1) when n is odd.
  if (p[2] % 2) {
    eng += " || " + [p[1], +(p[2]) + 1].join(".")
  }

  output.write(
    ["This utility will walk you through creating a package.json file."
    ,"It only covers the most common items, and tries to guess sane defaults."
    ,""
    ,"See `npm help json` for definitive documentation on these fields"
    ,"and exactly what they do."
    ,""
    ,"Use `npm install <pkg> --save` afterwards to install a package and"
    ,"save it as a dependency in the package.json file."
    ,""
    ,"Press ^C at any time to quit."
    ,""
    ].join("\n"))
  promiseChain(cb)
    ( read
    , [{prompt: "Package name: ", default: defaultName(folder, data)}]
    , function (n) { data.name = n }
    )
    ( read
    , [{prompt: "Description: ", default: data.description}]
    , function (d) { data.description = d }
    )
    ( defaultVersion, [folder, data], function (v) { data.version = v } )
    (function (cb) {
      read( { prompt: "Package version: ", default: data.version }
          , function (er, v) {
        if (er) return cb(er)
        data.version = v
        cb()
      })
    }, [])
    ( read
    , [ { prompt: "Project homepage: "
        , default: data.homepage || data.url || "none" } ]
    , function (u) {
        if (u === "none") return
        data.homepage = u
        delete data.url
      }
    )
    ( defaultRepo, [folder, data], function (r) { data.repository = r } )
    (function (cb) {
      read( { prompt: "Project git repository: "
            , default: data.repository && data.repository.url || "none" }
          , function (er, r) {
              if (er) return cb(er)
              if (r !== "none") {
                data.repository = (data.repository || {}).url = r
              }
              cb()
            }
          )
    }, [])
    ( read
    , [{ prompt: "Author name: ", default: data.author && data.author.name }]
    , function (n) {
        if (!n) return
        (data.author = data.author || {}).name = n
      }
    )
    ( read
    , [ { prompt: "Author email: "
        , default: data.author && data.author.email || "none" } ]
    , function (n) {
        if (n === "none") return
        (data.author = data.author || {}).email = n
      }
    )
    ( read
    , [ { prompt: "Author url: "
        , default: data.author && data.author.url || "none" } ]
    , function (n) {
        if (n === "none") return
        (data.author = data.author || {}).url = n
      }
    )
    ( read
    , [ { prompt: "Main module/entry point: ", default: data.main || "none" } ]
    , function (m) {
        if (m === "none") {
          delete data.main
          return
        }
        data.main = m
      }
    )
    ( read
    , [ { prompt: "Test command: "
        , default: data.scripts && data.scripts.test || "none" } ]
    , function (t) {
        if (t === "none") return
        (data.scripts = data.scripts || {}).test = t
      }
    )
    ( read
    , [ { prompt: "What versions of node does it run on? "
        , default: data.engines && data.engines.node || (eng) } ]
    , function (nodever) {
        (data.engines = data.engines || {}).node = nodever
      }
    )
    (cleanupPaths, [data, folder])
    (function (cb) {
      try { data = readJson.processJson(data) }
      catch (er) { return cb(er) }
      Object.keys(data)
        .filter(function (k) { return k.match(/^_/) })
        .forEach(function (k) { delete data[k] })
      readJson.unParsePeople(data)
      var str = JSON.stringify(data, null, 2)
        , msg = "About to write to "
              + path.join(folder, "package.json")
              + "\n\n"
              + str
              + "\n\n"
      output.write(msg, cb)
    })
    (function (cb) {
      read({ prompt: "\nIs this ok? ", default: "yes" }, function (er, ok) {
        if (er) return cb(er)
        if (ok.toLowerCase().charAt(0) !== "y") {
          return cb(new Error("cancelled"))
        }
        return cb()
      })
    })
    (function (cb) {
      fs.writeFile( path.join(folder, "package.json")
                  , JSON.stringify(data, null, 2) + "\n"
                  , cb )
    })
    ()
}

// sync - no io
function defaultName (folder, data) {
  if (data.name) return data.name
  return path.basename(folder)
             .replace(/^node[-\._]?|([-\._]node)[-\._]?(js)?$/g, "")
}

function defaultVersion (folder, data, cb) {
  if (data.version) return cb(null, data.version)
  exec(npm.config.get("git"), ["describe", "--tags"], process.env, false, folder,
       function (er, code, out) {
    out = (out || "").trim()
    if (semver.valid(out)) return cb(null, out)
    out = npm.config.get("init.version")
    if (semver.valid(out)) return cb(null, out)
    return cb(null, "0.0.0")
  })
}

function defaultRepo (folder, data, cb) {
  if (data.repository) return cb(null, data.repository)
  exec( npm.config.get("git"), ["remote", "-v"], process.env, false, folder
      , function (er, code, out) {
    out = (out || "")
      .trim()
      .split("\n").filter(function (line) {
        return line.search(/^origin/) !== -1
      })[0]
    if (!out) return cb(null, {})
    var repo =
      { type: "git"
      , url: out.split(/\s/)[1]
                .replace("git@github.com:", "git://github.com/")
      }
    return cb(null, repo)
  })
}

function cleanupPaths (data, folder, cb) {
  if (data.main) {
    data.main = cleanupPath(data.main, folder)
  }
  var dirs = data.directories
  if (dirs) {
    Object.keys(dirs).forEach(function (dir) {
      dirs[dir] = cleanupPath(dirs[dir], folder)
    })
  }
  cb()
}

function cleanupPath (m, folder) {
  if (m.indexOf(folder) === 0) m = path.join(".", m.substr(folder.length))
  return m
}
<commit_msg>init: Don't add engines section<commit_after>
// initialize a package.json file

module.exports = init

var read = require("read")
  , path = require("path")
  , readJson = require("./utils/read-json.js")
  , fs = require("graceful-fs")
  , promiseChain = require("./utils/promise-chain.js")
  , exec = require("./utils/exec.js")
  , semver = require("semver")
  , log = require("./utils/log.js")
  , npm = require("./npm.js")
  , output = require("./utils/output.js")

init.usage = "npm init [folder]"

function init (args, cb) {
  var folder = args[0] || "."
    , ll = npm.config.get("loglevel")
  npm.config.set("loglevel", "paused")
  if (folder.charAt(0) !== "/") folder = path.join(process.cwd(), folder)

  readJson(path.join(folder, "package.json"), function (er, data) {
    if (er) data = {}

    data.author = data.author ||
      { name: npm.config.get("init.author.name")
      , email: npm.config.get("init.author.email")
      , url: npm.config.get("init.author.url") }

    init_(data, folder, function (er) {
      npm.config.set("loglevel", ll)
      if (!er) log(path.resolve(folder, "package.json"), "written")
      cb(er)
    })
  })
}

function init_ (data, folder, cb) {
  var nv = npm.config.get("node-version")
    , p = semver.parse(nv)
    , eng = ""

  if (!p[5]) eng = "~" + nv
  else eng = "~" + [p[1], p[2], p[3]].join(".") + " || " + nv

  // node version 0.n is api-compatible with 0.(n+1) when n is odd.
  if (p[2] % 2) {
    eng += " || " + [p[1], +(p[2]) + 1].join(".")
  }

  output.write(
    ["This utility will walk you through creating a package.json file."
    ,"It only covers the most common items, and tries to guess sane defaults."
    ,""
    ,"See `npm help json` for definitive documentation on these fields"
    ,"and exactly what they do."
    ,""
    ,"Use `npm install <pkg> --save` afterwards to install a package and"
    ,"save it as a dependency in the package.json file."
    ,""
    ,"Press ^C at any time to quit."
    ,""
    ].join("\n"))
  promiseChain(cb)
    ( read
    , [{prompt: "Package name: ", default: defaultName(folder, data)}]
    , function (n) { data.name = n }
    )
    ( read
    , [{prompt: "Description: ", default: data.description}]
    , function (d) { data.description = d }
    )
    ( defaultVersion, [folder, data], function (v) { data.version = v } )
    (function (cb) {
      read( { prompt: "Package version: ", default: data.version }
          , function (er, v) {
        if (er) return cb(er)
        data.version = v
        cb()
      })
    }, [])
    ( read
    , [ { prompt: "Project homepage: "
        , default: data.homepage || data.url || "none" } ]
    , function (u) {
        if (u === "none") return
        data.homepage = u
        delete data.url
      }
    )
    ( defaultRepo, [folder, data], function (r) { data.repository = r } )
    (function (cb) {
      read( { prompt: "Project git repository: "
            , default: data.repository && data.repository.url || "none" }
          , function (er, r) {
              if (er) return cb(er)
              if (r !== "none") {
                data.repository = (data.repository || {}).url = r
              }
              cb()
            }
          )
    }, [])
    ( read
    , [{ prompt: "Author name: ", default: data.author && data.author.name }]
    , function (n) {
        if (!n) return
        (data.author = data.author || {}).name = n
      }
    )
    ( read
    , [ { prompt: "Author email: "
        , default: data.author && data.author.email || "none" } ]
    , function (n) {
        if (n === "none") return
        (data.author = data.author || {}).email = n
      }
    )
    ( read
    , [ { prompt: "Author url: "
        , default: data.author && data.author.url || "none" } ]
    , function (n) {
        if (n === "none") return
        (data.author = data.author || {}).url = n
      }
    )
    ( read
    , [ { prompt: "Main module/entry point: ", default: data.main || "none" } ]
    , function (m) {
        if (m === "none") {
          delete data.main
          return
        }
        data.main = m
      }
    )
    ( read
    , [ { prompt: "Test command: "
        , default: data.scripts && data.scripts.test || "none" } ]
    , function (t) {
        if (t === "none") return
        (data.scripts = data.scripts || {}).test = t
      }
    )
    (cleanupPaths, [data, folder])
    (function (cb) {
      try { data = readJson.processJson(data) }
      catch (er) { return cb(er) }
      Object.keys(data)
        .filter(function (k) { return k.match(/^_/) })
        .forEach(function (k) { delete data[k] })
      readJson.unParsePeople(data)
      var str = JSON.stringify(data, null, 2)
        , msg = "About to write to "
              + path.join(folder, "package.json")
              + "\n\n"
              + str
              + "\n\n"
      output.write(msg, cb)
    })
    (function (cb) {
      read({ prompt: "\nIs this ok? ", default: "yes" }, function (er, ok) {
        if (er) return cb(er)
        if (ok.toLowerCase().charAt(0) !== "y") {
          return cb(new Error("cancelled"))
        }
        return cb()
      })
    })
    (function (cb) {
      fs.writeFile( path.join(folder, "package.json")
                  , JSON.stringify(data, null, 2) + "\n"
                  , cb )
    })
    ()
}

// sync - no io
function defaultName (folder, data) {
  if (data.name) return data.name
  return path.basename(folder)
             .replace(/^node[-\._]?|([-\._]node)[-\._]?(js)?$/g, "")
}

function defaultVersion (folder, data, cb) {
  if (data.version) return cb(null, data.version)
  exec(npm.config.get("git"), ["describe", "--tags"], process.env, false, folder,
       function (er, code, out) {
    out = (out || "").trim()
    if (semver.valid(out)) return cb(null, out)
    out = npm.config.get("init.version")
    if (semver.valid(out)) return cb(null, out)
    return cb(null, "0.0.0")
  })
}

function defaultRepo (folder, data, cb) {
  if (data.repository) return cb(null, data.repository)
  exec( npm.config.get("git"), ["remote", "-v"], process.env, false, folder
      , function (er, code, out) {
    out = (out || "")
      .trim()
      .split("\n").filter(function (line) {
        return line.search(/^origin/) !== -1
      })[0]
    if (!out) return cb(null, {})
    var repo =
      { type: "git"
      , url: out.split(/\s/)[1]
                .replace("git@github.com:", "git://github.com/")
      }
    return cb(null, repo)
  })
}

function cleanupPaths (data, folder, cb) {
  if (data.main) {
    data.main = cleanupPath(data.main, folder)
  }
  var dirs = data.directories
  if (dirs) {
    Object.keys(dirs).forEach(function (dir) {
      dirs[dir] = cleanupPath(dirs[dir], folder)
    })
  }
  cb()
}

function cleanupPath (m, folder) {
  if (m.indexOf(folder) === 0) m = path.join(".", m.substr(folder.length))
  return m
}
<|endoftext|>


<commit_before>
/*!
 * Jade
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Parser = require('./parser')
  , Compiler = require('./compiler')
// if node
  , fs = require('fs');
// end

/**
 * Library version.
 */

exports.version = '0.13.0';

/**
 * Intermediate JavaScript cache.
 */

var cache = exports.cache = {};

/**
 * Expose self closing tags.
 */

exports.selfClosing = require('./self-closing');

/**
 * Default supported doctypes.
 */

exports.doctypes = require('./doctypes');

/**
 * Text filters.
 */

exports.filters = require('./filters');

/**
 * Utilities.
 */

exports.utils = require('./utils');

/**
 * Expose `Compiler`.
 */

exports.Compiler = Compiler;

/**
 * Expose `Parser`.
 */

exports.Parser = Parser;

/**
 * Nodes.
 */

exports.nodes = require('./nodes');

/**
 * Render the given attributes object.
 *
 * @param {Object} obj
 * @return {String}
 * @api private
 */

function attrs(obj){
  var buf = []
    , terse = obj.terse;
  delete obj.terse;
  var keys = Object.keys(obj)
    , len = keys.length;
  if (len) {
    buf.push('');
    for (var i = 0; i < len; ++i) {
      var key = keys[i]
        , val = obj[key];
      if ('boolean' == typeof val || null == val) {
        if (val) {
          terse
            ? buf.push(key)
            : buf.push(key + '="' + key + '"');
        }
      } else if ('class' == key && Array.isArray(val)) {
        buf.push(key + '="' + escape(val.join(' ')) + '"');
      } else {
        buf.push(key + '="' + escape(val) + '"');
      }
    }
  }
  return buf.join(' ');
}

/**
 * Escape the given string of `html`.
 *
 * @param {String} html
 * @return {String}
 * @api private
 */

function escape(html){
  return String(html)
    .replace(/&(?!\w+;)/g, '&')
    .replace(/</g, '<')
    .replace(/>/g, '>')
    .replace(/"/g, '"');
}

/**
 * Re-throw the given `err` in context to the
 * `str` of jade, `filename`, and `lineno`.
 *
 * @param {Error} err
 * @param {String} str
 * @param {String} filename
 * @param {String} lineno
 * @api private
 */

function rethrow(err, str, filename, lineno){
  var context = 3
    , lines = str.split('\n')
    , start = Math.max(lineno - context, 0)
    , end = Math.min(lines.length, lineno + context);

  // Error context
  var context = lines.slice(start, end).map(function(line, i){
    var curr = i + start + 1;
    return (curr == lineno ? '  > ' : '    ')
      + curr
      + '| '
      + line;
  }).join('\n');

  // Alter exception message
  err.path = filename;
  err.message = (filename || 'Jade') + ':' + lineno
    + '\n' + context + '\n\n' + err.message;
  throw err;
}

/**
 * Parse the given `str` of jade and return a function body.
 *
 * @param {String} str
 * @param {Object} options
 * @return {String}
 * @api private
 */

function parse(str, options){
  var filename = options.filename
    , helpers = ''

  if (options.helpers !== 'inline') {
    jadeHelpers = {
      attrs: attrs,
      escape: escape
    }
    helpers = 'var attrs = jadeHelpers.attrs, escape = jadeHelpers.escape;\n';
  } else {
    helpers = attrs.toString() + '\n' + escape.toString() + '\n';
  }

  try {
    // Parse
    var parser = new Parser(str, filename);
    if (options.debug) parser.debug();

    // Compile
    var compiler = new (options.compiler || Compiler)(parser.parse(), options)
      , js = compiler.compile();

    // Debug compiler
    if (options.debug) {
      console.log('\n\x1b[1mCompiled Function\x1b[0m:\n\n%s', js.replace(/^/gm, '  '));
    }

    try {
      return ''
        + helpers
        + 'var buf = [];\n'
        + (options.self
          ? 'var self = locals || {}, __ = __ || locals.__;\n' + js
          : 'with (locals || {}) {' + js + '}')
        + 'return buf.join("");';
    } catch (err) {
      process.compile(js, filename || 'Jade');
      return;
    }
  } catch (err) {
    rethrow(err, str, filename, parser.lexer.lineno);
  }
}

/**
 * Compile a `Function` representation of the given jade `str`.
 *
 * Options:
 *   - `.compileDebug`     Enable/disable debug helpers such as rethrow (`true`)
 *   - `helpers`  Include helpers as `inline` or get from `global` Jade export, defaults to `global`
 *
 * @param {String} str
 * @param {Options} options
 * @return {Function}
 * @api public
 */

exports.compile = function(str, options){
  var options = options || {}
    , input = JSON.stringify(str)
    , filename = options.filename
      ? JSON.stringify(options.filename)
      : 'undefined'
    , fn = []
    , helpers = '';

  if (options.helpers !== 'inline') {
    jadeHelpers = {
      rethrow: rethrow
    };
    helpers = 'var rethrow = jadeHelpers.rethrow;';
  } else {
    helpers = rethrow.toString();
  }

  if (options.compileDebug !== false) {
    // Reduce closure madness by injecting some locals
    fn = [
        'var __ = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };'
      , helpers
      , 'try {'
      , parse(String(str), options || {})
      , '} catch (err) {'
      , '  rethrow(err, __.input, __.filename, __.lineno);'
      , '}'
    ].join('\n');
  } else {
    fn = parse(String(str), options || {});
  }

  return new Function('locals', fn);
};

/**
 * Render the given `str` of jade.
 *
 * Options:
 *
 *   - `scope`     Evaluation scope (`this`)
 *   - `locals`    Local variable object
 *   - `filename`  Used in exceptions, and required by `cache`
 *   - `cache`     Cache intermediate JavaScript in memory keyed by `filename`
 *   - `compiler`  Compiler to replade jade's default
 *   - `doctype`   Specify the default doctype
 *   - `compileDebug`   Include/exclude debug helpers such as rethrow, defaults to `true`
 *
 * @param {String|Buffer} str
 * @param {Object} options
 * @return {String}
 * @api public
 */

exports.render = function(str, options){
  var fn
    , options = options || {}
    , filename = options.filename;

  // Accept Buffers
  str = String(str);

  // Cache support
  if (options.cache) {
    if (filename) {
      if (cache[filename]) {
        fn = cache[filename];
      } else {
        fn = cache[filename] = new Function('locals', parse(str, options));
      }
    } else {
      throw new Error('filename is required when using the cache option');
    }
  } else {
    fn = new Function('locals', parse(str, options));
  }

  // Render the template
  try {
    var locals = options.locals || {}
      , meta = { lineno: 1 };
    locals.__ = meta;
    return fn.call(options.scope, locals);
  } catch (err) {
    rethrow(err, str, filename, meta.lineno);
  }
};

/**
 * Render jade template at the given `path`.
 *
 * @param {String} path
 * @param {Object} options
 * @param {Function} fn
 * @api public
 */

exports.renderFile = function(path, options, fn){
  var ret;

  if (typeof options === 'function') {
    fn = options;
    options = {};
  }
  options.filename = path;

  // Primed cache
  if (options.cache && cache[path]) {
    try {
      ret = exports.render('', options);
    } catch (err) {
      return fn(err);
    }
    fn(null, ret);
  } else {
    fs.readFile(path, 'utf8', function(err, str){
      if (err) return fn(err);
      try {
        ret = exports.render(str, options);
      } catch (err) {
        return fn(err);
      }
      fn(null, ret);
    });
  }
};<commit_msg>refactored some part<commit_after>
/*!
 * Jade
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Parser = require('./parser')
  , Compiler = require('./compiler')
// if node
  , fs = require('fs');
// end

/**
 * Library version.
 */

exports.version = '0.13.0';

/**
 * Intermediate JavaScript cache.
 */

var cache = exports.cache = {};

/**
 * Expose self closing tags.
 */

exports.selfClosing = require('./self-closing');

/**
 * Default supported doctypes.
 */

exports.doctypes = require('./doctypes');

/**
 * Text filters.
 */

exports.filters = require('./filters');

/**
 * Utilities.
 */

exports.utils = require('./utils');

/**
 * Expose `Compiler`.
 */

exports.Compiler = Compiler;

/**
 * Expose `Parser`.
 */

exports.Parser = Parser;

/**
 * Nodes.
 */

exports.nodes = require('./nodes');

/**
 * Render the given attributes object.
 *
 * @param {Object} obj
 * @return {String}
 * @api private
 */

function attrs(obj){
  var buf = []
    , terse = obj.terse;
  delete obj.terse;
  var keys = Object.keys(obj)
    , len = keys.length;
  if (len) {
    buf.push('');
    for (var i = 0; i < len; ++i) {
      var key = keys[i]
        , val = obj[key];
      if ('boolean' == typeof val || null == val) {
        if (val) {
          terse
            ? buf.push(key)
            : buf.push(key + '="' + key + '"');
        }
      } else if ('class' == key && Array.isArray(val)) {
        buf.push(key + '="' + escape(val.join(' ')) + '"');
      } else {
        buf.push(key + '="' + escape(val) + '"');
      }
    }
  }
  return buf.join(' ');
}

/**
 * Escape the given string of `html`.
 *
 * @param {String} html
 * @return {String}
 * @api private
 */

function escape(html){
  return String(html)
    .replace(/&(?!\w+;)/g, '&')
    .replace(/</g, '<')
    .replace(/>/g, '>')
    .replace(/"/g, '"');
}

/**
 * Re-throw the given `err` in context to the
 * `str` of jade, `filename`, and `lineno`.
 *
 * @param {Error} err
 * @param {String} str
 * @param {String} filename
 * @param {String} lineno
 * @api private
 */

function rethrow(err, str, filename, lineno){
  var context = 3
    , lines = str.split('\n')
    , start = Math.max(lineno - context, 0)
    , end = Math.min(lines.length, lineno + context);

  // Error context
  var context = lines.slice(start, end).map(function(line, i){
    var curr = i + start + 1;
    return (curr == lineno ? '  > ' : '    ')
      + curr
      + '| '
      + line;
  }).join('\n');

  // Alter exception message
  err.path = filename;
  err.message = (filename || 'Jade') + ':' + lineno
    + '\n' + context + '\n\n' + err.message;
  throw err;
}

/**
 * Parse the given `str` of jade and return a function body.
 *
 * @param {String} str
 * @param {Object} options
 * @return {String}
 * @api private
 */

function parse(str, options){
  var filename = options.filename
    , helpers = ''

  if (options.helpers !== 'inline') {
    jadeHelpers = {
      attrs: attrs,
      escape: escape
    }
    helpers = 'var attrs = jadeHelpers.attrs, escape = jadeHelpers.escape;\n';
  } else {
    helpers = attrs.toString() + '\n' + escape.toString() + '\n';
  }

  try {
    // Parse
    var parser = new Parser(str, filename);
    if (options.debug) parser.debug();

    // Compile
    var compiler = new (options.compiler || Compiler)(parser.parse(), options)
      , js = compiler.compile();

    // Debug compiler
    if (options.debug) {
      console.log('\n\x1b[1mCompiled Function\x1b[0m:\n\n%s', js.replace(/^/gm, '  '));
    }

    try {
      return ''
        + helpers
        + 'var buf = [];\n'
        + (options.self
          ? 'var self = locals || {}, __ = __ || locals.__;\n' + js
          : 'with (locals || {}) {' + js + '}')
        + 'return buf.join("");';
    } catch (err) {
      process.compile(js, filename || 'Jade');
      return;
    }
  } catch (err) {
    rethrow(err, str, filename, parser.lexer.lineno);
  }
}

/**
 * Compile a `Function` representation of the given jade `str`.
 *
 * Options:
 *   - `compileDebug`     Enable/disable debug helpers such as rethrow (`true`)
 *   - `helpers`  Include helpers as `inline` or get from `global` Jade export, defaults to `global`
 *
 * @param {String} str
 * @param {Options} options
 * @return {Function}
 * @api public
 */

exports.compile = function(str, options){
  var options = options || {}
    , input = JSON.stringify(str)
    , filename = options.filename
      ? JSON.stringify(options.filename)
      : 'undefined'
    , fn = []
    , helpers = '';

  if (options.helpers !== 'inline') {
    jadeHelpers = {
      rethrow: rethrow
    };
    helpers = 'var rethrow = jadeHelpers.rethrow;';
  } else {
    helpers = rethrow.toString();
  }

  if (options.compileDebug !== false) {
    // Reduce closure madness by injecting some locals
    fn = [
        'var __ = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };'
      , helpers
      , 'try {'
      , parse(String(str), options || {})
      , '} catch (err) {'
      , '  rethrow(err, __.input, __.filename, __.lineno);'
      , '}'
    ].join('\n');
  } else {
    fn = parse(String(str), options || {});
  }

  return new Function('locals', fn);
};

/**
 * Render the given `str` of jade.
 *
 * Options:
 *
 *   - `scope`     Evaluation scope (`this`)
 *   - `locals`    Local variable object
 *   - `filename`  Used in exceptions, and required by `cache`
 *   - `cache`     Cache intermediate JavaScript in memory keyed by `filename`
 *   - `compiler`  Compiler to replade jade's default
 *   - `doctype`   Specify the default doctype
 *
 * @param {String|Buffer} str
 * @param {Object} options
 * @return {String}
 * @api public
 */

exports.render = function(str, options){
  var fn
    , options = options || {}
    , filename = options.filename;

  // Accept Buffers
  str = String(str);

  // Cache support
  if (options.cache) {
    if (filename) {
      if (cache[filename]) {
        fn = cache[filename];
      } else {
        fn = cache[filename] = new Function('locals', parse(str, options));
      }
    } else {
      throw new Error('filename is required when using the cache option');
    }
  } else {
    fn = new Function('locals', parse(str, options));
  }

  // Render the template
  try {
    var locals = options.locals || {}
      , meta = { lineno: 1 };
    locals.__ = meta;
    return fn.call(options.scope, locals);
  } catch (err) {
    rethrow(err, str, filename, meta.lineno);
  }
};

/**
 * Render jade template at the given `path`.
 *
 * @param {String} path
 * @param {Object} options
 * @param {Function} fn
 * @api public
 */

exports.renderFile = function(path, options, fn){
  var ret;

  if (typeof options === 'function') {
    fn = options;
    options = {};
  }
  options.filename = path;

  // Primed cache
  if (options.cache && cache[path]) {
    try {
      ret = exports.render('', options);
    } catch (err) {
      return fn(err);
    }
    fn(null, ret);
  } else {
    fs.readFile(path, 'utf8', function(err, str){
      if (err) return fn(err);
      try {
        ret = exports.render(str, options);
      } catch (err) {
        return fn(err);
      }
      fn(null, ret);
    });
  }
};<|endoftext|>


<commit_before>//var program = process.argv[2];

var converter = new Showdown.converter();

var imports = {};

function binaryNumOp(args, env, f){
	var arg1 = parseFloat(executeExpression(args[0], env));
	var arg2 = parseFloat(executeExpression(args[1], env));
	return f(arg1, arg2);
}

var ops = {
	'-' : function(args, env){
		    var total = parseInt(executeExpression(args[0], env));
			for(var i=1;i<args.length;i++){
				total -= parseInt(executeExpression(args[i], env));
			}
			return total;
		},
	'+' : function(args, env){
		    var total = 0;
			for(var i in args){
				total += parseInt(executeExpression(args[i], env));
			}
			return total;
		},
	'*' : function(args, env){
		    var total = parseInt(executeExpression(args[0], env));
			for(var i=1;i<args.length;i++){
				total *= parseInt(executeExpression(args[i], env));
			}
			return total;
		},
	'pageName' : function(args, env){
			return pageName;
		},
	'=' : function(args, env){
			return binaryNumOp(args, env, function(a,b){return a == b});
		},
	'<' : function(args, env){
			return binaryNumOp(args, env, function(a,b){return a < b});
		},
	'<=' : function(args, env){
			return binaryNumOp(args, env, function(a,b){return a <= b});
		},
	'>' : function(args, env){
			return binaryNumOp(args, env, function(a,b){return a > b});
		},
	'>=' : function(args, env){
			return binaryNumOp(args, env, function(a,b){return a >= b});
		},
	'length' : function(args, env){
		    return executeExpression(args[0], env).content.length;
		},
	'dotPath' : function(args, env){
			var dotPath = executeExpression(args[0], env)
			var json = executeExpression(args[1], env)
		    return json[dotPath];
		},
	'subseq' : function(args, env){
			var start = executeExpression(args[0], env);

			if(args.length == 2){
				var list = executeExpression(args[1], env).content;
				return new List(list.slice(start));
			} else if(args.length == 3){
				var end = executeExpression(args[1], env);
				var list = executeExpression(args[2], env).content;
				return new List(list.slice(start, end));
			}
		},
	'nth' : function(args, env){
			var pos = executeExpression(args[0], env);
		    var list = executeExpression(args[1], env).content;

		    return list[pos];
		},
	'list' : function(args, env){
		    var list = [];
			for(var i in args){
				list.push(executeExpression(args[i], env));
			}
			return new List(list);
		},
	'sort' : function(args, env){
		    var list = executeExpression(args[0], env).content.slice();
		    var sortFn = executeExpression(args[1], env);

			var sort = function(a, b){
				var result = parseInt(sortFn(new Array(a, b), env));
				return result;
			}

			var sortedContent = list.sort(sort);
			var sortedList = new List(sortedContent);

			return sortedList;
		},
	'begin' : function(args, env){
			for(var i=0;i<args.length-1;i++){
				executeExpression(args[i], env);
			}
			return executeExpression(args[args.length-1], env);
		},
	'if' : function(args, env){
			var bool = executeExpression(args[0], env);

			var ret;
			if(bool == true){
				ret = executeExpression(args[1], env);
			} else {
				ret = executeExpression(args[2], env);
			}
			return ret;
		},
	'json' : function(args, env){
			var url = executeExpression(args[0], env);
			var fn = executeExpression(args[1], env);
			$.ajax({
			        async: true,
			        type: "GET",
			        contentType: "application/json; charset=utf-8",
			        dataType: "json",
			        url: url,
			        success: function(jsonData) {
			            fn(new Array(jsonData), env);
			        },
			        error: function(){
			        	//
			        }
			    });

		},
	'import' : function(args, env){
		    var str = "";
			for(var i in args){
				var importedPage = executeExpression(args[i], env);
				var url = './'+importedPage+'/code';

				if(url in imports){
					str += imports[url];
				} else {
					var jsonStringData;

					$.ajax({
				        async: false,
				        type: "GET",
				        contentType: "application/json; charset=utf-8",
				        dataType: "json",
				        url: url,
				        success: function(jsonData) {
				            jsonStringData = jsonData.data;
				        },
				        error: function(){
				        	jsonStringData = null;
				        }
				    });
				    imports[url] = jsonStringData;
					str += jsonStringData;
				}
			}

			if(jsonStringData){
				var newEnv = clone(env);
				newEnv.overrides = true;

				evalLispWithEnv(str, newEnv);
			}

			return null;
		},
	'concat' : function(args, env){
		    var str = "";
			for(i in args){
				str += executeExpression(args[i], env);
			}
			return str;
		},
	'defun' : function(args, outerEnv){
			var fnName = args.shift();

			if(! (outerEnv.overrides && (fnName in ops))){
				var fnArgs = args.shift();
				var fnBody = args.shift();
				var fn = function(params, env){
					env = $.extend(env,outerEnv);
					var tmpEnv = {};
					for(var i in fnArgs){
						var arg = fnArgs[i];
						var value = executeExpression(params[i], env);
						tmpEnv[arg] = value;
					}
					return executeExpression(fnBody.slice(), $.extend(env,tmpEnv));
				}
			    ops[fnName] = fn;
			}
		},
	'markdown' : function(args, env){
			return converter.makeHtml(ops['concat'](args, env));
		},
	'print' : function(args, env){
			if(args.length == 1){
				env.out(null, executeExpression(args[0], env));
			} else if(args.length == 2){
				env.out(
					executeExpression(args[0], env),
					executeExpression(args[1], env));
			}
		}
}

function Lambda(args, outerEnv){
	var fnArgs = args.shift();
	var fnBody = args.shift();
	return function(params, env){
		env = $.extend(env,outerEnv);
		var tmpEnv = {};
		for(var i in fnArgs){
			var arg = fnArgs[i];
			var value = executeExpression(params[i], env);
			tmpEnv[arg] = value;
		}
		return executeExpression(fnBody.slice(), $.extend(env,tmpEnv));
	}
}

function List(content) {
    this.content = content;
}

var trim = String.prototype.trim || function(){
	return (this + '').replace(/^\s+|\s+$/g, '');
};

function isBlank(str) {
    return (!str || /^\s*$/.test(str));
}

function evalLisp(program, callback){
	var env = {out:callback};
	return evalLispWithEnv(program, env);
}

function evalLispWithEnv(program, env){
	return execute(parseExpressions(program), env);
}

function execute(expressions, env){
	for(var i in expressions){
		env.out(null, executeExpression(expressions[i], env));
	}
}

function clone(obj){
	return jQuery.extend(true, {}, obj);
}

function executeExpression(stack, env){
	env = clone(env);
	if (stack instanceof List){
		return stack;
	}

	if (!Array.isArray(stack)){
		if(stack in env){
			return env[stack];
		} else {
			if(stack == 'Nil'){
				return null;
			} else {
				 return stack;
			}
		}
	}

	stack = stack.slice();
	if(env == null){
		throw new Error("Environment is NULL.");
	}

	var fn = null;
	var args = [];
	var operator = executeExpression(stack.shift(),env);

	if(operator == 'lambda'){
		return new Lambda(stack, env);
	}

	var fn;
	if (typeof(operator) == "function"){
		fn = operator;
	} else {
		fn = ops[operator];
	}

	if(env[operator]){
		fn = env[operator];
	}

	if(!fn){
		throw new Error("Symbol: " + operator + " is not defined.");
	}

	for(var i=0;i<stack.length;i++){
		var arg = stack[i];
		if(arg in env){
			arg = env[arg];
		}
		args.push(arg);
	}

	return fn(args, env);
}

function getArgName(arg){
	if(arg.indexOf('.') === -1){
		return arg;
	} else {
		return arg.substr(0, arg.indexOf('.'));
	}
}

function parseExpressions(text){
	text = trim.call(text);

	var token = text.charAt(0);

	if (token != '(') {
		//throw new Error('unexepected token: ' + token);
	}

	var inQuotes = false;

	var stack = [];
	var parens = 0;
	var expression = "";

	while(text.length > 0){
		var token = text.charAt(0);
		text = text.substring(1);

		if (token == '"') {
			inQuotes = !inQuotes;
		}

		if(!inQuotes){
			if (token == '(') {
				parens++;
			} else if (token == ')'){
				parens--;
			}
		}

		expression += token;

		if (parens == '0'){
			if(!isBlank(expression)){
				stack.push(parseExpression(expression));
			}
			expression = "";
		}

	}

	return stack;
}

function parseExpression(text){
	text = trim.call(text);

	if (text.charAt(0) != '(') return text;

	var stack = [];
	var token;
	var tokens = '';
	var comment = false;
	var i = 0;
	var expr;

	while (i < text.length){
		token = text.charAt(i++);

		if (comment & token != '"'){
			tokens += token;
			continue;
		}

		if (token == '(' || token == ')' || (token == ' ' && !comment)){
			if (expr && tokens.length){
				var n = +tokens;
				var stripped = tokens.replace(/^\"|\"$/g, "");
				expr.push(isNaN(n) ? stripped : n);
			}
			tokens = '';
		} else {
			if (token == '"') comment = !comment;
			if (!/\s/.test(token) || comment) tokens += token;
		}

		if (token == '('){

			var previous = expr;
			expr = [];

			if (previous){
				// push the previous expresion to the stack
				stack.push(previous);
				// if expr is not top-level, append the expression
				previous.push(expr);
			}

		} else if (token == ')'){

			// pop one from stack
			var pop = stack.pop();
			// stack is empty, so expr is the top-level expression
			if (!pop) return expr;
			expr = pop;

		}

	}

	//throw new Error('unbalanced parentheses');

};

//execute(parseExpressions(program));<commit_msg>Allow for comments in source files.<commit_after>//var program = process.argv[2];

var converter = new Showdown.converter();

var imports = {};

function binaryNumOp(args, env, f){
	var arg1 = parseFloat(executeExpression(args[0], env));
	var arg2 = parseFloat(executeExpression(args[1], env));
	return f(arg1, arg2);
}

var ops = {
	'-' : function(args, env){
		    var total = parseInt(executeExpression(args[0], env));
			for(var i=1;i<args.length;i++){
				total -= parseInt(executeExpression(args[i], env));
			}
			return total;
		},
	'+' : function(args, env){
		    var total = 0;
			for(var i in args){
				total += parseInt(executeExpression(args[i], env));
			}
			return total;
		},
	'*' : function(args, env){
		    var total = parseInt(executeExpression(args[0], env));
			for(var i=1;i<args.length;i++){
				total *= parseInt(executeExpression(args[i], env));
			}
			return total;
		},
	'pageName' : function(args, env){
			return pageName;
		},
	'=' : function(args, env){
			return binaryNumOp(args, env, function(a,b){return a == b});
		},
	'<' : function(args, env){
			return binaryNumOp(args, env, function(a,b){return a < b});
		},
	'<=' : function(args, env){
			return binaryNumOp(args, env, function(a,b){return a <= b});
		},
	'>' : function(args, env){
			return binaryNumOp(args, env, function(a,b){return a > b});
		},
	'>=' : function(args, env){
			return binaryNumOp(args, env, function(a,b){return a >= b});
		},
	'length' : function(args, env){
		    return executeExpression(args[0], env).content.length;
		},
	'dotPath' : function(args, env){
			var dotPath = executeExpression(args[0], env)
			var json = executeExpression(args[1], env)
		    return json[dotPath];
		},
	'subseq' : function(args, env){
			var start = executeExpression(args[0], env);

			if(args.length == 2){
				var list = executeExpression(args[1], env).content;
				return new List(list.slice(start));
			} else if(args.length == 3){
				var end = executeExpression(args[1], env);
				var list = executeExpression(args[2], env).content;
				return new List(list.slice(start, end));
			}
		},
	'nth' : function(args, env){
			var pos = executeExpression(args[0], env);
		    var list = executeExpression(args[1], env).content;

		    return list[pos];
		},
	'list' : function(args, env){
		    var list = [];
			for(var i in args){
				list.push(executeExpression(args[i], env));
			}
			return new List(list);
		},
	'sort' : function(args, env){
		    var list = executeExpression(args[0], env).content.slice();
		    var sortFn = executeExpression(args[1], env);

			var sort = function(a, b){
				var result = parseInt(sortFn(new Array(a, b), env));
				return result;
			}

			var sortedContent = list.sort(sort);
			var sortedList = new List(sortedContent);

			return sortedList;
		},
	'begin' : function(args, env){
			for(var i=0;i<args.length-1;i++){
				executeExpression(args[i], env);
			}
			return executeExpression(args[args.length-1], env);
		},
	'if' : function(args, env){
			var bool = executeExpression(args[0], env);

			var ret;
			if(bool == true){
				ret = executeExpression(args[1], env);
			} else {
				ret = executeExpression(args[2], env);
			}
			return ret;
		},
	'json' : function(args, env){
			var url = executeExpression(args[0], env);
			var fn = executeExpression(args[1], env);
			$.ajax({
			        async: true,
			        type: "GET",
			        contentType: "application/json; charset=utf-8",
			        dataType: "json",
			        url: url,
			        success: function(jsonData) {
			            fn(new Array(jsonData), env);
			        },
			        error: function(){
			        	//
			        }
			    });

		},
	'import' : function(args, env){
		    var str = "";
			for(var i in args){
				var importedPage = executeExpression(args[i], env);
				var url = './'+importedPage+'/code';

				if(url in imports){
					str += imports[url];
				} else {
					var jsonStringData;

					$.ajax({
				        async: false,
				        type: "GET",
				        contentType: "application/json; charset=utf-8",
				        dataType: "json",
				        url: url,
				        success: function(jsonData) {
				            jsonStringData = jsonData.data;
				        },
				        error: function(){
				        	jsonStringData = null;
				        }
				    });
				    imports[url] = jsonStringData;
					str += jsonStringData;
				}
			}

			if(jsonStringData){
				var newEnv = clone(env);
				newEnv.overrides = true;

				evalLispWithEnv(str, newEnv);
			}

			return null;
		},
	'concat' : function(args, env){
		    var str = "";
			for(i in args){
				str += executeExpression(args[i], env);
			}
			return str;
		},
	'defun' : function(args, outerEnv){
			var fnName = args.shift();

			if(! (outerEnv.overrides && (fnName in ops))){
				var fnArgs = args.shift();
				var fnBody = args.shift();
				var fn = function(params, env){
					env = $.extend(env,outerEnv);
					var tmpEnv = {};
					for(var i in fnArgs){
						var arg = fnArgs[i];
						var value = executeExpression(params[i], env);
						tmpEnv[arg] = value;
					}
					return executeExpression(fnBody.slice(), $.extend(env,tmpEnv));
				}
			    ops[fnName] = fn;
			}
		},
	'markdown' : function(args, env){
			return converter.makeHtml(ops['concat'](args, env));
		},
	'print' : function(args, env){
			if(args.length == 1){
				env.out(null, executeExpression(args[0], env));
			} else if(args.length == 2){
				env.out(
					executeExpression(args[0], env),
					executeExpression(args[1], env));
			}
		}
}

function Lambda(args, outerEnv){
	var fnArgs = args.shift();
	var fnBody = args.shift();
	return function(params, env){
		env = $.extend(env,outerEnv);
		var tmpEnv = {};
		for(var i in fnArgs){
			var arg = fnArgs[i];
			var value = executeExpression(params[i], env);
			tmpEnv[arg] = value;
		}
		return executeExpression(fnBody.slice(), $.extend(env,tmpEnv));
	}
}

function List(content) {
    this.content = content;
}

function trim(str){
	return stripComments(str).replace(/^\s+|\s+$/g, '');
};

function stripComments(str){
	return str.replace(/^\s*;.+/gm, '');
}

function isBlank(str) {
    return (!str || /^\s*$/.test(str));
}

function evalLisp(program, callback){
	var env = {out:callback};
	return evalLispWithEnv(program, env);
}

function evalLispWithEnv(program, env){
	return execute(parseExpressions(program), env);
}

function execute(expressions, env){
	for(var i in expressions){
		env.out(null, executeExpression(expressions[i], env));
	}
}

function clone(obj){
	return jQuery.extend(true, {}, obj);
}

function executeExpression(stack, env){
	env = clone(env);
	if (stack instanceof List){
		return stack;
	}

	if (!Array.isArray(stack)){
		if(stack in env){
			return env[stack];
		} else {
			if(stack == 'Nil'){
				return null;
			} else {
				 return stack;
			}
		}
	}

	stack = stack.slice();
	if(env == null){
		throw new Error("Environment is NULL.");
	}

	var fn = null;
	var args = [];
	var operator = executeExpression(stack.shift(),env);

	if(operator == 'lambda'){
		return new Lambda(stack, env);
	}

	var fn;
	if (typeof(operator) == "function"){
		fn = operator;
	} else {
		fn = ops[operator];
	}

	if(env[operator]){
		fn = env[operator];
	}

	if(!fn){
		throw new Error("Symbol: " + operator + " is not defined.");
	}

	for(var i=0;i<stack.length;i++){
		var arg = stack[i];
		if(arg in env){
			arg = env[arg];
		}
		args.push(arg);
	}

	return fn(args, env);
}

function getArgName(arg){
	if(arg.indexOf('.') === -1){
		return arg;
	} else {
		return arg.substr(0, arg.indexOf('.'));
	}
}

function parseExpressions(text){
	text = trim(text);

	var token = text.charAt(0);

	if (token != '(') {
		//throw new Error('unexepected token: ' + token);
	}

	var inQuotes = false;

	var stack = [];
	var parens = 0;
	var expression = "";

	while(text.length > 0){
		var token = text.charAt(0);
		text = text.substring(1);

		if (token == '"') {
			inQuotes = !inQuotes;
		}

		if(!inQuotes){
			if (token == '(') {
				parens++;
			} else if (token == ')'){
				parens--;
			}
		}

		expression += token;

		if (parens == '0'){
			if(!isBlank(expression)){
				stack.push(parseExpression(expression));
			}
			expression = "";
		}

	}

	return stack;
}

function parseExpression(text){
	text = trim(text);

	if (text.charAt(0) != '(') return text;

	var stack = [];
	var token;
	var tokens = '';
	var comment = false;
	var i = 0;
	var expr;

	while (i < text.length){
		token = text.charAt(i++);

		if (comment & token != '"'){
			tokens += token;
			continue;
		}

		if (token == '(' || token == ')' || (token == ' ' && !comment)){
			if (expr && tokens.length){
				var n = +tokens;
				var stripped = tokens.replace(/^\"|\"$/g, "");
				expr.push(isNaN(n) ? stripped : n);
			}
			tokens = '';
		} else {
			if (token == '"') comment = !comment;
			if (!/\s/.test(token) || comment) tokens += token;
		}

		if (token == '('){

			var previous = expr;
			expr = [];

			if (previous){
				// push the previous expresion to the stack
				stack.push(previous);
				// if expr is not top-level, append the expression
				previous.push(expr);
			}

		} else if (token == ')'){

			// pop one from stack
			var pop = stack.pop();
			// stack is empty, so expr is the top-level expression
			if (!pop) return expr;
			expr = pop;

		}

	}

	//throw new Error('unbalanced parentheses');

};

//execute(parseExpressions(program));<|endoftext|>


<commit_before>var $fh = require('fh-mbaas-api');
var express = require('express');
var bodyParser = require('body-parser');
var cors = require('cors');

function leadRoute() {
  var lead = new express.Router();
  lead.use(cors());
  lead.use(bodyParser());

  // POST REST endpoint - note we use 'body-parser' middleware above to parse the request body in this route.
  // This can also be added in application.js
  // See: https://github.com/senchalabs/connect#middleware for a list of Express 4 middleware
  lead.post('/', function(req, res) {
    // check question
    var options = {
      "act": "read",
      "type": "question",
      "guid": req.body.answer.split(":")[0]
    };

    $fh.db(options, function (err, data) {
      if (err) {
        console.error("Error " + err);
      } else {
        console.log("Question: " + JSON.stringify(data));
        console.log("Correct Answr: " + data.fields.correct);
        console.log("User Asnwer: " + req.body.answer.split(":")[1]);
        console.log(data.fields.correct.valueOf() == req.body.answer.split(":")[1].valueOf());

        lottery = (data.fields.correct.valueOf() == req.body.answer.split(":")[1].valueOf());
      }
    });

    var options = {
      "act": "create",
      "type": "lead", // Entity/Collection name
      "fields": { // The structure of the entry/row data. A data is analogous to "Row" in MySql or "Documents" in MongoDB
        "name": req.body.name,
        "email": req.body.email,
        "company": req.body.company,
        "job": req.body.job,
        "lottery": lottery
      }
    };

    $fh.db(options, function (err, data) {
      if (err) {
        console.error("Error " + err);
        res.json({msg: err, status: 'error'});
      } else {
        res.json({msg: "Registered", status: 'success'});
      }
    });
  });

  return lead;
}

module.exports = leadRoute;

<commit_msg>updated<commit_after>var $fh = require('fh-mbaas-api');
var express = require('express');
var bodyParser = require('body-parser');
var cors = require('cors');

function leadRoute() {
  var lead = new express.Router();
  lead.use(cors());
  lead.use(bodyParser());

  // POST REST endpoint - note we use 'body-parser' middleware above to parse the request body in this route.
  // This can also be added in application.js
  // See: https://github.com/senchalabs/connect#middleware for a list of Express 4 middleware
  lead.post('/', function(req, res) {
    lottery = false;

    // check question
    var options = {
      "act": "read",
      "type": "question",
      "guid": req.body.answer.split(":")[0]
    };

    $fh.db(options, function (err, data) {
      if (err) {
        console.error("Error " + err);
      } else {
        console.log("Question: " + JSON.stringify(data));
        console.log("Correct Answr: " + data.fields.correct);
        console.log("User Asnwer: " + req.body.answer.split(":")[1]);
        console.log(data.fields.correct.valueOf() == req.body.answer.split(":")[1].valueOf());

        lottery = (data.fields.correct.valueOf() == req.body.answer.split(":")[1].valueOf());
      }
    });

    var options = {
      "act": "create",
      "type": "lead", // Entity/Collection name
      "fields": { // The structure of the entry/row data. A data is analogous to "Row" in MySql or "Documents" in MongoDB
        "name": req.body.name,
        "email": req.body.email,
        "company": req.body.company,
        "job": req.body.job,
        "lottery": lottery
      }
    };

    $fh.db(options, function (err, data) {
      if (err) {
        console.error("Error " + err);
        res.json({msg: err, status: 'error'});
      } else {
        res.json({msg: "Registered", status: 'success'});
      }
    });
  });

  return lead;
}

module.exports = leadRoute;

<|endoftext|>


<commit_before>var _ = require('lodash');
var uuid = require('uuid');
var defaultFns = require('racer/lib/Model/defaultFns');
var Query = require('./query');

module.exports = View;

function View(views, path, viewName) {
  this.views = views;
  this.model = views.model.pass({$view: this});
  this.path = path;
  this.segments = path.split('.');
  this.bundle = true;

  if(typeof viewName === 'function') {
    this.viewFn = viewName;
    this.viewName = uuid.v4();
  } else {
    this.viewName = viewName;
    this.viewFn = this.model.root._namedFns[this.viewName] || defaultFns[this.viewName];
  }

  var segments = ['$views', this.viewName, path.replace(/\./g, '|')];
  // Parent path for all ids for all queries based upon this view
  this.querySegments = segments.slice(0);
  this.querySegments.splice(2, 0, 'queries');
  // Keeps the order of all keys
  this.keysSegments = segments.slice(0);
  this.keysSegments.splice(2, 0, 'keys');
  // Hashmap mapping keys to the value of each emitted path
  this.pathsSegments = segments.slice(0);
  this.pathsSegments.splice(2, 0, 'paths');
  // Keeps track of all keys related a specific id, on the structure of: {<id>: [<key1_of_id>, <key2_of_id>, ...], ...}
  this.idsSegments = segments.slice(0);
  this.idsSegments.splice(2, 0, 'ids');
  // Ensure paths and ids is a hash
  this.model.root._set(this.pathsSegments, {});
  this.model.root._set(this.idsSegments, {});

  this.initialized = false;
  this.from = null;
  this.fromSegments = null;
  this.queries = [];
  this.queryPerLevelInitialized = false;
  this.queryPerLevelFrom = null;
  this.queriesPerLevelFromMap = {};
}

View.prototype.get = function() {
  // Ensure initialized
  this._init();

  return this.model.root._get(this.pathsSegments);
};

View.prototype.ref = function(from) {
  // Ensure initialized
  this._init();

  from = this.model.path(from);
  this.from = from;
  this.fromSegments = from.split('.');

  // FIXME: This is not appropriate - the whole thing with the FromMap is over-used for our purposes
  this.views.fromMap[from] = this;
  return this.model.root.ref(from, this.pathsSegments.join('.'));
};

View.prototype.query = function (start, end) {
  // Ensure initialized
  this._init();

  var query = new Query(this.model, this, start, end);
  this.queries.push(query);
  return query;
};

View.prototype.queryPerLevel = function (from) {
  // Ensure initialized
  this._init();

  // Init initial queries
  this.queryPerLevelInitialized = true;
  from = this.model.path(from);
  this.queryPerLevelFrom = from;

  var groups = this.model._get(this.pathsSegments);
  var keys = Object.keys(groups);

  for(var i = 0, len = keys.length; i < len; i++) {
    var key = keys[i];

    var query = this.query(key, key + 'z');
    query.ref(from + '.' + key);
    this.queriesPerLevelFromMap[key] = query;
  }
};

// Duplicate naming for more Derby-aligned naming
View.prototype.refList = View.prototype.query;

// TODO: Implement
View.prototype.subscribe = function () {

};

// TODO: Implement
View.prototype.fetch = function () {

};

// TODO: Review this - including properly cleaning up all related queries
View.prototype.destroy = function() {
  delete this.views.fromMap[this.from];

  // this.model._removeRef(this.idsSegments);
  // this.model._del(this.idsSegments);

  if(!this.initialized) return;
  this.model._del(this.keysSegments);
  this.model._del(this.pathsSegments);
  this.model._del(this.idsSegments);
};

View.prototype._init = function () {
  // Only initialize once
  if(this.initialized) return;
  this.initialized = true;

  var data = this.model.root._get(this.segments);
  if(!data) return;

  var ids = Object.keys(data);

  for(var i = 0, len = ids.length; i < len; i++) {
    var id = ids[i];
    var obj = data[id];

    this._trigger(obj, id);
  }
};

View.prototype._delete = function (id) {
  // TODO: Check if we need to go to root here - I dont think so
  var keys = this.model.root._get(this.idsSegments.concat(id))

  if(typeof keys !== 'undefined') {
    for(var i = 0, len = keys.length; i < len; i++) {
      var key = keys[i].key;
      var position = this._insertPosition(key);

      this.model.root._remove(this.keysSegments, position, 1);

      var refSegments = this.pathsSegments.concat(key);
      this.model.root._removeRef(refSegments, refSegments.join('.'));
    }
  }
  this.model._del(this.idsSegments.concat(id));
};

View.prototype._insert = function (key) {
  var position = this._insertPosition(key);
  this.model._insert(this.keysSegments, position, key);
};

View.prototype._insertPosition = function (key, options) {
  var keys = this.model.root._get(this.keysSegments);
  if(!keys) return 0;
  var len = keys.length;
  var lower = 0;
  var upper = len;
  var done = false;
  var pos;
  var options = options || {};

  while(!done) {
    pos = parseInt((upper + lower) / 2);

    if(pos === lower || pos === upper) {
      done = true;
      continue;
    }

    if(keys[pos] > key) {
      upper = pos;
    } else {
      lower = pos;
    }
  }

  if((pos == 0 && keys[pos] > key) || (!(options && options.upperBound) && keys[pos] === key)) pos--;

  return ++pos;
};

View.prototype._trigger = function (obj, id) {
  var processed = this._getDiffs(obj, id);
  var diffs = processed.diffs;
  var res = processed.res;

  this._commitRes(res, id);

  for(var i = 0, len = diffs.length; i < len; i++) {
    var diff = diffs[i];
    this._commitDiff(diff);
  }
};

View.prototype._getOriginalObject = function (id) {
  return this.model._get(this.segments.concat(id));
};

View.prototype._getDiffs = function (obj, id) {
  var view = this;
  var res = {};

  function emit(key, path) {
    var path = path || view.path + '.' + id;
    res[key] = path;
  }

  // Trigger view fn and all emits
  if(obj) this.viewFn(emit, obj, id);

  var rootModel = view.model.root;
  var previous = view.model.root._getCopy(this.idsSegments.concat(id)) || {};
  var diffs = [];

  _.each(res, function (path, key) {
    var prev = previous[key];
    // Remove since it's been handled already
    delete previous[key];

    // Add no diff if nothing has changed
    if(prev === path) return;

    // Did not exist previously, let's add it
    if(!prev) {
      diffs.push({
        type: 'add',
        key: key,
        path: path
      });

      return;
    }

    // It was neither added newly, nor no change compared to previously, let's trigger a change
    diffs.push({
      type: 'change',
      key: key,
      path: path
    });
  });

  // Let's add all delete diffs
  _.each(previous, function (path, key) {
    diffs.push({
      type: 'del',
      key: key
    });
  });

  return {
    diffs: diffs,
    res: res
  };
};

View.prototype._commitDiff = function(diff) {
  var view = this;
  var rootModel = this.model.root;

  // TODO: Review if we should move these onto View prototype for more DRYness
  function del(key) {
    var keySegments = key.split('.');
    var position = view._insertPosition(key);

    rootModel._remove(view.keysSegments, position, 1);

    var refSegments = view.pathsSegments.concat(keySegments);
    var segments = refSegments.slice(0);

    rootModel._removeRef(refSegments, refSegments.join('.'));

    // Do additional cleanup for multi level keys
    if(keySegments.length > 1) {
      var done = false;
      var latestSegment;

      // We need to remove each level of data unless there are other items with the same base segments as key
      while(!done && segments !== view.pathsSegments && (latestSegment = segments.pop())) {
        if(Object.keys(rootModel._get(segments) || {}).length > 1) done = true;
      }

      rootModel._del(segments.concat([latestSegment]));
    }
  }

  function add(key, path) {
    var keySegments = key.split('.');
    var segments = view.pathsSegments.slice(0);

    while(keySegments.length > 1) {
      segments.push(keySegments.shift());

      if(rootModel._get(segments)) continue;

      rootModel._set(segments, {});
    }

    rootModel.ref(view.pathsSegments.concat(key).join('.'), path);
    view._insert(key);
  }

  function change(key, path) {
    var viewPathPath = view.pathsSegments.concat(key).join('.');

    rootModel.removeRef(viewPathPath);

    var position = view._insertPosition(key); // Need to verify if this actually gets the same position as of the key
    view.model._set(view.keysSegments.concat(position), path);

    rootModel.ref(viewPathPath, path);
  }

  var key = diff.key;
  var path = diff.path;

  if(diff.type === 'del') {
    del(key);
  } else if(diff.type === 'add') {
    add(key, path);
  } else {
    change(key, path);
  }

  // Update all queries
  function delQueryPerLevel(key) {
    var keySegments = key.split('.');
    var segments = view.pathsSegments.slice(0);
    var category = keySegments[0];

    segments.push(category);

    if(!view.mode._get(segments)) {
      // TODO: Add proper deletion of queries which cleans up properly
      delete this.queriesPerLevelFromMap[category];
    }
  }

  function addQueryPerLevel(key, path) {
    var keySegments = key.split('.');
    var category = keySegments[0];

    // Check if query exists on category, otherwise create
    if(!this.queriesPerLevelFromMap[category]) {
      var query = this.query(category, category + 'z');
      query.ref(from + '.' + category);
      this.queriesPerLevelFromMap[category] = query;
    }
  }

  if(this.queryPerLevelInitialized) {
    // Update which queries we keep maintained
    if(diff.type === 'del') {
      delQueryPerLevel(key);
    } else if(diff.type === 'add') {
      addQueryPerLevel(key, path);
    }
  }

  for(var i = 0, len = this.queries.length; i < len; i++) {
    var query = this.queries[i];

    query.update();
  }
};

View.prototype._commitRes = function (res, id) {
  var rootModel = this.model.root;

  // Ids segments change
  if(_.isEmpty(res)) {
    rootModel._del(this.idsSegments.concat(id));
  } else {
    rootModel._set(this.idsSegments.concat(id), res);
  }
};
<commit_msg>Add proper casing for Query include...<commit_after>var _ = require('lodash');
var uuid = require('uuid');
var defaultFns = require('racer/lib/Model/defaultFns');
var Query = require('./Query');

module.exports = View;

function View(views, path, viewName) {
  this.views = views;
  this.model = views.model.pass({$view: this});
  this.path = path;
  this.segments = path.split('.');
  this.bundle = true;

  if(typeof viewName === 'function') {
    this.viewFn = viewName;
    this.viewName = uuid.v4();
  } else {
    this.viewName = viewName;
    this.viewFn = this.model.root._namedFns[this.viewName] || defaultFns[this.viewName];
  }

  var segments = ['$views', this.viewName, path.replace(/\./g, '|')];
  // Parent path for all ids for all queries based upon this view
  this.querySegments = segments.slice(0);
  this.querySegments.splice(2, 0, 'queries');
  // Keeps the order of all keys
  this.keysSegments = segments.slice(0);
  this.keysSegments.splice(2, 0, 'keys');
  // Hashmap mapping keys to the value of each emitted path
  this.pathsSegments = segments.slice(0);
  this.pathsSegments.splice(2, 0, 'paths');
  // Keeps track of all keys related a specific id, on the structure of: {<id>: [<key1_of_id>, <key2_of_id>, ...], ...}
  this.idsSegments = segments.slice(0);
  this.idsSegments.splice(2, 0, 'ids');
  // Ensure paths and ids is a hash
  this.model.root._set(this.pathsSegments, {});
  this.model.root._set(this.idsSegments, {});

  this.initialized = false;
  this.from = null;
  this.fromSegments = null;
  this.queries = [];
  this.queryPerLevelInitialized = false;
  this.queryPerLevelFrom = null;
  this.queriesPerLevelFromMap = {};
}

View.prototype.get = function() {
  // Ensure initialized
  this._init();

  return this.model.root._get(this.pathsSegments);
};

View.prototype.ref = function(from) {
  // Ensure initialized
  this._init();

  from = this.model.path(from);
  this.from = from;
  this.fromSegments = from.split('.');

  // FIXME: This is not appropriate - the whole thing with the FromMap is over-used for our purposes
  this.views.fromMap[from] = this;
  return this.model.root.ref(from, this.pathsSegments.join('.'));
};

View.prototype.query = function (start, end) {
  // Ensure initialized
  this._init();

  var query = new Query(this.model, this, start, end);
  this.queries.push(query);
  return query;
};

View.prototype.queryPerLevel = function (from) {
  // Ensure initialized
  this._init();

  // Init initial queries
  this.queryPerLevelInitialized = true;
  from = this.model.path(from);
  this.queryPerLevelFrom = from;

  var groups = this.model._get(this.pathsSegments);
  var keys = Object.keys(groups);

  for(var i = 0, len = keys.length; i < len; i++) {
    var key = keys[i];

    var query = this.query(key, key + 'z');
    query.ref(from + '.' + key);
    this.queriesPerLevelFromMap[key] = query;
  }
};

// Duplicate naming for more Derby-aligned naming
View.prototype.refList = View.prototype.query;

// TODO: Implement
View.prototype.subscribe = function () {

};

// TODO: Implement
View.prototype.fetch = function () {

};

// TODO: Review this - including properly cleaning up all related queries
View.prototype.destroy = function() {
  delete this.views.fromMap[this.from];

  // this.model._removeRef(this.idsSegments);
  // this.model._del(this.idsSegments);

  if(!this.initialized) return;
  this.model._del(this.keysSegments);
  this.model._del(this.pathsSegments);
  this.model._del(this.idsSegments);
};

View.prototype._init = function () {
  // Only initialize once
  if(this.initialized) return;
  this.initialized = true;

  var data = this.model.root._get(this.segments);
  if(!data) return;

  var ids = Object.keys(data);

  for(var i = 0, len = ids.length; i < len; i++) {
    var id = ids[i];
    var obj = data[id];

    this._trigger(obj, id);
  }
};

View.prototype._delete = function (id) {
  // TODO: Check if we need to go to root here - I dont think so
  var keys = this.model.root._get(this.idsSegments.concat(id))

  if(typeof keys !== 'undefined') {
    for(var i = 0, len = keys.length; i < len; i++) {
      var key = keys[i].key;
      var position = this._insertPosition(key);

      this.model.root._remove(this.keysSegments, position, 1);

      var refSegments = this.pathsSegments.concat(key);
      this.model.root._removeRef(refSegments, refSegments.join('.'));
    }
  }
  this.model._del(this.idsSegments.concat(id));
};

View.prototype._insert = function (key) {
  var position = this._insertPosition(key);
  this.model._insert(this.keysSegments, position, key);
};

View.prototype._insertPosition = function (key, options) {
  var keys = this.model.root._get(this.keysSegments);
  if(!keys) return 0;
  var len = keys.length;
  var lower = 0;
  var upper = len;
  var done = false;
  var pos;
  var options = options || {};

  while(!done) {
    pos = parseInt((upper + lower) / 2);

    if(pos === lower || pos === upper) {
      done = true;
      continue;
    }

    if(keys[pos] > key) {
      upper = pos;
    } else {
      lower = pos;
    }
  }

  if((pos == 0 && keys[pos] > key) || (!(options && options.upperBound) && keys[pos] === key)) pos--;

  return ++pos;
};

View.prototype._trigger = function (obj, id) {
  var processed = this._getDiffs(obj, id);
  var diffs = processed.diffs;
  var res = processed.res;

  this._commitRes(res, id);

  for(var i = 0, len = diffs.length; i < len; i++) {
    var diff = diffs[i];
    this._commitDiff(diff);
  }
};

View.prototype._getOriginalObject = function (id) {
  return this.model._get(this.segments.concat(id));
};

View.prototype._getDiffs = function (obj, id) {
  var view = this;
  var res = {};

  function emit(key, path) {
    var path = path || view.path + '.' + id;
    res[key] = path;
  }

  // Trigger view fn and all emits
  if(obj) this.viewFn(emit, obj, id);

  var rootModel = view.model.root;
  var previous = view.model.root._getCopy(this.idsSegments.concat(id)) || {};
  var diffs = [];

  _.each(res, function (path, key) {
    var prev = previous[key];
    // Remove since it's been handled already
    delete previous[key];

    // Add no diff if nothing has changed
    if(prev === path) return;

    // Did not exist previously, let's add it
    if(!prev) {
      diffs.push({
        type: 'add',
        key: key,
        path: path
      });

      return;
    }

    // It was neither added newly, nor no change compared to previously, let's trigger a change
    diffs.push({
      type: 'change',
      key: key,
      path: path
    });
  });

  // Let's add all delete diffs
  _.each(previous, function (path, key) {
    diffs.push({
      type: 'del',
      key: key
    });
  });

  return {
    diffs: diffs,
    res: res
  };
};

View.prototype._commitDiff = function(diff) {
  var view = this;
  var rootModel = this.model.root;

  // TODO: Review if we should move these onto View prototype for more DRYness
  function del(key) {
    var keySegments = key.split('.');
    var position = view._insertPosition(key);

    rootModel._remove(view.keysSegments, position, 1);

    var refSegments = view.pathsSegments.concat(keySegments);
    var segments = refSegments.slice(0);

    rootModel._removeRef(refSegments, refSegments.join('.'));

    // Do additional cleanup for multi level keys
    if(keySegments.length > 1) {
      var done = false;
      var latestSegment;

      // We need to remove each level of data unless there are other items with the same base segments as key
      while(!done && segments !== view.pathsSegments && (latestSegment = segments.pop())) {
        if(Object.keys(rootModel._get(segments) || {}).length > 1) done = true;
      }

      rootModel._del(segments.concat([latestSegment]));
    }
  }

  function add(key, path) {
    var keySegments = key.split('.');
    var segments = view.pathsSegments.slice(0);

    while(keySegments.length > 1) {
      segments.push(keySegments.shift());

      if(rootModel._get(segments)) continue;

      rootModel._set(segments, {});
    }

    rootModel.ref(view.pathsSegments.concat(key).join('.'), path);
    view._insert(key);
  }

  function change(key, path) {
    var viewPathPath = view.pathsSegments.concat(key).join('.');

    rootModel.removeRef(viewPathPath);

    var position = view._insertPosition(key); // Need to verify if this actually gets the same position as of the key
    view.model._set(view.keysSegments.concat(position), path);

    rootModel.ref(viewPathPath, path);
  }

  var key = diff.key;
  var path = diff.path;

  if(diff.type === 'del') {
    del(key);
  } else if(diff.type === 'add') {
    add(key, path);
  } else {
    change(key, path);
  }

  // Update all queries
  function delQueryPerLevel(key) {
    var keySegments = key.split('.');
    var segments = view.pathsSegments.slice(0);
    var category = keySegments[0];

    segments.push(category);

    if(!view.mode._get(segments)) {
      // TODO: Add proper deletion of queries which cleans up properly
      delete this.queriesPerLevelFromMap[category];
    }
  }

  function addQueryPerLevel(key, path) {
    var keySegments = key.split('.');
    var category = keySegments[0];

    // Check if query exists on category, otherwise create
    if(!this.queriesPerLevelFromMap[category]) {
      var query = this.query(category, category + 'z');
      query.ref(from + '.' + category);
      this.queriesPerLevelFromMap[category] = query;
    }
  }

  if(this.queryPerLevelInitialized) {
    // Update which queries we keep maintained
    if(diff.type === 'del') {
      delQueryPerLevel(key);
    } else if(diff.type === 'add') {
      addQueryPerLevel(key, path);
    }
  }

  for(var i = 0, len = this.queries.length; i < len; i++) {
    var query = this.queries[i];

    query.update();
  }
};

View.prototype._commitRes = function (res, id) {
  var rootModel = this.model.root;

  // Ids segments change
  if(_.isEmpty(res)) {
    rootModel._del(this.idsSegments.concat(id));
  } else {
    rootModel._set(this.idsSegments.concat(id), res);
  }
};
<|endoftext|>


<commit_before>var URL = require( 'url' )
var https = require( 'https' )

/**
 * ACME Protocol
 * @constructor
 * @param {Object} options
 * @return {ACME}
 */
function ACME( options ) {

  if( !(this instanceof ACME) )
    return new ACME( options )

  this.options = Object.assign( {}, ACME.defaults, options )

  if( !this.options.baseUrl || typeof this.options.baseUrl !== 'string' )
    throw new TypeError( 'baseUrl must be a string' )

  this.directory = null

}

/**
 * ACME default options
 * @type {Object}
 */
ACME.defaults = {}

// Resource types
// @see https://ietf-wg-acme.github.io/acme/#rfc.section.5.1
ACME.NEW_REGISTRATION = 'new-reg'
ACME.RECOVER_REGISTRATION = 'recover-reg'
ACME.NEW_AUTHORIZATION = 'new-authz'
ACME.NEW_CERTIFICATE = 'new-cert'
ACME.REVOKE_CERTIFICATE = 'revoke-cert'
ACME.REGISTRATION = 'reg'
ACME.AUTHORIZATION = 'authz'
ACME.CHALLENGE = 'challenge'
ACME.CERTIFICATE = 'cert'

// Error codes
// @see https://ietf-wg-acme.github.io/acme/#rfc.section.5.4
// @see http://tools.ietf.org/html/draft-ietf-appsawg-http-problem-02
ACME.E_BADCSR = ' The CSR is unacceptable (e.g., due to a short key)'
ACME.E_BADNONCE = ' The client sent an unacceptable anti-replay nonce'
ACME.E_CONNECTION = ' The server could not connect to the client for DV'
ACME.E_DNSSEC = ' The server could not validate a DNSSEC signed domain'
ACME.E_MALFORMED = 'The request message was malformed'
ACME.E_SERVERINTERNAL = ' The server experienced an internal error'
ACME.E_TLS = 'The server experienced a TLS error during DV'
ACME.E_UNAUTHORIZED = ' The client lacks sufficient authorization'
ACME.E_UNKNOWNHOST = 'The server could not resolve a domain name'
ACME.E_RATELIMITED = 'The request exceeds a rate limit'

/**
 * ACME prototype
 * @type {Object}
 */
ACME.prototype = {

  constructor: ACME,

  getDirectory: function( callback ) {

    var self = this
    var options = URL.parse( this.options.baseUrl )

    options.method = 'GET'
    options.path = '/directory'

    var req = https.request( options, function( res ) {

      var buffer = ''

      res.setEncoding( 'utf8' )
      res.on( 'readable', function() {
        var chunk = null
        while( chunk = this.read() )
          buffer += chunk
      })

      res.on( 'end', function() {
        var error, data
        try { data = JSON.parse( buffer ) }
        catch( e ) { error = e }
        self.directory = data
        callback( error, data )
      })

    })

    req.on( 'error', callback )
    req.end()

  },

  register: function() {
    // New registration 'new-reg'
  },

  recover: function() {
    // Recover registration 'recover-reg'
  },

  authorize: function() {
    // New authorization 'new-authz'
  },

  getCertificate: function() {
    // New certificate 'new-cert'
  },

  renewCertificate: function() {
    // ...?
  },

  revokeCertificate: function() {
    // Revoke certificate 'revoke-cert'
  },

  getRegistration: function() {
    // NOTE: Unsure about method name
    // Registration 'reg'
  },

  getAuthorization: function() {
    // NOTE: Unsure about method name
    // Authorization 'authz'
  },

  getChallenge: function() {
    // NOTE: Unsure about method name
    // Challenge 'challenge'
  },

}

// Exports
module.exports = ACME
<commit_msg>Update lib/acme: Add `ACME.generateNonce()`<commit_after>var URL = require( 'url' )
var https = require( 'https' )
var crypto = require( 'crypto' )

/**
 * ACME Protocol
 * @constructor
 * @param {Object} options
 * @return {ACME}
 */
function ACME( options ) {

  if( !(this instanceof ACME) )
    return new ACME( options )

  this.options = Object.assign( {}, ACME.defaults, options )

  if( !this.options.baseUrl || typeof this.options.baseUrl !== 'string' )
    throw new TypeError( 'baseUrl must be a string' )

  this.directory = null

}

/**
 * ACME default options
 * @type {Object}
 */
ACME.defaults = {}

// Resource types
// @see https://ietf-wg-acme.github.io/acme/#rfc.section.5.1
ACME.NEW_REGISTRATION = 'new-reg'
ACME.RECOVER_REGISTRATION = 'recover-reg'
ACME.NEW_AUTHORIZATION = 'new-authz'
ACME.NEW_CERTIFICATE = 'new-cert'
ACME.REVOKE_CERTIFICATE = 'revoke-cert'
ACME.REGISTRATION = 'reg'
ACME.AUTHORIZATION = 'authz'
ACME.CHALLENGE = 'challenge'
ACME.CERTIFICATE = 'cert'

// Error codes
// @see https://ietf-wg-acme.github.io/acme/#rfc.section.5.4
// @see http://tools.ietf.org/html/draft-ietf-appsawg-http-problem-02
ACME.E_BADCSR = ' The CSR is unacceptable (e.g., due to a short key)'
ACME.E_BADNONCE = ' The client sent an unacceptable anti-replay nonce'
ACME.E_CONNECTION = ' The server could not connect to the client for DV'
ACME.E_DNSSEC = ' The server could not validate a DNSSEC signed domain'
ACME.E_MALFORMED = 'The request message was malformed'
ACME.E_SERVERINTERNAL = ' The server experienced an internal error'
ACME.E_TLS = 'The server experienced a TLS error during DV'
ACME.E_UNAUTHORIZED = ' The client lacks sufficient authorization'
ACME.E_UNKNOWNHOST = 'The server could not resolve a domain name'
ACME.E_RATELIMITED = 'The request exceeds a rate limit'

ACME.generateNonce = function( n, callback ) {
  crypto.randomBytes( n, function( error, buffer ) {
    callback( error, buffer ? buffer.toString( 'hex' ) : null )
  })
}

/**
 * ACME prototype
 * @type {Object}
 */
ACME.prototype = {

  constructor: ACME,

  getDirectory: function( callback ) {

    var self = this
    var options = URL.parse( this.options.baseUrl )

    options.method = 'GET'
    options.path = '/directory'

    var req = https.request( options, function( res ) {

      var buffer = ''

      res.setEncoding( 'utf8' )
      res.on( 'readable', function() {
        var chunk = null
        while( chunk = this.read() )
          buffer += chunk
      })

      res.on( 'end', function() {
        var error, data
        try { data = JSON.parse( buffer ) }
        catch( e ) { error = e }
        self.directory = data
        callback( error, data )
      })

    })

    req.on( 'error', callback )
    req.end()

  },

  register: function() {
    // New registration 'new-reg'
  },

  recover: function() {
    // Recover registration 'recover-reg'
  },

  authorize: function() {
    // New authorization 'new-authz'
  },

  getCertificate: function() {
    // New certificate 'new-cert'
  },

  renewCertificate: function() {
    // ...?
  },

  revokeCertificate: function() {
    // Revoke certificate 'revoke-cert'
  },

  getRegistration: function() {
    // NOTE: Unsure about method name
    // Registration 'reg'
  },

  getAuthorization: function() {
    // NOTE: Unsure about method name
    // Authorization 'authz'
  },

  getChallenge: function() {
    // NOTE: Unsure about method name
    // Challenge 'challenge'
  },

}

// Exports
module.exports = ACME
<|endoftext|>


<commit_before>/*
 * @author: vivaxy
 * @date:   2015-04-02 20:46:03
 * @last modified by:   vivaxy
 * @last modified time: 2015-04-03 09:38:19
 */

'use strict';

/**
 * @constructor
 * @param {[type]} options [description]
 */
var Ajax = function (options) {
        this.events = {};

        this.url = options.url;
        this.type = options.type;

    },
    p = {};

Ajax.prototype = p;

/**
 * on `success`
 * @param  {[type]}   event    [description]
 * @param  {Function} callback [description]
 * @return {[type]}            [description]
 */
p.on = function (event, callback) {
    if (!this.events[event]) {
        this.events[event] = [];
    }
    this.events[event].push(callback);
    return this;
};

/**
 * fire events
 * @param  {[type]} event [description]
 * @return {[type]}       [description]
 */
p.fire = function (event) {
    var callbacks = this.events[event],
        _this = this,
        _arguments = arguments;
    if (callbacks) {
        callbacks.forEach(function (callback) {
            callback.apply(null, Array.prototype.slice.call(_arguments, 1));
        });
    }
    return this;
};

/**
 * send data
 * @param  {[type]} data [description]
 * @return {[type]}      [description]
 */
p.send = function (data) {
    var _this = this,
        xhr = new XMLHttpRequest();
    xhr.addEventListener('readystatechange', function () {
        if (xhr.readyState === 4) {
            if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
                // 2** is valid response status, and 304 means get from the cache
                _this.fire('success', xhr.responseText, xhr);
            }
        }
        _this.fire('readystatechange', xhr);
    });
    if (this.type && this.type.toUpperCase() === 'POST') {
        xhr.open('POST', this.url, true);
        xhr.send(data);
    } else {
        var a = document.createElement('a');
        a.href = this.url;
        var url = a.origin + a.pathname + this.getQueryString(data);
        xhr.open('GET', url, true);
        xhr.send();
    }
    return this;
};

/**
 * get query string from data
 * @param  {[type]} data [description]
 * @return {[type]}        [description]
 */
p.getQueryString = function (data) {
    if (typeof data === 'string') return data === '' ? '' : '?' + data;
    var querystring = '?';
    for (var key in data) {
        if (data.hasOwnProperty(key)) {
            var value = data[key];
            if (typeof value !== 'string') {
                try {
                    value = JSON.stringify(value);
                } catch (e) {
                    throw 'data can not be parsed to querystring';
                }
            }
            querystring += encodeURIComponent(key) + '=' + encodeURIComponent(value) + '&';
        }
    }
    return querystring.slice(0, -1);
};
<commit_msg>get add timestamp<commit_after>/*
 * @author: vivaxy
 * @date:   2015-04-02 20:46:03
 * @last modified by:   vivaxy
 * @last modified time: 2015-04-03 09:38:19
 */

'use strict';

/**
 *
 * @param options
 * @constructor
 */
var Ajax = function (options) {
        this.events = {};

        this.url = options.url;
        this.type = options.type;

    },
    p = {};

Ajax.prototype = p;

/**
 *
 * @param event
 * @param callback
 * @returns {p}
 */
p.on = function (event, callback) {
    if (!this.events[event]) {
        this.events[event] = [];
    }
    this.events[event].push(callback);
    return this;
};

/**
 *
 * @param event
 * @returns {p}
 */
p.fire = function (event) {
    var callbacks = this.events[event],
        _this = this,
        _arguments = arguments;
    if (callbacks) {
        callbacks.forEach(function (callback) {
            callback.apply(null, Array.prototype.slice.call(_arguments, 1));
        });
    }
    return this;
};

/**
 *
 * @param data
 * @returns {p}
 */
p.send = function (data) {
    var _this = this,
        xhr = new XMLHttpRequest();
    xhr.addEventListener('readystatechange', function () {
        if (xhr.readyState === 4) {
            if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
                // 2** is valid response status, and 304 means get from the cache
                _this.fire('success', xhr.responseText, xhr);
            }
        }
        _this.fire('readystatechange', xhr);
    });
    if (this.type && this.type.toUpperCase() === 'POST') {
        xhr.open('POST', this.url, true);
        xhr.send(data);
    } else {
        var a = document.createElement('a');
        a.href = this.url;
        var url = a.origin + a.pathname + this.getQueryString(this.mixin(data, {_: new Date().getTime()}));
        xhr.open('GET', url, true);
        xhr.send();
    }
    return this;
};

/**
 *
 * @param data
 * @returns {*}
 */
p.getQueryString = function (data) {
    if (typeof data === 'string') return data === '' ? '' : '?' + data;
    var queryString = '?';
    for (var key in data) {
        if (data.hasOwnProperty(key)) {
            var value = data[key];
            if (typeof value !== 'string') {
                try {
                    value = JSON.stringify(value);
                } catch (e) {
                    throw 'data can not be parsed to querystring';
                }
            }
            queryString += encodeURIComponent(key) + '=' + encodeURIComponent(value) + '&';
        }
    }
    return queryString.slice(0, -1);
};

p.mixin = function (a, b) {
    var r = {};
    r = this.copy(a, r);
    r = this.copy(b, r);
    return r;
};

/**
 *
 * @param a
 * @param r
 * @returns {*}
 */
p.copy = function (a, r) {
    for (var i in a) {
        if (a.hasOwnProperty(i)) {
            r[i] = a[i];
        }
    }
    return r;
};
<|endoftext|>