<commit_before>/**
 * Copyright 2014 GetHuman LLC
 * Author: Jeff Whelpley
 * Date: 4/15/14
 *
 * This will translate a pancake page or partial into the angular client
 * equivalent. The final output will contain a contro
 */
var _           = require('lodash');
var jangular    = require('jangular');
var path        = require('path');
var delim       = path.normalize('/');

/**
 * Transform a given page or partial module into its various parts. A page/partial is
 * potentially made up of many components: the template, initial model/partial model,
 * client controller, validations, etc.
 *
 * @param flapjack
 * @param options
 * @returns string
 */
function transform(flapjack, options) {
    var filePath    = options.filePath;
    var names       = this.parseNames(filePath, options.prefix, options.appName);
    var uipart      = this.loadUIPart(names.appShortName, filePath);

    // if there is no client side module for this ui part, return resolved
    if (!uipart.view || uipart.serverOnly || uipart.abstract) { return null; }

    // use the uipart to get the directive scope (for partials), view html and controller
    var scope = uipart.scope ? JSON.stringify(uipart.scope) : null;
    var html = this.getHtml(uipart, options);

    if (options.htmlOnly) {
        return html;
    }

    options.isPage = names.isPage;
    var ctrlTemplateModel = this.getCtrlTemplateModel(uipart, options);

    // combine all the data we have into one templateModel that will go into the template
    var templateModel = _.extend(ctrlTemplateModel, names, { directiveScope: scope, viewHtml: html });

    //TODO: refactor this; complete hack to add initialModel to sideviews
    if (names.controllerName.match(/Sideview/)) {
        templateModel.params = templateModel.params || [];
        templateModel.convertedParams = templateModel.convertedParams || [];
        templateModel.params.push('initialModel');
        templateModel.convertedParams.push('initialModel');
    }

    // return the generated code
    return this.template(templateModel);
}

/**
 * Using the file path, parse out all the names needed for the UI part template
 * @param filePath
 * @param prefix
 * @param defaultAppName
 */
function parseNames(filePath, prefix, defaultAppName) {
    var appName = this.getAppName(filePath, defaultAppName);
    var names = {
        appShortName: appName,
        appName:    this.getAppModuleName(prefix, appName),
        isPartial:  !!filePath.match(/^.*\.partial\.js/)
    };
    names.isPage = !names.isPartial;

    // name of the page used for setting the css style (ex. my.home.page.js would be my.home)
    // the class name on the maincontent in HTML would be something like gh-my-home
    var lastSlash = filePath.lastIndexOf(delim);
    names.uiPartName = filePath.substring(lastSlash + 1)
        .replace('.page.js', '')
        .replace('.partial.js', '');

    // view url is what is used as unique key in template cache for generated HTML
    names.viewUrl = 'templates/' + names.uiPartName;

    // get the directive and controller name (ex. directive ghAnswerList and controller AnswerListCtrl
    var moduleNamePascal = this.pancakes.utils.getPascalCase(filePath)
        .replace('Page', '')
        .replace('Partial', '');
    names.directiveName = prefix + moduleNamePascal;
    names.controllerName = moduleNamePascal + 'Ctrl';

    return names;
}

/**
 * This is used to convert an object from { name -> flapjack } to { name -> rendered angular string }
 * that is ready to be injected.
 *
 * @param obj
 * @param transOpts
 */
function renderObjFns(obj, transOpts) {
    if (!obj || _.isEmpty(obj)) { return null; }

    var renderedObj = {};
    var me = this;

    _.each(obj, function (val, name) {
        renderedObj[name] = _.isFunction(val) ?
            me.transformers.basic.transform(val, transOpts) :
            _.isObject(val) ?
                JSON.stringify(val) :
                val;
    });

    return renderedObj;
}

/**
 * For a given ui part, get all the appropriate values that will be
 * use by the template to generate the controller
 *
 * @param uipart
 * @param options
 */
function getCtrlTemplateModel(uipart, options) {

    var remodelOnScopeChange = uipart.remodelOnScopeChange || (uipart.remodel && uipart.remodel.onScopeChange);
    var remodelOnEvent = uipart.remodelOnEvent || (uipart.remodel && uipart.remodel.onEvent);
    var rerenderOnScopeChange = uipart.rerenderOnScopeChange || (uipart.rerender && uipart.rerender.onScopeChange);
    var rerenderOnEvent = uipart.rerenderOnEvent || (uipart.rerender && uipart.rerender.onEvent);
    var remodelWatchers = remodelOnScopeChange ? JSON.stringify(remodelOnScopeChange) : 'null';
    var remodelEvents = remodelOnEvent ? JSON.stringify(remodelOnEvent) : 'null';
    var rerenderWatchers = rerenderOnScopeChange ? JSON.stringify(rerenderOnScopeChange) : 'null';
    var rerenderEvents = rerenderOnEvent ? JSON.stringify(rerenderOnEvent) : 'null';

    var defaults = uipart.defaults ? JSON.stringify(uipart.defaults) : 'null';
    var presets = uipart.presets ? JSON.stringify(uipart.presets) : null;
    var attachToScope = uipart.attachToScope ? JSON.stringify(uipart.attachToScope) : null;
    var paramInfo = this.getFilteredParamInfo(uipart.controller, options);
    var transOpts = _.extend({ raw: true, isClient: true }, options);
    var useRemodelOnWatch = uipart.model && remodelOnScopeChange && remodelOnScopeChange.length;
    var useRemodelOnEvent = uipart.model && remodelOnEvent && remodelOnEvent.length;
    var useRerenderOnWatch = uipart.model && rerenderOnScopeChange && rerenderOnScopeChange.length;
    var useRerenderOnEvent = uipart.model && rerenderOnEvent && rerenderOnEvent.length;
    var remodelFnExists = uipart.model && _.isFunction(uipart.model);
    var remodelObjExists = !remodelFnExists && uipart.model && _.isObject(uipart.model);
    var clientLoadExists = uipart.onClientLoad && _.isFunction(uipart.onClientLoad);

    // hack to get log working in uipart
    paramInfo.list = paramInfo.list.filter(function (val) {
        return val !== 'log';
    });

    paramInfo.converted = paramInfo.converted.filter(function (val) {
        return val !== 'log';
    });

    return {
        isPage:             options.isPage,
        params:             paramInfo.list,
        convertedParams:    paramInfo.converted,
        ngrefs:             paramInfo.ngrefs,
        defaults:           defaults,
        presets:            presets,
        attachToScope:      attachToScope,
        rerenderExists:     useRerenderOnEvent || useRerenderOnWatch,
        remodelFnExists:    remodelFnExists && (useRemodelOnEvent || useRemodelOnWatch || !options.isPage),
        remodelFn:          remodelFnExists && this.transformers.basic.transform(uipart.model, transOpts),
        remodelObjExists:   remodelObjExists,
        remodelObj:         remodelObjExists && this.renderObjFns(uipart.model, transOpts),
        clientLoadExists:   clientLoadExists,
        clientLoadFn:       clientLoadExists && this.transformers.basic.transform(uipart.onClientLoad, transOpts),
        remodelWatchers:    remodelWatchers,
        remodelEvents:      remodelEvents,
        rerenderWatchers:   rerenderWatchers,
        rerenderEvents:     rerenderEvents,
        useRemodelOnWatch:  useRemodelOnWatch,
        useRemodelOnEvent:  useRemodelOnEvent,
        useRerenderOnWatch: useRerenderOnWatch,
        useRerenderOnEvent: useRerenderOnEvent,
        validations:        this.renderObjFns(uipart.validations, transOpts),
        eventBusListeners:  this.renderObjFns(uipart.eventBusListeners, transOpts),
        uiEventHandlers:    this.renderObjFns(uipart.uiEventHandlers, transOpts),
        body:               this.getModuleBody(uipart.controller)
    };
}

/**
 * Get the HTML for a given ui part
 *
 * @param uipart
 * @param options
 * @returns {string}
 */
function getHtml(uipart, options) {
    options = options || {};
    var me = this;

    // if any subviews, add them as dependencies
    var model = {
        isMobile: options.isMobile,
        appName: options.appName,
        pageCssId: options.appName + 'PageCssId'
    };
    var deps = _.extend({
        subviews: {},
        model: model,
        pageContent: options.pageContent || ' ',
        sideviewContent: options.sideviewContent || ' '
    }, this.getJangularDeps());

    _.each(uipart.subviews, function (subview, subviewName) {
        deps.subviews[subviewName] = me.pancakes.cook(subview, { dependencies: deps });
    });

    // cook the view; the result will be jeff objects
    var view = this.pancakes.cook(uipart.view, { dependencies: deps });

    // we can now generate HTML off the jyt objects (using jyt render so angular NOT interpreted)
    var html = jangular.jytRender(view);
    html = html.replace(/\'/g, '\\\'');     // need to protect all single quotes

    return html;
}

/**
 * Get all Jangular dependencies (i.e. all html functions)
 * @returns {{}|*}
 */
function getJangularDeps() {
    if (this.jangularDeps) { return this.jangularDeps; }

    // add jangular functions to an object that can be injected as dependencies
    this.jangularDeps = {};
    jangular.addShortcutsToScope(this.jangularDeps);
    return this.jangularDeps;
}

// expose functions
module.exports = {
    transform: transform,
    parseNames: parseNames,
    renderObjFns: renderObjFns,
    getCtrlTemplateModel: getCtrlTemplateModel,
    getHtml: getHtml,
    getJangularDeps: getJangularDeps
};

// debug comments not being used right now
//    addDebugComments: function addDebugComments(html, filePath) {
//        var idx = filePath.indexOf('/app/');
//        var debugPath = filePath.substring(idx + 4);
//
//        html = html.replace('>', '><!-- ghstart: ' + debugPath + ' -->');
//        html = html.replace(/<([^<]*)$/, '<!-- ghend: ' + debugPath + ' --><$1');
//
//        return html;
//    },

<commit_msg>Fix for undefined issue<commit_after>/**
 * Copyright 2014 GetHuman LLC
 * Author: Jeff Whelpley
 * Date: 4/15/14
 *
 * This will translate a pancake page or partial into the angular client
 * equivalent. The final output will contain a contro
 */
