<commit_before>const cheerio = require('cheerio');
const keva = require('keva');
const access = require('./access');
const opt = access.readConfig();

module.exports = class HTMLCreator {
  constructor() {
    this.prefixes = access.readPrefixes();
  }

  create(key, value) {
    return this.renderFile(value).then((template) => {
      return {
        key: key,
        template: template.html,
        structure: template.structure,
        file: `${opt.root}bin/` + /(.*)\..*$/.exec(value.content)[1] + '.html',
      };
    });
  }

  renderFile(pageLocation) {
    return access.readPageData(pageLocation).then((data) => {
      let element = {
        template: data.template,
        content: data.content,
        type: pageLocation.name,
      };
      return this.resolveElements(element).then((html) => {
        if(access.readOptions().dev) {
          // replaces dev with data-dev (cheerio seems to bug with data attributes)
          // see http://regexr.com/3eoqv
          html = html.replace(/dev/g, 'data-dev');
          // html = html.replace(/(<.*\s)dev(=*\/?.*>)/g, '$1data-dev$2');
        }
        return {
          structure: data.content,
          html: html,
        };
      });
    });
  }

  resolveElements(element, depth = 0, nextKey, parentKey) {
    let $ = cheerio.load(element.template, {
      xmlMode: true,
    });
    if(parentKey && nextKey) {
      parentKey = `${parentKey} ${nextKey}`;
    } else if(nextKey) {
      parentKey = nextKey;
    }
    let rootChildren = $.root().children();
    if (depth > 0) {
      if (rootChildren.length > 1) {
        throw new Error('Elements must be wrapped in an enclosing tag');
      }
      $(rootChildren[0]).addClass(element.type);
    }
    this.insertContent(element.content, $, {
      key: access.readOptions().dev ? parentKey : null,
    });
    let promises = [];
    let level = Object.keys(opt.structure.folders)[depth];
    $('loop').each((_, loop) => {
      let name = $(loop).attr(`${opt.attributes.name}`);
      let elements = element.content[name];
      for (let i = 0; i < elements.length; i++) {
        if (typeof elements[i].data === 'string') {
          elements[i].data = {
            value: elements[i].data,
            single: true,
          };
        }
        elements[i].generate = true;
      }
      let html = $(loop).html();
      $(loop).empty();

      for (let i = 0; i < elements.length; i++) {
        $(loop).append(html);
        $(loop).find('target')
          .replaceWith(`<${level} type="${elements[i].type}">`);
      }
    });
    $(level).each((_, elem) => {
      let name = $(elem).attr(`${opt.attributes.name}`);
      let type = $(elem).attr(`${opt.attributes.type}`);
      let loopParent = $(elem).parents('loop').get(0);
      let currentContent;
      let nextKey;

      if (loopParent) {
        let loop = element.content[$(loopParent).attr(`${opt.attributes.name}`)];
        loop = loop.filter((loopElem) => loopElem.generate);
        delete loop[0].generate;
        currentContent = loop[0].data;
      } else {
        nextKey = name || type;
        if (typeof element.content[nextKey] === 'string') {
          element.content[nextKey] = {
            value: element.content[nextKey],
            single: true,
          };
        }
        currentContent = element.content[nextKey];
      }

      for (let [name, value] of keva(elem.attribs)) {
        let match = name.match(new RegExp(`^cms-(\w+)`));
        if (match) currentContent[match[1]] = value;
      }

      promises.push(
        access.readElement(level, `${type}.html`).then((template) => {
          return this.resolveElements({
            type: type,
            template: template,
            content: currentContent,
          }, depth + 1, nextKey, parentKey);
        }).then((html) => ({node: elem, html: html})));
    });

    return Promise.all(promises).then((data) => {
      data.forEach((elem) => {
        $(elem.node).replaceWith(elem.html);
      });
      $('loop').each((_, loop) => $(loop).replaceWith($(loop).html()));
      return $.html();
    });
  }

  insertContent(data, $, options) {
    $('*').each((_, elem) => {
      for (let [name, value] of keva(elem.attribs)) {
        let match = name.match(/^(\w+)-(.+)/);
        if (match && this.prefixes[match[1]]) {
          let toInsert;
          if (data.single) {
            toInsert = data.value;
          } else {
            toInsert = typeof data[value] === 'string' ?
              data[value] :
              data[value].value;
          }
          if (!this.prefixes[match[1]].test(toInsert)) {
            throw new Error(
              `"${toInsert}" did not match the prefix "${match[1]}"`
            );
          }
          if (data.single) {
            data.value = toInsert;
            data.type = match[1];
            delete data.single;
          } else if (typeof data[value] === 'string') {
            data[value] = {
              value: toInsert,
              type: match[1],
            };
          }
          $(elem).removeAttr(name);
          if (match[2] === opt.attributes.content) {
            let html = toInsert;
            $(elem).html(html);
          } else {
            $(elem).attr(match[2], toInsert);
          }
          if(options.key) {
            if(!$(elem).attr(`dev`)) {
              $(elem).attr(`dev`, options.key);
            }
            $(elem).attr('dev-targets',
              ($(elem).attr('dev-targets') || '') +
              ' ' +
              name +
              (value ? `:${value}` : '')
            );
          }
        }
      }
    });
    return data;
  }
};
<commit_msg>fixed data[value] bug<commit_after>const cheerio = require('cheerio');
const keva = require('keva');
const access = require('./access');
const opt = access.readConfig();

module.exports = class HTMLCreator {
  constructor() {
    this.prefixes = access.readPrefixes();
  }

  create(key, value) {
    return this.renderFile(value).then((template) => {
      return {
        key: key,
        template: template.html,
        structure: template.structure,
        file: `${opt.root}bin/` + /(.*)\..*$/.exec(value.content)[1] + '.html',
      };
    });
  }

  renderFile(pageLocation) {
    return access.readPageData(pageLocation).then((data) => {
      let element = {
        template: data.template,
        content: data.content,
        type: pageLocation.name,
      };
      return this.resolveElements(element).then((html) => {
        if(access.readOptions().dev) {
          // replaces dev with data-dev (cheerio seems to bug with data attributes)
          // see http://regexr.com/3eoqv
          html = html.replace(/dev/g, 'data-dev');
          // html = html.replace(/(<.*\s)dev(=*\/?.*>)/g, '$1data-dev$2');
        }
        return {
          structure: data.content,
          html: html,
        };
      });
    });
  }

  resolveElements(element, depth = 0, nextKey, parentKey) {
    let $ = cheerio.load(element.template, {
      xmlMode: true,
    });
    if(parentKey && nextKey) {
      parentKey = `${parentKey} ${nextKey}`;
    } else if(nextKey) {
      parentKey = nextKey;
    }
    let rootChildren = $.root().children();
    if (depth > 0) {
      if (rootChildren.length > 1) {
        throw new Error('Elements must be wrapped in an enclosing tag');
      }
      $(rootChildren[0]).addClass(element.type);
    }
    this.insertContent(element.content, $, {
      key: access.readOptions().dev ? parentKey : null,
    });
    let promises = [];
    let level = Object.keys(opt.structure.folders)[depth];
    $('loop').each((_, loop) => {
      let name = $(loop).attr(`${opt.attributes.name}`);
      let elements = element.content[name];
      for (let i = 0; i < elements.length; i++) {
        if (typeof elements[i].data === 'string') {
          elements[i].data = {
            value: elements[i].data,
            single: true,
          };
        }
        elements[i].generate = true;
      }
      let html = $(loop).html();
      $(loop).empty();

      for (let i = 0; i < elements.length; i++) {
        $(loop).append(html);
        $(loop).find('target')
          .replaceWith(`<${level} type="${elements[i].type}">`);
      }
    });
    $(level).each((_, elem) => {
      let name = $(elem).attr(`${opt.attributes.name}`);
      let type = $(elem).attr(`${opt.attributes.type}`);
      let loopParent = $(elem).parents('loop').get(0);
      let currentContent;
      let nextKey;

      if (loopParent) {
        let loop = element.content[$(loopParent).attr(`${opt.attributes.name}`)];
        loop = loop.filter((loopElem) => loopElem.generate);
        delete loop[0].generate;
        currentContent = loop[0].data;
      } else {
        nextKey = name || type;
        if (typeof element.content[nextKey] === 'string') {
          element.content[nextKey] = {
            value: element.content[nextKey],
            single: true,
          };
        }
        currentContent = element.content[nextKey];
      }

      for (let [name, value] of keva(elem.attribs)) {
        let match = name.match(new RegExp(`^cms-(\w+)`));
        if (match) currentContent[match[1]] = value;
      }

      promises.push(
        access.readElement(level, `${type}.html`).then((template) => {
          return this.resolveElements({
            type: type,
            template: template,
            content: currentContent,
          }, depth + 1, nextKey, parentKey);
        }).then((html) => ({node: elem, html: html})));
    });

    return Promise.all(promises).then((data) => {
      data.forEach((elem) => {
        $(elem.node).replaceWith(elem.html);
      });
      $('loop').each((_, loop) => $(loop).replaceWith($(loop).html()));
      return $.html();
    });
  }

    insertContent(data, $, options) {
    $('*').each((_, elem) => {
      for (let [name, value] of keva(elem.attribs)) {
        let match = name.match(/^(\w+)-(.+)/);
        if (match && this.prefixes[match[1]]) {
          let toInsert;
          if (data.single) {
            toInsert = data.value;
          } else if(data[value]) {
            if (typeof data[value] === 'string') {
              toInsert = data[value];
            } else {
              toInsert = data[value].value;
            }
          }
          if (!this.prefixes[match[1]].test(toInsert)) {
            throw new Error(
              `"${toInsert}" did not match the prefix "${match[1]}"`
            );
          }
          if (data.single) {
            data.value = toInsert;
            data.type = match[1];
            delete data.single;
          } else if (typeof data[value] === 'string') {
            data[value] = {
              value: toInsert,
              type: match[1],
            };
          }
          $(elem).removeAttr(name);
          if (match[2] === opt.attributes.content) {
            let html = toInsert;
            $(elem).html(html);
          } else {
            $(elem).attr(match[2], toInsert);
          }
          if(options.key) {
            if(!$(elem).attr(`dev`)) {
              $(elem).attr(`dev`, options.key);
            }
            $(elem).attr('dev-targets',
              ($(elem).attr('dev-targets') || '') +
              ' ' +
              name +
              (value ? `:${value}` : '')
            );
          }
        }
      }
    });
    return data;
  }
};
<|endoftext|>


