<commit_before>if (!document) {
    throw Error("electron-tabs module must be called in renderer process");
}

// Inject styles
(function () {
    const styles = `
        webview {
            display: flex;
            flex: 0 1;
            width: 0px;
            height: 0px;
        }
        webview.visible {
            width: 100%;
            height: 100%;
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
        }
    `;
    let styleTag = document.createElement("style");
    styleTag.innerHTML = styles;
    document.getElementsByTagName("head")[0].appendChild(styleTag);
})();

class TabGroup {
    constructor (args = {}) {
        let options = this.options = {
            tabContainerSelector: args.tabContainerSelector || ".tabs-tabcontainer",
            buttonsContainerSelector: args.buttonsContainerSelector || ".tabs-buttonscontainer",
            viewContainerSelector: args.viewContainerSelector || ".tabs-viewcontainer",
            tabClass: args.tabClass || "tabs-tab",
            viewClass: args.viewClass || "tabs-view",
            closeButtonText: args.closeButtonText || "❌",
            newTab: args.newTab,
            newTabButtonText: args.newTabButton || "+"
        };
        this.tabContainer = document.querySelector(options.tabContainerSelector);
        this.viewContainer = document.querySelector(options.viewContainerSelector);
        this.tabs = [];
        this.newTabId = 0;
        this.initNewTabButton();
    }

    initNewTabButton () {
        if (!this.options.newTab) return;
        let container = document.querySelector(this.options.buttonsContainerSelector);
        let button = container.appendChild(document.createElement("button"));
        button.classList.add(`${this.options.tabClass}-button-new`);
        button.innerHTML = this.options.newTabButtonText;
        button.addEventListener("click", this.addTab.bind(this, undefined), false);
    }

    addTab (args = this.options.newTab) {
        let id = this.newTabId;
        this.newTabId++;
        let tab = new Tab(this, id, args);
        this.pushTab(tab);
        return tab;
    }

    pushTab (tab) {
        this.tabs.push(tab);
    }

    removeTab (tab) {
        let id = tab.id;
        for (let i in this.tabs) {
            if (this.tabs[i].id === id) {
                this.tabs.splice(i, 1);
                break;
            }
        }
    }

    setActiveTab (tab) {
        this.removeTab(tab);
        this.pushTab(tab);
    }

    getActiveTab () {
        if (this.tabs.length < 1) return null;
        return this.tabs[this.tabs.length - 1];
    }

    activateRecentTab (tab) {
        let recentTab = this.tabs[this.tabs.length - 1];
        if (!recentTab) return;
        recentTab.activate();
    }
}

class Tab {
    constructor (tabGroup, id, args) {
        this.tabGroup = tabGroup;
        this.id = id;
        this.title = args.title;
        this.iconURL = args.iconURL;
        this.closable = args.closable === false ? false : true;
        this.webviewAttributes = args.webviewAttributes || {};
        this.webviewAttributes.src = args.src;
        this.tabElements = {};
        this.initTab();
        this.initWebview();
    }

    initTab () {
        let tabClass = this.tabGroup.options.tabClass;

        // Create tab element
        let tab = this.tab = document.createElement("div");
        tab.classList.add(tabClass);
        for (let el of ["icon", "title", "buttons"]) {
            let span = tab.appendChild(document.createElement("span"));
            span.classList.add(`${tabClass}-${el}`);
            this.tabElements[el] = span;
        }

        this.setTitle(this.title);
        this.setIcon(this.iconURL);
        this.setButtons();

        tab.addEventListener("click", this.tabClickHandler.bind(this), false);
        this.tabGroup.tabContainer.appendChild(this.tab);
    }

    initWebview () {
        this.webview = document.createElement("webview");
        this.webview.classList.add(this.tabGroup.options.viewClass);
        if (this.webviewAttributes) {
            let attrs = this.webviewAttributes;
            for (let key in attrs) {
                this.webview.setAttribute(key, attrs[key]);
            }
        }
        this.tabGroup.viewContainer.appendChild(this.webview);
    }

    setTitle (title) {
        let span = this.tabElements.title;
        span.innerHTML = title;
        this.title = title;
    }

    getTitle () {
        return this.title;
    }

    setIcon (iconURL) {
        this.iconURL = iconURL;
        let span = this.tabElements.icon;
        if (iconURL) {
            span.innerHTML = `<img src="${iconURL}" />`;
        }
    }

    getIcon () {
        return this.iconURL;
    }

    setButtons () {
        let container = this.tabElements.buttons;
        let tabClass = this.tabGroup.options.tabClass;
        if (this.closable) {
            let button = container.appendChild(document.createElement("button"));
            button.classList.add(`${tabClass}-button-close`);
            button.innerHTML = this.tabGroup.options.closeButtonText;
            button.addEventListener("click", this.close.bind(this), false);
        }
    }

    tabClickHandler (e) {
        if (e.which === 1) {
            this.activate();
        } else if (e.which === 2) {
            this.close();
        }
    }

    activate () {
        let activeTab = this.tabGroup.getActiveTab();
        if (activeTab) {
            activeTab.tab.classList.remove("active");
            activeTab.webview.classList.remove("visible");
        }
        this.tabGroup.setActiveTab(this);
        this.tab.classList.add("active");
        this.webview.classList.add("visible");
    }

    flash (flag) {
        if (flag !== false) {
            this.tab.classList.add("flash");
        } else {
            this.tab.classList.remove("flash");
        }
    }

    move (index) {
        // TODO: move
    }

    close (force) {
        if (!this.closable && !force) return;
        let tabGroup = this.tabGroup;
        tabGroup.tabContainer.removeChild(this.tab);
        tabGroup.viewContainer.removeChild(this.webview);
        tabGroup.removeTab(this);
        tabGroup.activateRecentTab();
    }
}

module.exports = TabGroup;
<commit_msg>Fix tabs activation<commit_after>if (!document) {
    throw Error("electron-tabs module must be called in renderer process");
}

// Inject styles
(function () {
    const styles = `
        webview {
            display: flex;
            flex: 0 1;
            width: 0px;
            height: 0px;
        }
        webview.visible {
            width: 100%;
            height: 100%;
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
        }
    `;
    let styleTag = document.createElement("style");
    styleTag.innerHTML = styles;
    document.getElementsByTagName("head")[0].appendChild(styleTag);
})();

class TabGroup {
    constructor (args = {}) {
        let options = this.options = {
            tabContainerSelector: args.tabContainerSelector || ".tabs-tabcontainer",
            buttonsContainerSelector: args.buttonsContainerSelector || ".tabs-buttonscontainer",
            viewContainerSelector: args.viewContainerSelector || ".tabs-viewcontainer",
            tabClass: args.tabClass || "tabs-tab",
            viewClass: args.viewClass || "tabs-view",
            closeButtonText: args.closeButtonText || "❌",
            newTab: args.newTab,
            newTabButtonText: args.newTabButton || "+"
        };
        this.tabContainer = document.querySelector(options.tabContainerSelector);
        this.viewContainer = document.querySelector(options.viewContainerSelector);
        this.tabs = [];
        this.newTabId = 0;
        this.initNewTabButton();
    }

    initNewTabButton () {
        if (!this.options.newTab) return;
        let container = document.querySelector(this.options.buttonsContainerSelector);
        let button = container.appendChild(document.createElement("button"));
        button.classList.add(`${this.options.tabClass}-button-new`);
        button.innerHTML = this.options.newTabButtonText;
        button.addEventListener("click", this.addTab.bind(this, undefined), false);
    }

    addTab (args = this.options.newTab) {
        let id = this.newTabId;
        this.newTabId++;
        let tab = new Tab(this, id, args);
        this.tabs.push(tab);
        return tab;
    }

    removeTab (tab) {
        let id = tab.id;
        for (let i in this.tabs) {
            if (this.tabs[i].id === id) {
                this.tabs.splice(i, 1);
                break;
            }
        }
    }

    setActiveTab (tab) {
        this.removeTab(tab);
        this.tabs.unshift(tab);
    }

    getActiveTab () {
        if (this.tabs.length === 0) return null;
        return this.tabs[0];
    }

    activateRecentTab (tab) {
        if (this.tabs.length === 0) return null;
        this.tabs[0].activate();
    }
}

class Tab {
    constructor (tabGroup, id, args) {
        this.tabGroup = tabGroup;
        this.id = id;
        this.title = args.title;
        this.iconURL = args.iconURL;
        this.closable = args.closable === false ? false : true;
        this.webviewAttributes = args.webviewAttributes || {};
        this.webviewAttributes.src = args.src;
        this.tabElements = {};
        this.initTab();
        this.initWebview();
    }

    initTab () {
        let tabClass = this.tabGroup.options.tabClass;

        // Create tab element
        let tab = this.tab = document.createElement("div");
        tab.classList.add(tabClass);
        for (let el of ["icon", "title", "buttons"]) {
            let span = tab.appendChild(document.createElement("span"));
            span.classList.add(`${tabClass}-${el}`);
            this.tabElements[el] = span;
        }

        this.setTitle(this.title);
        this.setIcon(this.iconURL);
        this.setButtons();

        tab.addEventListener("click", this.tabClickHandler.bind(this), false);
        this.tabGroup.tabContainer.appendChild(this.tab);
    }

    initWebview () {
        this.webview = document.createElement("webview");
        this.webview.classList.add(this.tabGroup.options.viewClass);
        if (this.webviewAttributes) {
            let attrs = this.webviewAttributes;
            for (let key in attrs) {
                this.webview.setAttribute(key, attrs[key]);
            }
        }
        this.tabGroup.viewContainer.appendChild(this.webview);
    }

    setTitle (title) {
        let span = this.tabElements.title;
        span.innerHTML = title;
        this.title = title;
    }

    getTitle () {
        return this.title;
    }

    setIcon (iconURL) {
        this.iconURL = iconURL;
        let span = this.tabElements.icon;
        if (iconURL) {
            span.innerHTML = `<img src="${iconURL}" />`;
        }
    }

    getIcon () {
        return this.iconURL;
    }

    setButtons () {
        let container = this.tabElements.buttons;
        let tabClass = this.tabGroup.options.tabClass;
        if (this.closable) {
            let button = container.appendChild(document.createElement("button"));
            button.classList.add(`${tabClass}-button-close`);
            button.innerHTML = this.tabGroup.options.closeButtonText;
            button.addEventListener("click", this.close.bind(this), false);
        }
    }

    tabClickHandler (e) {
        if (e.which === 1) {
            this.activate();
        } else if (e.which === 2) {
            this.close();
        }
    }

    activate () {
        let activeTab = this.tabGroup.getActiveTab();
        if (activeTab) {
            activeTab.tab.classList.remove("active");
            activeTab.webview.classList.remove("visible");
        }
        this.tabGroup.setActiveTab(this);
        this.tab.classList.add("active");
        this.webview.classList.add("visible");
    }

    flash (flag) {
        if (flag !== false) {
            this.tab.classList.add("flash");
        } else {
            this.tab.classList.remove("flash");
        }
    }

    move (index) {
        // TODO: move
    }

    close (force) {
        if (!this.closable && !force) return;
        let tabGroup = this.tabGroup;
        tabGroup.tabContainer.removeChild(this.tab);
        tabGroup.viewContainer.removeChild(this.webview);
        tabGroup.removeTab(this);
        tabGroup.activateRecentTab();
    }
}

module.exports = TabGroup;
<|endoftext|>


<commit_before>var express = require('express'),
	swig = require('swig'),
	winston = require('winston'),
	fs = require('fs');
var app,
	apiClient = require('./apiClient');
