<commit_before>const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const env = process.env.NAME;

module.exports = {
  devtool: 'source-map',
  target: 'electron-renderer',
  mode: env,

  entry: [
    path.join(__dirname, '../src/renderer/index.js'),
  ],

  output: {
    path: path.join(__dirname, '../app'),
    filename: 'renderer.js',
  },

  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      },
      {
        test: /\.scss$/,
        use: [
          {
            loader: 'style-loader',
          },
          {
            loader: 'css-loader',
            options: {
              modules: true,
            },
          },
          {
            loader: 'sass-loader',
          },
        ],
      },
      {
        test: /\.png$/,
        use: {
          loader: 'url-loader',
        },
      },
    ],
  },

  plugins: [
    new webpack.NoEmitOnErrorsPlugin(),
    new HtmlWebpackPlugin({
      template: path.join(__dirname, '../src/renderer/index.html'),
    }),
  ],

  devServer: {
    historyApiFallback: true,
  },
};
<commit_msg>fix(webpack-dev-server): make it possible to reload at sub path<commit_after>const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const env = process.env.NAME;

module.exports = {
  devtool: 'source-map',
  target: 'electron-renderer',
  mode: env,

  entry: [
    path.join(__dirname, '../src/renderer/index.js'),
  ],

  output: {
    path: path.join(__dirname, '../app'),
    filename: 'renderer.js',
  },

  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      },
      {
        test: /\.scss$/,
        use: [
          {
            loader: 'style-loader',
          },
          {
            loader: 'css-loader',
            options: {
              modules: true,
            },
          },
          {
            loader: 'sass-loader',
          },
        ],
      },
      {
        test: /\.png$/,
        use: {
          loader: 'url-loader',
        },
      },
    ],
  },

  plugins: [
    new webpack.NoEmitOnErrorsPlugin(),
    new HtmlWebpackPlugin({
      template: path.join(__dirname, '../src/renderer/index.html'),
    }),
  ],

  devServer: {
    historyApiFallback: {
      index: './app/index.html'
    },
  },
};
<|endoftext|>


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

'use strict';

const async = require('async');
const ms = require('ms');
const storj = require('storj-lib');
const program = require('commander');
const Config = require('../lib/config');
const Storage = require('storj-service-storage-models');
const complex = require('storj-complex');

program.version(require('../package').version);
program.option('-c, --config <path_to_config_file>', 'path to the config file');
program.option('-d, --datadir <path_to_datadir>', 'path to the data directory');
program.parse(process.argv);

const NOW = Date.now();
const HOURS_24 = ms('24h');

const logger = require('kad-logger-json')(0);
const config = new Config(process.env.NODE_ENV || 'develop', program.config,
                          program.datadir);
const { mongoUrl, mongoOpts } = config.storage;
const storage = new Storage(mongoUrl, mongoOpts, { logger });
const network = complex.createClient(config.complex);
const cursor = storage.models.Shard.find({
  'contracts.contract.store_end': {
    $gte: NOW,
    $lte: NOW + HOURS_24
  }
}).cursor();
const counter = { processed: 0, renewed: 0, errored: 0 };

cursor
  .on('error', handleCursorError)
  .on('data', handleCursorData)
  .on('end', handleCursorClose);

/**
 * Prints the error and continues processing cursor
 * @function
 * @param {error} error
 */
function handleCursorError(err) {
  process.stderr.write(JSON.stringify({ error: err.message }));
  process.exit(1);
}

/**
 * Prints close event + cleanup + report
 * @function
 */
function handleCursorClose() {
  process.stdout.write(JSON.stringify(counter));
  process.exit();
}

/**
 * Inspects the contract to ensure it's still valid and in use
 * If the end time is within 24 hours, renew it for another 3 months
 * @function
 * @param {object} shard
 */
function handleCursorData(shard) {
  let needsRenewal = [];

  cursor.pause();

  for (let contractInfo of shard.contracts) {
    let { contract: contractObj, nodeID } = contractInfo;
    let contract = new storj.Contract(contractObj);
    let willExpireNext24 = (contract.get('store_end') - HOURS_24) <= NOW;

    if (willExpireNext24) {
      needsRenewal.push([nodeID, contract]);
    }
  }

  let renewalContracts = needsRenewal.map(([nodeId, contract]) => {
    contract.set('store_begin', NOW);
    contract.set('store_end', NOW + ms('90d'));

    return [nodeId, contract];
  });

  async.map(renewalContracts, lookupFarmer, maybeRenewContracts);
}

function lookupFarmer([nodeId, contract], next) {
  storage.models.Contact.findOne({ _id: nodeId }, (err, contact) => {
    if (err || !contact) {
      counter.errored++;
      return next(null, null);
    }

    next(null , [storj.Contact(contact.toObject()), contract]);
  });
}

function maybeRenewContracts(err, results) {
  let canBeRenewed = results.filter((result) => !!result);

  async.eachLimit(canBeRenewed, 6, checkIfNeedsRenew,
                  () => cursor.resume());
}

function finishProcessingContract(done) {
  counter.processed++;
  done();
}

function checkIfNeedsRenew([contact, contract], done) {
  let shardHash = contract.get('data_hash');

  async.waterfall(
    [
      (next) => getPointerObjects(shardHash, next),
      (pointers, next) => getAssociatedFrames(pointers, next),
      (frames, next) => getParentBucketEntries(frames, next),
      (entries, next) => renewContract([contact, contract], entries, next)
    ],
    () => finishProcessingContract(done)
  );
}

function getPointerObjects(shardHash, next) {
  storage.models.Pointer.find({ hash: shardHash }, (err, pointers) => {
    next(err || pointers.length === 0, pointers);
  });
}

function getAssociatedFrames(pointers, next) {
  storage.models.Frame.find({
    shards: {
      $in: pointers.map((pointer) => pointer._id)
    }
  }, (err, frames) => {
    next(err || frames.length === 0, frames);
  });
}

function getParentBucketEntries(frames, next) {
  storage.models.BucketEntry.find({
    frame: {
      $in: frames.map((frame) => frame._id)
    }
  }, (err, entries) => {
    next(err || entries.length === 0, entries);
  });
}

function updateContractRecord(contact, contract, next) {
  storage.models.Shard.findOne({
    hash: contract.get('data_hash')
  }, function(err, shard) {
    if (err) {
      return next(err);
    }

    for (let contract of shard.contracts) {
      if (contract.nodeID !== contact.nodeID) {
        continue;
      }

      contract.contract = contract.toObject();
    }

    shard.save(next);
  });
}

function renewContract([contact, contract], entries, next) {
  network.renewContract(contract, contact, (err) => {
    if (err) {
      counter.errored++;
      next();
    } else {
      counter.renewed++;
      updateContractRecord(contact, contract, next);
    }
  });
}
<commit_msg>remove extraneous check<commit_after>#!/usr/bin/env node

'use strict';

const async = require('async');
const ms = require('ms');
const storj = require('storj-lib');
const program = require('commander');
const Config = require('../lib/config');
const Storage = require('storj-service-storage-models');
const complex = require('storj-complex');

program.version(require('../package').version);
program.option('-c, --config <path_to_config_file>', 'path to the config file');
program.option('-d, --datadir <path_to_datadir>', 'path to the data directory');
program.parse(process.argv);

const NOW = Date.now();
const HOURS_24 = ms('24h');

const logger = require('kad-logger-json')(0);
const config = new Config(process.env.NODE_ENV || 'develop', program.config,
                          program.datadir);
const { mongoUrl, mongoOpts } = config.storage;
const storage = new Storage(mongoUrl, mongoOpts, { logger });
const network = complex.createClient(config.complex);
const cursor = storage.models.Shard.find({
  'contracts.contract.store_end': {
    $gte: NOW,
    $lte: NOW + HOURS_24
  }
}).cursor();
const counter = { processed: 0, renewed: 0, errored: 0 };

cursor
  .on('error', handleCursorError)
  .on('data', handleCursorData)
  .on('end', handleCursorClose);

/**
 * Prints the error and continues processing cursor
 * @function
 * @param {error} error
 */
function handleCursorError(err) {
  process.stderr.write(JSON.stringify({ error: err.message }));
  process.exit(1);
}

/**
 * Prints close event + cleanup + report
 * @function
 */
function handleCursorClose() {
  process.stdout.write(JSON.stringify(counter));
  process.exit();
}

/**
 * Inspects the contract to ensure it's still valid and in use
 * If the end time is within 24 hours, renew it for another 3 months
 * @function
 * @param {object} shard
 */
function handleCursorData(shard) {
  let needsRenewal = [];

  cursor.pause();

  for (let contractInfo of shard.contracts) {
    let { contract: contractObj, nodeID } = contractInfo;
    let contract = new storj.Contract(contractObj);

    needsRenewal.push([nodeID, contract]);
  }

  let renewalContracts = needsRenewal.map(([nodeId, contract]) => {
    contract.set('store_begin', NOW);
    contract.set('store_end', NOW + ms('90d'));

    return [nodeId, contract];
  });

  async.map(renewalContracts, lookupFarmer, maybeRenewContracts);
}

function lookupFarmer([nodeId, contract], next) {
  storage.models.Contact.findOne({ _id: nodeId }, (err, contact) => {
    if (err || !contact) {
      counter.errored++;
      return next(null, null);
    }

    next(null , [storj.Contact(contact.toObject()), contract]);
  });
}

function maybeRenewContracts(err, results) {
  let canBeRenewed = results.filter((result) => !!result);

  async.eachLimit(canBeRenewed, 6, checkIfNeedsRenew,
                  () => cursor.resume());
}

function finishProcessingContract(done) {
  counter.processed++;
  done();
}

function checkIfNeedsRenew([contact, contract], done) {
  let shardHash = contract.get('data_hash');

  async.waterfall(
    [
      (next) => getPointerObjects(shardHash, next),
      (pointers, next) => getAssociatedFrames(pointers, next),
      (frames, next) => getParentBucketEntries(frames, next),
      (entries, next) => renewContract([contact, contract], entries, next)
    ],
    () => finishProcessingContract(done)
  );
}