<commit_before>'use strict'

const http = require('http')
const repl = require('repl')
const got = require('got')
const normalizeUrl = require('normalize-url')
const stylize = require('./ext/index.js')

// If you're sending GETs with a request body, we kindly suggest you to take your
// HTTP REPLing business somewhere else ;)
const METHODS_WITH_BODY = new Set(['POST', 'PUT', 'PATCH'])

class AwaitingBodyError extends Error {}

class HTTPConsole {
  constructor (options) {
    this.baseUrl = normalizeUrl(options.baseUrl)
    this.headers = {}
    this.got = got.extend({
      prefixUrl: this.baseUrl,
      throwHttpErrors: false
    })
    this.json = options.json === true
    this.verbose = options.verbose === true

    this.input = options.input || process.stdin
    this.output = options.output || process.stdout

    this.colors = typeof options.colors === 'boolean' ? options.colors : this.output.isTTY

    // TODO: load those from files
    this.bodyHistory = []
    this.commandHistory = []

    // It might be wise to keep completers to one item, since they're additive.
    // For example, combining the OpenAPI completer with the basic autocompleter
    // will result in a fuck all of method autocompletion. Dunno.
    this.completers = options.completers || []

    this._waitingForBody = false
  }

  start () {
    this.repl = repl.start({
      prompt: `${this.baseUrl}> `,
      eval: this.eval.bind(this),
      input: this.input,
      output: this.output,
      useColors: this.colors,
      completer: this.completer.bind(this)
    })

    this.completers.forEach(completer => completer.onstart && completer.onstart(this))

    this.repl.on('SIGINT', () => {
      this._waitForBody(false)
    })
  }

  completer (partial, cb) {
    let completions = [], finished = 0

    const addCompletions = (err, newCompletions) => {
      if (!err) completions.push(...newCompletions)
      if (++finished === this.completers.length) cb(null, [completions, partial])
    }

    // Node seems to just *exit* when we don't return from this callback. Doing
    // *something* would be reasonable, but just dropping dead? Possible core bug.
    if (this.completers.length === 0) return cb(null, [[], partial])

    for (const completer of this.completers) {
      if (this._waitingForBody) completer.completeBody(partial, addCompletions)
      else completer.completeCommand(partial, addCompletions)
    }
  }

  evalWithBody(cmd, cb) {
    // We need to handle the following cases here for JSON:
    //   * incomplete body read, continue reading until JSON termination
    //   * complete body read, send out
    //   * empty body - first line's empty

    const body = cmd.split('\n').slice(1).join('\n')

    let options = this._waitingForBody

    if (this.json && body) {
      try {
        options.json = JSON.parse(body)
      }
      catch (e) {
        if (e.name === 'SyntaxError' && e.message.match(/Unexpected end of JSON input/))
          return cb(new repl.Recoverable(e))
        else throw e
      }
    }
    else options.body = body

    this.bodyHistory.push(body)

    this._waitForBody(false)
    return this.req(options, cb)
  }

  eval (cmd, _a, _b, cb) {
    cmd = cmd.trim()

    if (this._waitingForBody)
      return this.evalWithBody(cmd, cb)

    if (cmd === '') return cb()

    this.commandHistory.push(cmd)

    const [method, url] = cmd.split(' ').map(s => s.trim())

    let options = { url: url || '/', method, headers: this.headers }

    if (METHODS_WITH_BODY.has(method.toUpperCase())) {
      this._waitForBody(options)
      return cb(new repl.Recoverable(new AwaitingBodyError()))
    }

    this.req(options, cb)
  }

  renderHeaders (res) {
    const stylizeStatusLine = statusLine => {
      let style = 'green'

      // got follows redirects, so we don't need to worry about them.
      if (res.statusCode >= 500) style = 'red'
      else if (res.statusCode >= 400) style = 'yellow'

      return this._stylize(this._stylize(statusLine, 'bold'), style)
    }

    const status = res.statusCode
    this.output.write(stylizeStatusLine(
      `HTTP/${res.httpVersion} ${status} ${http.STATUS_CODES[status]}\n`
    ))

    for (let [name, val] of Object.entries(res.headers))
      this.output.write(`${this._stylize(name, 'bold')}: ${val}\n`)
    this.output.write('\n')
  }

  _stylize (str, style) {
    return this.colors ? stylize(str, style) : str
  }

  _waitForBody (options) {
    // Modify the history so that only request bodies are in it if we're
    // switching to body mode, and vice versa.
    this._waitingForBody = options
    this.repl.history = options ? this.bodyHistory : this.commandHistory
  }

  async req (options, cb) {
    const url = options.url
    delete options.url

    if (this.json) options.responseType = 'json'

    // We're using a prefixed got, so trim the first slash if we have it.
    const resp = await this.got(url[0] === '/' ? url.slice(1) : url, options)
    this.renderHeaders(resp)
    cb(null, resp.body)
  }
}

module.exports = HTTPConsole
<commit_msg>Use `util.inspect` with no depth limit as the stringifier<commit_after>'use strict'

const util = require('util')
const http = require('http')
const repl = require('repl')
const got = require('got')
const normalizeUrl = require('normalize-url')
const stylize = require('./ext/index.js')

// If you're sending GETs with a request body, we kindly suggest you to take your
// HTTP REPLing business somewhere else ;)
const METHODS_WITH_BODY = new Set(['POST', 'PUT', 'PATCH'])

class AwaitingBodyError extends Error {}

class HTTPConsole {
  constructor (options) {
    this.baseUrl = normalizeUrl(options.baseUrl)
    this.headers = {}
    this.got = got.extend({
      prefixUrl: this.baseUrl,
      throwHttpErrors: false
    })
    this.json = options.json === true
    this.verbose = options.verbose === true

    this.input = options.input || process.stdin
    this.output = options.output || process.stdout

    this.colors = typeof options.colors === 'boolean' ? options.colors : this.output.isTTY

    // TODO: load those from files
    this.bodyHistory = []
    this.commandHistory = []

    // It might be wise to keep completers to one item, since they're additive.
    // For example, combining the OpenAPI completer with the basic autocompleter
    // will result in a fuck all of method autocompletion. Dunno.
    this.completers = options.completers || []

    this._waitingForBody = false
  }

  start () {
    this.repl = repl.start({
      prompt: `${this.baseUrl}> `,
      eval: this.eval.bind(this),
      input: this.input,
      output: this.output,
      useColors: this.colors,
      completer: this.completer.bind(this),
      writer: (data) => util.inspect(data, {
        depth: null,
        colors: this.colors
      })
    })

    this.completers.forEach(completer => completer.onstart && completer.onstart(this))

    this.repl.on('SIGINT', () => {
      this._waitForBody(false)
    })
  }

  completer (partial, cb) {
    let completions = [], finished = 0

    const addCompletions = (err, newCompletions) => {
      if (!err) completions.push(...newCompletions)
      if (++finished === this.completers.length) cb(null, [completions, partial])
    }

    // Node seems to just *exit* when we don't return from this callback. Doing
    // *something* would be reasonable, but just dropping dead? Possible core bug.
    if (this.completers.length === 0) return cb(null, [[], partial])

    for (const completer of this.completers) {
      if (this._waitingForBody) completer.completeBody(partial, addCompletions)
      else completer.completeCommand(partial, addCompletions)
    }
  }

  evalWithBody(cmd, cb) {
    // We need to handle the following cases here for JSON:
    //   * incomplete body read, continue reading until JSON termination
    //   * complete body read, send out
    //   * empty body - first line's empty

    const body = cmd.split('\n').slice(1).join('\n')

    let options = this._waitingForBody

    if (this.json && body) {
      try {
        options.json = JSON.parse(body)
      }
      catch (e) {
        if (e.name === 'SyntaxError' && e.message.match(/Unexpected end of JSON input/))
          return cb(new repl.Recoverable(e))
        else throw e
      }
    }
    else options.body = body

    this.bodyHistory.push(body)

    this._waitForBody(false)
    return this.req(options, cb)
  }

  eval (cmd, _a, _b, cb) {
    cmd = cmd.trim()

    if (this._waitingForBody)
      return this.evalWithBody(cmd, cb)

    if (cmd === '') return cb()

    this.commandHistory.push(cmd)

    const [method, url] = cmd.split(' ').map(s => s.trim())

    let options = { url: url || '/', method, headers: this.headers }

    if (METHODS_WITH_BODY.has(method.toUpperCase())) {
      this._waitForBody(options)
      return cb(new repl.Recoverable(new AwaitingBodyError()))
    }

    this.req(options, cb)
  }

  renderHeaders (res) {
    const stylizeStatusLine = statusLine => {
      let style = 'green'

      // got follows redirects, so we don't need to worry about them.
      if (res.statusCode >= 500) style = 'red'
      else if (res.statusCode >= 400) style = 'yellow'

      return this._stylize(this._stylize(statusLine, 'bold'), style)
    }

    const status = res.statusCode
    this.output.write(stylizeStatusLine(
      `HTTP/${res.httpVersion} ${status} ${http.STATUS_CODES[status]}\n`
    ))

    for (let [name, val] of Object.entries(res.headers))
      this.output.write(`${this._stylize(name, 'bold')}: ${val}\n`)
    this.output.write('\n')
  }

  _stylize (str, style) {
    return this.colors ? stylize(str, style) : str
  }