function setup(app, siteName){
	app.use(express.logger({format: 'dev'}));
	app.engine('html', swig.renderFile);
	app.set('view engine', 'html');
	app.set('view cache', false);
	app.set('views', __dirname + '/views');
	swig.setDefaults({cache: false});
	app.use(express.static(__dirname + '/public'));
	app.use(express.methodOverride());
	app.use(express.urlencoded())
	app.use(express.json());
	app.use(express.cookieParser());
	app.use(express.session({secret: 'secret'}));
	app.use(express.favicon());
	app.use(app.router);

	// Config
	app.locals.siteName = siteName;
	// Helpers
	app.locals.now = function(){
		return new Date();
	};
	app.locals.timeago = require('timeago');

	setupRoutes();

	app.get('*', function(req, res){
		res.status(404);
		res.render('404.html');
	});
}

function setupRoutes(){
	require('./routes')(app, apiClient);
}

function init(port, siteName){
	if(!app){
		app = express();
	}

	setup(app, siteName);

	app.listen(port, function(){
		winston.info('Client listening at 0.0.0.0:' + port);
	});
}

module.exports = init;<commit_msg>add express winston logger<commit_after>var express = require('express'),
	swig = require('swig'),
	winston = require('winston'),
	expressWinston = require('express-winston'),
	fs = require('fs')
var app,
	apiClient = require('./apiClient');
function setup(app, siteName){
	app.engine('html', swig.renderFile);
	app.set('view engine', 'html');
	app.set('view cache', false);
	app.set('views', __dirname + '/views');
	swig.setDefaults({cache: false});
	app.use(express.static(__dirname + '/public'));
	app.use(express.methodOverride());
	app.use(express.urlencoded())
	app.use(express.json());
	app.use(express.cookieParser());
	app.use(express.session({secret: 'secret'}));
	app.use(express.favicon());
	app.use(app.router);
	app.use(expressWinston.errorLogger({
		transports: [
			new winston.transports.Console({
				json: true,
				colorize: true
			})
		],
		meta: true,
		msg: "HTTP {{req.method}} {{req.url}}"
	}));

	// Config
	app.locals.siteName = siteName;
	// Helpers
	app.locals.now = function(){
		return new Date();
	};
	app.locals.timeago = require('timeago');

	setupRoutes();

	app.get('*', function(req, res){
		res.status(404);
		res.render('404.html');
	});
}

function setupRoutes(){
	require('./routes')(app, apiClient);
}

function init(port, siteName){
	if(!app){
		app = express();
	}

	setup(app, siteName);

	app.listen(port, function(){
		winston.info('Client listening at 0.0.0.0:' + port);
	});
}

module.exports = init;<|endoftext|>


<commit_before>const getOptions = require('mocha/bin/options')
const url = require('url')
const {
  each
} = require('lodash')
const {
  resolve
} = require('path')
const {
  BrowserWindow,
  app,
  ipcMain
} = require('electron')
const Coverage = require('./lib/Coverage')
const parseArgs = require('./lib/parseArgs')
const runMocha = require('./lib/runMocha')

function fail (error) {
  console.error(error.message)
  console.error(error.stack)
  app.exit(1)
}

// load mocha.opts into process.argv
getOptions()

// opts
const opts = parseArgs(process.argv)
opts.root = process.cwd()

// `--require-main` scripts
if (opts.requireMain.length) {
  try {
    each(opts.requireMain, mainModule => {
      require(mainModule)
    })
  } catch (error) {
    fail(error)
  }
}

app.on('quit', () => { })
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
  app.exit(1)
})
app.on('ready', () => {
  if (opts.interactive) {
    opts.renderer = true
    opts.debug = true
    opts.reporter = 'HTML'
  }
  if (!opts.renderer) {
    let coverage
    try {
      if (opts.coverage) {
        coverage = new Coverage(opts.root, opts.coveragePattern)
      }
      runMocha(opts, count => {
        if (coverage) {
          coverage.report()
        }
        app.exit(count)
      })
    } catch (error) {
      fail(error)
    }
  } else {
    let win = new BrowserWindow({
      focusable: opts.debug,
      height: opts.height,
      show: false,
      webPreferences: {
        webSecurity: false
      },
      width: opts.width
    })

    win.on('closed', () => {
      win = null
    })
    win.webContents.once('did-finish-load', () => {
      if (opts.debug) {
        win.show()
        win.webContents.openDevTools()
        win.webContents.on('devtools-opened', () => {
          // Debugger is not immediately ready!
          setTimeout(() => {
            win.webContents.send('mocha-start')
          }, 250)
        })

        // Called on reload in --interactive mode
        ipcMain.on('mocha-ready-to-run', () => {
          win.webContents.send('mocha-start')
        })
      } else {
        win.webContents.send('mocha-start')
      }
    })

    ipcMain.on('mocha-done', (event, count) => {
      win.webContents.once('destroyed', () => app.exit(count))
      if (!opts.interactive) {
        win.close()
      }
    })
    ipcMain.on('mocha-error', (_, error) => fail(error))

    win.loadURL(url.format({
      hash: encodeURIComponent(JSON.stringify(opts)),
      pathname: resolve(__dirname, './renderer/index.html'),
      protocol: 'file:',
      slashes: true
    }))

    if (!opts.debug && process.platform === 'darwin') {
      app.dock.hide()
    }
  }
})
<commit_msg>#2 restore window bounds<commit_after>const getOptions = require('mocha/bin/options')
const url = require('url')
const {
  assign,
  each
} = require('lodash')
const {
  readFileSync,
  writeFileSync
} = require('fs')
const {
  resolve
} = require('path')
const {
  BrowserWindow,
  app,
  ipcMain
} = require('electron')
const Coverage = require('./lib/Coverage')
const parseArgs = require('./lib/parseArgs')
const runMocha = require('./lib/runMocha')

function fail (error) {
  console.error(error.message)
  console.error(error.stack)
  app.exit(1)
}

// configuration
const configPath = resolve(app.getPath('userData'), './config.json')
function restoreBounds (winOpts) {
  let data
  try {
    data = JSON.parse(readFileSync(configPath, 'utf8'))
  } catch (e) {
    // do nothing
  }
  if (data && data.bounds) {
    assign(winOpts, data.bounds)
  }
}
function saveBounds (win) {
  writeFileSync(configPath, JSON.stringify({
    bounds: win.getBounds()
  }))
}

// load mocha.opts into process.argv
getOptions()

// opts
const opts = parseArgs(process.argv)
opts.root = process.cwd()

// `--require-main` scripts
if (opts.requireMain.length) {
  try {
    each(opts.requireMain, mainModule => {
      require(mainModule)
    })
  } catch (error) {
    fail(error)
  }
}

app.on('quit', () => { })
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
  app.exit(1)
})
app.on('ready', () => {
  if (opts.interactive) {
    opts.renderer = true
    opts.debug = true
    opts.reporter = 'HTML'
  }
  if (!opts.renderer) {
    let coverage
    try {
      if (opts.coverage) {
        coverage = new Coverage(opts.root, opts.coveragePattern)
      }
      runMocha(opts, count => {
        if (coverage) {
          coverage.report()
        }
        app.exit(count)
      })
    } catch (error) {
      fail(error)
    }
  } else {
    const winOpts = {
      focusable: opts.debug,
      height: opts.height,
      show: false,
      width: opts.width,
      webPreferences: {
        webSecurity: false
      }
    }
    restoreBounds(winOpts)
    let win = new BrowserWindow(winOpts)

    win.on('close', () => {
      saveBounds(win)
    })
    win.on('closed', () => {
      win = null
    })
    win.webContents.once('did-finish-load', () => {
      if (opts.debug) {
        win.show()
        win.webContents.openDevTools()
        win.webContents.on('devtools-opened', () => {
          // Debugger is not immediately ready!
          setTimeout(() => {
            win.webContents.send('mocha-start')
          }, 250)
        })

        // Called on reload in --interactive mode
        ipcMain.on('mocha-ready-to-run', () => {
          win.webContents.send('mocha-start')
        })
      } else {
        win.webContents.send('mocha-start')
      }
    })

    ipcMain.on('mocha-done', (event, count) => {
      win.webContents.once('destroyed', () => app.exit(count))
      if (!opts.interactive) {
        win.close()
      }
    })
    ipcMain.on('mocha-error', (_, error) => fail(error))

    win.loadURL(url.format({
      hash: encodeURIComponent(JSON.stringify(opts)),
      pathname: resolve(__dirname, './renderer/index.html'),
      protocol: 'file:',
      slashes: true
    }))

    if (!opts.debug && process.platform === 'darwin') {
      app.dock.hide()
    }
  }
})
<|endoftext|>


<commit_before>'use strict';

const Boom = require('boom');
const Hoek = require('hoek');
const Joi = require('joi');
const MediaType = require('media-type');

const Package = require('./package');

const internals = {
    optionsSchema: Joi.object({
        validVersions: Joi.array().items(Joi.number().integer()).min(1).required(),
        defaultVersion: Joi.any().valid(Joi.ref('validVersions')).required(),
        vendorName: Joi.string().trim().min(1).required(),
        versionHeader: Joi.string().trim().min(1).default('api-version'),
        passiveMode: Joi.boolean().default(false),
        basePath: Joi.string().trim().min(1).default('/')
    })
};

const _extractVersionFromCustomHeader = function (request, options) {

    const apiVersionHeader = request.headers[options.versionHeader];

    if (apiVersionHeader && (/^[0-9]+$/).test(apiVersionHeader)) {
        return parseInt(apiVersionHeader);
    }

    return null;
};

const _extractVersionFromAcceptHeader = function (request, options) {

    const acceptHeader = request.headers.accept;
    const media = MediaType.fromString(acceptHeader);

    if (media.isValid() && (/^vnd.[a-zA-Z0-9]+\.v[0-9]+$/).test(media.subtype)) {

        if (media.subtypeFacets[1] !== options.vendorName) {
            return null;
        }

        const version = media.subtypeFacets[2].replace('v', '');

        return parseInt(version);
    }

    return null;
};

//Set a response header containing the version number
const _addVersionToResponseHeader = function (request, reply, requestedVersion, options) {

    const headerName = options.versionHeader;
    const response = request.response;

    if (request.response.isBoom) {
        response.output.headers[headerName] = requestedVersion;
    }
    else {
        response.header(headerName, requestedVersion);
    }
    reply.continue();
};

exports.register = function (server, options, next) {

    const validateOptions = internals.optionsSchema.validate(options);

    if (validateOptions.error) {
        return next(validateOptions.error);
    }

    //Use the validated and maybe converted values from Joi
    options = validateOptions.value;

    server.ext('onRequest', (request, reply) => {

        //First check for custom header
        let requestedVersion = _extractVersionFromCustomHeader(request, options);

        //If no version check accept header
        if (!requestedVersion) {
            requestedVersion = _extractVersionFromAcceptHeader(request, options);
        }

        //If passive mode skips the rest for non versioned routes
        if (options.passiveMode === true && !requestedVersion) {
            return reply.continue();
        }

        //If there was a version by now check if it is valid
        if (requestedVersion && !Hoek.contain(options.validVersions, requestedVersion)) {
            return reply(Boom.badRequest('Invalid api-version! Valid values: ' + options.validVersions.join()));
        }

        //If there was no version by now use the default version
        if (!requestedVersion) {
            requestedVersion = options.defaultVersion;
        }

        const versionedPath = options.basePath + 'v' + requestedVersion + request.path.slice(options.basePath.length - 1);

        const route = server.match(request.method, versionedPath);

        if (route && route.path.indexOf(options.basePath + 'v' + requestedVersion + '/') === 0) {
            request.setUrl(options.basePath + 'v' + requestedVersion + request.url.path.slice(options.basePath.length - 1)); //required to preserve query parameters
        }

        //Set version for usage in handler
        request.pre.apiVersion = requestedVersion;

        return reply.continue();
    });

    server.ext('onPreResponse', (request, reply) => {

        _addVersionToResponseHeader(request, reply, request.pre.apiVersion, options);
    });

    return next();
};