function getPointerObjects(shardHash, next) {
  storage.models.Pointer.find({ hash: shardHash }, (err, pointers) => {
    next(err || pointers.length === 0, pointers);
  });
}

function getAssociatedFrames(pointers, next) {
  storage.models.Frame.find({
    shards: {
      $in: pointers.map((pointer) => pointer._id)
    }
  }, (err, frames) => {
    next(err || frames.length === 0, frames);
  });
}

function getParentBucketEntries(frames, next) {
  storage.models.BucketEntry.find({
    frame: {
      $in: frames.map((frame) => frame._id)
    }
  }, (err, entries) => {
    next(err || entries.length === 0, entries);
  });
}

function updateContractRecord(contact, contract, next) {
  storage.models.Shard.findOne({
    hash: contract.get('data_hash')
  }, function(err, shard) {
    if (err) {
      return next(err);
    }

    for (let contract of shard.contracts) {
      if (contract.nodeID !== contact.nodeID) {
        continue;
      }

      contract.contract = contract.toObject();
    }

    shard.save(next);
  });
}

function renewContract([contact, contract], entries, next) {
  network.renewContract(contract, contact, (err) => {
    if (err) {
      counter.errored++;
      next();
    } else {
      counter.renewed++;
      updateContractRecord(contact, contract, next);
    }
  });
}
<|endoftext|>


<commit_before>/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 *
*/

// Tries to load all plugins' js-modules.
// This is an async process, but onDeviceReady is blocked on onPluginsReady.
// onPluginsReady is fired when there are no plugins to load, or they are all done.
(function (context) {
    // To be populated with the handler by handlePluginsObject.
    var onScriptLoadingComplete;

    var scriptCounter = 0;
    function scriptLoadedCallback() {
        scriptCounter--;
        if (scriptCounter === 0) {
            onScriptLoadingComplete && onScriptLoadingComplete();
        }
    }

    // Helper function to inject a <script> tag.
    function injectScript(path) {
        scriptCounter++;
        var script = document.createElement("script");
        script.onload = scriptLoadedCallback;
        script.src = path;
        document.head.appendChild(script);
    }

    // Called when:
    // * There are plugins defined and all plugins are finished loading.
    // * There are no plugins to load.
    function finishPluginLoading() {
        context.cordova.require('cordova/channel').onPluginsReady.fire();
    }

    // Handler for the cordova_plugins.json content.
    // See plugman's plugin_loader.js for the details of this object.
    // This function is only called if the really is a plugins array that isn't empty.
    // Otherwise the XHR response handler will just call finishPluginLoading().
    function handlePluginsObject(modules, path) {
        // First create the callback for when all plugins are loaded.
        var mapper = context.cordova.require('cordova/modulemapper');
        onScriptLoadingComplete = function() {
            // Loop through all the plugins and then through their clobbers and merges.
            for (var i = 0; i < modules.length; i++) {
                var module = modules[i];
                if (!module) continue;

                if (module.clobbers && module.clobbers.length) {
                    for (var j = 0; j < module.clobbers.length; j++) {
                        mapper.clobbers(module.id, module.clobbers[j]);
                    }
                }

                if (module.merges && module.merges.length) {
                    for (var k = 0; k < module.merges.length; k++) {
                        mapper.merges(module.id, module.merges[k]);
                    }
                }

                // Finally, if runs is truthy we want to simply require() the module.
                // This can be skipped if it had any merges or clobbers, though,
                // since the mapper will already have required the module.
                if (module.runs && !(module.clobbers && module.clobbers.length) && !(module.merges && module.merges.length)) {
                    context.cordova.require(module.id);
                }
            }

            finishPluginLoading();
        };

        // Now inject the scripts.
        for (var i = 0; i < modules.length; i++) {
            injectScript(path + modules[i].file);
        }
    }

    // Find the root of the app
    var path = '';
    var scripts = document.getElementsByTagName('script');
    var term = 'cordova.js';
    for (var n = scripts.length-1; n>-1; n--) {
        var src = scripts[n].src;
        if (src.indexOf(term) == (src.length - term.length)) {
            path = src.substring(0, src.length - term.length);
            break;
        }
    }
    // Try to XHR the cordova_plugins.json file asynchronously.
    var xhr = new XMLHttpRequest();
    xhr.onload = function() {
        // If the response is a JSON string which composes an array, call handlePluginsObject.
        // If the request fails, or the response is not a JSON array, just call finishPluginLoading.
        var obj;
        try {
            obj = (this.status == 0 || this.status == 200) && this.responseText && JSON.parse(this.responseText);
        } catch (err) {
            // obj will be undefined.
        }
        if (Array.isArray(obj) && obj.length > 0) {
            handlePluginsObject(obj, path);
        } else {
            finishPluginLoading();
        }
    };
    xhr.onerror = function() {
        finishPluginLoading();
    };
    var plugins_json = path + 'cordova_plugins.json';
    try { // we commented we were going to try, so let us actually try and catch
        xhr.open('GET', plugins_json, true); // Async
        xhr.send();
    } catch(err){
        finishPluginLoading();
    }
}(window));

<commit_msg>Testing non-xhr loader with Fil<commit_after>/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 *
*/

// Tries to load all plugins' js-modules.
// This is an async process, but onDeviceReady is blocked on onPluginsReady.
// onPluginsReady is fired when there are no plugins to load, or they are all done.
(function (context) {
    // To be populated with the handler by handlePluginsObject.
    var onScriptLoadingComplete;

    var scriptCounter = 0;
    function scriptLoadedCallback() {
        scriptCounter--;
        if (scriptCounter === 0) {
            onScriptLoadingComplete && onScriptLoadingComplete();
        }
    }

    // Helper function to inject a <script> tag.
    function injectScript(path) {
        scriptCounter++;
        var script = document.createElement("script");
        script.onload = scriptLoadedCallback;
        script.src = path;
        document.head.appendChild(script);
    }

    // Called when:
    // * There are plugins defined and all plugins are finished loading.
    // * There are no plugins to load.
    function finishPluginLoading() {
        context.cordova.require('cordova/channel').onPluginsReady.fire();
    }

    // Handler for the cordova_plugins.json content.
    // See plugman's plugin_loader.js for the details of this object.
    // This function is only called if the really is a plugins array that isn't empty.
    // Otherwise the XHR response handler will just call finishPluginLoading().
    function handlePluginsObject(modules, path) {
        // First create the callback for when all plugins are loaded.
        var mapper = context.cordova.require('cordova/modulemapper');
        onScriptLoadingComplete = function() {
            // Loop through all the plugins and then through their clobbers and merges.
            for (var i = 0; i < modules.length; i++) {
                var module = modules[i];
                if (!module) continue;

                if (module.clobbers && module.clobbers.length) {
                    for (var j = 0; j < module.clobbers.length; j++) {
                        mapper.clobbers(module.id, module.clobbers[j]);
                    }
                }

                if (module.merges && module.merges.length) {
                    for (var k = 0; k < module.merges.length; k++) {
                        mapper.merges(module.id, module.merges[k]);
                    }
                }

                // Finally, if runs is truthy we want to simply require() the module.
                // This can be skipped if it had any merges or clobbers, though,
                // since the mapper will already have required the module.
                if (module.runs && !(module.clobbers && module.clobbers.length) && !(module.merges && module.merges.length)) {
                    context.cordova.require(module.id);
                }
            }

            finishPluginLoading();
        };

        // Now inject the scripts.
        for (var i = 0; i < modules.length; i++) {
            injectScript(path + modules[i].file);
        }
    }

    // Find the root of the app
    var path = '';
    var scripts = document.getElementsByTagName('script');
    var term = 'cordova.js';
    for (var n = scripts.length-1; n>-1; n--) {
        var src = scripts[n].src;
        if (src.indexOf(term) == (src.length - term.length)) {
            path = src.substring(0, src.length - term.length);
            break;
        }
    }

    // // Try to XHR the cordova_plugins.json file asynchronously.
    // var xhr = new XMLHttpRequest();
    // xhr.onload = function() {
    //     // If the response is a JSON string which composes an array, call handlePluginsObject.
    //     // If the request fails, or the response is not a JSON array, just call finishPluginLoading.
    //     var obj;
    //     try {
    //         obj = (this.status == 0 || this.status == 200) && this.responseText && JSON.parse(this.responseText);
    //     } catch (err) {
    //         // obj will be undefined.
    //     }
    //     if (Array.isArray(obj) && obj.length > 0) {
    //         handlePluginsObject(obj, path);
    //     } else {
    //         finishPluginLoading();
    //     }
    // };
    // xhr.onerror = function() {
    //     finishPluginLoading();
    // };

    var plugins_js = path + 'cordova_plugins.js';
    try { // we commented we were going to try, so let us actually try and catch
        //xhr.open('GET', plugins_json, true); // Async
        //xhr.send();
        var script = document.createElement("script");
        script.onload = function(){
            var list = cordova.require("cordova/plugin_list");
            handlePluginsObject(list,path);

        };
        script.src = plugins_js;
        document.head.appendChild(script);

    } catch(err){
        finishPluginLoading();
    }
}(window));

<|endoftext|>


<commit_before>/**
 * Created by vedi on 09/02/15.
 */
'use strict';

var _ = require('lodash');
var HTTP_STATUSES = require('http-statuses');

class SequelizeDataSource {
  constructor(ModelClass) {
    this.ModelClass = ModelClass;

    this.defaultIdField = 'id';
    this.defaultArrayMethods = ['$addToSet', '$pop', '$push', '$pull'];
  }

  initialize (options) {
    this.idField = options.idField;
    this.fieldMap = options.fieldMap || {};
    this.modelFieldNames = options.modelFieldNames;
  }

  find(options) {
    var filter = options.filter;
    var fields = options.fields;
    var q = options.q;
    var qFields = options.qFields;
    var sort = options.sort;
    var limit = parseInt(options.limit, 10);
    var skip = parseInt(options.skip, 10);
    var queryPipe = options.queryPipe;

    this._normalizeFilter(filter, this.ModelClass);
    this._applyQ(q, qFields, filter);
    var query = {};

    query.attributes = this._normalizeFields(fields, filter, query);

    query.where = filter;

    if (sort) {
      query.order = [];
      _.forOwn(sort, (value, key) => {
        query.order.push([key, +value > 0 ? 'ASC' : 'DESC']);
      });
      //query.order = sort;
    }
    query.limit = limit;
    if (skip > 0) {
      query.offset = skip;
    }
    if (queryPipe) {
      queryPipe(query);
    }

    return this.ModelClass
      .findAll(query)
      .then((docs) => {
        return _.map(docs, (doc) => {
          return this.toObject(doc);
        });
      });
  }