  _waitForBody (options) {
    // Modify the history so that only request bodies are in it if we're
    // switching to body mode, and vice versa.
    this._waitingForBody = options
    this.repl.history = options ? this.bodyHistory : this.commandHistory
  }

  async req (options, cb) {
    const url = options.url
    delete options.url

    if (this.json) options.responseType = 'json'

    // We're using a prefixed got, so trim the first slash if we have it.
    const resp = await this.got(url[0] === '/' ? url.slice(1) : url, options)
    this.renderHeaders(resp)
    cb(null, resp.body)
  }
}

module.exports = HTTPConsole
<|endoftext|>


<commit_before>/* jslint node: true, esnext: true */

"use strict";

const path = require('path'),
	route = require('koa-route'),
	step = require('kronos-step'),
	ReadableStream = require('stream').Readable,
	FormData = require('form-data'),
	endpoint = require('kronos-endpoint');

/**
 * Endpoint to link against a koa route
 */
class RouteSendEndpoint extends endpoint.SendEndpoint {

	/**
	 * @param name {String} endpoint name
	 * @param owner {Step} the owner of the endpoint
	 * @param method {String} http method defaults to get
	 * @param content
	 */
	constructor(name, owner, path, method, content, serviceName) {
		super(name, owner);

		// The path in the URL
		Object.defineProperty(this, 'path', {
			value: path
		});

		method = method ? method.toLowerCase() : "get";

		// The HTTP method to use (GET, POST, ...)
		Object.defineProperty(this, 'method', {
			value: method
		});

		// The path in the URL
		Object.defineProperty(this, 'serviceName', {
			value: serviceName
		});
	}

	/**
	 *
	 */
	get route() {
		if (!this._route) {
			this._route = route[this.method](this.path, ctx => {

				this.owner.info(`${this.method} ${this.path}`);

				const message = {
					"info": {
						"request": ctx.request,
					},
					"payload": ctx.req
				};

				return this.receive(message).then(response => {
					//this.owner.info(`${this.method} ${this.path}: ${JSON.stringify(response)}`);
					this.owner.info(`${this.method} ${this.path}`);

					if (response && (response.payload.readable)) {
						ctx.set('content-type', response.payload.getHeaders()["content-type"]);
						ctx.body = response.payload;
					} else {
						ctx.body = response;
					}

				});
			});
		}
		return this._route;
	}

	toString() {
		return `${this.method} ${this.name}`;
	}
}

const httpRoutingStep = Object.assign({}, step.Step, {
	"name": "kronos-http-routing",
	"description": "routes http requests to endpoints",
	initialize(manager, name, conf, props) {
		props._listener = {
			value: conf.listener || 'default-listener'
		};
	},

	_start() {
		// wait until names service is present
		return this.manager.declareService({
			'type': 'koa',
			'name': this._listener
		}, true).then(service => {
			this.listener = service;

			const registry = this.manager.services.registry;

			for (let en in this.endpoints) {
				const ep = this.endpoints[en];
				const route = ep.route;

				if (route) {
					service.koa.use(route);

					if (registry && ep.serviceName) {
						registry.registerService(ep.serviceName, {
							url: path.join(this.listener.url, route.path)
						});
					}
				}
			}

			return service.start();
		});
	},

	_stop() {
		const registry = this.manager.services.registry;

		for (let en in this.endpoints) {
			const ep = this.endpoints[en];
			const route = ep.route;
			if (route) {
				if (registry && ep.serviceName) {
					registry.unregisterService(ep.serviceName, {
						url: path.join(this.listener.url, route.path)
					});
				}

				this.trace(level => `removing route ${this.endpoints[en]}`);
				this.listener.koa.delete(route);
			}
		}
		return Promise.resolve();
	},

	createEndpoints(def) {
		for (let name in def.endpoints) {
			const r = def.endpoints[name];

			const ep = new RouteSendEndpoint(name, this, r.path || name, r.method, r.serviceName);

			if (r.interceptors) {
				ep.interceptors = r.interceptors.map(icDef => this.manager.createInterceptorInstanceFromConfig(icDef, ep));
			}

			this.addEndpoint(ep);
		}
	}
});

exports.registerWithManager = manager => manager.registerStep(httpRoutingStep);
<commit_msg>fix: decission between response.payload.readable and plain response<commit_after>/* jslint node: true, esnext: true */

"use strict";

const path = require('path'),
	route = require('koa-route'),
	step = require('kronos-step'),
	ReadableStream = require('stream').Readable,
	FormData = require('form-data'),
	endpoint = require('kronos-endpoint');

/**
 * Endpoint to link against a koa route
 */
class RouteSendEndpoint extends endpoint.SendEndpoint {

	/**
	 * @param name {String} endpoint name
	 * @param owner {Step} the owner of the endpoint
	 * @param method {String} http method defaults to get
	 * @param content
	 */
	constructor(name, owner, path, method, content, serviceName) {
		super(name, owner);

		// The path in the URL
		Object.defineProperty(this, 'path', {
			value: path
		});

		method = method ? method.toLowerCase() : "get";

		// The HTTP method to use (GET, POST, ...)
		Object.defineProperty(this, 'method', {
			value: method
		});

		// The path in the URL
		Object.defineProperty(this, 'serviceName', {
			value: serviceName
		});
	}

	/**
	 *
	 */
	get route() {
		if (!this._route) {
			this._route = route[this.method](this.path, ctx => {

				this.owner.info(`${this.method} ${this.path}`);

				const message = {
					"info": {
						"request": ctx.request,
					},
					"payload": ctx.req
				};

				return this.receive(message).then(response => {
					//this.owner.info(`${this.method} ${this.path}: ${JSON.stringify(response)}`);
					this.owner.info(`${this.method} ${this.path}`);

					if (response.payload && response.payload.readable) {
						ctx.set('content-type', response.payload.getHeaders()["content-type"]);
						ctx.body = response.payload;
					} else {
						ctx.body = response;
					}

				});
			});
		}
		return this._route;
	}

	toString() {
		return `${this.method} ${this.name}`;
	}
}

const httpRoutingStep = Object.assign({}, step.Step, {
	"name": "kronos-http-routing",
	"description": "routes http requests to endpoints",
	initialize(manager, name, conf, props) {
		props._listener = {
			value: conf.listener || 'default-listener'
		};
	},

	_start() {
		// wait until names service is present
		return this.manager.declareService({
			'type': 'koa',
			'name': this._listener
		}, true).then(service => {
			this.listener = service;

			const registry = this.manager.services.registry;

			for (let en in this.endpoints) {
				const ep = this.endpoints[en];
				const route = ep.route;

				if (route) {
					service.koa.use(route);

					if (registry && ep.serviceName) {
						registry.registerService(ep.serviceName, {
							url: path.join(this.listener.url, route.path)
						});
					}
				}
			}

			return service.start();
		});
	},

	_stop() {
		const registry = this.manager.services.registry;

		for (let en in this.endpoints) {
			const ep = this.endpoints[en];
			const route = ep.route;
			if (route) {
				if (registry && ep.serviceName) {
					registry.unregisterService(ep.serviceName, {
						url: path.join(this.listener.url, route.path)
					});
				}

				this.trace(level => `removing route ${this.endpoints[en]}`);
				this.listener.koa.delete(route);
			}
		}
		return Promise.resolve();
	},

	createEndpoints(def) {
		for (let name in def.endpoints) {
			const r = def.endpoints[name];

			const ep = new RouteSendEndpoint(name, this, r.path || name, r.method, r.serviceName);

			if (r.interceptors) {
				ep.interceptors = r.interceptors.map(icDef => this.manager.createInterceptorInstanceFromConfig(icDef, ep));
			}

			this.addEndpoint(ep);
		}
	}
});

exports.registerWithManager = manager => manager.registerStep(httpRoutingStep);
<|endoftext|>


<commit_before>// Copyright Aditya Patadia, Octal Consulting LLP
var fs = require('fs');
var debug = require('debug')('bone');
var bone = require('./bone');
var verror = require("verror");
var eeprom = require('./eeprom');

module.exports = {

    watchdog: require("./watchdog"),

    pwm: require("./pwm"),

    digital: require("./digital"),

    analog: require("./analog"),

    readPinState: function(pin, callback) {
        debug("readPinState(" + pin.key + ")");
        var p = "ocp:" + pin.key + "_pinmux";
        bone.find_sysfsFile(p, bone.is_ocp(), p , onFindPinmux);

        function onFindPinmux(err, data) {
            if (err) {
                callback(err, null);
            } else if (!data.path) {
                err = new verror("Pinmux file for " + p + " could not be found");
                callback(err, null);
            } else {
                fs.readFile(data.path + "/state", 'utf8', function(err, state) {
                    callback(null, state.trim());
                });
            }
        }
    },

    setPinMode: function(pin, mode, callback) {
        if (mode == "gpio" || mode == "gpio_pu" || mode == "gpio_pd") {

            module.exports.digital.setPinMode(pin, mode, callback);

        } else if (mode == "pwm") {

            module.exports.pwm.setPinMode(pin, mode, callback);

        } else {

            err = new verror('This mode is currently not supported by octalbonescript');
            if(typeof callback == 'function') callback(err);

        }
    },

    setPinModeSync: function(pin, mode) {
        if (mode == "gpio" || mode == "gpio_pu" || mode == "gpio_pd") {

            return module.exports.digital.setPinModeSync(pin, mode);

        } else if (mode == "pwm") {

            return module.exports.pwm.setPinModeSync(pin, mode);

        } else {

            return new verror('This mode is currently not supported by octalbonescript');

        }
    },

    readEeproms: function(eeproms) {
        var EepromFiles = {
            '/sys/bus/i2c/drivers/at24/0-0050/eeprom': {
                type: 'bone'
            },
            '/sys/bus/i2c/drivers/at24/2-0054/eeprom': {
                type: 'cape'
            },
            '/sys/bus/i2c/drivers/at24/2-0055/eeprom': {
                type: 'cape'
            },
            '/sys/bus/i2c/drivers/at24/2-0056/eeprom': {
                type: 'cape'
            },
            '/sys/bus/i2c/drivers/at24/2-0057/eeprom': {
                type: 'cape'
            }
        };
        eeproms = eeprom.readEeproms(EepromFiles);
        return (eeproms);
    },

    readPlatform: function(platform) {
        var eeproms = eeprom.readEeproms({
            '/sys/bus/i2c/drivers/at24/0-0050/eeprom': {
                type: 'bone'
            }
        });
        var x = eeproms['/sys/bus/i2c/drivers/at24/0-0050/eeprom'];
        console.log('Andy Test x', x);
        if (x.boardName == 'A335BONE') platform.name = 'BeagleBone';
        if (x.boardName == 'A335BNLT') platform.name = 'BeagleBone Black';
        platform.version = x.version;
        if (!platform.version.match(/^[\040-\176]*$/)) delete platform.version;
        platform.serialNumber = x.serialNumber;
        if (!platform.serialNumber.match(/^[\040-\176]*$/)) delete platform.serialNumber;
        if (platform.serialNumber && platform.serialNumber.substring(0,4) == 'BBG') platform.name = 'BeagleBone Green';
        try {
            platform.dogtag = fs.readFileSync('/etc/dogtag', 'ascii');
        } catch (ex) {}
        return (platform);
    }
};
<commit_msg>detect and autoload of universial fixes with some cleanup<commit_after>// Copyright Aditya Patadia, Octal Consulting LLP
var fs = require('fs');
var debug = require('debug')('bone');
var bone = require('./bone');
var verror = require("verror");
var eeprom = require('./eeprom');