exports.register.attributes = {
    name: Package.name,
    version: Package.version
};
<commit_msg>Update index.js<commit_after>'use strict';

const Boom = require('boom');
const Hoek = require('hoek');
const Joi = require('joi');
const MediaType = require('media-type');

const Package = require('./package');

const internals = {
    optionsSchema: Joi.object({
        validVersions: Joi.array().items(Joi.number().integer()).min(1).required(),
        defaultVersion: Joi.any().valid(Joi.ref('validVersions')).required(),
        vendorName: Joi.string().trim().min(1).required(),
        versionHeader: Joi.string().trim().min(1).default('api-version'),
        passiveMode: Joi.boolean().default(false),
        basePath: Joi.string().trim().min(1).default('/')
    })
};

const _extractVersionFromCustomHeader = function (request, options) {

    const apiVersionHeader = request.headers[options.versionHeader];

    if (apiVersionHeader && (/^[0-9]+$/).test(apiVersionHeader)) {
        return parseInt(apiVersionHeader);
    }

    return null;
};

const _extractVersionFromAcceptHeader = function (request, options) {

    const acceptHeader = request.headers.accept;
    const media = MediaType.fromString(acceptHeader);

    if (media.isValid() && (/^vnd.[a-zA-Z0-9]+\.v[0-9]+$/).test(media.subtype)) {

        if (media.subtypeFacets[1] !== options.vendorName) {
            return null;
        }

        const version = media.subtypeFacets[2].replace('v', '');

        return parseInt(version);
    }

    return null;
};

//Set a response header containing the version number
const _addVersionToResponseHeader = function (request, reply, requestedVersion, options) {

    const headerName = options.versionHeader;
    const response = request.response;

    if (request.response.isBoom) {
        response.output.headers[headerName] = requestedVersion;
    }
    else {
        response.header(headerName, requestedVersion);
    }
    reply.continue();
};

exports.register = function (server, options, next) {

    const validateOptions = internals.optionsSchema.validate(options);

    if (validateOptions.error) {
        return next(validateOptions.error);
    }

    //Use the validated and maybe converted values from Joi
    options = validateOptions.value;

    server.ext('onRequest', (request, reply) => {

        //First check for custom header
        let requestedVersion = _extractVersionFromCustomHeader(request, options);

        //If no version check accept header
        if (!requestedVersion) {
            requestedVersion = _extractVersionFromAcceptHeader(request, options);
        }

        //If passive mode skips the rest for non versioned routes
        if (options.passiveMode === true && !requestedVersion) {
            return reply.continue();
        }

        //If there was a version by now check if it is valid
        if (requestedVersion && !Hoek.contain(options.validVersions, requestedVersion)) {
            return reply(Boom.badRequest('Invalid api-version! Valid values: ' + options.validVersions.join()));
        }

        //If there was no version by now use the default version
        if (!requestedVersion) {
            requestedVersion = options.defaultVersion;
        }

        const versionedPath = options.basePath + 'v' + requestedVersion + request.path.slice(options.basePath.length - 1);

        const method = request.method === 'options' ? request.headers['access-control-request-method'] : request.method;

        const route = server.match(method, versionedPath);

        if (route && route.path.indexOf(options.basePath + 'v' + requestedVersion + '/') === 0) {
            request.setUrl(options.basePath + 'v' + requestedVersion + request.url.path.slice(options.basePath.length - 1)); //required to preserve query parameters
        }

        //Set version for usage in handler
        request.pre.apiVersion = requestedVersion;

        return reply.continue();
    });

    server.ext('onPreResponse', (request, reply) => {

        _addVersionToResponseHeader(request, reply, request.pre.apiVersion, options);
    });

    return next();
};

exports.register.attributes = {
    name: Package.name,
    version: Package.version
};
<|endoftext|>


<commit_before>module.exports = magnetURIDecode
module.exports.decode = magnetURIDecode
module.exports.encode = magnetURIEncode

var base32 = require('thirty-two')
var extend = require('xtend')
var uniq = require('uniq')

/**
 * Parse a magnet URI and return an object of keys/values
 *
 * @param  {string} uri
 * @return {Object} parsed uri
 */
function magnetURIDecode (uri) {
  var result = {}
  var data = uri.split('magnet:?')[1]

  var params = (data && data.length >= 0)
    ? data.split('&')
    : []

  params.forEach(function (param) {
    var keyval = param.split('=')

    // This keyval is invalid, skip it
    if (keyval.length !== 2) return

    var key = keyval[0]
    var val = keyval[1]

    // Clean up torrent name
    if (key === 'dn') val = decodeURIComponent(val).replace(/\+/g, ' ')

    // Address tracker (tr), exact source (xs), and acceptable source (as) are encoded
    // URIs, so decode them
    if (key === 'tr' || key === 'xs' || key === 'as' || key === 'ws') {
      val = decodeURIComponent(val)
    }

    // Return keywords as an array
    if (key === 'kt') val = decodeURIComponent(val).split('+')

    // If there are repeated parameters, return an array of values
    if (result[key]) {
      if (Array.isArray(result[key])) {
        result[key].push(val)
      } else {
        var old = result[key]
        result[key] = [old, val]
      }
    } else {
      result[key] = val
    }
  })

  // Convenience properties for parity with `parse-torrent-file` module
  var m
  if (result.xt) {
    var xts = Array.isArray(result.xt) ? result.xt : [ result.xt ]
    xts.forEach(function (xt) {
      if ((m = xt.match(/^urn:btih:(.{40})/))) {
        result.infoHash = m[1]
      } else if ((m = xt.match(/^urn:btih:(.{32})/))) {
        var decodedStr = base32.decode(m[1])
        result.infoHash = new Buffer(decodedStr, 'binary').toString('hex')
      }
    })
  }
  if (result.infoHash) result.infoHashBuffer = new Buffer(result.infoHash, 'hex')

  if (result.dn) result.name = result.dn
  if (result.kt) result.keywords = result.kt

  if (typeof result.tr === 'string') result.announce = [ result.tr ]
  else if (Array.isArray(result.tr)) result.announce = result.tr
  else result.announce = []

  uniq(result.announce)

  result.urlList = []
  if (typeof result.as === 'string' || Array.isArray(result.as)) {
    result.urlList = result.urlList.concat(result.as)
  }
  if (typeof result.ws === 'string' || Array.isArray(result.ws)) {
    result.urlList = result.urlList.concat(result.ws)
  }

  return result
}

function magnetURIEncode (obj) {
  obj = extend(obj) // clone obj, so we can mutate it

  // support using convenience names, in addition to spec names
  // (example: `infoHash` for `xt`, `name` for `dn`)
  if (obj.infoHashBuffer) obj.xt = 'urn:btih:' + obj.infoHashBuffer.toString('hex')
  if (obj.infoHash) obj.xt = 'urn:btih:' + obj.infoHash
  if (obj.name) obj.dn = obj.name
  if (obj.keywords) obj.kt = obj.keywords
  if (obj.announce) obj.tr = obj.announce
  if (obj.urlList) {
    obj.ws = obj.urlList
    delete obj.as
  }

  var result = 'magnet:?'
  Object.keys(obj)
    .filter(function (key) {
      return key.length === 2
    })
    .forEach(function (key, i) {
      var values = Array.isArray(obj[key]) ? obj[key] : [ obj[key] ]
      values.forEach(function (val, j) {
        if ((i > 0 || j > 0) && (key !== 'kt' || j === 0)) result += '&'

        if (key === 'dn') val = encodeURIComponent(val).replace(/%20/g, '+')
        if (key === 'tr' || key === 'xs' || key === 'as' || key === 'ws') {
          val = encodeURIComponent(val)
        }
        if (key === 'kt') val = encodeURIComponent(val)

        if (key === 'kt' && j > 0) result += '+' + val
        else result += key + '=' + val
      })
    })

  return result
}
<commit_msg>Changed infohash to always be lowercase when it's a string<commit_after>module.exports = magnetURIDecode
module.exports.decode = magnetURIDecode
module.exports.encode = magnetURIEncode

var base32 = require('thirty-two')
var extend = require('xtend')
var uniq = require('uniq')

/**
 * Parse a magnet URI and return an object of keys/values
 *
 * @param  {string} uri
 * @return {Object} parsed uri
 */
function magnetURIDecode (uri) {
  var result = {}
  var data = uri.split('magnet:?')[1]

  var params = (data && data.length >= 0)
    ? data.split('&')
    : []

  params.forEach(function (param) {
    var keyval = param.split('=')

    // This keyval is invalid, skip it
    if (keyval.length !== 2) return

    var key = keyval[0]
    var val = keyval[1]

    // Clean up torrent name
    if (key === 'dn') val = decodeURIComponent(val).replace(/\+/g, ' ')

    // Address tracker (tr), exact source (xs), and acceptable source (as) are encoded
    // URIs, so decode them
    if (key === 'tr' || key === 'xs' || key === 'as' || key === 'ws') {
      val = decodeURIComponent(val)
    }

    // Return keywords as an array
    if (key === 'kt') val = decodeURIComponent(val).split('+')

    // If there are repeated parameters, return an array of values
    if (result[key]) {
      if (Array.isArray(result[key])) {
        result[key].push(val)
      } else {
        var old = result[key]
        result[key] = [old, val]
      }
    } else {
      result[key] = val
    }
  })

  // Convenience properties for parity with `parse-torrent-file` module
  var m
  if (result.xt) {
    var xts = Array.isArray(result.xt) ? result.xt : [ result.xt ]
    xts.forEach(function (xt) {
      if ((m = xt.match(/^urn:btih:(.{40})/))) {
        result.infoHash = m[1].toLowerCase()
      } else if ((m = xt.match(/^urn:btih:(.{32})/))) {
        var decodedStr = base32.decode(m[1])
        result.infoHash = new Buffer(decodedStr, 'binary').toString('hex')
      }
    })
  }
  if (result.infoHash) result.infoHashBuffer = new Buffer(result.infoHash, 'hex')

  if (result.dn) result.name = result.dn
  if (result.kt) result.keywords = result.kt

  if (typeof result.tr === 'string') result.announce = [ result.tr ]
  else if (Array.isArray(result.tr)) result.announce = result.tr
  else result.announce = []

  uniq(result.announce)

  result.urlList = []
  if (typeof result.as === 'string' || Array.isArray(result.as)) {
    result.urlList = result.urlList.concat(result.as)
  }
  if (typeof result.ws === 'string' || Array.isArray(result.ws)) {
    result.urlList = result.urlList.concat(result.ws)
  }

  return result
}

function magnetURIEncode (obj) {
  obj = extend(obj) // clone obj, so we can mutate it

  // support using convenience names, in addition to spec names
  // (example: `infoHash` for `xt`, `name` for `dn`)
  if (obj.infoHashBuffer) obj.xt = 'urn:btih:' + obj.infoHashBuffer.toString('hex')
  if (obj.infoHash) obj.xt = 'urn:btih:' + obj.infoHash
  if (obj.name) obj.dn = obj.name
  if (obj.keywords) obj.kt = obj.keywords
  if (obj.announce) obj.tr = obj.announce
  if (obj.urlList) {
    obj.ws = obj.urlList
    delete obj.as
  }

  var result = 'magnet:?'
  Object.keys(obj)
    .filter(function (key) {
      return key.length === 2
    })
    .forEach(function (key, i) {
      var values = Array.isArray(obj[key]) ? obj[key] : [ obj[key] ]
      values.forEach(function (val, j) {
        if ((i > 0 || j > 0) && (key !== 'kt' || j === 0)) result += '&'

        if (key === 'dn') val = encodeURIComponent(val).replace(/%20/g, '+')
        if (key === 'tr' || key === 'xs' || key === 'as' || key === 'ws') {
          val = encodeURIComponent(val)
        }
        if (key === 'kt') val = encodeURIComponent(val)

        if (key === 'kt' && j > 0) result += '+' + val
        else result += key + '=' + val
      })
    })

  return result
}
<|endoftext|>