  findOne(options) {
    var filter = options.filter;
    var fields = options.fields;
    var queryPipe = options.queryPipe;

    this._normalizeFilter(filter, this.ModelClass);

    var query = {};

    query.attributes = this._normalizeFields(fields, filter, query);

    query.where = filter;

    if (queryPipe) {
      queryPipe(query);
    }
    return this.ModelClass.findOne(query);
  }

  create(data) {
    return this.ModelClass.build(data);
  }

  save(doc) {
    return doc
      .save()
      .then((newDoc) => {
        var where = {};
        where[this.idField] = newDoc[this.idField];
        return this.findOne({filter: where, fields: this.fieldMap});
      });
  }

  remove(doc) {
    return doc
      .destroy()
      .then(() => {
        return doc;
      });
  }

  count(options) {
    var filter = options.filter;
    var q = options.q;
    var qFields = options.qFields;

    this._normalizeFilter(filter, this.ModelClass);
    this._applyQ(q, qFields, filter);

    var query = {};
    this._normalizeFields(this.modelFieldNames || this.getModelFieldNames(), filter, query); // for filtering by associations
    query.where = filter;

    query.limit = 1;

    // return this.ModelClass.count(query); -- count shows wrong results in some complex cases.
    return this.ModelClass
      .findAndCountAll(query)
      .then((result) => {
        return result.count;
      });
  }

  toObject(model) {
    return model.get({
      plain: true
    });
  }

  getFieldValue(model, fieldName) {
    return this._resolveProp(model, fieldName);
  }

  setFieldValue(model, fieldName, value) {
    this._setProp(model, fieldName, value);
  }

  proceedArrayMethod(source, methodName, fieldName, scope) {
    // TODO: Implement
    //// get sure we have an array
    //if (dest[fieldName] === undefined) {
    //  dest[fieldName] = [];
    //}
    //
    //if (methodName === '$addToSet') {
    //  dest[fieldName].addToSet(source);
    //} else if (methodName === '$pop') {
    //  if (source === 1) {
    //    dest[fieldName].pop();
    //  } else if (source === -1) {
    //    dest[fieldName].shift();
    //  } else {
    //    throw new Error('Illegal param value for $pop method');
    //  }
    //} else if (methodName === '$push') {
    //  dest[fieldName].push(source);
    //} else if (methodName === '$pull') {
    //  dest[fieldName].pull(source);
    //}
  }

  assignField(fieldName, scope) {
    var dest = scope.model;
    var source = scope.source;
    dest.set(fieldName, source[fieldName]);
  }

  getModelFieldNames() {
    return _.keys(this.ModelClass.rawAttributes);
  }

  parseError(err) {
    // TODO: Implement
    var result = {};
    if (err.name === 'SequelizeValidationError') {
      result.status = HTTP_STATUSES.BAD_REQUEST;
      result.details = err.errors;
    } else if (err.name === 'SequelizeUniqueConstraintError') {
      result.status = HTTP_STATUSES.BAD_REQUEST;
      result.message = err.message;
      result.details = {};
      _.each(err.errors, (error) => {
        result.details[error.path] = {path: error.path, type: error.type, value: error.value, message: error.message};
      });

      result.details = err.errors;
    }
    //else if (err.name == 'CastError') {
    //  result.status = HTTP_STATUSES.BAD_REQUEST;
    //  result.details = {};
    //  result.details[err.path] = {
    //    message: err.message,
    //    name: err.name,
    //    path: err.path,
    //    type: err.type,
    //    value: err.value
    //  };
    //  result.message = 'CastError';
    //}
    //else if (err.name == 'MongoError' && (err.code == 11000 || err.code == 11001)) { // E11000(1) duplicate key error index
    //  result.status = HTTP_STATUSES.BAD_REQUEST;
    //  result.details = err.err;
    //}
    //else if (err.name == 'VersionError') {
    //  result.status = HTTP_STATUSES.CONFLICT;
    //  result.details = err.message;
    //} else {
    //  return;
    //}
    else {
      // it's just for testing
      result.status = HTTP_STATUSES.BAD_REQUEST;
      result.details = err.message;
    }

    return result;
  }

  _applyQ(q, qFields, filter) {
    var qExpr = q ? this._buildQ(qFields, q) : undefined;
    if (!_.isUndefined(qExpr) && qExpr.length > 0) {
      filter.$or = qExpr;
    }
  }

  _buildQ(qFields, q) {
    return _.map(qFields, (field) => {
      var result = {};
      result[field] = { $like: '%' + q + '%' };
      return result;
    });
  }

  /**
   * @param fields
   * @param filter
   * @param query
   * @param filterDriven if set, `include`s will be created for filtered values only
   * @returns {*}
   * @private
   */
  _normalizeFields(fields, filter, query, filterDriven) {
    query.include = query.include || [];
    fields = this._resolveAssociations(this.ModelClass, this.fieldMap, fields, filter, query.include, filterDriven);

    if (!filterDriven && fields.indexOf(this.ModelClass.primaryKeyField) < 0) {
      fields.push(this.ModelClass.primaryKeyField);
    }

    return fields;
  }

  _resolveAssociations(ModelClass, fieldMap, fields, filter, include, filterDriven) {
    include = include || [];
    var fieldsToRemove = [];
    var filterToRemove = [];
    var result = _.map(fields, (field) => {
      var isObject = typeof(field) === 'object';
      var fieldName = isObject ? field.name : field;
      var fieldMeta = fieldMap && fieldMap[fieldName];
      var association = ModelClass.associations[fieldName];
      if (fieldMeta && association) {
        if (!filterDriven) {
          fieldsToRemove.push(fieldName);
        }

        var associationFields;
        var required;
        if (isObject && field.fields) {
          associationFields = field.fields;
          required = field.required;
        } else if (fieldMeta.fields) {
          associationFields = fieldMeta.fields;
          required = fieldMeta.required;
        } else {
          associationFields = [association.targetKey];
          required = undefined;
        }

        var filterValue = filter ? filter[fieldName] : undefined;

        var nestedInclude = [];

        associationFields = this._resolveAssociations(association.target, fieldMeta.fields, associationFields, filterValue, nestedInclude, filterDriven);

        var cleanFilterValue = filterValue ? _.transform(filterValue, (result, value, key) => {
          if (associationFields.indexOf(key) >= 0) {
            result[key] = value;
          }
          return result;
        }) : undefined;

        if (cleanFilterValue) {
          filterToRemove.push(fieldName);
        }

        if (!filterDriven || cleanFilterValue) {
          // put to include
          include.push({
            association: association,
            attributes: associationFields,
            include: nestedInclude,
            required: required,
            where: cleanFilterValue
          });
        }
      }
      return fieldName;
    });

    if (!filterDriven) {
      _.each(fieldsToRemove, (field) => {
        _.pull(result, field);
      });
    }

    _.each(filterToRemove, (filterItem) => {
      delete filter[filterItem];
    });

    return result;
  }

  _normalizeFilter(filter, root) {
    // TODO: Implement
    //_.forEach(_.keys(filter), function (key) {
    //  var path = root.schema.paths[key];
    //  // if it's an operator
    //  if (key.substr(0, 1) === '$') {
    //    // increase the level without changing the root
    //    this._normalizeFilter(filter[key], root);
    //  } else if (path) {
    //    var typeName = path.options.type.name;
    //    // it's embedded document
    //    if (!_.isUndefined(path.schema)) {
    //      this._normalizeFilter(filter[key], root.schema.paths[key]);
    //    } else if (typeName === 'ObjectId') {
    //      if (typeof(filter[key]) === 'string') {
    //        filter[key] = ObjectID(filter[key]);
    //      }
    //    } else if (typeName === 'Date') {
    //      if (typeof(filter[key]) === 'string') {
    //        filter[key] = new Date(filter[key]);
    //      }
    //      else if (typeof(filter[key]) === 'object') {
    //        _.forOwn(filter[key], function (value, innerKey) {
    //          if (typeof(value) === 'string') {
    //            filter[key][innerKey] = new Date(value);
    //          }
    //        });
    //      }
    //    }
    //  }
    //}, this);
  }

  _resolveProp(obj, stringPath) {
    stringPath = stringPath.replace(/\[(\w+)]/g, '.$1');  // convert indexes to properties
    stringPath = stringPath.replace(/^\./, '');           // strip a leading dot
    var pathArray = stringPath.split('.');
    while (pathArray.length) {
      var pathItem = pathArray.shift();
      if (pathItem in obj) {
        obj = obj[pathItem];
      } else {
        return;
      }
    }
    return obj;
  }

  _setProp(obj, stringPath, value) {
    stringPath = stringPath.replace(/\[(\w+)]/g, '.$1');  // convert indexes to properties
    stringPath = stringPath.replace(/^\./, '');           // strip a leading dot
    var pathArray = stringPath.split('.');
    while (pathArray.length - 1) {
      var pathItem = pathArray.shift();
      if (pathItem in obj) {
        obj = obj[pathItem];
      } else {
        return;
      }
    }
    return obj[pathArray.length ? pathArray[0] : stringPath] = value;
  }
}

module.exports = SequelizeDataSource;<commit_msg>implement filter hint $$<commit_after>/**
 * Created by vedi on 09/02/15.
 */
'use strict';

var _ = require('lodash');
var HTTP_STATUSES = require('http-statuses');

class SequelizeDataSource {
  constructor(ModelClass) {
    this.ModelClass = ModelClass;

    this.defaultIdField = 'id';
    this.defaultArrayMethods = ['$addToSet', '$pop', '$push', '$pull'];
  }

  initialize (options) {
    this.idField = options.idField;
    this.fieldMap = options.fieldMap || {};
    this.modelFieldNames = options.modelFieldNames;
  }