module.exports = {

    watchdog: require("./watchdog"),

    pwm: require("./pwm"),

    digital: require("./digital"),

    analog: require("./analog"),

    readPinState: function(pin, callback) {
        debug("readPinState(" + pin.key + ")");
        var p = "ocp:" + pin.key + "_pinmux";
        bone.find_sysfsFile(p, bone.is_ocp(), p , onFindPinmux);

        function onFindPinmux(err, data) {
            if (err) {
                callback(err, null);
            } else if (!data.path) {
                err = new verror("Pinmux file for " + p + " could not be found");
                callback(err, null);
            } else {
                fs.readFile(data.path + "/state", 'utf8', function(err, state) {
                    callback(null, state.trim());
                });
            }
        }
    },

    setPinMode: function(pin, mode, callback) {
        if (mode == "gpio" || mode == "gpio_pu" || mode == "gpio_pd") {

            module.exports.digital.setPinMode(pin, mode, callback);

        } else if (mode == "pwm") {

            module.exports.pwm.setPinMode(pin, mode, callback);

        } else {

            err = new verror('This mode is currently not supported by octalbonescript');
            if(typeof callback == 'function') callback(err);

        }
    },

    setPinModeSync: function(pin, mode) {
        if (mode == "gpio" || mode == "gpio_pu" || mode == "gpio_pd") {

            return module.exports.digital.setPinModeSync(pin, mode);

        } else if (mode == "pwm") {

            return module.exports.pwm.setPinModeSync(pin, mode);

        } else {

            return new verror('This mode is currently not supported by octalbonescript');

        }
    },

    readEeproms: function(eeproms) {
        var EepromFiles = {
            '/sys/bus/i2c/drivers/at24/0-0050/eeprom': {
                type: 'bone'
            },
            '/sys/bus/i2c/drivers/at24/2-0054/eeprom': {
                type: 'cape'
            },
            '/sys/bus/i2c/drivers/at24/2-0055/eeprom': {
                type: 'cape'
            },
            '/sys/bus/i2c/drivers/at24/2-0056/eeprom': {
                type: 'cape'
            },
            '/sys/bus/i2c/drivers/at24/2-0057/eeprom': {
                type: 'cape'
            }
        };
        eeproms = eeprom.readEeproms(EepromFiles);
        return (eeproms);
    },

    readPlatform: function(platform) {
        var eeproms = eeprom.readEeproms({
            '/sys/bus/i2c/drivers/at24/0-0050/eeprom': {
                type: 'bone'
            }
        });
        var x = eeproms['/sys/bus/i2c/drivers/at24/0-0050/eeprom'];
        if (x.boardName == 'A335BONE') platform.name = 'BeagleBone';
        if (x.boardName == 'A335BNLT') platform.name = 'BeagleBone Black';
        platform.version = x.version;
        if (!platform.version.match(/^[\040-\176]*$/)) delete platform.version;
        platform.serialNumber = x.serialNumber;
        if (!platform.serialNumber.match(/^[\040-\176]*$/)) delete platform.serialNumber;
        try {
            platform.dogtag = fs.readFileSync('/etc/dogtag', 'ascii');
        } catch (ex) {}
        return (platform);
    }
};
<|endoftext|>


<commit_before>var async = require('async'),
    request = require('request'),
    _ = require('lodash');

var IMAGE_SEARCH_URI = 'http://localhost:5000/search';

function doSearch(imgUrl, onFinished) {
    var content = JSON.stringify({
        'image_url': imgUrl
    });

    var options = {
        uri: IMAGE_SEARCH_URI,
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Content-Length': content.length
        },
        body: content
    };

    request(options, function(err, res, body) {
        if (err || res.statusCode !== 200) {
            return onFinished(new Error('Request failure: ' + err.message));
        }

        onFinished(err, JSON.parse(body));
    });
}

/**
 * Choose the next image to search for using the results
 * of the previous search images until now.
 */
function chooseNextSearchImage(possibleSearchImages, alreadySearchedImages) {
    if (possibleSearchImages.length === 0) {
        console.warn('No images to choose from.');
        return false;
    }

    // Avoid infinite oscillation by not searching with images we've previously
    // searched for.
    var resultImage = _.find(possibleSearchImages, function(img) {
        return !_.contains(alreadySearchedImages, img);
    });

    return resultImage;
}

module.exports = {
    doRecursiveImageSearch: function(count, searchImageUrl, onFinished) {
        var startCount = count;
        var resultImageUrls = [];

        // Add the initial search image url.
        resultImageUrls.push(searchImageUrl);

        async.doWhilst(
            // Work callback.
            function(cb) {
                console.log('Performing search [' + (startCount - count + 1) + '] for: ' + searchImageUrl);

                doSearch(searchImageUrl, function(err, results) {
                    if (err) {
                        return cb(err);
                    }

                    var prevSearchImageUrl = searchImageUrl;
                    searchImageUrl = chooseNextSearchImage(results.similar_images, resultImageUrls);

                    if (!searchImageUrl) {
                        return cb(new Error('Searching for image [' + prevSearchImageUrl + '] produced no searchable results.'));
                    }

                    resultImageUrls.push(searchImageUrl);

                    cb();
                });

                count--;
            },
            // Condition check callback.
            function() {
                return count > 0;
            },
            // Finish callback.
            function(err) {
                if (err) {
                    console.error('Error: ' + err.message);
                }

                onFinished(err, resultImageUrls);
            }
        );
    }
};
<commit_msg>Fix off by 1 bug with # of image searches.<commit_after>var async = require('async'),
    request = require('request'),
    _ = require('lodash');

var IMAGE_SEARCH_URI = 'http://localhost:5000/search';

function doSearch(imgUrl, onFinished) {
    var content = JSON.stringify({
        'image_url': imgUrl
    });

    var options = {
        uri: IMAGE_SEARCH_URI,
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Content-Length': content.length
        },
        body: content
    };

    request(options, function(err, res, body) {
        if (err || res.statusCode !== 200) {
            return onFinished(new Error('Request failure: ' + err.message));
        }

        onFinished(err, JSON.parse(body));
    });
}

/**
 * Choose the next image to search for using the results
 * of the previous search images until now.
 */
function chooseNextSearchImage(possibleSearchImages, alreadySearchedImages) {
    if (possibleSearchImages.length === 0) {
        console.warn('No images to choose from.');
        return false;
    }

    // Avoid infinite oscillation by not searching with images we've previously
    // searched for.
    var resultImage = _.find(possibleSearchImages, function(img) {
        return !_.contains(alreadySearchedImages, img);
    });

    return resultImage;
}

module.exports = {
    doRecursiveImageSearch: function(count, searchImageUrl, onFinished) {
        var startCount = count;
        var resultImageUrls = [];

        // Add the initial search image url.
        resultImageUrls.push(searchImageUrl);

        async.whilst(
            // Condition check callback.
            function() {
                return count > 0;
            },
            // Work callback.
            function(cb) {
                console.log('Performing search [' + (startCount - count + 1) + '] for: ' + searchImageUrl);

                doSearch(searchImageUrl, function(err, results) {
                    if (err) {
                        return cb(err);
                    }

                    var prevSearchImageUrl = searchImageUrl;
                    searchImageUrl = chooseNextSearchImage(results.similar_images, resultImageUrls);

                    if (!searchImageUrl) {
                        return cb(new Error('Searching for image [' + prevSearchImageUrl + '] produced no searchable results.'));
                    }

                    resultImageUrls.push(searchImageUrl);

                    cb();
                });

                count--;
            },
            // Finish callback.
            function(err) {
                if (err) {
                    console.error('Error: ' + err.message);
                }

                onFinished(err, resultImageUrls);
            }
        );
    }
};
<|endoftext|>