<commit_before>var request = require('superagent'),
    Q = require('q');

var METHOD_MAP = {
  'create': 'post',
  'update': 'put',
  'delete': 'del',
  'read': 'get',
  'patch': 'patch'
};

// Main exported sync function. Returns a Q promise to mimic Backbone + jQuery,
// if using the built in cache support it will check the cache for data or send
// off the HTTP request.
//
// @param {Function} method
// @param {Object} model
// @param {Object} options
// @return {Object} A Q promise to mimc how Backbone work with jQuery

module.exports = function(method, model, options) {
  var cacheKey = urlDataCacheKey(method, model, options)[2];
  var deferred = Q.defer();
  if (options.cache && module.exports.cacheClient) {
    module.exports.cacheClient.get(cacheKey, function(err, cachedJSON) {
      if (err || cachedJSON) model.trigger('request', model, {}, options);
      if (err) {
        error(options, err, deferred.reject);
      } else if (cachedJSON) {
        success(options, JSON.parse(cachedJSON), deferred.resolve);
      } else {
        send(method, model, options, deferred.resolve, deferred.reject);
      }
    });
  } else {
    send(method, model, options, deferred.resolve, deferred.reject);
  }
  return deferred.promise.fin(function() {
    deferred = null;
  });
};

// Helper to compute the requesting url, params, and cache key based off those
// two. Used when sending a new http request or determing the cache key to read.
//
// @param {Function} method
// @param {Object} model
// @param {Object} options
// @return {Array} Array of [url, data, cacheKey]

var urlDataCacheKey = function(method, model, options) {
  var url = (options.url ||
    (typeof model.url == 'function' ? model.url() : model.url));
  var data = (options.data ||
    (method === 'create' || method === 'update' ? model.toJSON(options) : {}));
  var cacheKey = url + JSON.stringify(data);
  return [url, data, cacheKey];
}

// Builds and sends the actual http request. This reflects the guts of the
// default Backbone.sync logic.
//
// @param {Function} method
// @param {Object} model
// @param {Object} options
// @param {Function} resolve Deferred resolve
// @param {Function} reject  Deferred reject

var send = function (method, model, options, resolve, reject) {
  var url = urlDataCacheKey(method, model, options)[0];
  var data = urlDataCacheKey(method, model, options)[1];
  var cacheKey = urlDataCacheKey(method, model, options)[2];

  // Allow intercepting of the request object to inject sync-wide things like
  // an oAuth token.
  // module.exports.editRequest(req, method, model, options);
  request[METHOD_MAP[method]](url)
    .send(method == 'create' || method == 'update' ? data : null)
    .query(method == 'create' || method == 'update' ? null : data)
    .set(options.headers || {})
    .timeout(options.timeout || module.exports.timeout)
    .end(function(err, res) {
      if (err || !res.ok) return error(options, (err || res), reject);
      if (options.cache && module.exports.cacheClient) {
        module.exports.cacheClient.set(cacheKey, JSON.stringify({
          body: res.body,
          headers: res.headers
        }));
        module.exports.cacheClient.expire(cacheKey,
          (options.cacheTime || module.exports.defaultCacheTime));
      }
      success(options, res, resolve);
    });
  model.trigger('request', model, {});
}

// DRYs up resolving the callbacks and deferreds for a successful response,
// whether that's from the cache or a resolved http request.
//
// @param {Object} options Backbone options
// @param {Object} res A response object with { body: {}, headers: {} }
// @param {Function} resolve Deferred resolve

var success = function(options, res, resolve) {
  options.res = { headers: res.headers };
  if (options.success) options.success(res.body);
  if (options.complete) options.complete(res.body);
  resolve(res.body);
}

// DRYs up resolving the callbacks and deferreds for an unsuccessful response,
// whether that's from the cache or a resolved http request.
//
// @param {Object} options Backbone options
// @param {Object} err
// @param {Function} reject  Deferred reject

var error = function(options, err, reject) {
  if (options.error) options.error(err);
  if (options.complete) options.complete(err);
  reject(err);
}

// Configuration that can be overwritten by the user. Includes being able
// to modify the request, a cache client library, default cache expiry, and
// the default timeout for a sent http request.

module.exports.editRequest = function(req) {};
module.exports.cacheClient = null;
module.exports.defaultCacheTime = 3600;
module.exports.timeout = 2000;
<commit_msg>cleanup<commit_after>var request = require('superagent'),
    Q = require('q');

var METHOD_MAP = {
  'create': 'post',
  'update': 'put',
  'delete': 'del',
  'read': 'get',
  'patch': 'patch'
};

// Main exported sync function. Returns a Q promise to mimic Backbone + jQuery,
// if using the built in cache support it will check the cache for data or send
// off the HTTP request.
//
// @param {Function} method
// @param {Object} model
// @param {Object} options
// @return {Object} A Q promise to mimc how Backbone work with jQuery

module.exports = function(method, model, options) {
  var cacheKey = urlDataCacheKey(method, model, options)[2];
  var deferred = Q.defer();
  if (options.cache && module.exports.cacheClient) {
    module.exports.cacheClient.get(cacheKey, function(err, cachedJSON) {
      if (err || cachedJSON) model.trigger('request', model, {}, options);
      if (err) {
        error(options, err, deferred.reject);
      } else if (cachedJSON) {
        success(options, JSON.parse(cachedJSON), deferred.resolve);
      } else {
        send(method, model, options, deferred.resolve, deferred.reject);
      }
    });
  } else {
    send(method, model, options, deferred.resolve, deferred.reject);
  }
  return deferred.promise.fin(function() {
    deferred = null;
  });
};

// Helper to compute the requesting url, params, and cache key based off those
// two. Used when sending a new http request or determing the cache key to read.
//
// @param {Function} method
// @param {Object} model
// @param {Object} options
// @return {Array} Array of [url, data, cacheKey]

var urlDataCacheKey = function(method, model, options) {
  var url = (options.url ||
    (typeof model.url == 'function' ? model.url() : model.url));
  var data = (options.data ||
    (method === 'create' || method === 'update' ? model.toJSON(options) : {}));
  var cacheKey = url + JSON.stringify(data);
  return [url, data, cacheKey];
}

// Builds and sends the actual http request. This reflects the guts of the
// default Backbone.sync logic.
//
// @param {Function} method
// @param {Object} model
// @param {Object} options
// @param {Function} resolve Deferred resolve
// @param {Function} reject  Deferred reject

var send = function (method, model, options, resolve, reject) {
  var url = urlDataCacheKey(method, model, options)[0];
  var data = urlDataCacheKey(method, model, options)[1];
  var cacheKey = urlDataCacheKey(method, model, options)[2];

  // Allow intercepting of the request object to inject sync-wide things like
  // an oAuth token.
  request[METHOD_MAP[method]](url)
    .send(method == 'create' || method == 'update' ? data : null)
    .query(method == 'create' || method == 'update' ? null : data)
    .set(options.headers || {})
    .timeout(options.timeout || module.exports.timeout)
    .end(function(err, res) {
      if (err || !res.ok) return error(options, (err || res), reject);
      if (options.cache && module.exports.cacheClient) {
        module.exports.cacheClient.set(cacheKey, JSON.stringify({
          body: res.body,
          headers: res.headers
        }));
        module.exports.cacheClient.expire(cacheKey,
          (options.cacheTime || module.exports.defaultCacheTime));
      }
      success(options, res, resolve);
    });
  model.trigger('request', model, {});
}

// DRYs up resolving the callbacks and deferreds for a successful response,
// whether that's from the cache or a resolved http request.
//
// @param {Object} options Backbone options
// @param {Object} res A response object with { body: {}, headers: {} }
// @param {Function} resolve Deferred resolve

var success = function(options, res, resolve) {
  options.res = { headers: res.headers };
  if (options.success) options.success(res.body);
  if (options.complete) options.complete(res.body);
  resolve(res.body);
}

// DRYs up resolving the callbacks and deferreds for an unsuccessful response,
// whether that's from the cache or a resolved http request.
//
// @param {Object} options Backbone options
// @param {Object} err
// @param {Function} reject  Deferred reject

var error = function(options, err, reject) {
  if (options.error) options.error(err);
  if (options.complete) options.complete(err);
  reject(err);
}

// Configuration that can be overwritten by the user. Includes a optional
// cache client library integration, default cache expiry, and
// the default timeout for a sent http request.

module.exports.cacheClient = null;
module.exports.defaultCacheTime = 3600;
module.exports.timeout = 2000;
<|endoftext|>


<commit_before>/**
 * Isomorphic, functional type-checking for Javascript.
 * @module typical
 * @typicalname t
 * @example
 * const t = require('typical')
 * const allDefined = array.every(t.isDefined)
 */

/**
 * Returns true if input is a number (including infinity). It is a more reasonable alternative to `typeof n` which returns `number` for `NaN`.
 *
 * @param {*} n the input to test
 * @returns {boolean} - true if input is a number
 * @static
 * @example
 * > t.isNumber(0)
 * true
 * > t.isNumber(1)
 * true
 * > t.isNumber(1.1)
 * true
 * > t.isNumber(0xff)
 * true
 * > t.isNumber(0644)
 * true
 * > t.isNumber(6.2e5)
 * true
 * > t.isNumber(NaN)
 * false
 * > t.isNumber(Infinity)
 * true
 */
export function isNumber (n) {
  return !isNaN(parseFloat(n))
}

/**
 * Returns true if input is a finite number. Identical to `isNumber` beside excluding infinity.
 *
 * @param {*} n the input to test
 * @returns {boolean}
 * @static
 * @example
 * > t.isFiniteNumber(0)
 * true
 * > t.isFiniteNumber(1)
 * true
 * > t.isFiniteNumber(1.1)
 * true
 * > t.isFiniteNumber(0xff)
 * true
 * > t.isFiniteNumber(0644)
 * true
 * > t.isFiniteNumber(6.2e5)
 * true
 * > t.isFiniteNumber(NaN)
 * false
 * > t.isFiniteNumber(Infinity)
 * false
 */
export function isFiniteNumber (n) {
  return !isNaN(parseFloat(n)) && isFinite(n)
}

/**
 * A plain object is a simple object literal, it is not an instance of a class. Returns true if the input `typeof` is `object` and directly decends from `Object`.
 *
 * @param {*} input the input to test
 * @returns {boolean}
 * @static
 * @example
 * > t.isPlainObject({ something: 'one' })
 * true
 * > t.isPlainObject(new Date())
 * false
 * > t.isPlainObject([ 0, 1 ])
 * false
 * > t.isPlainObject(/test/)
 * false
 * > t.isPlainObject(1)
 * false
 * > t.isPlainObject('one')
 * false
 * > t.isPlainObject(null)
 * false
 * > t.isPlainObject((function * () {})())
 * false
 * > t.isPlainObject(function * () {})
 * false
 */
export function isPlainObject (input) {
  return input !== null && typeof input === 'object' && input.constructor === Object
}