  find(options) {
    var filter = options.filter;
    var fields = options.fields;
    var q = options.q;
    var qFields = options.qFields;
    var sort = options.sort;
    var limit = parseInt(options.limit, 10);
    var skip = parseInt(options.skip, 10);
    var queryPipe = options.queryPipe;

    this._normalizeFilter(filter, this.ModelClass);
    this._applyQ(q, qFields, filter);
    var query = {};

    query.attributes = this._normalizeFields(fields, filter, query);

    query.where = filter;

    if (sort) {
      query.order = [];
      _.forOwn(sort, (value, key) => {
        query.order.push([key, +value > 0 ? 'ASC' : 'DESC']);
      });
      //query.order = sort;
    }
    query.limit = limit;
    if (skip > 0) {
      query.offset = skip;
    }
    if (queryPipe) {
      queryPipe(query);
    }

    return this.ModelClass
      .findAll(query)
      .then((docs) => {
        return _.map(docs, (doc) => {
          return this.toObject(doc);
        });
      });
  }

  findOne(options) {
    var filter = options.filter;
    var fields = options.fields;
    var queryPipe = options.queryPipe;

    this._normalizeFilter(filter, this.ModelClass);

    var query = {};

    query.attributes = this._normalizeFields(fields, filter, query);

    query.where = filter;

    if (queryPipe) {
      queryPipe(query);
    }
    return this.ModelClass.findOne(query);
  }

  create(data) {
    return this.ModelClass.build(data);
  }

  save(doc) {
    return doc
      .save()
      .then((newDoc) => {
        var where = {};
        where[this.idField] = newDoc[this.idField];
        return this.findOne({filter: where, fields: this.fieldMap});
      });
  }

  remove(doc) {
    return doc
      .destroy()
      .then(() => {
        return doc;
      });
  }

  count(options) {
    var filter = options.filter;
    var q = options.q;
    var qFields = options.qFields;

    this._normalizeFilter(filter, this.ModelClass);
    this._applyQ(q, qFields, filter);

    var query = {};
    this._normalizeFields(this.modelFieldNames || this.getModelFieldNames(), filter, query); // for filtering by associations
    query.where = filter;

    query.limit = 1;

    // return this.ModelClass.count(query); -- count shows wrong results in some complex cases.
    return this.ModelClass
      .findAndCountAll(query)
      .then((result) => {
        return result.count;
      });
  }

  toObject(model) {
    return model.get({
      plain: true
    });
  }

  getFieldValue(model, fieldName) {
    return this._resolveProp(model, fieldName);
  }

  setFieldValue(model, fieldName, value) {
    this._setProp(model, fieldName, value);
  }

  proceedArrayMethod(source, methodName, fieldName, scope) {
    // TODO: Implement
    //// get sure we have an array
    //if (dest[fieldName] === undefined) {
    //  dest[fieldName] = [];
    //}
    //
    //if (methodName === '$addToSet') {
    //  dest[fieldName].addToSet(source);
    //} else if (methodName === '$pop') {
    //  if (source === 1) {
    //    dest[fieldName].pop();
    //  } else if (source === -1) {
    //    dest[fieldName].shift();
    //  } else {
    //    throw new Error('Illegal param value for $pop method');
    //  }
    //} else if (methodName === '$push') {
    //  dest[fieldName].push(source);
    //} else if (methodName === '$pull') {
    //  dest[fieldName].pull(source);
    //}
  }

  assignField(fieldName, scope) {
    var dest = scope.model;
    var source = scope.source;
    dest.set(fieldName, source[fieldName]);
  }

  getModelFieldNames() {
    return _.keys(this.ModelClass.rawAttributes);
  }

  parseError(err) {
    // TODO: Implement
    var result = {};
    if (err.name === 'SequelizeValidationError') {
      result.status = HTTP_STATUSES.BAD_REQUEST;
      result.details = err.errors;
    } else if (err.name === 'SequelizeUniqueConstraintError') {
      result.status = HTTP_STATUSES.BAD_REQUEST;
      result.message = err.message;
      result.details = {};
      _.each(err.errors, (error) => {
        result.details[error.path] = {path: error.path, type: error.type, value: error.value, message: error.message};
      });

      result.details = err.errors;
    }
    //else if (err.name == 'CastError') {
    //  result.status = HTTP_STATUSES.BAD_REQUEST;
    //  result.details = {};
    //  result.details[err.path] = {
    //    message: err.message,
    //    name: err.name,
    //    path: err.path,
    //    type: err.type,
    //    value: err.value
    //  };
    //  result.message = 'CastError';
    //}
    //else if (err.name == 'MongoError' && (err.code == 11000 || err.code == 11001)) { // E11000(1) duplicate key error index
    //  result.status = HTTP_STATUSES.BAD_REQUEST;
    //  result.details = err.err;
    //}
    //else if (err.name == 'VersionError') {
    //  result.status = HTTP_STATUSES.CONFLICT;
    //  result.details = err.message;
    //} else {
    //  return;
    //}
    else {
      // it's just for testing
      result.status = HTTP_STATUSES.BAD_REQUEST;
      result.details = err.message;
    }

    return result;
  }

  _applyQ(q, qFields, filter) {
    var qExpr = q ? this._buildQ(qFields, q) : undefined;
    if (!_.isUndefined(qExpr) && qExpr.length > 0) {
      filter.$or = qExpr;
    }
  }

  _buildQ(qFields, q) {
    return _.map(qFields, (field) => {
      var result = {};
      result[field] = { $like: '%' + q + '%' };
      return result;
    });
  }

  /**
   * @param fields
   * @param filter
   * @param query
   * @param filterDriven if set, `include`s will be created for filtered values only
   * @returns {*}
   * @private
   */
  _normalizeFields(fields, filter, query, filterDriven) {
    query.include = query.include || [];
    fields = this._resolveAssociations(this.ModelClass, this.fieldMap, fields, filter, query.include, filterDriven);

    if (!filterDriven && fields.indexOf(this.ModelClass.primaryKeyField) < 0) {
      fields.push(this.ModelClass.primaryKeyField);
    }

    return fields;
  }

  _resolveAssociations(ModelClass, fieldMap, fields, filter, include, filterDriven) {
    include = include || [];
    var fieldsToRemove = [];
    var filterToRemove = [];
    var result = _.map(fields, (field) => {
      var isObject = typeof(field) === 'object';
      var fieldName = isObject ? field.name : field;
      var fieldMeta = fieldMap && fieldMap[fieldName];
      var association = ModelClass.associations[fieldName];
      if (fieldMeta && association) {
        if (!filterDriven) {
          fieldsToRemove.push(fieldName);
        }

        var associationFields;
        var required;
        if (isObject && field.fields) {
          associationFields = field.fields;
          required = field.required;
        } else if (fieldMeta.fields) {
          associationFields = fieldMeta.fields;
          required = fieldMeta.required;
        } else {
          associationFields = [association.targetKey];
          required = undefined;
        }

        var filterValue = filter ? filter[fieldName] : undefined;

        var nestedInclude = [];

        associationFields = this._resolveAssociations(association.target, fieldMeta.fields, associationFields, filterValue, nestedInclude, filterDriven);

        var cleanFilterValue = filterValue ? _.transform(filterValue, (result, value, key) => {
          if (associationFields.indexOf(key) >= 0) {
            result[key] = value;
          } else if (key === '$$') {
            _.assign(result, value);
          }
          return result;
        }) : undefined;

        if (cleanFilterValue) {
          filterToRemove.push(fieldName);
        }

        if (!filterDriven || cleanFilterValue) {
          // put to include
          include.push({
            association: association,
            attributes: associationFields,
            include: nestedInclude,
            required: required,
            where: cleanFilterValue
          });
        }
      }
      return fieldName;
    });

    if (!filterDriven) {
      _.each(fieldsToRemove, (field) => {
        _.pull(result, field);
      });
    }

    _.each(filterToRemove, (filterItem) => {
      delete filter[filterItem];
    });

    return result;
  }

  _normalizeFilter(filter, root) {
    // TODO: Implement
    //_.forEach(_.keys(filter), function (key) {
    //  var path = root.schema.paths[key];
    //  // if it's an operator
    //  if (key.substr(0, 1) === '$') {
    //    // increase the level without changing the root
    //    this._normalizeFilter(filter[key], root);
    //  } else if (path) {
    //    var typeName = path.options.type.name;
    //    // it's embedded document
    //    if (!_.isUndefined(path.schema)) {
    //      this._normalizeFilter(filter[key], root.schema.paths[key]);
    //    } else if (typeName === 'ObjectId') {
    //      if (typeof(filter[key]) === 'string') {
    //        filter[key] = ObjectID(filter[key]);
    //      }
    //    } else if (typeName === 'Date') {
    //      if (typeof(filter[key]) === 'string') {
    //        filter[key] = new Date(filter[key]);
    //      }
    //      else if (typeof(filter[key]) === 'object') {
    //        _.forOwn(filter[key], function (value, innerKey) {
    //          if (typeof(value) === 'string') {
    //            filter[key][innerKey] = new Date(value);
    //          }
    //        });
    //      }
    //    }
    //  }
    //}, this);
  }

  _resolveProp(obj, stringPath) {
    stringPath = stringPath.replace(/\[(\w+)]/g, '.$1');  // convert indexes to properties
    stringPath = stringPath.replace(/^\./, '');           // strip a leading dot
    var pathArray = stringPath.split('.');
    while (pathArray.length) {
      var pathItem = pathArray.shift();
      if (pathItem in obj) {
        obj = obj[pathItem];
      } else {
        return;
      }
    }
    return obj;
  }

  _setProp(obj, stringPath, value) {
    stringPath = stringPath.replace(/\[(\w+)]/g, '.$1');  // convert indexes to properties
    stringPath = stringPath.replace(/^\./, '');           // strip a leading dot
    var pathArray = stringPath.split('.');
    while (pathArray.length - 1) {
      var pathItem = pathArray.shift();
      if (pathItem in obj) {
        obj = obj[pathItem];
      } else {
        return;
      }
    }
    return obj[pathArray.length ? pathArray[0] : stringPath] = value;
  }
}