var _           = require('lodash');
var jangular    = require('jangular');
var path        = require('path');
var delim       = path.normalize('/');

/**
 * Transform a given page or partial module into its various parts. A page/partial is
 * potentially made up of many components: the template, initial model/partial model,
 * client controller, validations, etc.
 *
 * @param flapjack
 * @param options
 * @returns string
 */
function transform(flapjack, options) {
    var filePath    = options.filePath;
    var names       = this.parseNames(filePath, options.prefix, options.appName);
    var uipart      = this.loadUIPart(names.appShortName, filePath);

    // if there is no client side module for this ui part, return resolved
    if (!uipart.view || uipart.serverOnly || uipart.abstract) { return null; }

    // use the uipart to get the directive scope (for partials), view html and controller
    var scope = uipart.scope ? JSON.stringify(uipart.scope) : null;
    var html = this.getHtml(uipart, options);

    if (options.htmlOnly) {
        return html;
    }

    options.isPage = names.isPage;
    var ctrlTemplateModel = this.getCtrlTemplateModel(uipart, options);

    // combine all the data we have into one templateModel that will go into the template
    var templateModel = _.extend(ctrlTemplateModel, names, { directiveScope: scope, viewHtml: html });

    //TODO: refactor this; complete hack to add initialModel to sideviews
    if (names.controllerName.match(/Sideview/)) {
        templateModel.params = templateModel.params || [];
        templateModel.convertedParams = templateModel.convertedParams || [];
        templateModel.params.push('initialModel');
        templateModel.convertedParams.push('initialModel');
    }

    // return the generated code
    return this.template(templateModel);
}

/**
 * Using the file path, parse out all the names needed for the UI part template
 * @param filePath
 * @param prefix
 * @param defaultAppName
 */
function parseNames(filePath, prefix, defaultAppName) {
    var appName = this.getAppName(filePath, defaultAppName);
    var names = {
        appShortName: appName,
        appName:    this.getAppModuleName(prefix, appName),
        isPartial:  !!filePath.match(/^.*\.partial\.js/)
    };
    names.isPage = !names.isPartial;

    // name of the page used for setting the css style (ex. my.home.page.js would be my.home)
    // the class name on the maincontent in HTML would be something like gh-my-home
    var lastSlash = filePath.lastIndexOf(delim);
    names.uiPartName = filePath.substring(lastSlash + 1)
        .replace('.page.js', '')
        .replace('.partial.js', '');

    // view url is what is used as unique key in template cache for generated HTML
    names.viewUrl = 'templates/' + names.uiPartName;

    // get the directive and controller name (ex. directive ghAnswerList and controller AnswerListCtrl
    var moduleNamePascal = this.pancakes.utils.getPascalCase(filePath)
        .replace('Page', '')
        .replace('Partial', '');
    names.directiveName = prefix + moduleNamePascal;
    names.controllerName = moduleNamePascal + 'Ctrl';

    return names;
}

/**
 * This is used to convert an object from { name -> flapjack } to { name -> rendered angular string }
 * that is ready to be injected.
 *
 * @param obj
 * @param transOpts
 */
function renderObjFns(obj, transOpts) {
    if (!obj || _.isEmpty(obj)) { return null; }

    var renderedObj = {};
    var me = this;

    _.each(obj, function (val, name) {
        renderedObj[name] = _.isFunction(val) ?
            me.transformers.basic.transform(val, transOpts) :
            _.isObject(val) ?
                JSON.stringify(val) :
                val;
    });

    return renderedObj;
}

/**
 * For a given ui part, get all the appropriate values that will be
 * use by the template to generate the controller
 *
 * @param uipart
 * @param options
 */
function getCtrlTemplateModel(uipart, options) {

    var remodelOnScopeChange = uipart.remodelOnScopeChange || (uipart.remodel && uipart.remodel.onScopeChange);
    var remodelOnEvent = uipart.remodelOnEvent || (uipart.remodel && uipart.remodel.onEvent);
    var rerenderOnScopeChange = uipart.rerenderOnScopeChange || (uipart.rerender && uipart.rerender.onScopeChange);
    var rerenderOnEvent = uipart.rerenderOnEvent || (uipart.rerender && uipart.rerender.onEvent);
    var remodelWatchers = remodelOnScopeChange ? JSON.stringify(remodelOnScopeChange) : 'null';
    var remodelEvents = remodelOnEvent ? JSON.stringify(remodelOnEvent) : 'null';
    var rerenderWatchers = rerenderOnScopeChange ? JSON.stringify(rerenderOnScopeChange) : 'null';
    var rerenderEvents = rerenderOnEvent ? JSON.stringify(rerenderOnEvent) : 'null';

    var defaults = uipart.defaults ? JSON.stringify(uipart.defaults) : 'null';
    var presets = uipart.presets ? JSON.stringify(uipart.presets) : null;
    var attachToScope = uipart.attachToScope ? JSON.stringify(uipart.attachToScope) : null;
    var paramInfo = this.getFilteredParamInfo(uipart.controller, options);
    var transOpts = _.extend({ raw: true, isClient: true }, options);
    var useRemodelOnWatch = uipart.model && remodelOnScopeChange && remodelOnScopeChange.length;
    var useRemodelOnEvent = uipart.model && remodelOnEvent && remodelOnEvent.length;
    var useRerenderOnWatch = uipart.model && rerenderOnScopeChange && rerenderOnScopeChange.length;
    var useRerenderOnEvent = uipart.model && rerenderOnEvent && rerenderOnEvent.length;
    var remodelFnExists = uipart.model && _.isFunction(uipart.model);
    var remodelObjExists = !remodelFnExists && uipart.model && _.isObject(uipart.model);
    var clientLoadExists = uipart.onClientLoad && _.isFunction(uipart.onClientLoad);

    // hack to get log working in uipart
    if (paramInfo.list && paramInfo.list.length) {
        paramInfo.list = paramInfo.list.filter(function (val) {
            return val !== 'log';
        });

        paramInfo.converted = paramInfo.converted.filter(function (val) {
            return val !== 'log';
        });
    }

    return {
        isPage:             options.isPage,
        params:             paramInfo.list,
        convertedParams:    paramInfo.converted,
        ngrefs:             paramInfo.ngrefs,
        defaults:           defaults,
        presets:            presets,
        attachToScope:      attachToScope,
        rerenderExists:     useRerenderOnEvent || useRerenderOnWatch,
        remodelFnExists:    remodelFnExists && (useRemodelOnEvent || useRemodelOnWatch || !options.isPage),
        remodelFn:          remodelFnExists && this.transformers.basic.transform(uipart.model, transOpts),
        remodelObjExists:   remodelObjExists,
        remodelObj:         remodelObjExists && this.renderObjFns(uipart.model, transOpts),
        clientLoadExists:   clientLoadExists,
        clientLoadFn:       clientLoadExists && this.transformers.basic.transform(uipart.onClientLoad, transOpts),
        remodelWatchers:    remodelWatchers,
        remodelEvents:      remodelEvents,
        rerenderWatchers:   rerenderWatchers,
        rerenderEvents:     rerenderEvents,
        useRemodelOnWatch:  useRemodelOnWatch,
        useRemodelOnEvent:  useRemodelOnEvent,
        useRerenderOnWatch: useRerenderOnWatch,
        useRerenderOnEvent: useRerenderOnEvent,
        validations:        this.renderObjFns(uipart.validations, transOpts),
        eventBusListeners:  this.renderObjFns(uipart.eventBusListeners, transOpts),
        uiEventHandlers:    this.renderObjFns(uipart.uiEventHandlers, transOpts),
        body:               this.getModuleBody(uipart.controller)
    };
}

/**
 * Get the HTML for a given ui part
 *
 * @param uipart
 * @param options
 * @returns {string}
 */
function getHtml(uipart, options) {
    options = options || {};
    var me = this;

    // if any subviews, add them as dependencies
    var model = {
        isMobile: options.isMobile,
        appName: options.appName,
        pageCssId: options.appName + 'PageCssId'
    };
    var deps = _.extend({
        subviews: {},
        model: model,
        pageContent: options.pageContent || ' ',
        sideviewContent: options.sideviewContent || ' '
    }, this.getJangularDeps());

    _.each(uipart.subviews, function (subview, subviewName) {
        deps.subviews[subviewName] = me.pancakes.cook(subview, { dependencies: deps });
    });

    // cook the view; the result will be jeff objects
    var view = this.pancakes.cook(uipart.view, { dependencies: deps });

    // we can now generate HTML off the jyt objects (using jyt render so angular NOT interpreted)
    var html = jangular.jytRender(view);
    html = html.replace(/\'/g, '\\\'');     // need to protect all single quotes

    return html;
}

/**
 * Get all Jangular dependencies (i.e. all html functions)
 * @returns {{}|*}
 */
function getJangularDeps() {
    if (this.jangularDeps) { return this.jangularDeps; }

    // add jangular functions to an object that can be injected as dependencies
    this.jangularDeps = {};
    jangular.addShortcutsToScope(this.jangularDeps);
    return this.jangularDeps;
}

// expose functions
module.exports = {
    transform: transform,
    parseNames: parseNames,
    renderObjFns: renderObjFns,
    getCtrlTemplateModel: getCtrlTemplateModel,
    getHtml: getHtml,
    getJangularDeps: getJangularDeps
};

// debug comments not being used right now
//    addDebugComments: function addDebugComments(html, filePath) {
//        var idx = filePath.indexOf('/app/');
//        var debugPath = filePath.substring(idx + 4);
//
//        html = html.replace('>', '><!-- ghstart: ' + debugPath + ' -->');
//        html = html.replace(/<([^<]*)$/, '<!-- ghend: ' + debugPath + ' --><$1');
//
//        return html;
//    },

<|endoftext|>


<commit_before>/*jslint node: true */
"use strict";