/**
 * An array-like value has all the properties of an array yet is not an array instance. An example is the `arguments` object. Returns `true`` if the input value is an object, not `null`` and has a `length` property set with a numeric value.
 *
 * @param {*} input the input to test
 * @returns {boolean}
 * @static
 * @example
 * function sum(x, y){
 *   console.log(t.isArrayLike(arguments))
 *   // prints `true`
 * }
 */
export function isArrayLike (input) {
  return isObject(input) && typeof input.length === 'number'
}

/**
 * Returns true if the typeof input is `'object'` but not null.
 * @param {*} input the input to test
 * @returns {boolean}
 * @static
 */
export function isObject (input) {
  return typeof input === 'object' && input !== null
}

/**
 * Returns true if the input value is defined.
 * @param {*} input the input to test
 * @returns {boolean}
 * @static
 */
export function isDefined (input) {
  return typeof input !== 'undefined'
}

/**
 * Returns true if the input value is undefined.
 * @param {*} input the input to test
 * @returns {boolean}
 * @static
 */
export function isUndefined (input) {
  return !isDefined(input)
}

/**
 * Returns true if the input value is null.
 * @param {*} input the input to test
 * @returns {boolean}
 * @static
 */
export function isNull (input) {
 return input === null
}

/**
 * Returns true if the input value is not one of `undefined`, `null`, or `NaN`.
 * @param {*} input the input to test
 * @returns {boolean}
 * @static
 */
export function isDefinedValue (input) {
 return isDefined(input) && !isNull(input) && !Number.isNaN(input)
}

/**
 * Returns true if the input value is an ES2015 `class`.
 * @param {*} input the input to test
 * @returns {boolean}
 * @static
 */
export function isClass (input) {
  if (typeof input === 'function') {
    return /^class /.test(Function.prototype.toString.call(input))
  } else {
    return false
  }
}

/**
 * Returns true if the input is a string, number, symbol, boolean, null or undefined value.
 * @param {*} input - The input to test
 * @returns {boolean}
 * @static
 */
export function isPrimitive (input) {
  if (input === null) return true
  switch (typeof input) {
    case 'string':
    case 'number':
    case 'symbol':
    case 'undefined':
    case 'boolean':
      return true
    default:
      return false
  }
}

/**
 * Returns true if the input is a Promise.
 * @param {*} input - The input to test
 * @returns {boolean}
 * @static
 */
export function isPromise (input) {
  if (input) {
    const isPromise = isDefined(Promise) && input instanceof Promise
    const isThenable = input.then && typeof input.then === 'function'
    return !!(isPromise || isThenable)
  } else {
    return false
  }
}

/**
 * Returns true if the input is an iterable (`Map`, `Set`, `Array`, Generator etc.).
 * @param {*} input - The input to test
 * @returns {boolean}
 * @static
 * @example
 * > t.isIterable('string')
 * true
 * > t.isIterable(new Map())
 * true
 * > t.isIterable([])
 * true
 * > t.isIterable((function * () {})())
 * true
 * > t.isIterable(Promise.resolve())
 * false
 * > t.isIterable(Promise)
 * false
 * > t.isIterable(true)
 * false
 * > t.isIterable({})
 * false
 * > t.isIterable(0)
 * false
 * > t.isIterable(1.1)
 * false
 * > t.isIterable(NaN)
 * false
 * > t.isIterable(Infinity)
 * false
 * > t.isIterable(function () {})
 * false
 * > t.isIterable(Date)
 * false
 * > t.isIterable()
 * false
 * > t.isIterable({ then: function () {} })
 * false
 */
export function isIterable (input) {
  if (input === null || !isDefined(input)) {
    return false
  } else {
    return (
      typeof input[Symbol.iterator] === 'function' ||
      typeof input[Symbol.asyncIterator] === 'function'
    )
  }
}

/**
 * Returns true if the input value is a string. The equivalent of `typeof input === 'string'` for use in funcitonal contexts.
 * @param {*} input - The input to test
 * @returns {boolean}
 * @static
 */
export function isString (input) {
  return typeof input === 'string'
}

/**
 * Returns true if the input value is a function. The equivalent of `typeof input === 'function'` for use in funcitonal contexts.
 * @param {*} input - The input to test
 * @returns {boolean}
 * @static
 */
export function isFunction (input) {
  return typeof input === 'function'
}

export default {
  isNumber,
  isFiniteNumber,
  isPlainObject,
  isArrayLike,
  isObject,
  isDefined,
  isUndefined,
  isNull,
  isDefinedValue,
  isClass,
  isPrimitive,
  isPromise,
  isIterable,
  isString,
  isFunction
}
<commit_msg>use -<commit_after>/**
 * Isomorphic, functional type-checking for Javascript.
 * @module typical
 * @typicalname t
 * @example
 * const t = require('typical')
 * const allDefined = array.every(t.isDefined)
 */

/**
 * Returns true if input is a number (including infinity). It is a more reasonable alternative to `typeof n` which returns `number` for `NaN`.
 *
 * @param {*} n - The input to test
 * @returns {boolean} - true if input is a number
 * @static
 * @example
 * > t.isNumber(0)
 * true
 * > t.isNumber(1)
 * true
 * > t.isNumber(1.1)
 * true
 * > t.isNumber(0xff)
 * true
 * > t.isNumber(0644)
 * true
 * > t.isNumber(6.2e5)
 * true
 * > t.isNumber(NaN)
 * false
 * > t.isNumber(Infinity)
 * true
 */
export function isNumber (n) {
  return !isNaN(parseFloat(n))
}

/**
 * Returns true if input is a finite number. Identical to `isNumber` beside excluding infinity.
 *
 * @param {*} n - The input to test
 * @returns {boolean}
 * @static
 * @example
 * > t.isFiniteNumber(0)
 * true
 * > t.isFiniteNumber(1)
 * true
 * > t.isFiniteNumber(1.1)
 * true
 * > t.isFiniteNumber(0xff)
 * true
 * > t.isFiniteNumber(0644)
 * true
 * > t.isFiniteNumber(6.2e5)
 * true
 * > t.isFiniteNumber(NaN)
 * false
 * > t.isFiniteNumber(Infinity)
 * false
 */
export function isFiniteNumber (n) {
  return !isNaN(parseFloat(n)) && isFinite(n)
}

/**
 * A plain object is a simple object literal, it is not an instance of a class. Returns true if the input `typeof` is `object` and directly decends from `Object`.
 *
 * @param {*} input - The input to test
 * @returns {boolean}
 * @static
 * @example
 * > t.isPlainObject({ something: 'one' })
 * true
 * > t.isPlainObject(new Date())
 * false
 * > t.isPlainObject([ 0, 1 ])
 * false
 * > t.isPlainObject(/test/)
 * false
 * > t.isPlainObject(1)
 * false
 * > t.isPlainObject('one')
 * false
 * > t.isPlainObject(null)
 * false
 * > t.isPlainObject((function * () {})())
 * false
 * > t.isPlainObject(function * () {})
 * false
 */
export function isPlainObject (input) {
  return input !== null && typeof input === 'object' && input.constructor === Object
}

/**
 * An array-like value has all the properties of an array yet is not an array instance. An example is the `arguments` object. Returns `true`` if the input value is an object, not `null`` and has a `length` property set with a numeric value.
 *
 * @param {*} input - The input to test
 * @returns {boolean}
 * @static
 * @example
 * function sum(x, y){
 *   console.log(t.isArrayLike(arguments))
 *   // prints `true`
 * }
 */
export function isArrayLike (input) {
  return isObject(input) && typeof input.length === 'number'
}

/**
 * Returns true if the typeof input is `'object'` but not null.
 * @param {*} input - The input to test
 * @returns {boolean}
 * @static
 */
export function isObject (input) {
  return typeof input === 'object' && input !== null
}

/**
 * Returns true if the input value is defined.
 * @param {*} input - The input to test
 * @returns {boolean}
 * @static
 */
export function isDefined (input) {
  return typeof input !== 'undefined'
}

/**
 * Returns true if the input value is undefined.
 * @param {*} input the input to test
 * @returns {boolean}
 * @static
 */
export function isUndefined (input) {
  return !isDefined(input)
}

/**
 * Returns true if the input value is null.
 * @param {*} input the input to test
 * @returns {boolean}
 * @static
 */
export function isNull (input) {
 return input === null
}

/**
 * Returns true if the input value is not one of `undefined`, `null`, or `NaN`.
 * @param {*} input the input to test
 * @returns {boolean}
 * @static
 */
export function isDefinedValue (input) {
 return isDefined(input) && !isNull(input) && !Number.isNaN(input)
}

/**
 * Returns true if the input value is an ES2015 `class`.
 * @param {*} input the input to test
 * @returns {boolean}
 * @static
 */
export function isClass (input) {
  if (typeof input === 'function') {
    return /^class /.test(Function.prototype.toString.call(input))
  } else {
    return false
  }
}

/**
 * Returns true if the input is a string, number, symbol, boolean, null or undefined value.
 * @param {*} input - The input to test
 * @returns {boolean}
 * @static
 */
export function isPrimitive (input) {
  if (input === null) return true
  switch (typeof input) {
    case 'string':
    case 'number':
    case 'symbol':
    case 'undefined':
    case 'boolean':
      return true
    default:
      return false
  }
}

/**
 * Returns true if the input is a Promise.
 * @param {*} input - The input to test
 * @returns {boolean}
 * @static
 */
export function isPromise (input) {
  if (input) {
    const isPromise = isDefined(Promise) && input instanceof Promise
    const isThenable = input.then && typeof input.then === 'function'
    return !!(isPromise || isThenable)
  } else {
    return false
  }
}

/**
 * Returns true if the input is an iterable (`Map`, `Set`, `Array`, Generator etc.).
 * @param {*} input - The input to test
 * @returns {boolean}
 * @static
 * @example
 * > t.isIterable('string')
 * true
 * > t.isIterable(new Map())
 * true
 * > t.isIterable([])
 * true
 * > t.isIterable((function * () {})())
 * true
 * > t.isIterable(Promise.resolve())
 * false
 * > t.isIterable(Promise)
 * false
 * > t.isIterable(true)
 * false
 * > t.isIterable({})
 * false
 * > t.isIterable(0)
 * false
 * > t.isIterable(1.1)
 * false
 * > t.isIterable(NaN)
 * false
 * > t.isIterable(Infinity)
 * false
 * > t.isIterable(function () {})
 * false
 * > t.isIterable(Date)
 * false
 * > t.isIterable()
 * false
 * > t.isIterable({ then: function () {} })
 * false
 */
export function isIterable (input) {
  if (input === null || !isDefined(input)) {
    return false
  } else {
    return (
      typeof input[Symbol.iterator] === 'function' ||
      typeof input[Symbol.asyncIterator] === 'function'
    )
  }
}

/**
 * Returns true if the input value is a string. The equivalent of `typeof input === 'string'` for use in funcitonal contexts.
 * @param {*} input - The input to test
 * @returns {boolean}
 * @static
 */
export function isString (input) {
  return typeof input === 'string'
}

/**
 * Returns true if the input value is a function. The equivalent of `typeof input === 'function'` for use in funcitonal contexts.
 * @param {*} input - The input to test
 * @returns {boolean}
 * @static
 */
export function isFunction (input) {
  return typeof input === 'function'
}

export default {
  isNumber,
  isFiniteNumber,
  isPlainObject,
  isArrayLike,
  isObject,
  isDefined,
  isUndefined,
  isNull,
  isDefinedValue,
  isClass,
  isPrimitive,
  isPromise,
  isIterable,
  isString,
  isFunction
}
<|endoftext|>