module.exports = SequelizeDataSource;<|endoftext|>


<commit_before>"use strict";
/* eslint-disable */
/**
 * @fileoverview SessionDescriptionHandler
 */

/* SessionDescriptionHandler
 * @class PeerConnection helper Class.
 * @param {SIP.Session} session
 * @param {Object} [options]
 */
module.exports = function (EventEmitter) {
var SessionDescriptionHandler = function(session, observer, options) {};

SessionDescriptionHandler.prototype = Object.create(EventEmitter.prototype, {

  /**
   * Destructor
   */
  close: {value: function close () {}},

  /**
   * Gets the local description from the underlying media implementation
   * @param {Object} [options] Options object to be used by getDescription
   * @param {Array} [modifiers] Array with one time use description modifiers
   * @returns {Promise} Promise that resolves with the local description to be used for the session
   */
  getDescription: {value: function getDescription (options, modifiers) {}},

  /**
   * Check if the Session Description Handler can handle the Content-Type described by a SIP Message
   * @param {String} contentType The content type that is in the SIP Message
   * @returns {boolean}
   */
  hasDescription: {value: function hasSessionDescription (contentType) {}},

  /**
   * The modifier that should be used when the session would like to place the call on hold
   * @param {String} [sdp] The description that will be modified
   * @returns {Promise} Promise that resolves with modified SDP
   */
  holdModifier: {value: function holdModifier (sdp) {}},

  /**
   * Set the remote description to the underlying media implementation
   * @param {String} sessionDescription The description provided by a SIP message to be set on the media implementation
   * @param {Object} [options] Options object to be used by setDescription
   * @param {Array} [modifiers] Array with one time use description modifiers
   * @returns {Promise} Promise that resolves once the description is set
   */
  setDescription: {value: function setDescription (sessionDescription, options, modifiers) {}},

  /**
   * Send DTMF via RTP (RFC 4733)
   * @param {String} tones A string containing DTMF digits
   * @param {Object} [options] Options object to be used by sendDtmf
   * @returns {boolean} true if DTMF send is successful, false otherwise
   */
   sendDtmf: {value: function sendDtmf (tones, options) {}},

   /**
   * Get the direction of the session description
   * @returns {String} direction of the description
   */
   getDirection: {value: function getDirection() {}},
});

return SessionDescriptionHandler;
};
<commit_msg>Session Description Handler template constructor does not have any defined arguments<commit_after>"use strict";
/* eslint-disable */
/**
 * @fileoverview SessionDescriptionHandler
 */

/* SessionDescriptionHandler
 * @class PeerConnection helper Class.
 * @param {SIP.Session} session
 * @param {Object} [options]
 */
module.exports = function (EventEmitter) {
var SessionDescriptionHandler = function() {};

SessionDescriptionHandler.prototype = Object.create(EventEmitter.prototype, {

  /**
   * Destructor
   */
  close: {value: function close () {}},

  /**
   * Gets the local description from the underlying media implementation
   * @param {Object} [options] Options object to be used by getDescription
   * @param {Array} [modifiers] Array with one time use description modifiers
   * @returns {Promise} Promise that resolves with the local description to be used for the session
   */
  getDescription: {value: function getDescription (options, modifiers) {}},

  /**
   * Check if the Session Description Handler can handle the Content-Type described by a SIP Message
   * @param {String} contentType The content type that is in the SIP Message
   * @returns {boolean}
   */
  hasDescription: {value: function hasSessionDescription (contentType) {}},

  /**
   * The modifier that should be used when the session would like to place the call on hold
   * @param {String} [sdp] The description that will be modified
   * @returns {Promise} Promise that resolves with modified SDP
   */
  holdModifier: {value: function holdModifier (sdp) {}},

  /**
   * Set the remote description to the underlying media implementation
   * @param {String} sessionDescription The description provided by a SIP message to be set on the media implementation
   * @param {Object} [options] Options object to be used by setDescription
   * @param {Array} [modifiers] Array with one time use description modifiers
   * @returns {Promise} Promise that resolves once the description is set
   */
  setDescription: {value: function setDescription (sessionDescription, options, modifiers) {}},

  /**
   * Send DTMF via RTP (RFC 4733)
   * @param {String} tones A string containing DTMF digits
   * @param {Object} [options] Options object to be used by sendDtmf
   * @returns {boolean} true if DTMF send is successful, false otherwise
   */
   sendDtmf: {value: function sendDtmf (tones, options) {}},

   /**
   * Get the direction of the session description
   * @returns {String} direction of the description
   */
   getDirection: {value: function getDirection() {}},
});

return SessionDescriptionHandler;
};
<|endoftext|>


<commit_before>var urlParse = Npm.require('url').parse;
var urlResolve = Npm.require('url').resolve;

Balancer._buildCookie = function _buildCookie(name, service) {
  return name + "::" + service;
};

Balancer._urlToTarget = function _urlToTarget(url) {
  var parsedUrl = urlParse(url);
  var target = {
    host: parsedUrl.hostname,
    port: parsedUrl.port
  };

  return target;
};

Balancer._pickAndSetEndpointHash =
function _pickAndSetEndpointHash(cookies) {
  var service = Cluster._uiService;
  var endpointHash = Cluster.discovery.pickEndpointHash(service);
  if(endpointHash) {
    var cookieOptions = {
      httpOnly: true,
      // expire the cookie in one hour
      // then we can expect that long lasting sessions
      // does not affect to the load distribution much
      maxAge: 1000 * 60 * 60
    };
    var cookieName = Balancer._buildCookie('cluster-endpoint', service);
    cookies.set(cookieName, endpointHash, cookieOptions);
    return endpointHash;
  } else {
    // no endpoint point, simply process the request here
    return false;
  }
};

Balancer._pickEndpoint =
function _pickEndpoint(endpointHash, cookies, retries) {
  retries = retries || 0;
  if(retries > 1) return false;

  if(!endpointHash) {
    endpointHash = Balancer._pickAndSetEndpointHash(cookies);
    if(!endpointHash) {
      // no endpoint, simply process the request here
      return false;
    }
  }

  var endpoint = Cluster.discovery.hashToEndpoint(endpointHash);
  if(!endpoint) {
    // oops, no such endpoint. Let's get a new one.
    return Balancer._pickEndpoint(null, cookies, ++retries);
  }

  return endpoint;
};

Balancer._pickJustEndpoint = function _pickJustEndpoint(endpointHash, service) {
  if(!service) throw new Error("service name is required");

  if(!endpointHash) {
    // no hash, pick a new endpoint
    return Cluster.discovery.pickEndpoint(service);
  }

  var endpoint = Cluster.discovery.hashToEndpoint(endpointHash);
  if(!endpoint) {
    // oops, no such endpoint for this hash
    // pick a new endpoint
    return Cluster.discovery.pickEndpoint(service);
  }

  return endpoint;
};

Balancer._setFromBalanceUrlHeader =
function _setFromBalanceUrlHeader(req, balancerUrl) {
  req.headers['from-balancer'] = "YES";
};

Balancer._sendSockJsInfo =
function _sendSockJsInfo(req, res, cookies) {
  var urlParsed = req.url.match(/(\w+)\/sockjs\/info/);
  var serviceName = urlParsed && urlParsed[1];

  if(!serviceName) {
    serviceName = Cluster._uiService;
  }

  if(serviceName === Cluster._uiService) {
    var cookieName = Balancer._buildCookie('cluster-endpoint', serviceName);
    var endpointHash = cookies.get(cookieName);
    var endpoint = Balancer._pickJustEndpoint(endpointHash, serviceName);
  } else if(Cluster._isPublicService(serviceName)) {
    var endpoint = Balancer._pickJustEndpoint(null, serviceName);
  }

  if(!endpoint) {
    // we can't process this here.
    // TODO: better error handling
    console.error("Cluster: no such endpoint for service:" + serviceName);
    res.writeHead(404);
    return res.end("no such endpoint for service: " + serviceName);
  }

  var endpointHash = Cluster.discovery.endpointToHash(endpoint);
  var balancer = Cluster.discovery.pickBalancer(endpointHash) || "";
  var base_url =
    urlResolve(balancer, "/cluster-ddp/" + endpointHash + "/" + serviceName);

  var info = {
    websocket: !process.env['DISABLE_WEBSOCKETS'],
    origins: ["*:*"],
    cookie_needed: false,
    entropy: Math.ceil(Math.random() * 9999999999),
    base_url: base_url
  };

  res.writeHead(200, {
    'content-type': 'application/json',
    'access-control-allow-origin': '*'
  });
  res.end(JSON.stringify(info));
}

Balancer._rewriteDdpUrl = function _rewriteDdpUrl(req) {
  var regExp = /cluster-ddp\/(\w+)\/(\w+)/;
  var parsedUrl = req.url.match(regExp);
  if(parsedUrl) {
    req.url = req.url.replace(regExp, "sockjs/").replace(/[\/]+/g, "/");
    var endpointHash = {
      hash: parsedUrl[1],
      service: parsedUrl[2] || Cluster._uiService
    };
    return endpointHash;
  }
};

Balancer._proxyWeb = function _proxyWeb(req, res, endpoint, cookies, retries) {
  // give support for sockjs long polling
  // otherwise meteor kill the connection after 5 secs by default
  if(/sockjs/.test(req.url)) {
    res.setTimeout(2 * 60 * 1000);
  }

  retries = retries || 0;
  var target = Balancer._urlToTarget(endpoint);

  Balancer.proxy.web(req, res, {target: target}, function(error) {
    if(retries++ > 2) {
      printError();
    } else {
      // try to get a new endpoint
      var endpoint = Balancer._pickEndpoint(null, cookies);
      if(endpoint) {
        Balancer._proxyWeb(req, res, endpoint, cookies, ++retries);
      } else {
        printError();
      }
    }

    function printError() {
      console.error("Cluster: web proxy error: ", error.message);
      res.writeHead(500);
      res.end("Internal Error: Please reload.");
    }
  });
};