<commit_before>module.exports = exports = function (options, cmd, shell) {
    // If the command has pre-defined options then parse through them and validate against the supplied options.
    if (cmd.options) {

        var nonNamedIndex = 0;

        // Loop through the command's pre-defined options.
        for (var key in cmd.options) {

            // The option defined by the command.
            var definedOption = cmd.options[key];

            // If option has named=false, attach non-named parameters as option and remove from `options._` array.
            if (!(key in options) && definedOption.noName && options._.length > 0) {
                options[key] = options._[nonNamedIndex];
                options._.splice(nonNamedIndex, 1);
            }

            // If defined option was not supplied and it has aliases, check if aliases were supplied and attach option.
            if (!definedOption.noName && !(key in options) && definedOption.aliases) {
                definedOption.aliases.forEach(function (alias) {
                    if (alias in options) {
                        options[key] = options[alias];
                        delete options[alias];
                    }
                });
            }

            // Prompt the user for value if:
            // A) The option was not supplied and it is required or
            // B) the option was supplied but without a value.
            if (definedOption.prompt) {
                if ((!(key in options) && definedOption.required) || (key in options && options[key] === true)) {
                    shell.setPrompt(key, cmd.name, options);
                    if (definedOption.password)
                        shell.password();
                    if (typeof(definedOption.prompt) !== 'boolean')
                        shell.log(definedOption.prompt);
                    else
                        shell.log('Enter value for ' + key + '.');
                    // Return immediately without further validation.
                    return false;
                }
            }

            // If option has default value and was not found in supplied options then assign it.
            if (definedOption.default && !(key in options))
                options[key] = definedOption.default;

            // If defined option has a validate expression or function and the option was supplied then
            // validate the supplied option against the expression or function.
            if (definedOption.validate && (key in options)) {

                // If defined validation is a regular expression then validate the supplied value against it.
                if (definedOption.validate instanceof RegExp) {
                    // If value does not pass validation then do not invoke command and write error message.
                    if (!definedOption.validate.test(options[key])) {
                        shell.error('invalid value for "' + key + '"');
                        return false;
                    }
                }
                // If defined validation is a function then pass the value to it.
                else if (typeof(definedOption.validate) == 'function') {
                    try {
                        // If the validation function returns false then do not invoke the command and write
                        // error message.
                        var validationResult = definedOption.validate(options[key], options, shell);
                        if (validationResult !== true) {
                            if (typeof(validationResult) !== 'string')
                                shell.error('invalid value for "' + key + '"');
                            else
                                shell.error(validationResult);
                            return false;
                        }
                    }
                        // If the provided validation function throws an error at any point then handle it
                        // gracefully and simply fail validation.
                    catch (ex) {
                        shell.error(ex.message);
                        return false;
                    }
                }
            }

            // If option is required but is not found in supplied options then error.
            if (definedOption.required && !(key in options)) {
                shell.error('missing parameter "' + key + '"');
                return false;
            }
        }
    }
    // If we made it this far then all options are valid so return true.
    return true;
};<commit_msg>Swapped the order of arguments to validate functions. The convention should be that the shell is always passed before user-supplied options.<commit_after>module.exports = exports = function (options, cmd, shell) {
    // If the command has pre-defined options then parse through them and validate against the supplied options.
    if (cmd.options) {

        var nonNamedIndex = 0;

        // Loop through the command's pre-defined options.
        for (var key in cmd.options) {

            // The option defined by the command.
            var definedOption = cmd.options[key];

            // If option has named=false, attach non-named parameters as option and remove from `options._` array.
            if (!(key in options) && definedOption.noName && options._.length > 0) {
                options[key] = options._[nonNamedIndex];
                options._.splice(nonNamedIndex, 1);
            }

            // If defined option was not supplied and it has aliases, check if aliases were supplied and attach option.
            if (!definedOption.noName && !(key in options) && definedOption.aliases) {
                definedOption.aliases.forEach(function (alias) {
                    if (alias in options) {
                        options[key] = options[alias];
                        delete options[alias];
                    }
                });
            }

            // Prompt the user for value if:
            // A) The option was not supplied and it is required or
            // B) the option was supplied but without a value.
            if (definedOption.prompt) {
                if ((!(key in options) && definedOption.required) || (key in options && options[key] === true)) {
                    shell.setPrompt(key, cmd.name, options);
                    if (definedOption.password)
                        shell.password();
                    if (typeof(definedOption.prompt) !== 'boolean')
                        shell.log(definedOption.prompt);
                    else
                        shell.log('Enter value for ' + key + '.');
                    // Return immediately without further validation.
                    return false;
                }
            }

            // If option has default value and was not found in supplied options then assign it.
            if (definedOption.default && !(key in options))
                options[key] = definedOption.default;

            // If defined option has a validate expression or function and the option was supplied then
            // validate the supplied option against the expression or function.
            if (definedOption.validate && (key in options)) {

                // If defined validation is a regular expression then validate the supplied value against it.
                if (definedOption.validate instanceof RegExp) {
                    // If value does not pass validation then do not invoke command and write error message.
                    if (!definedOption.validate.test(options[key])) {
                        shell.error('invalid value for "' + key + '"');
                        return false;
                    }
                }
                // If defined validation is a function then pass the value to it.
                else if (typeof(definedOption.validate) == 'function') {
                    try {
                        // If the validation function returns false then do not invoke the command and write
                        // error message.
                        var validationResult = definedOption.validate(options[key], shell, options);
                        if (validationResult !== true) {
                            if (typeof(validationResult) !== 'string')
                                shell.error('invalid value for "' + key + '"');
                            else
                                shell.error(validationResult);
                            return false;
                        }
                    }
                        // If the provided validation function throws an error at any point then handle it
                        // gracefully and simply fail validation.
                    catch (ex) {
                        shell.error(ex.message);
                        return false;
                    }
                }
            }

            // If option is required but is not found in supplied options then error.
            if (definedOption.required && !(key in options)) {
                shell.error('missing parameter "' + key + '"');
                return false;
            }
        }
    }
    // If we made it this far then all options are valid so return true.
    return true;
};<|endoftext|>


<commit_before>'use strict';

var jsonpathLib = require('JSONPath')
  , minilog = require('minilog')
  , _s = require('underscore.string');

var jsonpath = jsonpathLib.eval;

function JsonAdapter(log) {
  this.log = log;
}

JsonAdapter.prototype.findNextStep = function(t, link) {
  validateLinkObject(link);
  var doc = t.lastStep.doc;
  this.log.debug('resolving link', link);
  switch (link.type) {
    case 'link-rel':
      return this._handleLinkRel(doc, link);
    case 'header':
      return this._handleHeader(t.lastStep.response, link);
    default:
      throw new Error('Link objects with type ' + link.type + ' are not ' +
        'supported by this adapter.', link);
  }
};

JsonAdapter.prototype._handleLinkRel = function(doc, link) {
  var linkRel = link.value;
  this.log.debug('looking for link-rel in doc', linkRel, doc);
  var url;
  if (this._testJSONPath(linkRel)) {
    return { url: this._resolveJSONPath(doc, linkRel) };
  } else if (doc[linkRel]) {
    return { url : doc[linkRel] };
  } else {
    throw new Error('Could not find property ' + linkRel +
        ' in document:\n', doc);
  }
};

function validateLinkObject(link) {
  if (typeof link === 'undefined' || link === null) {
    throw new Error('Link object is null or undefined.');
  }
  if (typeof link !== 'object') {
    throw new Error('Links must be objects, not ' + typeof link +
        ': ', link);
  }
  if (!link.type) {
    throw new Error('Link objects has no type attribute.', link);
  }
}

JsonAdapter.prototype._testJSONPath = function(link) {
  return _s.startsWith(link, '$.') || _s.startsWith(link, '$[');
};

JsonAdapter.prototype._resolveJSONPath = function(doc, link) {
  var matches = jsonpath(doc, link);
  if (matches.length === 1) {
    var url = matches[0];
    if (!url) {
      throw new Error('JSONPath expression ' + link +
        ' was resolved but the result was null, undefined or an empty' +
        ' string in document:\n' + JSON.stringify(doc));
    }
    if (typeof url !== 'string') {
      throw new Error('JSONPath expression ' + link +
        ' was resolved but the result is not a property of type string. ' +
        'Instead it has type "' + (typeof url) +
        '" in document:\n' + JSON.stringify(doc));
    }
    return url;
  } else if (matches.length > 1) {
    // ambigious match
    throw new Error('JSONPath expression ' + link +
      ' returned more than one match in document:\n' +
      JSON.stringify(doc));
  } else {
    // no match at all
    throw new Error('JSONPath expression ' + link +
      ' returned no match in document:\n' + JSON.stringify(doc));
  }
};

JsonAdapter.prototype._handleHeader = function(httpResponse, link) {
  switch (link.value) {
    case 'location':
      var locationHeader = httpResponse.headers.location;
      if (!locationHeader) {
        throw new Error('Following the location header but there was no ' +
          'location header in the last response.');
      }
      return { url : locationHeader };
    default:
      throw new Error('Link objects with type header and value ' + link.value +
        ' are not supported by this adapter.', link);
  }

};

module.exports = JsonAdapter;
<commit_msg>rm line break<commit_after>'use strict';

var jsonpathLib = require('JSONPath')
  , minilog = require('minilog')
  , _s = require('underscore.string');

var jsonpath = jsonpathLib.eval;

function JsonAdapter(log) {
  this.log = log;
}

JsonAdapter.prototype.findNextStep = function(t, link) {
  validateLinkObject(link);
  var doc = t.lastStep.doc;
  this.log.debug('resolving link', link);
  switch (link.type) {
    case 'link-rel':
      return this._handleLinkRel(doc, link);
    case 'header':
      return this._handleHeader(t.lastStep.response, link);
    default:
      throw new Error('Link objects with type ' + link.type + ' are not ' +
        'supported by this adapter.', link);
  }
};

JsonAdapter.prototype._handleLinkRel = function(doc, link) {
  var linkRel = link.value;
  this.log.debug('looking for link-rel in doc', linkRel, doc);
  var url;
  if (this._testJSONPath(linkRel)) {
    return { url: this._resolveJSONPath(doc, linkRel) };
  } else if (doc[linkRel]) {
    return { url : doc[linkRel] };
  } else {
    throw new Error('Could not find property ' + linkRel +
        ' in document:\n', doc);
  }
};

function validateLinkObject(link) {
  if (typeof link === 'undefined' || link === null) {
    throw new Error('Link object is null or undefined.');
  }
  if (typeof link !== 'object') {
    throw new Error('Links must be objects, not ' + typeof link +
        ': ', link);
  }
  if (!link.type) {
    throw new Error('Link objects has no type attribute.', link);
  }
}