<commit_before>var defaultToWhiteSpace, escapeRegExp, ltrim, makeString, parseFile, parseFileFallback, trimLeft;

module.exports = function(input) {
  var add, chunk, current, del, deleted_file, eof, file, files, from_file, index, j, len, line, lines, ln_add, ln_del, new_file, normal, parse, restart, schema, start, to_file;
  if (!input) {
    return [];
  }
  if (input.match(/^\s+$/)) {
    return [];
  }
  lines = input.split('\n');
  if (lines.length === 0) {
    return [];
  }
  files = [];
  file = null;
  ln_del = 0;
  ln_add = 0;
  current = null;
  start = function(line) {
    var fileNames;
    file = {
      chunks: [],
      deletions: 0,
      additions: 0
    };
    files.push(file);
    if (!file.to && !file.from) {
      fileNames = parseFile(line);
      if (fileNames) {
        file.from = fileNames[0];
        return file.to = fileNames[1];
      }
    }
  };
  restart = function() {
    if (!file || file.chunks.length) {
      return start();
    }
  };
  new_file = function() {
    restart();
    file["new"] = true;
    return file.from = '/dev/null';
  };
  deleted_file = function() {
    restart();
    file.deleted = true;
    return file.to = '/dev/null';
  };
  index = function(line) {
    restart();
    return file.index = line.split(' ').slice(1);
  };
  from_file = function(line) {
    restart();
    return file.from = parseFileFallback(line);
  };
  to_file = function(line) {
    restart();
    return file.to = parseFileFallback(line);
  };
  chunk = function(line, match) {
    var newLines, newStart, oldLines, oldStart;
    ln_del = oldStart = +match[1];
    oldLines = +(match[2] || 0);
    ln_add = newStart = +match[3];
    newLines = +(match[4] || 0);
    current = {
      content: line,
      changes: [],
      oldStart: oldStart,
      oldLines: oldLines,
      newStart: newStart,
      newLines: newLines
    };
    return file.chunks.push(current);
  };
  del = function(line) {
    current.changes.push({
      type: 'del',
      del: true,
      ln: ln_del++,
      content: line
    });
    return file.deletions++;
  };
  add = function(line) {
    current.changes.push({
      type: 'add',
      add: true,
      ln: ln_add++,
      content: line
    });
    return file.additions++;
  };
  normal = function(line) {
    return current.changes.push({
      type: 'normal',
      normal: true,
      ln1: ln_del++,
      ln2: ln_add++,
      content: line
    });
  };
  eof = function(line) {
    var obj, recentChange, ref;
    ref = current.changes, recentChange = ref[ref.length - 1];
    return current.changes.push((
      obj = {
        type: recentChange.type
      },
      obj["" + recentChange.type] = true,
      obj.ln1 = recentChange.ln1,
      obj.ln2 = recentChange.ln2,
      obj.ln = recentChange.ln,
      obj.content = line,
      obj
    ));
  };
  schema = [[/^\s+/, normal], [/^diff\s/, start], [/^new file mode \d+$/, new_file], [/^deleted file mode \d+$/, deleted_file], [/^index\s[\da-zA-Z]+\.\.[\da-zA-Z]+(\s(\d+))?$/, index], [/^---\s/, from_file], [/^\+\+\+\s/, to_file], [/^@@\s+\-(\d+),?(\d+)?\s+\+(\d+),?(\d+)?\s@@/, chunk], [/^-/, del], [/^\+/, add], [/^\\ No newline at end of file$/, eof]];
  parse = function(line) {
    var j, len, m, p;
    for (j = 0, len = schema.length; j < len; j++) {
      p = schema[j];
      m = line.match(p[0]);
      if (m) {
        p[1](line, m);
        return true;
      }
    }
    return false;
  };
  for (j = 0, len = lines.length; j < len; j++) {
    line = lines[j];
    parse(line);
  }
  return files;
};