Balancer._proxyWs = function proxyWs(req, socket, head, endpoint) {
  var target = Balancer._urlToTarget(endpoint);
  Balancer.proxy.ws(req, socket, head, {target: target}, function(error) {
    // not sure we can re-try websockets, simply log it
    console.error("WS proxying failed! to: " + endpoint);
  });
};<commit_msg>Revert the cookie back to a session cookie<commit_after>var urlParse = Npm.require('url').parse;
var urlResolve = Npm.require('url').resolve;

Balancer._buildCookie = function _buildCookie(name, service) {
  return name + "::" + service;
};

Balancer._urlToTarget = function _urlToTarget(url) {
  var parsedUrl = urlParse(url);
  var target = {
    host: parsedUrl.hostname,
    port: parsedUrl.port
  };

  return target;
};

Balancer._pickAndSetEndpointHash =
function _pickAndSetEndpointHash(cookies) {
  var service = Cluster._uiService;
  var endpointHash = Cluster.discovery.pickEndpointHash(service);
  if(endpointHash) {
    var cookieOptions = {
      httpOnly: true
    };
    var cookieName = Balancer._buildCookie('cluster-endpoint', service);
    cookies.set(cookieName, endpointHash, cookieOptions);
    return endpointHash;
  } else {
    // no endpoint point, simply process the request here
    return false;
  }
};

Balancer._pickEndpoint =
function _pickEndpoint(endpointHash, cookies, retries) {
  retries = retries || 0;
  if(retries > 1) return false;

  if(!endpointHash) {
    endpointHash = Balancer._pickAndSetEndpointHash(cookies);
    if(!endpointHash) {
      // no endpoint, simply process the request here
      return false;
    }
  }

  var endpoint = Cluster.discovery.hashToEndpoint(endpointHash);
  if(!endpoint) {
    // oops, no such endpoint. Let's get a new one.
    return Balancer._pickEndpoint(null, cookies, ++retries);
  }

  return endpoint;
};

Balancer._pickJustEndpoint = function _pickJustEndpoint(endpointHash, service) {
  if(!service) throw new Error("service name is required");

  if(!endpointHash) {
    // no hash, pick a new endpoint
    return Cluster.discovery.pickEndpoint(service);
  }

  var endpoint = Cluster.discovery.hashToEndpoint(endpointHash);
  if(!endpoint) {
    // oops, no such endpoint for this hash
    // pick a new endpoint
    return Cluster.discovery.pickEndpoint(service);
  }

  return endpoint;
};

Balancer._setFromBalanceUrlHeader =
function _setFromBalanceUrlHeader(req, balancerUrl) {
  req.headers['from-balancer'] = "YES";
};

Balancer._sendSockJsInfo =
function _sendSockJsInfo(req, res, cookies) {
  var urlParsed = req.url.match(/(\w+)\/sockjs\/info/);
  var serviceName = urlParsed && urlParsed[1];

  if(!serviceName) {
    serviceName = Cluster._uiService;
  }

  if(serviceName === Cluster._uiService) {
    var cookieName = Balancer._buildCookie('cluster-endpoint', serviceName);
    var endpointHash = cookies.get(cookieName);
    var endpoint = Balancer._pickJustEndpoint(endpointHash, serviceName);
  } else if(Cluster._isPublicService(serviceName)) {
    var endpoint = Balancer._pickJustEndpoint(null, serviceName);
  }

  if(!endpoint) {
    // we can't process this here.
    // TODO: better error handling
    console.error("Cluster: no such endpoint for service:" + serviceName);
    res.writeHead(404);
    return res.end("no such endpoint for service: " + serviceName);
  }

  var endpointHash = Cluster.discovery.endpointToHash(endpoint);
  var balancer = Cluster.discovery.pickBalancer(endpointHash) || "";
  var base_url =
    urlResolve(balancer, "/cluster-ddp/" + endpointHash + "/" + serviceName);

  var info = {
    websocket: !process.env['DISABLE_WEBSOCKETS'],
    origins: ["*:*"],
    cookie_needed: false,
    entropy: Math.ceil(Math.random() * 9999999999),
    base_url: base_url
  };

  res.writeHead(200, {
    'content-type': 'application/json',
    'access-control-allow-origin': '*'
  });
  res.end(JSON.stringify(info));
}

Balancer._rewriteDdpUrl = function _rewriteDdpUrl(req) {
  var regExp = /cluster-ddp\/(\w+)\/(\w+)/;
  var parsedUrl = req.url.match(regExp);
  if(parsedUrl) {
    req.url = req.url.replace(regExp, "sockjs/").replace(/[\/]+/g, "/");
    var endpointHash = {
      hash: parsedUrl[1],
      service: parsedUrl[2] || Cluster._uiService
    };
    return endpointHash;
  }
};

Balancer._proxyWeb = function _proxyWeb(req, res, endpoint, cookies, retries) {
  // give support for sockjs long polling
  // otherwise meteor kill the connection after 5 secs by default
  if(/sockjs/.test(req.url)) {
    res.setTimeout(2 * 60 * 1000);
  }

  retries = retries || 0;
  var target = Balancer._urlToTarget(endpoint);

  Balancer.proxy.web(req, res, {target: target}, function(error) {
    if(retries++ > 2) {
      printError();
    } else {
      // try to get a new endpoint
      var endpoint = Balancer._pickEndpoint(null, cookies);
      if(endpoint) {
        Balancer._proxyWeb(req, res, endpoint, cookies, ++retries);
      } else {
        printError();
      }
    }

    function printError() {
      console.error("Cluster: web proxy error: ", error.message);
      res.writeHead(500);
      res.end("Internal Error: Please reload.");
    }
  });
};

Balancer._proxyWs = function proxyWs(req, socket, head, endpoint) {
  var target = Balancer._urlToTarget(endpoint);
  Balancer.proxy.ws(req, socket, head, {target: target}, function(error) {
    // not sure we can re-try websockets, simply log it
    console.error("WS proxying failed! to: " + endpoint);
  });
};<|endoftext|>


<commit_before>var util = require('util');

var SalesInvoice = exports.SalesInvoice = function (Client) {
  this.client = Client;

  return this;
};

// ---- SALES INVOICE BEGIN ----

/**
 * Get back account
 * @param  {String}   customerId Account ID
 * @param  {Integer}  division  Division ID
 * @param  {Function} callback  Callback
 */
SalesInvoice.prototype.getSalesInvoicesFromCustomer = function(customerId, division, callback) {
  var params = {
    $filter: 'InvoiceTo eq guid\''+ customerId +'\''
  };

  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/salesinvoice/SalesInvoices', 'GET', params, null, callback);
};

/**
 * Get back account
 * @param  {String}   salesInvoiceId Account ID
 * @param  {Integer}  division  Division ID
 * @param  {Function} callback  Callback
 */
SalesInvoice.prototype.getSalesInvoice = function(salesInvoiceId, division, callback) {
  var params = {
    $filter: 'InvoiceID eq guid\''+ salesInvoiceId +'\''
  };

  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/SalesInvoice/SalesInvoices', 'GET', params, null, callback);
};

/**
 * Alter a bank account
 * @param  {String}   salesInvoiceId  JSON Object with content saved
 * @param  {String}   userData        JSON Object with content saved
 * @param  {Integer}  division        Division ID
 * @param  {Function} callback        Callback
 */
SalesInvoice.prototype.saveSalesInvoice = function(salesInvoiceId, userData, division, callback) {

  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/SalesInvoice/SalesInvoices(guid\'' + salesInvoiceId + '\')', 'PUT', null, userData, callback);
};

/**
 * Create Sales Invoice
 * @param {Object} fields   POST fields
 * @param {Integer} division Division ID
 * @param {Function} callback Gets called after request is complete
 */
SalesInvoice.prototype.createSalesInvoice = function(userData, division, callback) {
  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/SalesInvoice/SalesInvoices', 'POST', null, userData, callback);
};

// ---- SALES INVOICE END ----

/**
 * Create printed sales invoice
 * @param  {Object}   fields   POST fields
 * @param  {Integer}   division Division ID
 * @param  {Function} callback Callback
 */
SalesInvoice.prototype.createPrintedSalesInvoice = function(fields, division, callback) {
  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/SalesInvoice/PrintedSalesInvoices', 'POST', null, fields, callback);
};<commit_msg>Changed inline-comments of SalesInvoices to better reflect the actual functions.<commit_after>var util = require('util');

var SalesInvoice = exports.SalesInvoice = function (Client) {
  this.client = Client;

  return this;
};

// ---- SALES INVOICE BEGIN ----

/**
 * Get sales invoice based on customer ID
 * @param  {String}   customerId Account ID
 * @param  {Integer}  division  Division ID
 * @param  {Function} callback  Callback
 */
SalesInvoice.prototype.getSalesInvoicesFromCustomer = function(customerId, division, callback) {
  var params = {
    $filter: 'InvoiceTo eq guid\''+ customerId +'\''
  };

  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/salesinvoice/SalesInvoices', 'GET', params, null, callback);
};

/**
 * Get sales invoice based on the invoice ID
 * @param  {String}   salesInvoiceId Invoice ID
 * @param  {Integer}  division  Division ID
 * @param  {Function} callback  Callback
 */
SalesInvoice.prototype.getSalesInvoice = function(salesInvoiceId, division, callback) {
  var params = {
    $filter: 'InvoiceID eq guid\''+ salesInvoiceId +'\''
  };

  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/SalesInvoice/SalesInvoices', 'GET', params, null, callback);
};

/**
 * Alter an existing sales invoice
 * @param  {String}   salesInvoiceId  JSON Object with content saved
 * @param  {String}   userData        JSON Object with content saved
 * @param  {Integer}  division        Division ID
 * @param  {Function} callback        Callback
 */
SalesInvoice.prototype.saveSalesInvoice = function(salesInvoiceId, userData, division, callback) {

  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/SalesInvoice/SalesInvoices(guid\'' + salesInvoiceId + '\')', 'PUT', null, userData, callback);
};

/**
 * Create Sales Invoice
 * @param {Object} fields   POST fields
 * @param {Integer} division Division ID
 * @param {Function} callback Gets called after request is complete
 */
SalesInvoice.prototype.createSalesInvoice = function(userData, division, callback) {
  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/SalesInvoice/SalesInvoices', 'POST', null, userData, callback);
};

// ---- SALES INVOICE END ----