/*
 * This script sends the digital write 13 (for various reason Bean Pin 5) off and on.
 * I SUPER highly dont recommend you actually do it this way, this is just for testing.
 * Please see bean-serial for firmata.j
 * https://www.npmjs.com/package/bean-serial
 * or bean-io for a Johnny for Johnny Five support
 * https://www.npmjs.com/package/bean-io
 * Needs a firmata sketch programmed onto Arduino:
 * https://gist.github.com/jacobrosenthal/5044a5f660d2bda84060
 */

var Bean = require('../');

var intervalId;
var connectedBean;

Bean.discover(function(bean){
  connectedBean = bean;
  process.on('SIGINT', exitHandler.bind(this));

  bean.on("serial", function(data, valid){
    console.log(data.toString());
  });

  bean.on("disconnect", function(){
    process.exit();
  });

  bean.connectAndSetup(function(){

    bean.notifyOne(
      //called when theres data
      function(data){
        if(data && data.length>=2){
          var value = data[1]<<8 || (data[0]);
          console.log("one:", value);
        }
      },
      //called when the notify is successfully or unsuccessfully setup
      function(error){
        if(error) console.log("one setup: ", error);
      });

    setInterval(bean.write.bind(bean, new Buffer([0x91, 0x00, 0x00]), function(){}), 5000);
    setInterval(bean.write.bind(bean, new Buffer([0x91, 0x20, 0x00]), function(){}), 7500);

  });

});

process.stdin.resume();//so the program will not close instantly
var triedToExit = false;

//turns off led before disconnecting
var exitHandler = function exitHandler() {

  var self = this;
  if (connectedBean && !triedToExit) {
    triedToExit = true;
    console.log('Turning off led...');
    clearInterval(intervalId);
    connectedBean.setColor(new Buffer([0x0,0x0,0x0]), function(){});
    //no way to know if succesful but often behind other commands going out, so just wait 2 seconds
    console.log('Disconnecting from Device...');
    setTimeout(connectedBean.disconnect.bind(connectedBean, function(){}), 2000);
  } else {
    process.exit();
  }
};<commit_msg>better firmata test<commit_after>/*jslint node: true */
"use strict";

/*
 * This script sends digital write 13 (for various reasons Bean Pin 5 currently) off and on.
 * NOTE this has no relation to the RGB led on the bean, you would have to hook an led to pin 5.
 * a0 -> a4
 * a1 -> a5
 * d0 -> d6
 * d1 -> d9
 * d2 -> d10
 * d3 -> d11
 * d4 -> d12
 * d5 -> d13
 * I SUPER highly dont recommend you actually don't actually use this script.
 * other than for testing. There are great firmata implementations already written in
 * javascript. See bean-serial for a firmata.js implementation
 * https://www.npmjs.com/package/bean-serial
 * or bean-io for a Johnny for Johnny Five implementation
 * https://www.npmjs.com/package/bean-io
 *
 * Requires the default StandardFirmata found in the examples menu to be programmed onto Arduino:
 */

var Bean = require('../');

var intervalId;
var connectedBean;

Bean.discover(function(bean){
  connectedBean = bean;
  process.on('SIGINT', exitHandler.bind(this));

  bean.on("serial", function(data, valid){
    console.log("javascript received", data.toString('hex'), data.toString('utf8'));
  });

  bean.on("disconnect", function(){
    process.exit();
  });

  bean.connectAndSetup(function(){
      setInterval(toggle, 5000);
  });

});

var on = false;

function toggle(){

  if(on){
    connectedBean.write(new Buffer([0x91, 0x00, 0x00]), function(){
      console.log("toggled off");
    });
  }else{
    connectedBean.write(new Buffer([0x91, 0x20, 0x00]), function(){
      console.log("toggled on");
    });
  }

  on=!on;
}

process.stdin.resume();//so the program will not close instantly
var triedToExit = false;

//turns off led before disconnecting
var exitHandler = function exitHandler() {

  var self = this;
  if (connectedBean && !triedToExit) {
    triedToExit = true;
    console.log('Turning off led...');
    clearInterval(intervalId);
    connectedBean.setColor(new Buffer([0x0,0x0,0x0]), function(){});
    //no way to know if succesful but often behind other commands going out, so just wait 2 seconds
    console.log('Disconnecting from Device...');
    setTimeout(connectedBean.disconnect.bind(connectedBean, function(){}), 2000);
  } else {
    process.exit();
  }
};<|endoftext|>


<commit_before>import Component from '@ember/component';
import { A } from '@ember/array';
import { isNone, isPresent } from '@ember/utils';
import layout from '../templates/components/uni-select';