parseFile = function(s) {
  var fileNames;
  if (!s) {
    return;
  }
  fileNames = s.split(' ').slice(-2);
  fileNames.map(function(fileName, i) {
    return fileNames[i] = fileName.replace(/^(a|b)\//, '');
  });
  return fileNames;
};

parseFileFallback = function(s) {
  var t;
  s = ltrim(s, '-');
  s = ltrim(s, '+');
  s = s.trim();
  t = /\t.*|\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d(.\d+)?\s(\+|-)\d\d\d\d/.exec(s);
  if (t) {
    s = s.substring(0, t.index).trim();
  }
  if (s.match(/^(a|b)\//)) {
    return s.substr(2);
  } else {
    return s;
  }
};

ltrim = function(s, chars) {
  s = makeString(s);
  if (!chars && trimLeft) {
    return trimLeft.call(s);
  }
  chars = defaultToWhiteSpace(chars);
  return s.replace(new RegExp('^' + chars + '+'), '');
};

makeString = function(s) {
  if (s === null) {
    return '';
  } else {
    return s + '';
  }
};

trimLeft = String.prototype.trimLeft;

defaultToWhiteSpace = function(chars) {
  if (chars === null) {
    return '\\s';
  }
  if (chars.source) {
    return chars.source;
  }
  return '[' + escapeRegExp(chars) + ']';
};

escapeRegExp = function(s) {
  return makeString(s).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
};
<commit_msg>recompile<commit_after>// parses unified diff
// http://www.gnu.org/software/diffutils/manual/diffutils.html#Unified-Format
var defaultToWhiteSpace, escapeRegExp, ltrim, makeString, parseFile, parseFileFallback, trimLeft;

module.exports = function(input) {
  var add, chunk, current, del, deleted_file, eof, file, files, from_file, index, j, len, line, lines, ln_add, ln_del, new_file, normal, parse, restart, schema, start, to_file;
  if (!input) {
    return [];
  }
  if (input.match(/^\s+$/)) {
    return [];
  }
  lines = input.split('\n');
  if (lines.length === 0) {
    return [];
  }
  files = [];
  file = null;
  ln_del = 0;
  ln_add = 0;
  current = null;
  start = function(line) {
    var fileNames;
    file = {
      chunks: [],
      deletions: 0,
      additions: 0
    };
    files.push(file);
    if (!file.to && !file.from) {
      fileNames = parseFile(line);
      if (fileNames) {
        file.from = fileNames[0];
        return file.to = fileNames[1];
      }
    }
  };
  restart = function() {
    if (!file || file.chunks.length) {
      return start();
    }
  };
  new_file = function() {
    restart();
    file.new = true;
    return file.from = '/dev/null';
  };
  deleted_file = function() {
    restart();
    file.deleted = true;
    return file.to = '/dev/null';
  };
  index = function(line) {
    restart();
    return file.index = line.split(' ').slice(1);
  };
  from_file = function(line) {
    restart();
    return file.from = parseFileFallback(line);
  };
  to_file = function(line) {
    restart();
    return file.to = parseFileFallback(line);
  };
  chunk = function(line, match) {
    var newLines, newStart, oldLines, oldStart;
    ln_del = oldStart = +match[1];
    oldLines = +(match[2] || 0);
    ln_add = newStart = +match[3];
    newLines = +(match[4] || 0);
    current = {
      content: line,
      changes: [],
      oldStart,
      oldLines,
      newStart,
      newLines
    };
    return file.chunks.push(current);
  };
  del = function(line) {
    current.changes.push({
      type: 'del',
      del: true,
      ln: ln_del++,
      content: line
    });
    return file.deletions++;
  };
  add = function(line) {
    current.changes.push({
      type: 'add',
      add: true,
      ln: ln_add++,
      content: line
    });
    return file.additions++;
  };
  normal = function(line) {
    return current.changes.push({
      type: 'normal',
      normal: true,
      ln1: ln_del++,
      ln2: ln_add++,
      content: line
    });
  };
  eof = function(line) {
    var recentChange, ref;
    ref = current.changes, recentChange = ref[ref.length - 1];
    return current.changes.push({
      type: recentChange.type,
      [`${recentChange.type}`]: true,
      ln1: recentChange.ln1,
      ln2: recentChange.ln2,
      ln: recentChange.ln,
      content: line
    });
  };
  // todo beter regexp to avoid detect normal line starting with diff
  schema = [[/^\s+/, normal], [/^diff\s/, start], [/^new file mode \d+$/, new_file], [/^deleted file mode \d+$/, deleted_file], [/^index\s[\da-zA-Z]+\.\.[\da-zA-Z]+(\s(\d+))?$/, index], [/^---\s/, from_file], [/^\+\+\+\s/, to_file], [/^@@\s+\-(\d+),?(\d+)?\s+\+(\d+),?(\d+)?\s@@/, chunk], [/^-/, del], [/^\+/, add], [/^\\ No newline at end of file$/, eof]];
  parse = function(line) {
    var j, len, m, p;
    for (j = 0, len = schema.length; j < len; j++) {
      p = schema[j];
      m = line.match(p[0]);
      if (m) {
        p[1](line, m);
        return true;
      }
    }
    return false;
  };
  for (j = 0, len = lines.length; j < len; j++) {
    line = lines[j];
    parse(line);
  }
  return files;
};

parseFile = function(s) {
  var fileNames;
  if (!s) {
    return;
  }
  fileNames = s.split(' ').slice(-2);
  fileNames.map(function(fileName, i) {
    return fileNames[i] = fileName.replace(/^(a|b)\//, '');
  });
  return fileNames;
};

// fallback function to overwrite file.from and file.to if executed
parseFileFallback = function(s) {
  var t;
  s = ltrim(s, '-');
  s = ltrim(s, '+');
  s = s.trim();
  // ignore possible time stamp
  t = /\t.*|\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d(.\d+)?\s(\+|-)\d\d\d\d/.exec(s);
  if (t) {
    s = s.substring(0, t.index).trim();
  }
  // ignore git prefixes a/ or b/
  if (s.match(/^(a|b)\//)) {
    return s.substr(2);
  } else {
    return s;
  }
};

ltrim = function(s, chars) {
  s = makeString(s);
  if (!chars && trimLeft) {
    return trimLeft.call(s);
  }
  chars = defaultToWhiteSpace(chars);
  return s.replace(new RegExp('^' + chars + '+'), '');
};

makeString = function(s) {
  if (s === null) {
    return '';
  } else {
    return s + '';
  }
};

trimLeft = String.prototype.trimLeft;

defaultToWhiteSpace = function(chars) {
  if (chars === null) {
    return '\\s';
  }
  if (chars.source) {
    return chars.source;
  }
  return '[' + escapeRegExp(chars) + ']';
};

escapeRegExp = function(s) {
  return makeString(s).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
};
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');
var gutil = require('gulp-util');
var through = require('through2');

module.exports = function(opts) {
  opts = opts || {};
  if (!opts.dict) {
    throw new gutil.PluginError('gulp-replace-ids', 'Dictionary isn\'t specified');
  }

  var dict = opts.dict;
  var pattern = new RegExp(opts.pattern || '{{\ *([a-zA-Z0-9_-]+)\* }}', "g");

  return through.obj(function(file, enc, cb) {
    if (file.isNull()) {
      this.push(file);
      return cb();
    }

    if (file.isStream()) {
      this.emit('error', new gutil.PluginError('gulp-replace-ids', 'Streams not supported!'));
      return cb();
    }

    function replace(dict) {
      var contents = file.contents.toString('utf8');

      contents = contents.replace(pattern, function(m, p1) {
        return dict[p1] || p1;
      });

      file.contents = new Buffer(contents);
      this.push(file);
    }

    if (typeof dict === 'string') {
      fs.readFile(dict, function(err, data) {
        if (err) {
          this.emit('error', new gutil.PluginError('gulp-replace-ids', 'gulp-replace-ids failed: ' + err, {
            fileName: file.path
          }));
          return cb();
        }

        replace(JSON.parse(data));
        cb();
      }.bind(this));
    } else {
      if (dict === void 0) {
        dict = {};
      }
      replace(dict);
      cb();
    }
  });
};
<commit_msg>Refactor replace function<commit_after>'use strict';

var fs = require('fs');
var gutil = require('gulp-util');
var through = require('through2');

module.exports = function(opts) {
  opts = opts || {};
  if (!opts.dict) {
    throw new gutil.PluginError('gulp-replace-ids', 'Dictionary isn\'t specified');
  }

  var dict = opts.dict;
  var pattern = new RegExp(opts.pattern || '{{\ *([a-zA-Z0-9_-]+)\* }}', "g");

  return through.obj(function(file, enc, cb) {
    if (file.isNull()) {
      this.push(file);
      return cb();
    }

    if (file.isStream()) {
      this.emit('error', new gutil.PluginError('gulp-replace-ids', 'Streams not supported!'));
      return cb();
    }

    function replace(file, dict) {
      var contents = file.contents.toString('utf8');

      contents = contents.replace(pattern, function(m, p1) {
        return dict[p1] || p1;
      });

      return file.clone({contents: new Buffer(contents)});
    }

    if (typeof dict === 'string') {
      fs.readFile(dict, function(err, data) {
        if (err) {
          this.emit('error', new gutil.PluginError('gulp-replace-ids', 'gulp-replace-ids failed: ' + err, {
            fileName: file.path
          }));
          return cb();
        }

        this.push(replace(file, JSON.parse(data)));
        cb();
      }.bind(this));
    } else {
      if (dict === void 0) {
        dict = {};
      }
      this.push(replace(file, dict));
      cb();
    }
  });
};
<|endoftext|>


<commit_before>/*
 *  Copyright 2013 David Farrell
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

var fs = require('fs')
var util = require('util')
var parser = require('./parser')
var SL = require('./bindings')

var Fn = function(ins, outs, code)
{
    this.type = 'function'
    this.ins = ins
    this.outs = outs
    this.code = code
    this.toString = function() { return '[shockklang Fn]' }
}

var BindingFn = function(fn)
{
    this.type = 'function'
    this.fn = fn
    this.is_binding = true
    this.toString = function() { return '[shockklang Fn]' }
}

var state =
{
    scope: [{}],
}

state.top = function()
{
    return this.scope[this.scope.length - 1]
}

state.get = function(name)
{
    for(var i=this.scope.length-1; i>0; --i)
    {
        if(this.scope[i][name] !== undefined) return this.scope[i][name]
    }
    return this.scope[0][name]
}

state.find = function(name)
{
    for(var i=this.scope.length-1; i>0; --i)
    {
        if(this.scope[i][name] !== undefined) return this.scope[i]
    }
    return this.top()
}

state.bind_function = function(fn, name)
{
    state.scope[0][name] = new BindingFn(fn)
}

state.binding_call = function(fn, paramlist)
{
    if(paramlist === undefined) paramlist = []

    if(paramlist.length < fn.length - 1)
        throw new Error('not enough params')

    if(paramlist.length > fn.length - 1)
        console.log('\x1B[1m\x1B[33m-> warning <-\x1B[0m too many params, truncating')

    // evaluate each param in the param list
    var params = paramlist.map(function(v, k, a)
    {
        return state.evaluate(v)
    }).slice(0, fn.length - 1)

    var result = fn.apply(state.top(), [state].concat(params))
    return result !== undefined ? result : '[shockklang undefined]'
}

state.call = function(fn, paramlist)
{
    if(fn.is_binding) return state.binding_call(fn.fn, paramlist)

    if(paramlist === undefined) paramlist = []

    if(paramlist.length < fn.ins.length)
        throw new Error('not enough params')

    if(paramlist.length > fn.ins.length)
        console.log('\x1B[1m\x1B[33m-> warning <-\x1B[0m too many params, truncating')

    // evaluate each param in the param list
    var params = paramlist.map(function(v, k, a)
    {
        return state.evaluate(v)
    }).slice(0, fn.ins.length)

    var scope = {}

    // put inputs into function scope
    var i = 0
    for(var k in fn.ins)
    {
        scope[fn.ins[k].data] = params[i++]
    }

    // set initial values of outputs
    for(var k in fn.outs)
    {
        fn.last_outputs === undefined
        ? scope[fn.outs[k].identifier.data] = state.evaluate(fn.outs[k].initial)
        : scope[fn.outs[k].identifier.data] = fn.last_outputs[fn.outs[k].identifier.data]
    }

    state.scope.push(scope)

    // evaluate each statement in function code
    for(var i=0; i<fn.code.length; ++i)
    {
        state.evaluate(fn.code[i])

        if(state.function_ahead === true)
        {
            state.function_ahead = false
            break
        }
    }

    // get outputs from function scope
    fn.last_outputs = {}
    var outputs = fn.outs.map(function(v, k, a)
    {
        fn.last_outputs[v.identifier.data] = state.get(v.identifier.data)
        return state.get(v.identifier.data)
    })

    state.scope.pop()

    switch(outputs.length)
    {
        case 0: return undefined
        case 1: return outputs[0]
        default: return outputs
    }
}

state.set = function(name, value)
{
    if(name === undefined) return '[shockklang undefined]'

    switch(name.type)
    {
        case 'identifier':
            return (state.find()[name.data] = value)
        case 'PropertyAccess':
            var arr = state.evaluate(name.base)
            var index = state.evaluate(name.name)

            if(index === '') arr.push(value)
            else arr.members[index] = value

            return value
        default: console.log('assignable type unhandled: ' + name.type)
    }
}

state.evaluate = function(obj, eval_identifier)
{
    switch(typeof obj)
    {
        case 'object': break
        case 'undefined': return '[shockklang undefined]'
        default: return obj.toString()
    }

    switch(obj.type)
    {
        case '=':
            return state.set(obj.left, state.evaluate(obj.right))
        case '+':
            return state.evaluate(obj.left).binaryOp(state.evaluate(obj.right), function(one, two)
            {
                return one + two
            })
        case '-':
            return state.evaluate(obj.left).binaryOp(state.evaluate(obj.right), function(one, two)
            {
                return one - two
            })
        case '*':
            return state.evaluate(obj.left).binaryOp(state.evaluate(obj.right), function(one, two)
            {
                return one * two
            })
        case '&':
            return state.evaluate(obj.left).binaryOp(state.evaluate(obj.right), function(one, two)
            {
                return one & two
            })
        case '|':
            return state.evaluate(obj.left).binaryOp(state.evaluate(obj.right), function(one, two)
            {
                return one | two
            })
        case '<<':
            return state.evaluate(obj.left).binaryOp(state.evaluate(obj.right), function(one, two)
            {
                return one << two
            })
        case '>>':
            return state.evaluate(obj.left).binaryOp(state.evaluate(obj.right), function(one, two)
            {
                return one >> two
            })
        case '==':
            return state.evaluate(obj.left).binaryOp(state.evaluate(obj.right), function(one, two)
            {
                return one == two ? 1 : 0
            })
        case 'number':
            return new SL.Types.SLNumber(obj.data)
        case 'string':
            return new SL.Types.SLString(obj.data)
        case 'identifier':
            return eval_identifier === false
                 ? obj.data
                 : state.get(obj.data)
        case 'array':
            return new SL.Types.SLArray(obj.members.map(state.evaluate))
        case 'PropertyAccess':
            var arr = state.evaluate(obj.base)
            var index = state.evaluate(obj.name, false)

            if(index === '') var ret = arr.members[arr.members.length - 1]
            else var ret = arr.members[index]

            return ret !== undefined ? ret : '[shockklang undefined]'
        case 'conditional':
            for(var i=0; i<obj.data.length; ++i)
            {
                var condition = obj.data[i].condition === undefined
                              ? true
                              : state.evaluate(obj.data[i].condition)

                if(condition.data !== 0)
                {
                    var result
                    obj.data[i].code.forEach(function(v, k, a)
                    {
                        result = state.evaluate(v)
                    })
                    return result
                }
            }
            return undefined
        case 'function':
            return new Fn(obj.ins, obj.outs, obj.code)
        case 'call':
        case 'anoncall':
            if(obj.type === 'call') var fn = state.get(obj.identifier.data)
            else var fn = obj.fn

            if(fn === undefined)
                throw new Error('identifier `' + obj.identifier.data + '` is undefined')

            if(fn.type !== 'function')
                throw new Error('identifier `' + obj.identifier.data + '` is not a function')

            var result
            obj.paramlists.forEach(function(v, k, a)
            {
                result = state.call(fn, v)
            })
            fn.last_outputs = undefined
            delete fn.last_outputs

            return result !== undefined ? result : '[shockklang undefined]'
        case 'function_ahead':
            state.function_ahead = true
            return
        case 'infix':
            throw new Error('infix not implemented')
        default:
            if(obj.type !== undefined) console.log('type unhandled: ' + obj.type)
            else                       console.log('type missing: ' + util.inspect(obj[0]))
            break
        // TODO: implement scope for blocks too
    }
}

// load and bind all function bindings
var bindings = require('./bindings')
for(var k in bindings) state.bind_function(bindings[k], k)

var filename = process.argv[2]
fs.readFile(filename, function(err, data)
{
    if(err) throw err
    try
    {
        parser.parse(data.toString()).forEach(function(v, k, a)
        {
            state.evaluate(v)
        })
    }
    catch(e)
    {
        if(e.name === 'SyntaxError')
        {
            console.log(e.line + ':' + e.column + ' syntax error at `' + e.found + '`')
        }
        else throw e
    }
})
<commit_msg>Added support for calling JS functions in addition to wrapped JS functions.<commit_after>/*
 *  Copyright 2013 David Farrell
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

var fs = require('fs')
var util = require('util')
var parser = require('./parser')
var SL = require('./bindings')

var Fn = function(ins, outs, code)
{
    this.type = 'function'
    this.ins = ins
    this.outs = outs
    this.code = code
    this.toString = function() { return '[shockklang Fn]' }
}

var BindingFn = function(fn)
{
    this.type = 'function'
    this.fn = fn
    this.is_binding = true
    this.toString = function() { return '[shockklang Fn]' }
}

var state =
{
    scope: [{}],
}

state.top = function()
{
    return this.scope[this.scope.length - 1]
}

state.get = function(name)
{
    for(var i=this.scope.length-1; i>0; --i)
    {
        if(this.scope[i][name] !== undefined) return this.scope[i][name]
    }
    return this.scope[0][name]
}

state.find = function(name)
{
    for(var i=this.scope.length-1; i>0; --i)
    {
        if(this.scope[i][name] !== undefined) return this.scope[i]
    }
    return this.top()
}

state.bind_function = function(fn, name)
{
    state.scope[0][name] = new BindingFn(fn)
}

state.binding_call = function(fn, paramlist)
{
    if(paramlist === undefined) paramlist = []

    if(paramlist.length < fn.length - 1)
        throw new Error('not enough params')

    if(paramlist.length > fn.length - 1)
        console.log('\x1B[1m\x1B[33m-> warning <-\x1B[0m too many params, truncating')

    // evaluate each param in the param list
    var params = paramlist.map(function(v, k, a)
    {
        return state.evaluate(v)
    }).slice(0, fn.length - 1)

    var result = fn.apply(state.top(), [state].concat(params))
    return result !== undefined ? result : '[shockklang undefined]'
}

state.call = function(fn, paramlist)
{
    if(fn.is_binding) return state.binding_call(fn.fn, paramlist)
    if(typeof fn === 'function') return state.binding_call(fn, paramlist)

    if(paramlist === undefined) paramlist = []

    if(paramlist.length < fn.ins.length)
        throw new Error('not enough params')

    if(paramlist.length > fn.ins.length)
        console.log('\x1B[1m\x1B[33m-> warning <-\x1B[0m too many params, truncating')

    // evaluate each param in the param list
    var params = paramlist.map(function(v, k, a)
    {
        return state.evaluate(v)
    }).slice(0, fn.ins.length)

    var scope = {}

    // put inputs into function scope
    var i = 0
    for(var k in fn.ins)
    {
        scope[fn.ins[k].data] = params[i++]
    }

    // set initial values of outputs
    for(var k in fn.outs)
    {
        fn.last_outputs === undefined
        ? scope[fn.outs[k].identifier.data] = state.evaluate(fn.outs[k].initial)
        : scope[fn.outs[k].identifier.data] = fn.last_outputs[fn.outs[k].identifier.data]
    }

    state.scope.push(scope)

    // evaluate each statement in function code
    for(var i=0; i<fn.code.length; ++i)
    {
        state.evaluate(fn.code[i])

        if(state.function_ahead === true)
        {
            state.function_ahead = false
            break
        }
    }

    // get outputs from function scope
    fn.last_outputs = {}
    var outputs = fn.outs.map(function(v, k, a)
    {
        fn.last_outputs[v.identifier.data] = state.get(v.identifier.data)
        return state.get(v.identifier.data)
    })

    state.scope.pop()

    switch(outputs.length)
    {
        case 0: return undefined
        case 1: return outputs[0]
        default: return outputs
    }
}

state.set = function(name, value)
{
    if(name === undefined) return '[shockklang undefined]'

    switch(name.type)
    {
        case 'identifier':
            return (state.find()[name.data] = value)
        case 'PropertyAccess':
            var arr = state.evaluate(name.base)
            var index = state.evaluate(name.name)

            if(index === '') arr.push(value)
            else arr.members[index] = value

            return value
        default: console.log('assignable type unhandled: ' + name.type)
    }
}

state.evaluate = function(obj, eval_identifier)
{
    switch(typeof obj)
    {
        case 'object': break
        case 'undefined': return '[shockklang undefined]'
        default: return obj.toString()
    }

    switch(obj.type)
    {
        case '=':
            return state.set(obj.left, state.evaluate(obj.right))
        case '+':
            return state.evaluate(obj.left).binaryOp(state.evaluate(obj.right), function(one, two)
            {
                return one + two
            })
        case '-':
            return state.evaluate(obj.left).binaryOp(state.evaluate(obj.right), function(one, two)
            {
                return one - two
            })
        case '*':
            return state.evaluate(obj.left).binaryOp(state.evaluate(obj.right), function(one, two)
            {
                return one * two
            })
        case '&':
            return state.evaluate(obj.left).binaryOp(state.evaluate(obj.right), function(one, two)
            {
                return one & two
            })
        case '|':
            return state.evaluate(obj.left).binaryOp(state.evaluate(obj.right), function(one, two)
            {
                return one | two
            })
        case '<<':
            return state.evaluate(obj.left).binaryOp(state.evaluate(obj.right), function(one, two)
            {
                return one << two
            })
        case '>>':
            return state.evaluate(obj.left).binaryOp(state.evaluate(obj.right), function(one, two)
            {
                return one >> two
            })
        case '==':
            return state.evaluate(obj.left).binaryOp(state.evaluate(obj.right), function(one, two)
            {
                return one == two ? 1 : 0
            })
        case 'number':
            return new SL.Types.SLNumber(obj.data)
        case 'string':
            return new SL.Types.SLString(obj.data)
        case 'SLString': return obj
        case 'identifier':
            return eval_identifier === false
                 ? obj.data
                 : state.get(obj.data)
        case 'array':
            return new SL.Types.SLArray(obj.members.map(state.evaluate))
        case 'PropertyAccess':
            var arr = state.evaluate(obj.base)
            var index = state.evaluate(obj.name, false)

            if(index === '') var ret = arr.members[arr.members.length - 1]
            else var ret = arr.members[index]

            return ret !== undefined ? ret : '[shockklang undefined]'
        case 'conditional':
            for(var i=0; i<obj.data.length; ++i)
            {
                var condition = obj.data[i].condition === undefined
                              ? true
                              : state.evaluate(obj.data[i].condition)

                if(condition.data !== 0)
                {
                    var result
                    obj.data[i].code.forEach(function(v, k, a)
                    {
                        result = state.evaluate(v)
                    })
                    return result
                }
            }
            return undefined
        case 'function':
            return new Fn(obj.ins, obj.outs, obj.code)
        case 'call':
        case 'anoncall':
            if(obj.type === 'call') var fn = state.evaluate(obj.identifier)
            else var fn = obj.fn

            if(fn === undefined)
                throw new Error('identifier `' + obj.identifier.data + '` is undefined')

            if(fn.type !== 'function' && typeof fn !== 'function')
                throw new Error('identifier `' + obj.identifier.data + '` is not a function')

            var result
            obj.paramlists.forEach(function(v, k, a)
            {
                result = state.call(fn, v)
            })
            fn.last_outputs = undefined
            delete fn.last_outputs

            return result !== undefined ? result : '[shockklang undefined]'
        case 'function_ahead':
            state.function_ahead = true
            return
        case 'infix':
            throw new Error('infix not implemented')
        default:
            if(obj.type !== undefined) console.log('type unhandled: ' + obj.type)
            else                       console.log('type missing: ' + util.inspect(obj[0]))
            break
        // TODO: implement scope for blocks too
    }
}

// load and bind all function bindings
var bindings = require('./bindings')
for(var k in bindings) state.bind_function(bindings[k], k)

var filename = process.argv[2]
fs.readFile(filename, function(err, data)
{
    if(err) throw err
    try
    {
        parser.parse(data.toString()).forEach(function(v, k, a)
        {
            state.evaluate(v)
        })
    }
    catch(e)
    {
        if(e.name === 'SyntaxError')
        {
            console.log(e.line + ':' + e.column + ' syntax error at `' + e.found + '`')
        }
        else throw e
    }
})
<|endoftext|>


<commit_before>var service = require('./lib/service'),
    async = require('async'),
    joi = require("joi"),
    schema = require("./lib/schema"),
    _ = require('underscore');

var config = {};

var validateOptions = function(){
  var result = joi.validate(options, schema);
  if(result.error){
    throw result.error;
  }

  return result.value;
};

exports.register = function(plugin, options, next){
    plugin.log(["service-status"], "validating monitors");
    config = validateOptions(options);

    plugin.log(["service-status"], "registering service-status routes");
    plugin.route([
            {
                method: "GET",
                path: "/service-status",
                config: {
                    handler: function(request, reply) {
                        service.run(request.server, config.monitors[config.default || 0], function(result){
                            reply([result]);
                        });
                    }
                }
            },
            {
                method: "GET",
                path: "/service-status/all",
                config: {
                    handler: function(request, reply) {
                        var results = [];

                        var sendRequest = function(item, done){
                            service.run(request.server, item, function(result){
                                results.push(result);
                                done();
                            });
                        };

                        async.forEach(config.monitors, sendRequest, function(){
                            reply(results);
                        });
                    }
                }
            },
            {
                method: "GET",
                path: "/service-status/{monitorname}",
                config: {
                    handler: function(request, reply) {

                        var monitor = _.find(config.monitors, function(m){ return m.monitorname === request.params.monitorname; });

                        if(!monitor){
                            reply("Unknown monitor name: " + request.params.monitorname).code(404);
                            return;
                        }

                        service.run(request.server, monitor, function(result){
                            reply(result).code(200);
                        });
                    }
                }
            }
    ]);

    plugin.expose('selfTest', function(server, cb){
      service.selfTest(server, config.monitors, cb);
    });

    next();
};

exports.register.attributes = {
    pkg: require('./package.json')
};
<commit_msg>add missing function param<commit_after>var service = require('./lib/service'),
    async = require('async'),
    joi = require("joi"),
    schema = require("./lib/schema"),
    _ = require('underscore');

var config = {};

var validateOptions = function(options){
  var result = joi.validate(options, schema);
  if(result.error){
    throw result.error;
  }

  return result.value;
};

exports.register = function(plugin, options, next){
    plugin.log(["service-status"], "validating monitors");
    config = validateOptions(options);

    plugin.log(["service-status"], "registering service-status routes");
    plugin.route([
            {
                method: "GET",
                path: "/service-status",
                config: {
                    handler: function(request, reply) {
                        service.run(request.server, config.monitors[config.default || 0], function(result){
                            reply([result]);
                        });
                    }
                }
            },
            {
                method: "GET",
                path: "/service-status/all",
                config: {
                    handler: function(request, reply) {
                        var results = [];

                        var sendRequest = function(item, done){
                            service.run(request.server, item, function(result){
                                results.push(result);
                                done();
                            });
                        };

                        async.forEach(config.monitors, sendRequest, function(){
                            reply(results);
                        });
                    }
                }
            },
            {
                method: "GET",
                path: "/service-status/{monitorname}",
                config: {
                    handler: function(request, reply) {

                        var monitor = _.find(config.monitors, function(m){ return m.monitorname === request.params.monitorname; });

                        if(!monitor){
                            reply("Unknown monitor name: " + request.params.monitorname).code(404);
                            return;
                        }

                        service.run(request.server, monitor, function(result){
                            reply(result).code(200);
                        });
                    }
                }
            }
    ]);

    plugin.expose('selfTest', function(server, cb){
      service.selfTest(server, config.monitors, cb);
    });

    next();
};

exports.register.attributes = {
    pkg: require('./package.json')
};
<|endoftext|>


<commit_before>'use strict';

const Swagger = require('swagger-client');

class SwaggerPromisify extends Swagger {

  constructor(options) {

    const original = Object.assign({}, options);

    options.success = () => {

      this._promisify();

      if(typeof original.success === 'function')
        original.success();

    };

    super(options);

  }

  _promisify() {

    Object.keys(this.apis).forEach(api => {

      if(api === 'help')
        return;

      Object.keys(this.apis[api].operations).forEach(operation => {

        const original = this[api][operation].bind(this);

        // TODO: replace with fat arrow & ...args once node.js has the ES6 spead operator
        this[api][operation] = function() {

          const args = Array.prototype.slice.call(arguments);

          return new Promise((resolve, reject) => {

            args.push(response => resolve(response));
            args.push(response => reject(response));

            original.apply(this, args);

          });

        }.bind(this);

      });

    });

  }

}

exports = module.exports = SwaggerPromisify;
<commit_msg>adds at least one arg to operation to fix swagger-client bug<commit_after>'use strict';

const Swagger = require('swagger-client');

class SwaggerPromisify extends Swagger {

  constructor(options) {

    const original = Object.assign({}, options);

    options.success = () => {

      this._promisify();

      if(typeof original.success === 'function')
        original.success();

    };

    super(options);

  }

  _promisify() {

    Object.keys(this.apis).forEach(api => {

      if(api === 'help')
        return;

      Object.keys(this.apis[api].operations).forEach(operation => {

        const original = this[api][operation].bind(this);

        // TODO: replace with fat arrow & ...args once node.js has the ES6 spead operator
        this[api][operation] = function() {

          const args = Array.prototype.slice.call(arguments);

          if(! args.length)
            args.push(null);

          return new Promise((resolve, reject) => {

            args.push(response => resolve(response));
            args.push(response => reject(response));

            original.apply(this, args);

          });

        }.bind(this);

      });

    });

  }

}

exports = module.exports = SwaggerPromisify;
<|endoftext|>