/**
 * Create printed sales invoice
 * @param  {Object}   fields   POST fields
 * @param  {Integer}   division Division ID
 * @param  {Function} callback Callback
 */
SalesInvoice.prototype.createPrintedSalesInvoice = function(fields, division, callback) {
  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/SalesInvoice/PrintedSalesInvoices', 'POST', null, fields, callback);
};<|endoftext|>


<commit_before>var request = require('superagent');
var registryServer = process.env.REGISTRY_SERVER || 'http://registry.jsonresume.org';
var Spinner = require('cli-spinner').Spinner;
var spinner = new Spinner('changing theme...');
spinner.setSpinnerString('/-\\');
var read = require('read');
var chalk = require('chalk');

module.exports = function changeTheme(themeCredentials, callback) {

  callback = callback || function() {};

  spinner.start();
  request
    .put(registryServer + '/resume')
    .send(themeCredentials)
    .set('Accept', 'application/json')
    .end(function(error, res) {
      spinner.stop();

      callback(error, res);

      if (error && error.code === 'ENOTFOUND') {
        console.log('\nThere has been an error publishing your resume.'.red);
        console.log('Please check your network connection.'.cyan);
        process.exit();
      } else if (error || res.body.message === 'ERRORRRSSSS') {
        console.log(error, res.body.message);
        console.log('\nThere has been an error publishing your resume.'.red);
        // console.log('Details:', error, res.body.message);
        console.log('Please check you are using correct login details.'.blue);
      } else {

        console.log(chalk.green('\nDone! Your resume theme has been successfully changed to ' + themeCredentials.theme + '.'));
        read({
          prompt: 'Would you like to view your new themed resume in the web browser? [y/n]: '
        }, function(er, answer) {
          if (answer === 'y') {
            open(res.body.url);
            process.exit();
          } else if (answer === 'n') {
            process.exit();
          }
        });

      }
    });
};
<commit_msg>add missing dependency<commit_after>var request = require('superagent');
var registryServer = process.env.REGISTRY_SERVER || 'http://registry.jsonresume.org';
var Spinner = require('cli-spinner').Spinner;
var spinner = new Spinner('changing theme...');
spinner.setSpinnerString('/-\\');
var read = require('read');
var chalk = require('chalk');
var open = require('open');

module.exports = function changeTheme(themeCredentials, callback) {

  callback = callback || function() {};

  spinner.start();
  request
    .put(registryServer + '/resume')
    .send(themeCredentials)
    .set('Accept', 'application/json')
    .end(function(error, res) {
      spinner.stop();

      callback(error, res);

      if (error && error.code === 'ENOTFOUND') {
        console.log('\nThere has been an error publishing your resume.'.red);
        console.log('Please check your network connection.'.cyan);
        process.exit();
      } else if (error || res.body.message === 'ERRORRRSSSS') {
        console.log(error, res.body.message);
        console.log('\nThere has been an error publishing your resume.'.red);
        // console.log('Details:', error, res.body.message);
        console.log('Please check you are using correct login details.'.blue);
      } else {

        console.log(chalk.green('\nDone! Your resume theme has been successfully changed to ' + themeCredentials.theme + '.'));
        read({
          prompt: 'Would you like to view your new themed resume in the web browser? [y/n]: '
        }, function(er, answer) {
          if (answer === 'y') {
            open(res.body.url);
            process.exit();
          } else if (answer === 'n') {
            process.exit();
          }
        });

      }
    });
};
<|endoftext|>


<commit_before>const plugins = require('./plugins');

module.exports = {
  output: {
    libraryTarget: 'commonjs2'
  },
  plugins: [
    plugins['no-errors-plugin'],
    plugins['loader-options-plugin'],
    plugins['define-plugin']
  ],
  module: {
    loaders: [{
      test: /\.css?$/,
      loader: [
        'css-loader?',
        'modules&importLoaders=1&',
        'localIdentName=[name]__[local]___[hash:base64:5]!',
        'postcss-loader'
      ].join('')
    }]
  }
};
<commit_msg>handle aliases in webpack test<commit_after>const path = require('path');
const fs = require('fs');

const plugins = require('./plugins');
const CONTEXT = path.join(__dirname, '../src');
const ROOT = path.join(__dirname, '../..');

module.exports = {
  resolve: {
    modules: [
      ROOT,
      'node_modules'
    ],
    alias: fs.readdirSync(CONTEXT)
      .map((name) => path.join(CONTEXT, name))
      .filter((fullpath) => fs.statSync(fullpath).isDirectory())
      .reduce((aliases, fullpath) => Object.assign(aliases, {
        [`@${path.basename(fullpath)}`]: fullpath
      }), {
        '@root': CONTEXT
      })
  },
  output: {
    libraryTarget: 'commonjs2'
  },
  plugins: [
    plugins['no-errors'],
    plugins['loader-options'],
    plugins['define']
  ],
  module: {
    loaders: [{
      test: /\.css?$/,
      loader: [
        'css-loader?',
        'modules&importLoaders=1&',
        'localIdentName=[name]__[local]___[hash:base64:5]!',
        'postcss-loader'
      ].join('')
    }]
  }
};
<|endoftext|>


<commit_before>var _ = require('underscore');
var async = require('async');
var fs = require('fs');
var path = require('path');
var yaml = require('js-yaml');
var coffee = require('coffee-script');
var url = require('url');

var doctrine = require('doctrine');
var express = require('express');
var descriptor = {};
var resources = {};

/**
 * Read from yml file
 * @api    private
 * @param  {String}   file
 * @param  {Function} fn
 */
function readYml(file, fn) {
  var resource = require(path.resolve(process.cwd(), file));
  var api = {};

  api.resourcePath = resource.resourcePath;
  api.description = resource.description;
  descriptor.apis.push(api);
  resources[resource.resourcePath] = resource;

  fn();
}

/**
 * Parse jsDoc from a js file
 * @api    private
 * @param  {String}   file
 * @param  {Function} fn
 */
function parseJsDocs(file, fn) {
  fs.readFile(file, function (err, data) {
    if (err) {
      fn(err);
    }

    var js = data.toString();
    var regex = /\/\*\*([\s\S]*?)\*\//gm;
    var fragments = js.match(regex);
    var docs = [];

    if (!fragments) {
      fn(null, docs);
      return;
    }

    for (var i = 0; i < fragments.length; i++) {
      var fragment = fragments[i];
      var doc = doctrine.parse(fragment, { unwrap: true });

      docs.push(doc);

      if (i === fragments.length - 1) {
        fn(null, docs);
      }
    }
  });
}

/**
 * Parse coffeeDoc from a coffee file
 * @api    private
 * @param  {String}   file
 * @param  {Function} fn
 */
function parseCoffeeDocs(file, fn) {
    fs.readFile(file, function (err, data) {
        if (err) {
            fn(err);
        }

        var js = coffee.compile(data.toString());
        var regex = /\/\**([\s\S]*?)\*\//gm;
        var fragments = js.match(regex);
        var docs = [];

        for (var i = 0; i < fragments.length; i++) {
            var fragment = fragments[i];
            var doc = doctrine.parse(fragment, { unwrap: true });

            docs.push(doc);

            if (i === fragments.length - 1) {
                fn(null, docs);
            }
        }
    });
}

/**
 * Get jsDoc tag with title '@swagger'
 * @api    private
 * @param  {Object} fragment
 * @param  {Function} fn
 */
function getSwagger(fragment, fn) {
  for (var i = 0; i < fragment.tags.length; i++) {
    var tag = fragment.tags[i];
    if ('swagger' === tag.title) {
      return yaml.safeLoadAll(tag.description, fn);
    }
  }

  return fn(false);
}

/**
 * Read from jsDoc
 * @api    private
 * @param  {String}  file
 * @param  {Function} fn
 */
function readJsDoc(file, fn) {
  parseJsDocs(file, function (err, docs) {

    if (err) {
      fn(err);
    }

    var resource = { apis: [] };

    async.eachSeries(docs, function (doc, cb) {
      getSwagger(doc, function (api) {

        if (!api) {
          return cb();
        }

        if (api.resourcePath) {
          descriptor.apis.push(api);
          resource.resourcePath = api.resourcePath;
        } else if (api.models) {
          resource.models = api.models;
        } else {
          resource.apis.push(api);
        }

        cb();
      });
    }, function (err) {
      resources[resource.resourcePath] = resource;
      fn();
    });
  });
}

/**
 * Read from coffeeDoc
 * @api    private
 * @param  {String}  file
 * @param  {Function} fn
 */
function readCoffee(file, fn) {
    parseCoffeeDocs(file, function (err, docs) {

        if (err) {
            fn(err);
        }

        var resource = { apis: [] };

        async.eachSeries(docs, function (doc, cb) {
            getSwagger(doc, function (api) {

                if (!api) {
                    return cb();
                }

                if (api.resourcePath) {
                    descriptor.apis.push(api);
                    resource.resourcePath = api.resourcePath;
                } else if (api.models) {
                    resource.models = api.models;
                } else {
                    resource.apis.push(api);
                }

                cb();
            });
        }, function (err) {
            resources[resource.resourcePath] = resource;
            fn();
        });
    });
}

/**
 * Read API from file
 * @api    private
 * @param  {String}   file
 * @param  {Function} fn
 */
function readApi(file, fn) {
  var ext = path.extname(file);
  if ('.js' === ext) {
    readJsDoc(file, fn);
  } else if ('.yml' === ext) {
    readYml(file, fn);
  } else if ('.coffee' === ext) {
    readCoffee(file, fn);
  } else {
    throw new Error('Unsupported extension \'' + ext + '\'');
  }
}

/**
 * Generate Swagger documents
 * @api    private
 * @param  {Object} opt
 */