JsonAdapter.prototype._testJSONPath = function(link) {
  return _s.startsWith(link, '$.') || _s.startsWith(link, '$[');
};

JsonAdapter.prototype._resolveJSONPath = function(doc, link) {
  var matches = jsonpath(doc, link);
  if (matches.length === 1) {
    var url = matches[0];
    if (!url) {
      throw new Error('JSONPath expression ' + link +
        ' was resolved but the result was null, undefined or an empty' +
        ' string in document:\n' + JSON.stringify(doc));
    }
    if (typeof url !== 'string') {
      throw new Error('JSONPath expression ' + link +
        ' was resolved but the result is not a property of type string. ' +
        'Instead it has type "' + (typeof url) +
        '" in document:\n' + JSON.stringify(doc));
    }
    return url;
  } else if (matches.length > 1) {
    // ambigious match
    throw new Error('JSONPath expression ' + link +
      ' returned more than one match in document:\n' +
      JSON.stringify(doc));
  } else {
    // no match at all
    throw new Error('JSONPath expression ' + link +
      ' returned no match in document:\n' + JSON.stringify(doc));
  }
};

JsonAdapter.prototype._handleHeader = function(httpResponse, link) {
  switch (link.value) {
    case 'location':
      var locationHeader = httpResponse.headers.location;
      if (!locationHeader) {
        throw new Error('Following the location header but there was no ' +
          'location header in the last response.');
      }
      return { url : locationHeader };
    default:
      throw new Error('Link objects with type header and value ' + link.value +
        ' are not supported by this adapter.', link);
  }
};

module.exports = JsonAdapter;
<|endoftext|>


<commit_before>'use babel';

const originalNodePath = process.env.NODE_PATH;

import fs from 'fs';
import os from 'os';
import path from 'path';
import util from 'util';
import EventEmitter from 'events';
import { exec } from 'child_process';
import { existsSync, stat, watch } from 'fs';
import { Task } from 'atom';
import Promise from 'bluebird';

export function provideBuilder()
{
  const execAsync = Promise.promisify(exec);
  return class KrepelBuildProvider extends EventEmitter
  {
    constructor(cwd)
    {
      super();
      this.cwd = cwd;
      this.fileWatchers = [];
    }

    destructor()
    {
      this.fileWatchers.forEach(fw => fw.close());
    }

    getNiceName()
    {
      return 'krepel-build';
    }

    isEligible()
    {
      this.file = [ 'build.bat' ]
        .map(file => path.join(this.cwd, file))
        .filter(fs.existsSync)
        .slice(0, 1)
        .pop();
      return !!this.file;
    }

    settings()
    {
      const buildRuleToConfig = function(config) {
        return {
          name: config,
          exec: 'build.bat',
          args: [config],
          errorMatch:
            ["(?<file>[:\\/0-9a-zA-Z\\._\\\\\\-]+)\\((?<line>\\d+),(?<col>\\d+)\\): Error:.*",
            "core.exception.AssertError\\@(?<file>[:\\/0-9a-zA-Z\\._\\\\\\-]+)\\((?<line>\\d+)\\):.*"],
          sh: true
        };
      };
      return execAsync("build.bat" + " -rules",{cwd: this.cwd})
      .catch(err => {
        console.log("Error:" + err);
      })
      .then(outputBuffer => {
          return outputBuffer
          .toString("utf-8")
          .split(os.EOL)
          .filter((name)=>{
            const regex = "\\s*\\w+\\s*";
            return name.match(regex) != null;
          })
          .map(buildRuleToConfig);
        });
    }
  }
}
<commit_msg>Adds warnings and more error matching, removing ! Compiling from build targets<commit_after>'use babel';

const originalNodePath = process.env.NODE_PATH;

import fs from 'fs';
import os from 'os';
import path from 'path';
import util from 'util';
import EventEmitter from 'events';
import { exec } from 'child_process';
import { existsSync, stat, watch } from 'fs';
import { Task } from 'atom';
import Promise from 'bluebird';

export function provideBuilder()
{
  const execAsync = Promise.promisify(exec);
  return class KrepelBuildProvider extends EventEmitter
  {
    constructor(cwd)
    {
      super();
      this.cwd = cwd;
      this.fileWatchers = [];
    }

    destructor()
    {
      this.fileWatchers.forEach(fw => fw.close());
    }

    getNiceName()
    {
      return 'krepel-build';
    }

    isEligible()
    {
      this.file = [ 'build.bat' ]
        .map(file => path.join(this.cwd, file))
        .filter(fs.existsSync)
        .slice(0, 1)
        .pop();
      return !!this.file;
    }

    settings()
    {
      const buildRuleToConfig = function(config) {
        return {
          name: config,
          exec: 'build.bat',
          args: [config],
          errorMatch:
            ["(?<file>[:\\/0-9a-zA-Z\\._\\\\\\-]+)\\((?<line>\\d+),(?<col>\\d+)\\): Error:.*",
            "core.exception.AssertError\\@(?<file>[:\\/0-9a-zA-Z\\._\\\\\\-]+)\\((?<line>\\d+)\\):.*",
            "Failed compiling",
            "Exit code: -\\d+"],
          warningMatch:
            ["(?<file>[:\\/0-9a-zA-Z\\._\\\\\\-]+)\\((?<line>\\d+),(?<col>\\d+)\\): Warning:.*"],
          sh: true
        };
      };
      return execAsync("build.bat" + " -rules",{cwd: this.cwd})
      .catch(err => {
        console.log("Error:" + err);
      })
      .then(outputBuffer => {
          return outputBuffer
          .toString("utf-8")
          .split(os.EOL)
          .filter((name)=>{
            const regex = "\\s*\\w+\\s*";
            const regex2 = "[^!]+"
            return name.match(regex) != null && name.match(regex2) != null;
          })
          .map(buildRuleToConfig);
        });
    }
  }
}
<|endoftext|>


<commit_before>
var Parser = require("./parser"),
    path = require("path");

// cli -g file -i file :)
// cli -i file (g = std) :)
// cli -g file (i x) :)
// cli -g file -i -
// cli x

exports.main = function(args)
{
    var options = parseOptions(),
        grammar = options.grammar,
        input = options.input;

    if (!grammar && (!input || input === true))
    {
        console.error("Grammar and input can't both implicitly be stdin.");
        process.exit(1);
    }

    read(grammar || true, function(err, data) {
        if (err)
        {
            console.error("The Grammar file '"+grammar+"' could not be read.");
            process.exit(1);
        }
        var parser = new Parser(data);

        if (input !== undefined)
        {
            if (input !== true && !input.length)
            {
                console.error("No file name has been specified for the input. Please use '-i -' if you wish to use STDIN.")
                process.exit(1);
            }
            read(input, function(err, data) {
                if (err)
                {
                    console.error("The input file '"+input+"' could not be read.");
                    process.exit(1);
                }
                var result = parser.parse(data).toString();
                write(options.output || "-", result);
            });
        }
        else
        {
            var json = JSON.stringify(parser.compiledGrammar).toUnicodeEscapedString();

            if (options.table)
                write(options.output || "-", json);

            else
            {
                var directory = path.dirname(module.filename),
                    templatename = (options.browser) ? path.join(directory, "templates", "browser.js") : path.join(directory, "templates", "node.js");

                read(templatename, function(err, templatedata) {
                    if (options.browser)
                        templatedata = templatedata.replace(/%{NAMESPACE}/g, options.browser);

                    read(path.join(directory, "parser.js"), function(err, parserjsdata) {
                        templatedata = templatedata.replace(/%{PARSER}/g, parserjsdata)
                        templatedata = templatedata.replace(/%{COMPILED_GRAMMAR}/g, json);
                        write(options.output || "-", templatedata);
                    });
                });
            }
        }
    });
}

function parseOptions()
{
    return require("./utilities/nomnom").opts(
    {
        grammar:{
                    string: '-g PATH, --grammar=PATH',
                    help:"A Language grammar file."
                },

        input:  {
                    string:"-i, --input=PATH",
                    help:"An input file to parse. Use '-i -' for stdin."
                },

        output: {
                    string:"-o, --output=PATH",
                    help:"An output file to save the result. If ommited stdout is used."
                },

        table:  {
                    string:"-t, --table",
                    help:"Only output the parser table, not the entire generated parser."
                }

    }).parseArgs();
}

function read(filename, callback)
{
    if (filename === true)
    {
        var stdin = process.stdin,
            lines = "";
        process.stdout.write('Use Ctrl-D to stop input:\n> ');
        stdin.resume();
        stdin.on('data', function(chunk) {
            lines += chunk.toString();
            process.stdout.write('> ');
        }).on('end',function() {
            process.stdout.write('\n');
            callback(false, lines);
        }).on('error', function() {
            console.error("There was an error while taking input data from stdin.");
            process.exit(1);
        });
    }
    else
        require("fs").readFile(filename, "utf8", callback);
}

function write(filename, contents)
{
    if (filename === "-")
        console.log("%s", contents);
    else
        require("fs").writeFileSync(filename, contents);
}

String.prototype.toUnicodeEscapedString = function()
{
    var index = 0,
        count = this.length,
        characters = [];

    for (; index < count; ++index)
    {
        var code = this.charCodeAt(index);

        if (this.charCodeAt(index) <= 255)
        {
            characters.push(this.charAt(index));
            continue;
        }

        var escape = code.toString(16).toUpperCase();

        while (escape.length < 4)
            escape = '0' + escape;

        characters.push("\\u" + escape);
    }

    return characters.join("");
}

Array.prototype.toSource = function()
{
    var index = 0,
        count = this.length,
        sources = [];

    for (; index < count; ++index)
        sources.push(this[index].toSource());

    return "[" + sources.join(", ") + "]";
}

Number.prototype.toSource = function()
{
    return this + "";
}