export default Component.extend({
  layout,
  classNames: ['uni-select-wrapper'],
  classNameBindings: ['useAlias:uni-select-wrapper--use-alias'],

  options: [],
  selected: null,
  placeholder: null,
  useAlias: false,
  aliasValue: null,

  onChange() {},

  didReceiveAttrs() {
    this._super(...arguments);

    if (!this.get('useAlias')) {
      return;
    }

    if (this.get('selected')) {
      this._changeAliasValue(this.get('selected'));

      return;
    }

    if (isNone(this.get('placeholder'))) {
      this._changeAliasValue(this._getFirstAvailableValue());
    }
  },

  actions: {
    changeSelected({ target }) {
      if (this.get('useAlias')) {
        this._changeAliasValue(target.value);
      }

      this.get('onChange')(target.value);
    }
  },

  _changeAliasValue(key) {
    let { alias } = A(this.get('options')).findBy('key', key);
    this.set('aliasValue', alias);
  },

  _getFirstAvailableValue() {
    let option = A(this.get('options')).find(({ disabled }) => isNone(disabled));

    return isPresent(option) ? option.key : null;
  }
});
<commit_msg>Check if select option exists before accessing it (#257)<commit_after>import Component from '@ember/component';
import { A } from '@ember/array';
import { isNone, isPresent } from '@ember/utils';
import layout from '../templates/components/uni-select';

export default Component.extend({
  layout,
  classNames: ['uni-select-wrapper'],
  classNameBindings: ['useAlias:uni-select-wrapper--use-alias'],

  options: [],
  selected: null,
  placeholder: null,
  useAlias: false,
  aliasValue: null,

  onChange() {},

  didReceiveAttrs() {
    this._super(...arguments);

    if (!this.get('useAlias')) {
      return;
    }

    if (this.get('selected')) {
      this._changeAliasValue(this.get('selected'));

      return;
    }

    if (isNone(this.get('placeholder'))) {
      this._changeAliasValue(this._getFirstAvailableValue());
    }
  },

  actions: {
    changeSelected({ target }) {
      if (this.get('useAlias')) {
        this._changeAliasValue(target.value);
      }

      this.get('onChange')(target.value);
    }
  },

  _changeAliasValue(key) {
    let option = A(this.get('options')).findBy('key', key);

    if (isPresent(option)) {
      this.set('aliasValue', option.alias);
    }
  },

  _getFirstAvailableValue() {
    let option = A(this.get('options')).find(({ disabled }) => isNone(disabled));

    return isPresent(option) ? option.key : null;
  }
});
<|endoftext|>


<commit_before>'use strict'

const request = require('request-promise');

const options = {
  url : 'https://itunes.apple.com/search',
  json: true,
  qs  : {
    term     : '',
    country  : 'jp',
    media    : 'music',
    entity   : 'song',
    attribute: 'songTerm',
    limit    : 1,
    lang     : 'ja_jp'
  }
}

const itunesApi = {

  getArtworkUrl: function(songName) {
    this.setTerm(songName);

    return new Promise((resolve, reject) => {
      request(options)
      .then((json) => {
        if (json.results.length > 0) {
          resolve(json.results[0].artworkUrl100);
        } else {
          resolve('');
        }
      })
      .catch((err) => {
        console.error(err);
        reject();
      });
    })
  },

  setTerm: function(term) {
    options.qs.term = encodeURIComponent(term).replace(/%20/g, '+');
  }
}

module.exports = itunesApi;<commit_msg>fix artwork param<commit_after>'use strict'

const request = require('request-promise');

const options = {
  url : 'https://itunes.apple.com/search',
  json: true,
  qs  : {
    term     : '',
    country  : 'jp',
    media    : 'music',
    entity   : 'song',
    attribute: 'songTerm',
    limit    : 1,
    lang     : 'ja_jp'
  }
}

const itunesApi = {

  getArtworkUrl: function(songName) {
    this.setTerm(songName);

    return new Promise((resolve, reject) => {
      request(options)
      .then((json) => {
        if (json.results.length > 0) {
          resolve(json.results[0].artworkUrl100);
        } else {
          resolve('');
        }
      })
      .catch((err) => {
        console.error(err);
        reject();
      });
    })
  },

  setTerm: function(term) {
    options.qs.term = term;
  }
}

module.exports = itunesApi;<|endoftext|>


<commit_before>'use strict'
require('../style.css')
const render = require('../../lib/render')
const s = require('vigour-state/s')
const state = s({ title: 'dynamic text' }, false)

document.body.appendChild(render({
  key: 'app',
  text: 'context',
  components: {
    item: {
      class: 'complex-item',
      first: { $: 'first', class: 'nested', b: { c: { text: { $: 'text' } } } },
      second: { $: 'second', class: 'nested', b: { c: { text: { $: 'text' } } } },
      title: { text: 'context' },
      subtitle: { text: 'static & state order' },
      nested: { b: { c: { text: { $: 'title' } } } },
      symbol: {},
      symbol2: {
        class: 'symbol',
        order: -1
      }
    }
  },
  holder: {
    rowA: { type: 'item' },
    rowB: { type: 'item' }
  },
  removeButton: {
    class: 'basic-item',
    text: {
      $: 'first.text',
      $transform (val) {
        return !val ? 'add first' : 'remove ' + val
      }
    },
    // $: 'first',
    on: {
      click (data) {
        state.set({ first: state.first ? null : { text: 'first' } })
      }
    }
  },
  holder2: {
    class: 'holder',
    rowA: {
      class: 'complex-item',
      symbol: {},
      title: { text: 'no context' },
      first: { $: 'first', class: 'nested', b: { c: { text: { $: 'text' } } } },
      second: { $: 'second', class: 'nested', b: { c: { text: { $: 'text' } } } }
    },
    rowB: {
      class: 'complex-item',
      symbol: {},
      title: { text: 'no context' },
      subtitle: { text: 'path subscription' },
      first: { class: 'basic-item', $: 'first.text', text: 'first' },
      second: { class: 'basic-item', $: 'second.text', text: 'second' }
    },
    rowC: {
      class: 'complex-item',
      symbol: {},
      title: { text: 'no context' },
      subtitle: { text: 'mixed subscription' },
      first: { class: 'basic-item', $: 'first', text: 'first' },
      second: { class: 'basic-item', $: 'second.text', text: 'second' }
    }
    // rowD: {
    //   $: 'rootspawner',
    //   class: 'complex-item',
    //   symbol: {},
    //   title: { text: 'no context' },
    //   subtitle: { text: 'root subscription' },
    //   // now this does nto fire... on remove
    //   // and fires one to may after the remove for b
    //   first: { class: 'basic-item', $: '$root.a.first', text: 'first' },
    //   second: { class: 'basic-item', $: '$root.b.second', text: 'second' }
    // }
  }
}, state, (state, type, stamp, tree, subs, sType) => {
  console.log('%cFIRE', 'color: white;background-color: #333; padding: 2px;', state.path().join('/'), ' - ', type, ' - ', sType || 'normal', '\n\n')
}))

state.title.set('third')
state.set({ second: { text: 'second' } })
state.set({ first: { text: 'first' } })
// state.set({ rootspawner: {} })

console.error('\nREMOVE!')
// context removal is still broken
<commit_msg>update example<commit_after>'use strict'
require('../style.css')
const render = require('../../lib/render')
const s = require('vigour-state/s')
const state = s({ title: 'dynamic text' }, false)

document.body.appendChild(render({
  key: 'app',
  text: 'context',
  components: {
    item: {
      class: 'complex-item',
      first: { $: 'first', class: 'nested', b: { c: { text: { $: 'text' } } } },
      second: { $: 'second', class: 'nested', b: { c: { text: { $: 'text' } } } },
      title: { text: 'context' },
      subtitle: { text: 'static & state order' },
      nested: { b: { c: { text: { $: 'title' } } } },
      symbol: {},
      symbol2: {
        class: 'symbol',
        order: -1
      }
    }
  },
  holder: {
    rowA: { type: 'item' },
    rowB: { type: 'item' }
  },
  removeButton: {
    class: 'basic-item',
    // text: {
    //   $: 'first.text',
    //   $transform (val) {
    //     return !val ? 'add first' : 'remove ' + val
    //   }
    // },
    text: 'toggle',
    on: {
      click (data) {
        state.set({ first: state.first ? null : { text: 'first' } })
      }
    }
  },
  holder2: {
    class: 'holder',
    rowA: {
      class: 'complex-item',
      symbol: {},
      title: { text: 'no context' },
      first: { $: 'first', class: 'nested', b: { c: { text: { $: 'text' } } } },
      second: { $: 'second', class: 'nested', b: { c: { text: { $: 'text' } } } }
    },
    rowB: {
      class: 'complex-item',
      symbol: {},
      title: { text: 'no context' },
      subtitle: { text: 'path subscription' },
      first: { class: 'basic-item', $: 'first.text', text: 'first' },
      second: { class: 'basic-item', $: 'second.text', text: 'second' }
    },
    rowC: {
      class: 'complex-item',
      symbol: {},
      title: { text: 'no context' },
      subtitle: { text: 'mixed subscription' },
      first: { class: 'basic-item', $: 'first', text: 'first' },
      second: { class: 'basic-item', $: 'second.text', text: 'second' }
    }
    // rowD: {
    //   $: 'rootspawner',
    //   class: 'complex-item',
    //   symbol: {},
    //   title: { text: 'no context' },
    //   subtitle: { text: 'root subscription' },
    //   // now this does nto fire... on remove
    //   // and fires one to may after the remove for b
    //   first: { class: 'basic-item', $: '$root.a.first', text: 'first' },
    //   second: { class: 'basic-item', $: '$root.b.second', text: 'second' }
    // }
  }
}, state, (state, type, stamp, tree, subs, sType) => {
  console.log('%cFIRE', 'color: white;background-color: #333; padding: 2px;', state.path().join('/'), ' - ', type, ' - ', sType || 'normal', '\n\n')
}))

state.title.set('third')
state.set({ second: { text: 'second' } })
state.set({ first: { text: 'first' } })
// state.set({ rootspawner: {} })

console.error('\nREMOVE!')
// context removal is still broken
<|endoftext|>


<commit_before>import _glob from 'globby'
import readdirp from 'readdirp'
import _path from 'path'
import _replace from 'replace'
import fse from 'fs-extra'

// helpers
export const replace = _replace
export const path = _path
export const p = _path.join

// files
export const fs = fse
export const rm = promisify(fs.remove)
export const mkdir = promisify(fs.mkdirs)
export const move = promisify(fs.move)
export const writeFile = promisify(fs.writeFile)
const _readdir = promisify(readdirp)
export const readdir = (dir, opts = {}) => _readdir(Object.assign({ root: dir }, opts)).then(res => res.files)
const readFilePromise = promisify(fs.readFile)
export const readFile = file => readFilePromise(file, 'utf-8')
export const readJSON = file => readFile(file).then(res => JSON.parse(res))
export const writeJSON = (path, str) => writeFile(path, JSON.stringify(str))
export const touch = promisify(fs.ensureFile)
export const copy = promisify(fs.copy)
export const glob = _glob
export const exists = where => new Promise((res, rej) => fs.stat(where, err => res(!err)))
// TODO use promises
export const recreateDir = (dir) =>
  new Promise((res, rej) => {
    fs.remove(dir, err => {
      if (err) return rej(err)
      fs.mkdirs(dir, err => {
        if (err) return rej(err)
        res(dir)
      });
    })
  })

export async function globCopy(pattern, dest, opts = {}) {
  const srcs = await glob(pattern, { dot: false, nodir: true, ...opts })
  await Promise.all(srcs.map(f => _copy(p(opts.cwd || '', f), p(dest, f))))
}
<commit_msg>:fire: Cleanup the motion-fs module Only keep what we need, add things as needed<commit_after>'use strict'

/* @flow */

import FS from 'fs'
import Path from 'path'
import promisify from 'sb-promisify'

export const readFile = promisify(FS.readFile)
export const writeFile = promisify(FS.writeFile)
export async function readJSON(filePath: string, encoding: string = 'utf8'): Promise {
  const contents = await readFile(filePath)
  return JSON.parse(contents.toString(encoding))
}
export function exists(filePath: string): Promise<boolean> {
  return new Promise(function(resolve) {
    FS.access(filePath, FS.R_OK, function(error) {
      resolve(error === null)
    })
  })
}
<|endoftext|>


<commit_before>/**
 * Created by truthlighting on 9/20/2016.
 */
module.exports =
{
    initSpawnQue: function()
    {
        if(Memory.spawnQue == undefined)
            Memory.spawnQue = [ ];
    },

    addToQue: function(creep, unshift)
    {
        this.initSpawnQue();

        if(unshift != undefined && unshift === true)
            Memory.spawnQue.unshift(creep);
        else
            Memory.spawnQue.push(creep);
    },

    spawnNextInQue: function()
    {

        this.initSpawnQue();

        if(!Memory.spawnQue.length)
            return;

        var spawns = Game.rooms['W2N48'].find(FIND_MY_SPAWNS, {
            filter: function(spawn)
            {
                return spawn.spawning === undefined || spawn.spawning === null;
            }
        });
        //console.log(spawns);

        if(!spawns.length)
            return;

        var role = Memory.spawnQue[0];

        if(typeof role == "string")
        {
            role = { type: role, memory: { } };
        }

        var me = this;
        //console.log(spawns);
        var toSpawnAt = spawns.filter(function(spawn)
        {
            //console.log("spawn: " + spawn + " role.type: " + role.type);
            //console.log(me.canSpawn(spawn, role.type));
            return me.canSpawn(spawn, role.type);
        });
        //console.log(toSpawnAt.length);
        if(!toSpawnAt.length)
            return;
        //console.log("getting here1");
        toSpawnAt = toSpawnAt[0];
        this.spawn(role.type, role.memory, toSpawnAt);

        Memory.spawnQue.shift();
    },

    spawn: function(role, memory, spawnPoint)
    {
        if(!spawnPoint)
            spawnPoint = Game.spawns['Harmony'];

        var manager = require('roleManager');

        if(!manager.roleExists(role))
        {
            return;
        }

        if(!this.canSpawn(spawnPoint, role))
        {
            return;
        }

        if(memory == undefined)
            memory = { };

        memory['role'] = role;

        var nameCount = 0;
        var name = null;
        while(name == null)
        {
            nameCount++;
            var tryName = role + nameCount;
            if(Game.creeps[tryName] == undefined)
                name = tryName;
        }

        console.log('Spawning ' + role);
        console.log(spawnPoint.createCreep(manager.getRoleBodyParts(role), name, memory));
    },

    canSpawn: function(spawnPoint, role)
    {
        if(typeof spawnPoint == "string" && role == undefined)
        {
            role = spawnPoint;
            spawnPoint = Game.spawns['Harmony'];
        }
        //console.log(role);
        return spawnPoint.energy >= this.spawnCost(role)
            && (spawnPoint.spawning == null
            || spawnPoint.spawning == undefined);
    },

    spawnCost: function(role)
    {
        var manager = require('roleManager');
        var parts = manager.getRoleBodyParts(role);

        var total = 0;
        for(var index in parts)
        {
            var part = parts[index];
            switch(part)
            {
                case MOVE:
                    total += 50
                    break;

                case WORK:
                    total += 100
                    break;

                case CARRY:
                    total += 50
                    break;

                case ATTACK:
                    total += 80
                    break;

                case RANGED_ATTACK:
                    total += 150
                    break;

                case HEAL:
                    total += 250
                    break;

                case TOUGH:
                    total += 10
                    break;

                case CLAIM:
                    total += 600
            }
        }
        //console.log("total cost: " + total);
        return total;
    },

    killAll: function(role)
    {
        for(var i in Game.creeps) {
            if(role == undefined || Game.creeps[i].memory.role == role)
                Game.creeps[i].suicide();
        }
    }
}<commit_msg>Fixing miner<commit_after>/**
 * Created by truthlighting on 9/20/2016.
 */
module.exports =
{
    initSpawnQue: function()
    {
        if(Memory.spawnQue == undefined)
            Memory.spawnQue = [ ];
    },

    addToQue: function(creep, unshift)
    {
        this.initSpawnQue();

        if(unshift != undefined && unshift === true)
            Memory.spawnQue.unshift(creep);
        else
            Memory.spawnQue.push(creep);
    },

    spawnNextInQue: function()
    {

        this.initSpawnQue();

        if(!Memory.spawnQue.length)
            return;

        var spawns = Game.rooms['W2N48'].find(FIND_MY_SPAWNS, {
            filter: function(spawn)
            {
                return spawn.spawning === undefined || spawn.spawning === null;
            }
        });
        //console.log(spawns);

        if(!spawns.length)
            return;

        var role = Memory.spawnQue[0];

        if(typeof role == "string")
        {
            role = { type: role, memory: { } };
        }

        var me = this;
        //console.log(spawns);
        var toSpawnAt = spawns.filter(function(spawn)
        {
            //console.log("spawn: " + spawn + " role.type: " + role.type);
            //console.log(me.canSpawn(spawn, role.type));
            return me.canSpawn(spawn, role.type);
        });
        //console.log(toSpawnAt.length);
        if(!toSpawnAt.length)
            return;
        //console.log("getting here1");
        toSpawnAt = toSpawnAt[0];
        this.spawn(role.type, role.memory, toSpawnAt);

        Memory.spawnQue.shift();
    },

    spawn: function(role, memory, spawnPoint)
    {
        if(!spawnPoint)
            spawnPoint = Game.spawns['Harmony'];

        var manager = require('roleManager');

        if(!manager.roleExists(role))
        {
            return;
        }

        if(!this.canSpawn(spawnPoint, role))
        {
            return;
        }

        if(memory == undefined)
            memory = { };

        memory['role'] = role;

        var nameCount = 0;
        var name = null;
        while(name == null)
        {
            nameCount++;
            var tryName = role + nameCount;
            if(Game.creeps[tryName] == undefined)
                name = tryName;
        }

        console.log('Spawning ' + role);
        console.log(spawnPoint.createCreep(manager.getRoleBodyParts(role), name, memory));
    },

    canSpawn: function(spawnPoint, role)
    {
        if(typeof spawnPoint == "string" && role == undefined)
        {
            role = spawnPoint;
            spawnPoint = Game.spawns['Harmony'];
        }
        //console.log(role);
        return spawnPoint.energy >= this.spawnCost(role)
            && (spawnPoint.spawning == null
            || spawnPoint.spawning == undefined);
    },

    spawnCost: function(role)
    {
        var manager = require('roleManager');
        var parts = manager.getRoleBodyParts(role);

        var total = 0;
        for(var index in parts)
        {
            var part = parts[index];
            switch(part)
            {
                case MOVE:
                    total += 50
                    break;

                case WORK:
                    total += 100
                    break;

                case CARRY:
                    total += 50
                    break;

                case ATTACK:
                    total += 80
                    break;

                case RANGED_ATTACK:
                    total += 150
                    break;

                case HEAL:
                    total += 250
                    break;

                case TOUGH:
                    total += 10
                    break;

                case CLAIM:
                    total += 600
            }
        }
        console.log("total cost for " + role + ": " + total);
        return total;
    },

    killAll: function(role)
    {
        for(var i in Game.creeps) {
            if(role == undefined || Game.creeps[i].memory.role == role)
                Game.creeps[i].suicide();
        }
    }
}<|endoftext|>


<commit_before>let Verify = require('./Verify');
let CopyFilesTask = require('./tasks/CopyFilesTask');
let ConcatFilesTask = require('./tasks/ConcatenateFilesTask');
let VersionFilesTask = require('./tasks/VersionFilesTask');
let webpack = require('webpack');
let glob = require('glob');
let _ = require('lodash');

class Api {
    /**
     * Register the Webpack entry/output paths.
     *
     * @param {string|Array} entry
     * @param {string} output
     */
    js(entry, output) {
        Verify.js(entry, output);

        entry = [].concat(entry).map(file => new File(file));
        output = new File(output);

        Config.js.push({ entry, output });

        return this;
    }

    /**
     * Register support for the React framework.
     *
     * @param {string|Array} entry
     * @param {string} output
     */
    react(entry, output) {
        Config.react = true;

        Verify.dependency('babel-preset-react', ['babel-preset-react']);

        return this.js(entry, output);
    };

    /**
     * Register support for the TypeScript.
     */
    ts(entry, output) {
        Config.typeScript = true;

        Verify.dependency('ts-loader', ['ts-loader', 'typescript']);

        return this.js(entry, output);
    };

    /**
     * Register support for the TypeScript.
     */
    typeScript(entry, output) {
        return this.ts(entry, output);
    }

    /**
     * Register Sass compilation.
     *
     * @param {string} src
     * @param {string} output
     * @param {object} pluginOptions
     */
    sass(src, output, pluginOptions = {}) {
        pluginOptions = Object.assign({
            precision: 8,
            outputStyle: 'expanded'
        }, pluginOptions, { sourceMap: true });

        return this.preprocess('sass', src, output, pluginOptions);
    }

    /**
     * Register standalone-Sass compilation that will not run through Webpack.
     *
     * @param {string} src
     * @param {string} output
     * @param {object} pluginOptions
     */
    standaloneSass(src, output, pluginOptions = {}) {
        Verify.exists(src);

        return this.preprocess('fastSass', src, output, pluginOptions);
    };

    /**
     * Alias for standaloneSass.
     *
     * @param {string} src
     * @param {string} output
     * @param {object} pluginOptions
     */
    fastSass(...args) {
        return this.standaloneSass(...args);
    }

    /**
     * Register Less compilation.
     *
     * @param {string} src
     * @param {string} output
     * @param {object} pluginOptions
     */
    less(src, output, pluginOptions) {
        Verify.dependency('less-loader', ['less-loader', 'less']);

        return this.preprocess('less', src, output, pluginOptions);
    }

    /**
     * Register Stylus compilation.
     *
     * @param {string} src
     * @param {string} output
     * @param {object} pluginOptions
     */
    stylus(src, output, pluginOptions = {}) {
        Verify.dependency('stylus-loader', ['stylus-loader', 'stylus']);

        return this.preprocess('stylus', src, output, pluginOptions);
    };

    /**
     * Register postcss compilation.
     *
     * @param {string} src
     * @param {string} output
     * @param {array}  postCssPlugins
     */
    postCss(src, output, postCssPlugins = []) {
        Verify.preprocessor('postCss', src, output);

        src = new File(src);

        output = this._normalizeOutput(new File(output), src.nameWithoutExtension() + '.css');

        Config.preprocessors['postCss'] = (Config.preprocessors['postCss'] || []).concat({
            src, output, postCssPlugins
        });

        return this;
    };

    /**
     * Register a generic CSS preprocessor.
     *
     * @param {string} type
     * @param {string} src
     * @param {string} output
     * @param {object} pluginOptions
     */
    preprocess(type, src, output, pluginOptions = {}) {
        Verify.preprocessor(type, src, output);

        src = new File(src);

        output = this._normalizeOutput(new File(output), src.nameWithoutExtension() + '.css');

        Config.preprocessors[type] = (Config.preprocessors[type] || []).concat({
            src, output, pluginOptions
        });

        if (type === 'fastSass') {
            Mix.addAsset(output);
        }

        return this;
    }

    /**
     * Combine a collection of files.
     *
     * @param {string|Array} src
     * @param {string}       output
     * @param {Boolean}      babel
     */
    combine(src, output, babel = false) {
        output = new File(output || '');

        Verify.combine(src, output);

        if (typeof src === 'string' && File.find(src).isDirectory()) {
            src = _.pull(
                glob.sync(path.join(src, '**/*'), { nodir: true }),
                output.relativePath()
            );
        }

        let task = new ConcatFilesTask({ src, output, babel });

        Mix.addTask(task);

        return this;
    };

    /**
     * Alias for this.Mix.combine().
     *
     * @param {string|Array} src
     * @param {string}       output
     */
    scripts(src, output) {
        return this.combine(src, output);
    };

    /**
     * Identical to this.Mix.combine(), but includes Babel compilation.
     *
     * @param {string|Array} src
     * @param {string}       output
     */
    babel(src, output) {
        return this.combine(src, output, true);

        return this;
    };

    /**
     * Alias for this.Mix.combine().
     *
     * @param {string|Array} src
     * @param {string}       output
     */
    styles(src, output) {
        return this.combine(src, output);
    };

    /**
     * Minify the provided file.
     *
     * @param {string|Array} src
     */
    minify(src) {
        if (Array.isArray(src)) {
            src.forEach(file => this.minify(file));

            return this;
        }

        let output = src.replace(/\.([a-z]{2,})$/i, '.min.$1');

        return this.combine(src, output);
    };

    /**
     * Copy one or more files to a new location.
     *
     * @param {string} from
     * @param {string} to
     */
    copy(from, to) {
        let task = new CopyFilesTask({
            from, to: new File(to)
        });

        Mix.addTask(task);

        return this;
    };

    /**
     * Copy a directory to a new location. This is identical
     * to mix.copy().
     *
     * @param {string} from
     * @param {string} to
     */
    copyDirectory(from, to) {
        return this.copy(from, to);
    };

    /**
     * Enable Browsersync support for the project.
     *
     * @param {object} config
     */
    browserSync(config = {}) {
        Verify.dependency(
            'browser-sync-webpack-plugin',
            ['browser-sync-webpack-plugin', 'browser-sync'],
            true
        );

        if (typeof config === 'string') {
            config = { proxy: config };
        }

        Config.browserSync = config;

        return this;
    };

    /**
     * Enable automatic file versioning.
     *
     * @param {Array} files
     */
    version(files = []) {
        Config.versioning = true;

        files = flatten([].concat(files).map(filePath => {
            if (File.find(filePath).isDirectory()) {
                filePath += (path.sep + '**/*');
            }

            if (! filePath.includes('*')) return filePath;

            return glob.sync(
                new File(filePath).forceFromPublic().relativePath(),
                { nodir: true }
            );
        }));

        Mix.addTask(
            new VersionFilesTask({ files })
        );

        return this;
    }

    /**
     * Register vendor libs that should be extracted.
     * This helps drastically with long-term caching.
     *
     * @param {Array}  libs
     * @param {string} output
     */
    extract(libs, output) {
        Config.extractions.push({ libs, output });

        return this;
    };

    /**
     * Enable sourcemap support.
     *
     * @param {Boolean} productionToo
     * @param {string} type
     */
    sourceMaps(productionToo = true, type = 'inline-source-map') {
        if (Mix.inProduction()) {
            type = productionToo ? 'cheap-source-map' : false;
        }

        Config.sourcemaps = type;

        return this;
    };

    /**
     * Override the default path to your project's public directory.
     *
     * @param {string} path
     */
    setPublicPath(path) {
        Config.publicPath = path;

        return this;
    }

    /**
     * Set a prefix for all generated asset paths.
     *
     * @param {string} path
     */
    setResourceRoot(path) {
        Config.resourceRoot = path;

        return this;
    };

    /**
     * Disable all OS notifications.
     */
    disableNotifications() {
        Config.notifications = false;

        return this;
    };

    /**
     * Disable success notifications.
     */
    disableSuccessNotifications() {
        Config.notifications = {
            onSuccess: false,
            onFailure: true
        };

        return this;
    };

    /**
     * Register libraries to automatically "autoload" when
     * the appropriate variable is references in your JS.
     *
     * @param {Object} libs
     */
    autoload(libs) {
        let aliases = {};

        Object.keys(libs).forEach(library => {
            [].concat(libs[library]).forEach(alias => {
                aliases[alias] = library;
            });
        });

        Config.autoload = aliases;

        return this;
    };

    /**
     * Merge custom config with the provided webpack.config file.
     *
     * @param {object} config
     */
    webpackConfig(config) {
        Config.webpackConfig = (typeof config == 'function') ? config(webpack) : config;

        return this;
    }

    /* Set Mix-specific options.
     *
     * @param {object} options
     */
    options(options) {
        if (options.purifyCss) {
            options.purifyCss = require('./PurifyPaths').build(options.purifyCss);

            Verify.dependency(
                'purifycss-webpack',
                ['purifycss-webpack', 'purify-css'],
                true // abortOnComplete
            );
        }

        Config.merge(options);

        return this;
    };

    /**
     * Register a Webpack build event handler.
     *
     * @param {Function} callback
     */
    then(callback) {
        Mix.listen('build', callback);

        return this;
    }

    /**
     * Helper for determining a production environment.
     */
    inProduction() {
        return Mix.inProduction();
    }

    /**
     * Generate a full output path, using a fallback
     * file name, if a directory is provided.
     *
     * @param {Object} output
     * @param {Object} fallbackName
     */
    _normalizeOutput(output, fallbackName) {
        if (output.isDirectory()) {
            output = new File(path.join(output.filePath, fallbackName));
        }

        return output;
    }
}

module.exports = Api;
<commit_msg>We need this space.<commit_after>let Verify = require('./Verify');
let CopyFilesTask = require('./tasks/CopyFilesTask');
let ConcatFilesTask = require('./tasks/ConcatenateFilesTask');
let VersionFilesTask = require('./tasks/VersionFilesTask');
let webpack = require('webpack');
let glob = require('glob');
let _ = require('lodash');

class Api {
    /**
     * Register the Webpack entry/output paths.
     *
     * @param {string|Array} entry
     * @param {string} output
     */
    js(entry, output) {
        Verify.js(entry, output);

        entry = [].concat(entry).map(file => new File(file));
        output = new File(output);

        Config.js.push({ entry, output });

        return this;
    }

    /**
     * Register support for the React framework.
     *
     * @param {string|Array} entry
     * @param {string} output
     */
    react(entry, output) {
        Config.react = true;

        Verify.dependency('babel-preset-react', ['babel-preset-react']);

        return this.js(entry, output);
    };

    /**
     * Register support for the TypeScript.
     */
    ts(entry, output) {
        Config.typeScript = true;

        Verify.dependency('ts-loader', ['ts-loader', 'typescript']);

        return this.js(entry, output);
    };

    /**
     * Register support for the TypeScript.
     */
    typeScript(entry, output) {
        return this.ts(entry, output);
    }

    /**
     * Register Sass compilation.
     *
     * @param {string} src
     * @param {string} output
     * @param {object} pluginOptions
     */
    sass(src, output, pluginOptions = {}) {
        pluginOptions = Object.assign({
            precision: 8,
            outputStyle: 'expanded'
        }, pluginOptions, { sourceMap: true });

        return this.preprocess('sass', src, output, pluginOptions);
    }

    /**
     * Register standalone-Sass compilation that will not run through Webpack.
     *
     * @param {string} src
     * @param {string} output
     * @param {object} pluginOptions
     */
    standaloneSass(src, output, pluginOptions = {}) {
        Verify.exists(src);

        return this.preprocess('fastSass', src, output, pluginOptions);
    };

    /**
     * Alias for standaloneSass.
     *
     * @param {string} src
     * @param {string} output
     * @param {object} pluginOptions
     */
    fastSass(...args) {
        return this.standaloneSass(...args);
    }

    /**
     * Register Less compilation.
     *
     * @param {string} src
     * @param {string} output
     * @param {object} pluginOptions
     */
    less(src, output, pluginOptions) {
        Verify.dependency('less-loader', ['less-loader', 'less']);

        return this.preprocess('less', src, output, pluginOptions);
    }

    /**
     * Register Stylus compilation.
     *
     * @param {string} src
     * @param {string} output
     * @param {object} pluginOptions
     */
    stylus(src, output, pluginOptions = {}) {
        Verify.dependency('stylus-loader', ['stylus-loader', 'stylus']);

        return this.preprocess('stylus', src, output, pluginOptions);
    };

    /**
     * Register postcss compilation.
     *
     * @param {string} src
     * @param {string} output
     * @param {array}  postCssPlugins
     */
    postCss(src, output, postCssPlugins = []) {
        Verify.preprocessor('postCss', src, output);

        src = new File(src);

        output = this._normalizeOutput(new File(output), src.nameWithoutExtension() + '.css');

        Config.preprocessors['postCss'] = (Config.preprocessors['postCss'] || []).concat({
            src, output, postCssPlugins
        });

        return this;
    };

    /**
     * Register a generic CSS preprocessor.
     *
     * @param {string} type
     * @param {string} src
     * @param {string} output
     * @param {object} pluginOptions
     */
    preprocess(type, src, output, pluginOptions = {}) {
        Verify.preprocessor(type, src, output);

        src = new File(src);

        output = this._normalizeOutput(new File(output), src.nameWithoutExtension() + '.css');

        Config.preprocessors[type] = (Config.preprocessors[type] || []).concat({
            src, output, pluginOptions
        });

        if (type === 'fastSass') {
            Mix.addAsset(output);
        }

        return this;
    }

    /**
     * Combine a collection of files.
     *
     * @param {string|Array} src
     * @param {string}       output
     * @param {Boolean}      babel
     */
    combine(src, output, babel = false) {
        output = new File(output || '');

        Verify.combine(src, output);

        if (typeof src === 'string' && File.find(src).isDirectory()) {
            src = _.pull(
                glob.sync(path.join(src, '**/*'), { nodir: true }),
                output.relativePath()
            );
        }

        let task = new ConcatFilesTask({ src, output, babel });

        Mix.addTask(task);

        return this;
    };

    /**
     * Alias for this.Mix.combine().
     *
     * @param {string|Array} src
     * @param {string}       output
     */
    scripts(src, output) {
        return this.combine(src, output);
    };

    /**
     * Identical to this.Mix.combine(), but includes Babel compilation.
     *
     * @param {string|Array} src
     * @param {string}       output
     */
    babel(src, output) {
        return this.combine(src, output, true);

        return this;
    };

    /**
     * Alias for this.Mix.combine().
     *
     * @param {string|Array} src
     * @param {string}       output
     */
    styles(src, output) {
        return this.combine(src, output);
    };

    /**
     * Minify the provided file.
     *
     * @param {string|Array} src
     */
    minify(src) {
        if (Array.isArray(src)) {
            src.forEach(file => this.minify(file));

            return this;
        }

        let output = src.replace(/\.([a-z]{2,})$/i, '.min.$1');

        return this.combine(src, output);
    };

    /**
     * Copy one or more files to a new location.
     *
     * @param {string} from
     * @param {string} to
     */
    copy(from, to) {
        let task = new CopyFilesTask({
            from, to: new File(to)
        });

        Mix.addTask(task);

        return this;
    };

    /**
     * Copy a directory to a new location. This is identical
     * to mix.copy().
     *
     * @param {string} from
     * @param {string} to
     */
    copyDirectory(from, to) {
        return this.copy(from, to);
    };

    /**
     * Enable Browsersync support for the project.
     *
     * @param {object} config
     */
    browserSync(config = {}) {
        Verify.dependency(
            'browser-sync-webpack-plugin',
            ['browser-sync-webpack-plugin', 'browser-sync'],
            true
        );

        if (typeof config === 'string') {
            config = { proxy: config };
        }

        Config.browserSync = config;

        return this;
    };

    /**
     * Enable automatic file versioning.
     *
     * @param {Array} files
     */
    version(files = []) {
        Config.versioning = true;

        files = flatten([].concat(files).map(filePath => {
            if (File.find(filePath).isDirectory()) {
                filePath += (path.sep + '**/*');
            }

            if (! filePath.includes('*')) return filePath;

            return glob.sync(
                new File(filePath).forceFromPublic().relativePath(),
                { nodir: true }
            );
        }));

        Mix.addTask(
            new VersionFilesTask({ files })
        );

        return this;
    }

    /**
     * Register vendor libs that should be extracted.
     * This helps drastically with long-term caching.
     *
     * @param {Array}  libs
     * @param {string} output
     */
    extract(libs, output) {
        Config.extractions.push({ libs, output });

        return this;
    };

    /**
     * Enable sourcemap support.
     *
     * @param {Boolean} productionToo
     * @param {string}  type
     */
    sourceMaps(productionToo = true, type = 'inline-source-map') {
        if (Mix.inProduction()) {
            type = productionToo ? 'cheap-source-map' : false;
        }

        Config.sourcemaps = type;

        return this;
    };

    /**
     * Override the default path to your project's public directory.
     *
     * @param {string} path
     */
    setPublicPath(path) {
        Config.publicPath = path;

        return this;
    }

    /**
     * Set a prefix for all generated asset paths.
     *
     * @param {string} path
     */
    setResourceRoot(path) {
        Config.resourceRoot = path;

        return this;
    };

    /**
     * Disable all OS notifications.
     */
    disableNotifications() {
        Config.notifications = false;

        return this;
    };

    /**
     * Disable success notifications.
     */
    disableSuccessNotifications() {
        Config.notifications = {
            onSuccess: false,
            onFailure: true
        };

        return this;
    };

    /**
     * Register libraries to automatically "autoload" when
     * the appropriate variable is references in your JS.
     *
     * @param {Object} libs
     */
    autoload(libs) {
        let aliases = {};

        Object.keys(libs).forEach(library => {
            [].concat(libs[library]).forEach(alias => {
                aliases[alias] = library;
            });
        });

        Config.autoload = aliases;

        return this;
    };

    /**
     * Merge custom config with the provided webpack.config file.
     *
     * @param {object} config
     */
    webpackConfig(config) {
        Config.webpackConfig = (typeof config == 'function') ? config(webpack) : config;

        return this;
    }

    /* Set Mix-specific options.
     *
     * @param {object} options
     */
    options(options) {
        if (options.purifyCss) {
            options.purifyCss = require('./PurifyPaths').build(options.purifyCss);

            Verify.dependency(
                'purifycss-webpack',
                ['purifycss-webpack', 'purify-css'],
                true // abortOnComplete
            );
        }

        Config.merge(options);

        return this;
    };

    /**
     * Register a Webpack build event handler.
     *
     * @param {Function} callback
     */
    then(callback) {
        Mix.listen('build', callback);

        return this;
    }

    /**
     * Helper for determining a production environment.
     */
    inProduction() {
        return Mix.inProduction();
    }

    /**
     * Generate a full output path, using a fallback
     * file name, if a directory is provided.
     *
     * @param {Object} output
     * @param {Object} fallbackName
     */
    _normalizeOutput(output, fallbackName) {
        if (output.isDirectory()) {
            output = new File(path.join(output.filePath, fallbackName));
        }

        return output;
    }
}

module.exports = Api;
<|endoftext|>


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

var PORT = process.env.OPENSHIFT_NODEJS_PORT || 3000,
    IP_ADDRESS = process.env.OPENSHIFT_NODEJS_IP || '127.0.0.1';

if (process.env.OPENSHIFT_APP_DNS) {
    BASE_URL = 'http://' + process.env.OPENSHIFT_APP_DNS;
} else {
    BASE_URL = 'http://localhost:3000';
}

var fs = require('fs'),
    https = require('https'),
    url = require('url'),
    path = require('path');

var express = require('express'),
    hljs = require('highlight.js'),
    swig  = require('swig');

var app = express(),
    template = swig.compileFile('template.html');

String.prototype.format = function () {
    var s = this.toString();

    for (var i = 0; i < arguments.length; i++) {
        var re = new RegExp('\\{' + i + '\\}', 'gm');
        s = s.replace(re, arguments[i]);
    }

    return s;
};

/*

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String

*/
Object.defineProperty(String.prototype, 'startsWith', {
    enumerable: false,
    configurable: false,
    writable: false,
    value: function (searchString, position) {
        position = position || 0;
        return this.lastIndexOf(searchString, position) === position;
    }
});

Object.defineProperty(String.prototype, 'endsWith', {
    value: function (searchString, position) {
        var subjectString = this.toString();
        if (position === undefined || position > subjectString.length) {
            position = subjectString.length;
        }
        position -= searchString.length;
        var lastIndex = subjectString.indexOf(searchString, position);
        return lastIndex !== -1 && lastIndex === position;
    }
});

function escapeJS(s) {
    return s.replace(/\n/g, '\\n').replace(/\'/g, '\\\'').replace(/\"/g, '\\\"');
}

function highlight(code, language) {
    if (language) {
        return hljs.highlight(language, code).value;
    } else {
        return hljs.highlightAuto(code).value;
    }
}

function range(low, high) {
    var list = [];
    for (var i = low; i <= high; i++) {
        list.push(i);
    }
    return list;
}

function downloadFile(urlStr, callback) {
    var options = url.parse(urlStr);

    options.headers = {
        'User-Agent': 'Gistfy-App 0.1.0'
    };

    https.get(options, function (response) {
        response.setEncoding('utf8');

        var body = '';

        response.on('data', function (chunk) {
            body += chunk;
        });

        response.on('end', function () {
            callback(body);
        });

    }).on('error', function (e) {
        // TODO:
    });
}

function downloadJSON(url, callback) {
    downloadFile(url, function (data) {
        callback(JSON.parse(data));
    });
}

function guessLanguage(file) {
    if (file) {
        // FIX ME: Doesn't work for all extensions. e.g. ".cpp".
        // http://highlightjs.readthedocs.org/en/latest/css-classes-reference.html
        return file.split('.').pop();
    } else {
        return null;
    }
}

function processData(data, slice) {

    var start, end, len;

    // TODO: Use while, maybe more than once.
    if (data.startsWith('\n')) {
        data = data.substring(1);
    }

    if (data.endsWith('\n')) {
        data = data.substring(0, data.length - 1);
    }

    if (slice) {

        if (slice.indexOf(':') > -1) {
            slice = slice.split(':');
            if (slice) {
                // e.g 1:5 or -3:-1
                start = parseInt(slice.shift()) || 0;
                end = parseInt(slice.shift()) || -1;
            }
        } else {
            start = parseInt(slice) || 0;
            end = start;
        }

        len = data.split('\n').length;

        if (start < 0) {
            start = len + start;
        } else if (start + 1 > len) {
            start = 0
        }

        if (end < 0) {
            end = len + end;
        } else if (end + 1 > len) {
            end = len - 1
        }

        data = data.split('\n').slice(start, end + 1).join('\n');

    } else {
        start = 0;
        end = data.split('\n').length - 1;
    }

    return { data: data, start: start, end: end };
}

function buildResponse(type, options, callback) {
    switch (type) {
        case "js":
            var js = 'document.write(\'<link rel=\"stylesheet\" href=\"' + BASE_URL + '/css/gistfy.github.css\">\');\n'+
                     'document.write(\'' + escapeJS(template(options)) + '\');';
            callback(200, js, 'text/javascript');
            break;
        case "html":
            var html = '<link rel=\"stylesheet\" href=\"' + BASE_URL + '/css/gistfy.github.css\">
' + template(options);
            callback(200, html.replace('\n', '
'), 'text/html');
            break;
        default:
            callback(400, 'Invalid type.', 'text/html')
    }
}

app.get('/', function (req, res) {
    res.redirect('/index.html');
});

/*

Optional parameters:
    @param extended     Use extended template. Show user information at header. e.g., extended=true. Default: false.
    @param lang         Set code language, for highlight. e.g., lang=python. Default is based in file extension. e.g., file.py returns python highlight style.
    @param locale       Set template locale, for translation. e.g., locale=en. Default: en.
    @param slice        Slice file, returning only the lines selected. e.g., slice=1:8. Default: null.
    @param theme        Set template theme. e.g., theme=github, Default: github.
    @param type         Return type for content. e.g. type=html. Default: js.
*/
app.get('/github/gist/:id', function (req, res) {

    var extended = req.query.extended,
        lang = req.query.lang,
        locale = req.query.locale || 'en',
        slice = req.query.slice,
        theme = req.query.theme || 'github',
        type = req.query.type || 'js';

    var url = 'https://api.github.com/gists/{0}'.format(req.params.id);

    downloadJSON(url, function (data) {
        var files = [];

        for (var k in data.files) {
            var file = data.files[k];

            var newData = processData(file.content, slice),
                lines = range(newData.start, newData.end),
                c = highlight(newData.data, lang || guessLanguage(file.filename));

            files.push({
                htmlUrl: data.html_url,
                rawUrl: file.raw_url,
                fileName: file.filename,
                content: c,
                lineRange: lines,
            });
        }

        var options = {
            files: files,
            repoUrl: null,
            theme: theme,
            extended: extended
        };

        buildResponse(type, options, function (status, content, contentType) {
            res.setHeader('content-type', contentType);
            res.send(content);
        });
    });
});

/*

Optional parameters:
    @param branch       Set file branch or changeset. e.g., branch=master or branch=38d25e12627b. Default: master.
    @param extended     Use extended template. Show user information at header. e.g., extended=true. Default: false.
    @param lang         Set code language, for highlight. e.g., lang=python. Default is based in file extension. e.g., file.py returns python highlight style.
    @param locale       Set template locale, for translation. e.g., locale=en. Default: en.
    @param slice        Slice file, returning only the lines selected. e.g., slice=1:8. Default: null.
    @param theme        Set template theme. e.g., theme=github, Default: github.
    @param type         Return type for content. e.g. type=html. Default: js.
*/
app.get('/:host/:user/:repo/:path(*)', function (req, res) {

    var host = req.params.host.toLowerCase(),
        path = req.params.path,
        repo = req.params.repo,
        user = req.params.user,
        branch = req.query.branch || 'master',
        extended = req.query.extended,
        lang = req.query.lang,
        locale = req.query.locale || 'en',
        slice = req.query.slice,
        theme = req.query.theme || 'github',
        type = req.query.type || 'js',
        fileName = path.split('/').pop(),
        htmlUrl, rawUrl, repoUrl, from, to;

    if (host === 'github') {
        htmlUrl =  'https://github.com/{0}/{1}/blob/{2}/{3}'.format(user, repo, branch, path);
        rawUrl =  'https://raw.githubusercontent.com/{0}/{1}/{2}/{3}'.format(user, repo, branch, path);
        repoUrl = 'https://github.com/{0}/{1}'.format(user, repo);
    } else if (host === 'bitbucket') {
        htmlUrl =  'https://bitbucket.org/{0}/{1}/src/{2}/{3}'.format(user, repo, branch, path);
        rawUrl =  'https://api.bitbucket.org/1.0/repositories/{0}/{1}/raw/{2}/{3}'.format(user, repo, branch, path);
        repoUrl = 'https://bitbucket.org/{0}/{1}'.format(user, repo);
    } else {
        res.end();
        return;
    }

    downloadFile(rawUrl, function (data) {

        var newData = processData(data, slice),
            lines = range(newData.start, newData.end),
            content = highlight(newData.data, lang || guessLanguage(fileName));

        var options = {
            files: [{
                htmlUrl: htmlUrl,
                rawUrl: rawUrl,
                fileName: fileName,
                content: content,
                lineRange: lines
            }],
            repoUrl: repoUrl,
            theme: theme,
            extended: extended
        };

        buildResponse(type, options, function (status, content, contentType) {
            res.setHeader('content-type', contentType);
            res.send(content);
        });
    });
});

app.use(express.static(path.join(__dirname, 'static/')));

app.listen(PORT, IP_ADDRESS, function () {
    console.log('Listening on http://{0}:{1}'.format(IP_ADDRESS, PORT));
});
<commit_msg>Use node's built in format function<commit_after>#!/usr/bin/env node

var PORT = process.env.OPENSHIFT_NODEJS_PORT || 3000,
    IP_ADDRESS = process.env.OPENSHIFT_NODEJS_IP || '127.0.0.1';

if (process.env.OPENSHIFT_APP_DNS) {
    BASE_URL = 'http://' + process.env.OPENSHIFT_APP_DNS;
} else {
    BASE_URL = 'http://localhost:3000';
}

var fs = require('fs'),
    https = require('https'),
    url = require('url'),
    path = require('path'),
    util = require('util');

var express = require('express'),
    hljs = require('highlight.js'),
    swig  = require('swig');

var app = express(),
    template = swig.compileFile('template.html');

/*

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String

*/
Object.defineProperty(String.prototype, 'startsWith', {
    enumerable: false,
    configurable: false,
    writable: false,
    value: function (searchString, position) {
        position = position || 0;
        return this.lastIndexOf(searchString, position) === position;
    }
});

Object.defineProperty(String.prototype, 'endsWith', {
    value: function (searchString, position) {
        var subjectString = this.toString();
        if (position === undefined || position > subjectString.length) {
            position = subjectString.length;
        }
        position -= searchString.length;
        var lastIndex = subjectString.indexOf(searchString, position);
        return lastIndex !== -1 && lastIndex === position;
    }
});

function escapeJS(s) {
    return s.replace(/\n/g, '\\n').replace(/\'/g, '\\\'').replace(/\"/g, '\\\"');
}

function highlight(code, language) {
    if (language) {
        return hljs.highlight(language, code).value;
    } else {
        return hljs.highlightAuto(code).value;
    }
}

function range(low, high) {
    var list = [];
    for (var i = low; i <= high; i++) {
        list.push(i);
    }
    return list;
}

function downloadFile(urlStr, callback) {
    var options = url.parse(urlStr);

    options.headers = {
        'User-Agent': 'Gistfy-App 0.1.0'
    };

    https.get(options, function (response) {
        response.setEncoding('utf8');

        var body = '';

        response.on('data', function (chunk) {
            body += chunk;
        });

        response.on('end', function () {
            callback(body);
        });

    }).on('error', function (e) {
        // TODO:
    });
}

function downloadJSON(url, callback) {
    downloadFile(url, function (data) {
        callback(JSON.parse(data));
    });
}

function guessLanguage(file) {
    if (file) {
        // FIX ME: Doesn't work for all extensions. e.g. ".cpp".
        // http://highlightjs.readthedocs.org/en/latest/css-classes-reference.html
        return file.split('.').pop();
    } else {
        return null;
    }
}

function processData(data, slice) {

    var start, end, len;

    // TODO: Use while, maybe more than once.
    if (data.startsWith('\n')) {
        data = data.substring(1);
    }

    if (data.endsWith('\n')) {
        data = data.substring(0, data.length - 1);
    }

    if (slice) {

        if (slice.indexOf(':') > -1) {
            slice = slice.split(':');
            if (slice) {
                // e.g 1:5 or -3:-1
                start = parseInt(slice.shift()) || 0;
                end = parseInt(slice.shift()) || -1;
            }
        } else {
            start = parseInt(slice) || 0;
            end = start;
        }

        len = data.split('\n').length;

        if (start < 0) {
            start = len + start;
        } else if (start + 1 > len) {
            start = 0;
        }

        if (end < 0) {
            end = len + end;
        } else if (end + 1 > len) {
            end = len - 1;
        }

        data = data.split('\n').slice(start, end + 1).join('\n');

    } else {
        start = 0;
        end = data.split('\n').length - 1;
    }

    return { data: data, start: start, end: end };
}

function buildResponse(type, options, callback) {
    switch (type) {
        case "js":
            var js = 'document.write(\'<link rel=\"stylesheet\" href=\"' + BASE_URL + '/css/gistfy.github.css\">\');\n'+
                     'document.write(\'' + escapeJS(template(options)) + '\');';
            callback(200, js, 'text/javascript');
            break;
        case "html":
            var html = '<link rel=\"stylesheet\" href=\"' + BASE_URL + '/css/gistfy.github.css\">
' + template(options);
            callback(200, html.replace('\n', '
'), 'text/html');
            break;
        default:
            callback(400, 'Invalid type.', 'text/html');
    }
}

app.get('/', function (req, res) {
    res.redirect('/index.html');
});

/*

Optional parameters:
    @param extended     Use extended template. Show user information at header. e.g., extended=true. Default: false.
    @param lang         Set code language, for highlight. e.g., lang=python. Default is based in file extension. e.g., file.py returns python highlight style.
    @param locale       Set template locale, for translation. e.g., locale=en. Default: en.
    @param slice        Slice file, returning only the lines selected. e.g., slice=1:8. Default: null.
    @param theme        Set template theme. e.g., theme=github, Default: github.
    @param type         Return type for content. e.g. type=html. Default: js.
*/
app.get('/github/gist/:id', function (req, res) {

    var extended = req.query.extended,
        lang = req.query.lang,
        locale = req.query.locale || 'en',
        slice = req.query.slice,
        theme = req.query.theme || 'github',
        type = req.query.type || 'js';

    var url = util.format('https://api.github.com/gists/%s', req.params.id);

    downloadJSON(url, function (data) {
        var files = [];

        for (var k in data.files) {
            var file = data.files[k];

            var newData = processData(file.content, slice),
                lines = range(newData.start, newData.end),
                c = highlight(newData.data, lang || guessLanguage(file.filename));

            files.push({
                htmlUrl: data.html_url,
                rawUrl: file.raw_url,
                fileName: file.filename,
                content: c,
                lineRange: lines,
            });
        }

        var options = {
            files: files,
            repoUrl: null,
            theme: theme,
            extended: extended
        };

        buildResponse(type, options, function (status, content, contentType) {
            res.setHeader('content-type', contentType);
            res.send(content);
        });
    });
});

/*

Optional parameters:
    @param branch       Set file branch or changeset. e.g., branch=master or branch=38d25e12627b. Default: master.
    @param extended     Use extended template. Show user information at header. e.g., extended=true. Default: false.
    @param lang         Set code language, for highlight. e.g., lang=python. Default is based in file extension. e.g., file.py returns python highlight style.
    @param locale       Set template locale, for translation. e.g., locale=en. Default: en.
    @param slice        Slice file, returning only the lines selected. e.g., slice=1:8. Default: null.
    @param theme        Set template theme. e.g., theme=github, Default: github.
    @param type         Return type for content. e.g. type=html. Default: js.
*/
app.get('/:host/:user/:repo/:path(*)', function (req, res) {

    var host = req.params.host.toLowerCase(),
        path = req.params.path,
        repo = req.params.repo,
        user = req.params.user,
        branch = req.query.branch || 'master',
        extended = req.query.extended,
        lang = req.query.lang,
        locale = req.query.locale || 'en',
        slice = req.query.slice,
        theme = req.query.theme || 'github',
        type = req.query.type || 'js',
        fileName = path.split('/').pop(),
        htmlUrl, rawUrl, repoUrl, from, to;

    if (host === 'github') {
        htmlUrl =  util.format('https://github.com/%s/%s/blob/%s/%s', user, repo, branch, path);
        rawUrl =  util.format('https://raw.githubusercontent.com/%s/%s/%s/%s', user, repo, branch, path);
        repoUrl = util.format('https://github.com/%s/%s', user, repo);
    } else if (host === 'bitbucket') {
        htmlUrl =  util.format('https://bitbucket.org/%s/%s/src/%s/%s', user, repo, branch, path);
        rawUrl =  util.format('https://api.bitbucket.org/1.0/repositories/%s/%s/raw/%s/%s', user, repo, branch, path);
        repoUrl = util.format('https://bitbucket.org/%s/$s', user, repo);
    } else {
        res.end();
        return;
    }

    downloadFile(rawUrl, function (data) {

        var newData = processData(data, slice),
            lines = range(newData.start, newData.end),
            content = highlight(newData.data, lang || guessLanguage(fileName));

        var options = {
            files: [{
                htmlUrl: htmlUrl,
                rawUrl: rawUrl,
                fileName: fileName,
                content: content,
                lineRange: lines
            }],
            repoUrl: repoUrl,
            theme: theme,
            extended: extended
        };

        buildResponse(type, options, function (status, content, contentType) {
            res.setHeader('content-type', contentType);
            res.send(content);
        });
    });
});

app.use(express.static(path.join(__dirname, 'static/')));

app.listen(PORT, IP_ADDRESS, function () {
    console.log(util.format('Listening on http://%s:%s', IP_ADDRESS, PORT));
});
<|endoftext|>