function generate(opt) {
  if (!opt) {
    throw new Error('\'option\' is required.');
  }

  if (!opt.swaggerUI) {
    throw new Error('\'swaggerUI\' is required.');
  }

  if (!opt.basePath) {
     throw new Error('\'basePath\' is required.');
  }

  descriptor.basePath = opt.basePath;
  descriptor.apiVersion = (opt.apiVersion) ? opt.apiVersion : '1.0';
  descriptor.swaggerVersion = (opt.swaggerVersion) ? opt.swaggerVersion : '1.0';
  descriptor.swaggerURL = (opt.swaggerURL) ? opt.swaggerURL : '/swagger';
  descriptor.swaggerJSON = (opt.swaggerJSON) ? opt.swaggerJSON : '/api-docs.json';
  descriptor.apis = [];

  opt.apiVersion = descriptor.apiVersion;
  opt.swaggerVersion = descriptor.swaggerVersion;
  opt.swaggerURL = descriptor.swaggerURL;
  opt.swaggerJSON = descriptor.swaggerJSON;
  opt.fullSwaggerJSONPath = url.parse(opt.basePath + opt.swaggerJSON).path;

  if (opt.apis) {
    opt.apis.forEach(function (api) {
      readApi(api, function (err) {
        if (err) {
          throw err;
        }
      });
    });
  }
}

/**
 * Express middleware
 * @api    public
 * @param  {Object} app
 * @param  {Object} opt
 * @return {Function}
 */
exports.init = function (app, opt) {

  // generate resources
  generate(opt);

  // Serve up swagger ui static assets
  var swHandler = express['static'](opt.swaggerUI);

  // Serve up swagger ui interface.
  var swaggerURL = new RegExp('^'+ opt.swaggerURL +'(\/.*)?$');

  app.get(swaggerURL, function (req, res, next) {
    if (req.url === opt.swaggerURL) { // express static barfs on root url w/o trailing slash
      res.writeHead(302, { 'Location' : req.url + '/' });
      res.end();
      return;
    }

    // take off leading /swagger so that connect locates file correctly
    req.url = req.url.substr(opt.swaggerURL.length);
    return swHandler(req, res, next);
  });

  return function (req, res, next) {
    var match, resource, result;
    var regex = new RegExp('^'+ opt.fullSwaggerJSONPath +'(\/.*)?$');

    match = regex.exec(req.path);

    if (match) {
      result = _.clone(descriptor);

      if (match[1]) {

        resource = resources[match[1]];

        if (!resource) {
          return res.send(404);
        }

        result.resourcePath = resource.resourcePath;
        result.apis = resource.apis;
        result.models = resource.models;
      } else {
        result.apis = _.map(result.apis, function (api) {
          return {
            path: opt.swaggerJSON + api.resourcePath,
            description: api.description
          };
        });
      }

      if(typeof(opt.middleware) == 'function'){
          opt.middleware(req, res);
      }

      return res.json(result);
    }
    return next();
  };
};

exports.descriptor = descriptor;
exports.resources = resources;
<commit_msg>Fix JSHint warning<commit_after>var _ = require('underscore');
var async = require('async');
var fs = require('fs');
var path = require('path');
var yaml = require('js-yaml');
var coffee = require('coffee-script');
var url = require('url');

var doctrine = require('doctrine');
var express = require('express');
var descriptor = {};
var resources = {};

/**
 * Read from yml file
 * @api    private
 * @param  {String}   file
 * @param  {Function} fn
 */
function readYml(file, fn) {
  var resource = require(path.resolve(process.cwd(), file));
  var api = {};

  api.resourcePath = resource.resourcePath;
  api.description = resource.description;
  descriptor.apis.push(api);
  resources[resource.resourcePath] = resource;

  fn();
}

/**
 * Parse jsDoc from a js file
 * @api    private
 * @param  {String}   file
 * @param  {Function} fn
 */
function parseJsDocs(file, fn) {
  fs.readFile(file, function (err, data) {
    if (err) {
      fn(err);
    }

    var js = data.toString();
    var regex = /\/\*\*([\s\S]*?)\*\//gm;
    var fragments = js.match(regex);
    var docs = [];

    if (!fragments) {
      fn(null, docs);
      return;
    }

    for (var i = 0; i < fragments.length; i++) {
      var fragment = fragments[i];
      var doc = doctrine.parse(fragment, { unwrap: true });

      docs.push(doc);

      if (i === fragments.length - 1) {
        fn(null, docs);
      }
    }
  });
}

/**
 * Parse coffeeDoc from a coffee file
 * @api    private
 * @param  {String}   file
 * @param  {Function} fn
 */
function parseCoffeeDocs(file, fn) {
    fs.readFile(file, function (err, data) {
        if (err) {
            fn(err);
        }

        var js = coffee.compile(data.toString());
        var regex = /\/\**([\s\S]*?)\*\//gm;
        var fragments = js.match(regex);
        var docs = [];

        for (var i = 0; i < fragments.length; i++) {
            var fragment = fragments[i];
            var doc = doctrine.parse(fragment, { unwrap: true });

            docs.push(doc);

            if (i === fragments.length - 1) {
                fn(null, docs);
            }
        }
    });
}

/**
 * Get jsDoc tag with title '@swagger'
 * @api    private
 * @param  {Object} fragment
 * @param  {Function} fn
 */
function getSwagger(fragment, fn) {
  for (var i = 0; i < fragment.tags.length; i++) {
    var tag = fragment.tags[i];
    if ('swagger' === tag.title) {
      return yaml.safeLoadAll(tag.description, fn);
    }
  }

  return fn(false);
}

/**
 * Read from jsDoc
 * @api    private
 * @param  {String}  file
 * @param  {Function} fn
 */
function readJsDoc(file, fn) {
  parseJsDocs(file, function (err, docs) {

    if (err) {
      fn(err);
    }

    var resource = { apis: [] };

    async.eachSeries(docs, function (doc, cb) {
      getSwagger(doc, function (api) {

        if (!api) {
          return cb();
        }

        if (api.resourcePath) {
          descriptor.apis.push(api);
          resource.resourcePath = api.resourcePath;
        } else if (api.models) {
          resource.models = api.models;
        } else {
          resource.apis.push(api);
        }

        cb();
      });
    }, function (err) {
      resources[resource.resourcePath] = resource;
      fn();
    });
  });
}

/**
 * Read from coffeeDoc
 * @api    private
 * @param  {String}  file
 * @param  {Function} fn
 */
function readCoffee(file, fn) {
    parseCoffeeDocs(file, function (err, docs) {

        if (err) {
            fn(err);
        }

        var resource = { apis: [] };

        async.eachSeries(docs, function (doc, cb) {
            getSwagger(doc, function (api) {

                if (!api) {
                    return cb();
                }

                if (api.resourcePath) {
                    descriptor.apis.push(api);
                    resource.resourcePath = api.resourcePath;
                } else if (api.models) {
                    resource.models = api.models;
                } else {
                    resource.apis.push(api);
                }

                cb();
            });
        }, function (err) {
            resources[resource.resourcePath] = resource;
            fn();
        });
    });
}

/**
 * Read API from file
 * @api    private
 * @param  {String}   file
 * @param  {Function} fn
 */
function readApi(file, fn) {
  var ext = path.extname(file);
  if ('.js' === ext) {
    readJsDoc(file, fn);
  } else if ('.yml' === ext) {
    readYml(file, fn);
  } else if ('.coffee' === ext) {
    readCoffee(file, fn);
  } else {
    throw new Error('Unsupported extension \'' + ext + '\'');
  }
}

/**
 * Generate Swagger documents
 * @api    private
 * @param  {Object} opt
 */
function generate(opt) {
  if (!opt) {
    throw new Error('\'option\' is required.');
  }

  if (!opt.swaggerUI) {
    throw new Error('\'swaggerUI\' is required.');
  }

  if (!opt.basePath) {
     throw new Error('\'basePath\' is required.');
  }

  descriptor.basePath = opt.basePath;
  descriptor.apiVersion = (opt.apiVersion) ? opt.apiVersion : '1.0';
  descriptor.swaggerVersion = (opt.swaggerVersion) ? opt.swaggerVersion : '1.0';
  descriptor.swaggerURL = (opt.swaggerURL) ? opt.swaggerURL : '/swagger';
  descriptor.swaggerJSON = (opt.swaggerJSON) ? opt.swaggerJSON : '/api-docs.json';
  descriptor.apis = [];

  opt.apiVersion = descriptor.apiVersion;
  opt.swaggerVersion = descriptor.swaggerVersion;
  opt.swaggerURL = descriptor.swaggerURL;
  opt.swaggerJSON = descriptor.swaggerJSON;
  opt.fullSwaggerJSONPath = url.parse(opt.basePath + opt.swaggerJSON).path;

  if (opt.apis) {
    opt.apis.forEach(function (api) {
      readApi(api, function (err) {
        if (err) {
          throw err;
        }
      });
    });
  }
}

/**
 * Express middleware
 * @api    public
 * @param  {Object} app
 * @param  {Object} opt
 * @return {Function}
 */
exports.init = function (app, opt) {

  // generate resources
  generate(opt);

  // Serve up swagger ui static assets
  var swHandler = express.static(opt.swaggerUI);

  // Serve up swagger ui interface.
  var swaggerURL = new RegExp('^'+ opt.swaggerURL +'(\/.*)?$');

  app.get(swaggerURL, function (req, res, next) {
    if (req.url === opt.swaggerURL) { // express static barfs on root url w/o trailing slash
      res.writeHead(302, { 'Location' : req.url + '/' });
      res.end();
      return;
    }

    // take off leading /swagger so that connect locates file correctly
    req.url = req.url.substr(opt.swaggerURL.length);
    return swHandler(req, res, next);
  });

  return function (req, res, next) {
    var match, resource, result;
    var regex = new RegExp('^'+ opt.fullSwaggerJSONPath +'(\/.*)?$');

    match = regex.exec(req.path);

    if (match) {
      result = _.clone(descriptor);

      if (match[1]) {

        resource = resources[match[1]];

        if (!resource) {
          return res.send(404);
        }

        result.resourcePath = resource.resourcePath;
        result.apis = resource.apis;
        result.models = resource.models;
      } else {
        result.apis = _.map(result.apis, function (api) {
          return {
            path: opt.swaggerJSON + api.resourcePath,
            description: api.description
          };
        });
      }

      if(typeof(opt.middleware) == 'function'){
          opt.middleware(req, res);
      }

      return res.json(result);
    }
    return next();
  };
};

exports.descriptor = descriptor;
exports.resources = resources;
<|endoftext|>