String.prototype.toSource = function()
{
    return JSON.stringify(this.toUnicodeEscapedString());
}

RegExp.prototype.toSource = function()
{
    return this + "";
}

exports.main(process.argv);
//3 things: grammar, input, output
// table
// file
// cli
// browser
// full blown
// json?
<commit_msg>Make file write async and simplify logic of command line options. Now '-i', '-o', and '-g' without a parameter will default to using stdin or stdout. If '-g' is omitted stdin is used.<commit_after>
var Parser = require("./parser"),
    path = require("path");

// cli -g file -i file :)
// cli -i file (g = std) :)
// cli -g file (i x) :)
// cli -g file -i -
// cli x

exports.main = function(args)
{
    var options = parseOptions(),
        grammar = options.grammar,
        input = options.input,
        output = options.output;

    if (!grammar || !grammar.length)
    {
        console.log('Grammar via stdin:');
    }

    read(grammar, function(err, data) {
        if (err)
        {
            console.error("The Grammar file '"+grammar+"' could not be read.");
            process.exit(1);
        }
        var parser = new Parser(data);

        if (input !== undefined)
        {
            if (!input.length)
            {
                console.log('Input via stdin:');
            }

            read(input, function(err, data) {
                if (err)
                {
                    console.error("The input file '"+input+"' could not be read.");
                    process.exit(1);
                }
                var result = parser.parse(data).toString();
                write(output, result);
            });
        }
        else
        {
            var json = JSON.stringify(parser.compiledGrammar).toUnicodeEscapedString();

            if (options.table)
                write(output, json);

            else
            {
                var directory = path.dirname(module.filename),
                    templatename = (options.browser) ? path.join(directory, "templates", "browser.js") : path.join(directory, "templates", "node.js");

                read(templatename, function(err, templatedata) {
                    if (options.browser)
                        templatedata = templatedata.replace(/%{NAMESPACE}/g, options.browser);

                    read(path.join(directory, "parser.js"), function(err, parserjsdata) {
                        templatedata = templatedata.replace(/%{PARSER}/g, parserjsdata)
                        templatedata = templatedata.replace(/%{COMPILED_GRAMMAR}/g, json);
                        write(output, templatedata);
                    });
                });
            }
        }
    });
}

function parseOptions()
{
    return require("./utilities/nomnom").opts(
    {
        grammar:{
                    string: '-g PATH, --grammar=PATH',
                    help:"A Language grammar file. Omit for input via stdin."
                },

        input:  {
                    string:"-i, --input=PATH",
                    help:"An input file to parse. Omit for input via stdin."
                },

        output: {
                    string:"-o, --output=PATH",
                    help:"An output file to save the result. If omitted stdout is used."
                },

        table:  {
                    string:"-t, --table",
                    help:"Only output the parser table, not the entire generated parser."
                }

    }).parseArgs();
}

function read(filename, callback)
{
    if (!filename || !filename.length)
    {
        var stdin = process.stdin,
            lines = "";
        process.stdout.write('Use Ctrl-D to stop input:\n> ');
        stdin.resume();
        stdin.on('data', function(chunk) {
            lines += chunk.toString();
            process.stdout.write('> ');
        }).on('end',function() {
            process.stdout.write('\n');
            callback(false, lines);
        }).on('error', function() {
            console.error("There was an error while taking input data from stdin.");
            process.exit(1);
        });
    }
    else
        require("fs").readFile(filename, "utf8", callback);
}

function write(filename, contents)
{
    if (!filename || !filename.length)
        console.log("%s", contents);
    else
        require("fs").writeFile(filename, contents, function(err) {
            if (err)
            {
                console.error("There was an error writing to file '"+filename+"'.");
                process.exit(1);
            }
        });
}

String.prototype.toUnicodeEscapedString = function()
{
    var index = 0,
        count = this.length,
        characters = [];

    for (; index < count; ++index)
    {
        var code = this.charCodeAt(index);

        if (this.charCodeAt(index) <= 255)
        {
            characters.push(this.charAt(index));
            continue;
        }

        var escape = code.toString(16).toUpperCase();

        while (escape.length < 4)
            escape = '0' + escape;

        characters.push("\\u" + escape);
    }

    return characters.join("");
}

Array.prototype.toSource = function()
{
    var index = 0,
        count = this.length,
        sources = [];

    for (; index < count; ++index)
        sources.push(this[index].toSource());

    return "[" + sources.join(", ") + "]";
}

Number.prototype.toSource = function()
{
    return this + "";
}

String.prototype.toSource = function()
{
    return JSON.stringify(this.toUnicodeEscapedString());
}

RegExp.prototype.toSource = function()
{
    return this + "";
}

exports.main(process.argv);
//3 things: grammar, input, output
// table
// file
// cli
// browser
// full blown
// json?
<|endoftext|>


<commit_before>"use strict";

var $ = require('jquery'),
    _ = require('lodash'),
    Backbone = require('../../shim/backbone'),
    App = require('../app'),
    settings = require('../core/settings'),
    router = require('../router').router,
    views = require('./views'),
    models = require('./models');

function makeProject(lock) {
    var project = new models.ProjectModel({
        name: 'Untitled Project',
        created_at: Date.now(),
        area_of_interest: App.map.get('areaOfInterest'),
        area_of_interest_name: App.map.get('areaOfInterestName'),
        scenarios: new models.ScenariosCollection()
    });
    lock.resolve();
    return project;
}

function reinstateProject(number, lock) {
    var project = new models.ProjectModel({id: App.projectNumber});

    project
        .fetch()
        .done(function() {
            App.map.set({
                'areaOfInterest': project.get('area_of_interest'),
                'areaOfInterestName': project.get('area_of_interest_name')
            });
            lock.resolve();
        });

    return project;
}

var ModelingController = {
    projectPrepare: function(projectId) {
        if (!projectId && !App.map.get('areaOfInterest')) {
            router.navigate('', { trigger: true });
            return false;
        }
    },

    project: function(projectId, scenarioParam) {
        var project;

        if (projectId) {
            project = new models.ProjectModel({
                id: projectId
            });

            App.currentProject = project;

            project
                .fetch()
                .done(function() {
                    App.map.set({
                        'areaOfInterest': project.get('area_of_interest'),
                        'areaOfInterestName': project.get('area_of_interest_name')
                    });
                    initScenarioEvents(project);
                    initViews(project);
                    if (scenarioParam) {
                        var scenarioId = parseInt(scenarioParam, 10),
                            scenarios = project.get('scenarios');

                        if (!scenarios.setActiveScenarioById(scenarioId)) {
                            scenarios.makeFirstScenarioActive();
                        }
                    } else {
                        project.get('scenarios').makeFirstScenarioActive();
                    }
                    project.fetchResultsIfNeeded();

                    // If this project is an activity then the application's behavior changes.
                    if (project.get('is_activity')) {
                        settings.set('activityMode', true);
                    }

                    // Send URL to parent if in embed mode
                    updateItsiFromEmbedMode();
                });
        } else {
            if (App.currentProject && settings.get('activityMode')) {
                project = App.currentProject;
                // Reset flag is set so clear off old project data.
                if (project.get('needs_reset')) {
                    project.set({
                        'user_id': App.user.get('id'),
                        'area_of_interest': App.map.get('areaOfInterest'),
                        'area_of_interest_name': App.map.get('areaOfInterestName'),
                        'needs_reset': false
                    });

                    // Clear current scenarios and start over.
                    // Must convert to an array first to avoid conflicts with
                    // collection events that are disassociating the model during
                    // the loop.
                    var locks = [];
                    _.each(project.get('scenarios').toArray(), function(model) {
                        var $lock = $.Deferred();
                        locks.push($lock);
                        model.destroy({
                            success: function() {
                                $lock.resolve();
                            }
                        });
                    });

                    // When all models have been deleted...
                    $.when.apply($, locks).then(function() {
                        setupNewProjectScenarios(project);

                        // Don't reinitialize scenario events.
                        if (!project.get('scenarios_events_initialized')) {
                            initScenarioEvents(project);
                            project.set('scenarios_events_initialized', true);
                        }
                        // Make sure to save the new project id onto scenarios.
                        project.addIdsToScenarios();
                        // Save to ensure we capture AOI.
                        project.save();

                        // Now render.
                        initViews(project);
                        project.fetchResultsIfNeeded();
                    });
                } else {
                    initViews(project);
                    project.fetchResultsIfNeeded();
                    updateUrl();
                }
            } else {
                var lock = $.Deferred();

                if (!App.currentProject) {
                    // Only make new project if this is the first time
                    // hitting the modeling views.
                    if (!App.projectNumber) {
                        project = makeProject(lock);
                    } else {
                        project = reinstateProject(App.projectNumber, lock);
                    }

                    App.currentProject = project;
                    if (!App.projectNumber) {
                        setupNewProjectScenarios(project);
                    }
                } else {
                    project = App.currentProject;
                    updateUrl();
                    lock.resolve();
                }

                lock.done(function() {
                    project.on('change:id', updateUrl);
                    initScenarioEvents(project);
                    initViews(project);
                    project.fetchResultsIfNeeded();
                    if (App.projectNumber) {
                        updateUrl();
                    }
                });
            }
        }
    },

    projectCleanUp: function() {
        var scenarios = App.currentProject.get('scenarios');

        App.currentProject.off('change:id', updateUrl);
        scenarios.off('change:activeScenario change:id', updateScenario);
        // App.projectNumber holds the number of the project that was
        // in use when the user left the `/project` page.  The intent
        // is to allow the same project to be returned-to via the UI
        // arrow buttons (see issue #690).
        App.projectNumber = scenarios.at(0).get('project');
        App.getMapView().updateModifications(null);
        App.rootView.subHeaderRegion.empty();
        App.rootView.footerRegion.empty();
    },

    // Since we handle redirects after ITSI sign-up within Backbone,
    // but project cloning is done only on server side, we redirect
    // the project cloning route back to the server.
    projectClone: function() {
        window.location.replace(window.location.href);
    },

    // Load the project's area of interest, and move to Draw view
    projectDraw: function(projectId) {
        var project = new models.ProjectModel({
            id: projectId
        });

        App.currentProject = project;

        project
            .fetch()
            .done(function() {
                App.map.set({
                    'areaOfInterest': project.get('area_of_interest'),
                    'areaOfInterestName': project.get('area_of_interest_name')
                });
                if (project.get('scenarios').isEmpty()) {
                    // No scenarios available. Set the `needs_reset` flag so
                    // that this project is properly initialized by the
                    // modeling controller.
                    project.set('needs_reset', true);
                }

                if (project.get('is_activity')) {
                    settings.set('activityMode', true);
                }
            })
            .fail(function() {
                App.currentProject = null;
            })
            .always(function() {
                router.navigate('/', { trigger: true });
            });
    }
};

function updateItsiFromEmbedMode() {
    if (settings.get('itsi_embed')) {
        App.itsi.setLearnerUrl(Backbone.history.getFragment());
    }
}

function updateUrl() {
    // Use replace: true, so that the back button will work as expected.
    router.navigate(App.currentProject.getReferenceUrl(), { replace: true });
    updateItsiFromEmbedMode();
}

function updateScenario(scenario) {
    App.getMapView().updateModifications(scenario.get('modifications'));
    updateUrl();
}

function initScenarioEvents(project) {
    project.get('scenarios').on('change:activeScenario change:id', updateScenario);
}

function setupNewProjectScenarios(project) {
    project.get('scenarios').add([
        new models.ScenarioModel({
            name: 'Current Conditions',
            is_current_conditions: true,
            active: true
        }),
        new models.ScenarioModel({
            name: 'New Scenario'
        })
        // Silent is set to true because we don't actually want to save the
        // project without some user interaction. This initialization
        // should set the stage but we should wait for something else to
        // happen to save. Ideally we will move this into the project
        // creation when we get rid of the global.
    ], { silent: true });
}

function initViews(project) {
    var modelingResultsWindow = new views.ModelingResultsWindow({
            model: project
    }),
        modelingHeader = new views.ModelingHeaderView({
            model: project
        });

    App.rootView.subHeaderRegion.show(modelingHeader);
    App.rootView.footerRegion.show(modelingResultsWindow);
}

module.exports = {
    ModelingController: ModelingController
};
<commit_msg>Move helper functions to bottom of controller file<commit_after>"use strict";

var $ = require('jquery'),
    _ = require('lodash'),
    Backbone = require('../../shim/backbone'),
    App = require('../app'),
    settings = require('../core/settings'),
    router = require('../router').router,
    views = require('./views'),
    models = require('./models');

var ModelingController = {
    projectPrepare: function(projectId) {
        if (!projectId && !App.map.get('areaOfInterest')) {
            router.navigate('', { trigger: true });
            return false;
        }
    },

    project: function(projectId, scenarioParam) {
        var project;

        if (projectId) {
            project = new models.ProjectModel({
                id: projectId
            });

            App.currentProject = project;

            project
                .fetch()
                .done(function() {
                    App.map.set({
                        'areaOfInterest': project.get('area_of_interest'),
                        'areaOfInterestName': project.get('area_of_interest_name')
                    });
                    initScenarioEvents(project);
                    initViews(project);
                    if (scenarioParam) {
                        var scenarioId = parseInt(scenarioParam, 10),
                            scenarios = project.get('scenarios');

                        if (!scenarios.setActiveScenarioById(scenarioId)) {
                            scenarios.makeFirstScenarioActive();
                        }
                    } else {
                        project.get('scenarios').makeFirstScenarioActive();
                    }
                    project.fetchResultsIfNeeded();

                    // If this project is an activity then the application's behavior changes.
                    if (project.get('is_activity')) {
                        settings.set('activityMode', true);
                    }

                    // Send URL to parent if in embed mode
                    updateItsiFromEmbedMode();
                });
        } else {
            if (App.currentProject && settings.get('activityMode')) {
                project = App.currentProject;
                // Reset flag is set so clear off old project data.
                if (project.get('needs_reset')) {
                    project.set({
                        'user_id': App.user.get('id'),
                        'area_of_interest': App.map.get('areaOfInterest'),
                        'area_of_interest_name': App.map.get('areaOfInterestName'),
                        'needs_reset': false
                    });

                    // Clear current scenarios and start over.
                    // Must convert to an array first to avoid conflicts with
                    // collection events that are disassociating the model during
                    // the loop.
                    var locks = [];
                    _.each(project.get('scenarios').toArray(), function(model) {
                        var $lock = $.Deferred();
                        locks.push($lock);
                        model.destroy({
                            success: function() {
                                $lock.resolve();
                            }
                        });
                    });

                    // When all models have been deleted...
                    $.when.apply($, locks).then(function() {
                        setupNewProjectScenarios(project);

                        // Don't reinitialize scenario events.
                        if (!project.get('scenarios_events_initialized')) {
                            initScenarioEvents(project);
                            project.set('scenarios_events_initialized', true);
                        }
                        // Make sure to save the new project id onto scenarios.
                        project.addIdsToScenarios();
                        // Save to ensure we capture AOI.
                        project.save();

                        // Now render.
                        initViews(project);
                        project.fetchResultsIfNeeded();
                    });
                } else {
                    initViews(project);
                    project.fetchResultsIfNeeded();
                    updateUrl();
                }
            } else {
                var lock = $.Deferred();

                if (!App.currentProject) {
                    // Only make new project if this is the first time
                    // hitting the modeling views.
                    if (!App.projectNumber) {
                        project = makeProject(lock);
                    } else {
                        project = reinstateProject(App.projectNumber, lock);
                    }

                    App.currentProject = project;
                    if (!App.projectNumber) {
                        setupNewProjectScenarios(project);
                    }
                } else {
                    project = App.currentProject;
                    updateUrl();
                    lock.resolve();
                }

                lock.done(function() {
                    project.on('change:id', updateUrl);
                    initScenarioEvents(project);
                    initViews(project);
                    project.fetchResultsIfNeeded();
                    if (App.projectNumber) {
                        updateUrl();
                    }
                });
            }
        }
    },

    projectCleanUp: function() {
        var scenarios = App.currentProject.get('scenarios');

        App.currentProject.off('change:id', updateUrl);
        scenarios.off('change:activeScenario change:id', updateScenario);
        // App.projectNumber holds the number of the project that was
        // in use when the user left the `/project` page.  The intent
        // is to allow the same project to be returned-to via the UI
        // arrow buttons (see issue #690).
        App.projectNumber = scenarios.at(0).get('project');
        App.getMapView().updateModifications(null);
        App.rootView.subHeaderRegion.empty();
        App.rootView.footerRegion.empty();
    },

    // Since we handle redirects after ITSI sign-up within Backbone,
    // but project cloning is done only on server side, we redirect
    // the project cloning route back to the server.
    projectClone: function() {
        window.location.replace(window.location.href);
    },

    // Load the project's area of interest, and move to Draw view
    projectDraw: function(projectId) {
        var project = new models.ProjectModel({
            id: projectId
        });

        App.currentProject = project;

        project
            .fetch()
            .done(function() {
                App.map.set({
                    'areaOfInterest': project.get('area_of_interest'),
                    'areaOfInterestName': project.get('area_of_interest_name')
                });
                if (project.get('scenarios').isEmpty()) {
                    // No scenarios available. Set the `needs_reset` flag so
                    // that this project is properly initialized by the
                    // modeling controller.
                    project.set('needs_reset', true);
                }

                if (project.get('is_activity')) {
                    settings.set('activityMode', true);
                }
            })
            .fail(function() {
                App.currentProject = null;
            })
            .always(function() {
                router.navigate('/', { trigger: true });
            });
    }
};

function updateItsiFromEmbedMode() {
    if (settings.get('itsi_embed')) {
        App.itsi.setLearnerUrl(Backbone.history.getFragment());
    }
}

function updateUrl() {
    // Use replace: true, so that the back button will work as expected.
    router.navigate(App.currentProject.getReferenceUrl(), { replace: true });
    updateItsiFromEmbedMode();
}

function updateScenario(scenario) {
    App.getMapView().updateModifications(scenario.get('modifications'));
    updateUrl();
}

function initScenarioEvents(project) {
    project.get('scenarios').on('change:activeScenario change:id', updateScenario);
}

function setupNewProjectScenarios(project) {
    project.get('scenarios').add([
        new models.ScenarioModel({
            name: 'Current Conditions',
            is_current_conditions: true,
            active: true
        }),
        new models.ScenarioModel({
            name: 'New Scenario'
        })
        // Silent is set to true because we don't actually want to save the
        // project without some user interaction. This initialization
        // should set the stage but we should wait for something else to
        // happen to save. Ideally we will move this into the project
        // creation when we get rid of the global.
    ], { silent: true });
}

function initViews(project) {
    var modelingResultsWindow = new views.ModelingResultsWindow({
            model: project
    }),
        modelingHeader = new views.ModelingHeaderView({
            model: project
        });

    App.rootView.subHeaderRegion.show(modelingHeader);
    App.rootView.footerRegion.show(modelingResultsWindow);
}

function makeProject(lock) {
    var project = new models.ProjectModel({
        name: 'Untitled Project',
        created_at: Date.now(),
        area_of_interest: App.map.get('areaOfInterest'),
        area_of_interest_name: App.map.get('areaOfInterestName'),
        scenarios: new models.ScenariosCollection()
    });
    lock.resolve();
    return project;
}

function reinstateProject(number, lock) {
    var project = new models.ProjectModel({id: App.projectNumber});

    project
        .fetch()
        .done(function() {
            App.map.set({
                'areaOfInterest': project.get('area_of_interest'),
                'areaOfInterestName': project.get('area_of_interest_name')
            });
            lock.resolve();
        });

    return project;
}

module.exports = {
    ModelingController: ModelingController
};
<|endoftext|>