<commit_before>/*ngInject*/
export function setupRoutes($stateProvider, $urlRouterProvider) {
    $stateProvider
        .state('login', {
            url: '/login',
            template: '<mc-login></mc-login>'
        })
        .state('projects', {
            url: '/projects',
            abstract: true,
            template: '

'
        })
        .state('projects.list', {
            url: '/list',
            template: '<mc-projects></mc-projects>'
        })
        .state('projects.share', {
            url: '/share',
            template: '<mc-projects-share></mc-projects-share>'
        })
        .state('user', {
            url: '/user',
            abstract: true,
            template: '

'
        })
        .state('user.apikey', {
            url: '/apikey',
            template: '<mc-user-apikey></mc-user-apikey>'
        })
        .state('user.password', {
            url: '/password',
            template: '<mc-user-password></mc-user-password>'
        })
        .state('project', {
            url: '/project/:project_id',
            abstract: true,
            template: '<ui-view flex="100" layout="column"></ui-view>',
            resolve: {
                // Set the current project in the project service so all components
                // will resolve without having to worry if a promise has resolved.
                // The resolved object is ignored.
                _project: ["$stateParams", "projectsService", "project",
                    // Inject projects so that it resolves before looking up the project.
                    function($stateParams, projectsService, project) {
                        return projectsService.getProject($stateParams.project_id)
                            .then(function(proj) {
                                project.set(proj);
                                return proj;
                            });
                    }],

                _templates: ["processTemplates", "templates", "_project",
                    function(processTemplates, templates, project) {
                        var projectTemplates = processTemplates.templates(project.process_templates, project.id);
                        templates.set(projectTemplates);
                        return projectTemplates;
                    }]
            }
        })
        .state('project.home', {
            url: '/home',
            template: '<mc-project-home></mc-project-home>',
            // hack to update project view
            resolve: {
                // Set the current project in the project service so all components
                // will resolve without having to worry if a promise has resolved.
                // The resolved object is ignored.
                _project: ["$stateParams", "projectsService", "project",
                    // Inject projects so that it resolves before looking up the project.
                    function($stateParams, projectsService, project) {
                        return projectsService.getProject($stateParams.project_id)
                            .then(function(proj) {
                                project.set(proj);
                                return proj;
                            });
                    }]
            }
        })
        .state('project.search', {
            url: '/search/:query',
            template: '<mc-project-search></mc-project-search>'
        })
        .state('project.create', {
            url: '/create',
            abstract: true,
            template: '<ui-view flex layout="column"></ui-view>'
        })
        .state('project.experiment', {
            url: '/experiment/:experiment_id',
            template: '<mc-experiment></mc-experiment>'
        })
        .state('project.create.process', {
            url: '/process/:template_id/:process_id',
            template: '<mc-process-create></mc-process-create>',
            resolve: {
                _template: ['templates', 'template', '$stateParams', 'projectsService',
                    function(templates, template, $stateParams, projectsService) {
                        if ($stateParams.process_id) {
                            return projectsService.getProjectProcess($stateParams.project_id, $stateParams.process_id)
                                .then(function(process) {
                                    var t = templates.loadTemplateFromProcess($stateParams.template_id, process);
                                    template.set(t);
                                    return t;
                                });
                        } else {
                            var t = templates.getTemplate($stateParams.template_id);
                            template.set(t);
                            return t;
                        }
                    }]
            }
        })
        .state('project.experiments', {
            url: '/experiments',
            template: '<mc-project-experiments experiments="ctrl.experiments"></mc-project-experiments>',
            controllerAs: 'ctrl',
            controller: [function() {
                let ctrl = this;
                ctrl.experiments = [];
            }]
        })
        .state('project.processes', {
            url: '/processes',
            template: '<mc-project-processes processes="ctrl.processes"></mc-project-processes>',
            controllerAs: 'ctrl',
            controller: ['projectsService', '$stateParams', 'toastr',
                function(projectsService, $stateParams, toastr) {
                    var ctrl = this;
                    ctrl.processes = [];
                    projectsService.getProjectProcesses($stateParams.project_id).then(
                        (processes) => {
                            //console.dir(processes);
                            ctrl.processes = processes;
                        },
                        () => toastr.error('Unable to retrieve project processes', 'Error', {closeButton: true})
                    )
                }]
        })
        .state('project.processes.process', {
            url: '/process/:process_id',
            template: '<mc-process></mc-process>',
            resolve: {
                _process: ['process', 'projectsService', '$stateParams',
                    function(process, projectsService, $stateParams) {
                        return projectsService.getProjectProcess($stateParams.project_id, $stateParams.process_id)
                            .then(function(p) {
                                process.set(p);
                                return p;
                            });
                    }]
            }
        })
        .state('project.processes.edit', {
            url: '/edit/:process_id',
            template: '<mc-process-edit></mc-process-edit>',
            resolve: {
                _process: ['process', 'projectsService', '$stateParams', 'processEdit', 'templates',
                    function(process, projectsService, $stateParams, processEdit, templates) {
                        return projectsService.getProjectProcess($stateParams.project_id, $stateParams.process_id)
                            .then(function(proc) {
                                var t = templates.getTemplate(proc.process_name);
                                var p = processEdit.fillProcess(t, proc);
                                process.set(p);
                                return p;
                            });
                    }]
            }
        })
        .state('project.samples', {
            url: '/samples',
            template: '<mc-project-samples samples="ctrl.samples"></mc-project-samples>',
            controllerAs: 'ctrl',
            controller: ['samplesService', '$stateParams', 'toastr',
                function(samplesService, $stateParams, toastr) {
                    var ctrl = this;
                    ctrl.samples = [];
                    samplesService.getProjectSamples($stateParams.project_id).then(
                        (samples) => {
                            //console.dir(samples);
                            ctrl.samples = samples;
                        },
                        () => toastr.error('Error retrieving samples for project', 'Error', {closeButton: true})
                    );
                }]
        })
        .state('project.samples.sample', {
            url: '/sample/:sample_id',
            template: '<mc-sample></mc-sample>'
        })
        .state('project.files', {
            url: '/files',
            template: '<mc-file-tree flex layout-fill></mc-file-tree>'
        })
        .state('project.files.uploads', {
            url: '/uploads',
            template: '<mc-file-uploads></mc-file-uploads>'
        })
        .state('project.files.file', {
            url: '/file/:file_id',
            template: '<mc-file></mc-file>'
        })
        .state('project.files.dir', {
            url: '/dir/:dir_id',
            template: '<mc-dir></mc-dir>'
        })
        .state('project.settings', {
            url: '/settings',
            template: '<mc-project-settings></mc-project-settings>'
        });

    $urlRouterProvider.otherwise('/login');
}
<commit_msg>project.experiments route now passes all the experiments into the component.<commit_after>/*ngInject*/
export function setupRoutes($stateProvider, $urlRouterProvider) {
    $stateProvider
        .state('login', {
            url: '/login',
            template: '<mc-login></mc-login>'
        })
        .state('projects', {
            url: '/projects',
            abstract: true,
            template: '

'
        })
        .state('projects.list', {
            url: '/list',
            template: '<mc-projects></mc-projects>'
        })
        .state('projects.share', {
            url: '/share',
            template: '<mc-projects-share></mc-projects-share>'
        })
        .state('user', {
            url: '/user',
            abstract: true,
            template: '

'
        })
        .state('user.apikey', {
            url: '/apikey',
            template: '<mc-user-apikey></mc-user-apikey>'
        })
        .state('user.password', {
            url: '/password',
            template: '<mc-user-password></mc-user-password>'
        })
        .state('project', {
            url: '/project/:project_id',
            abstract: true,
            template: '<ui-view flex="100" layout="column"></ui-view>',
            resolve: {
                // Set the current project in the project service so all components
                // will resolve without having to worry if a promise has resolved.
                // The resolved object is ignored.
                _project: ["$stateParams", "projectsService", "project",
                    // Inject projects so that it resolves before looking up the project.
                    function($stateParams, projectsService, project) {
                        return projectsService.getProject($stateParams.project_id)
                            .then(function(proj) {
                                project.set(proj);
                                return proj;
                            });
                    }],

                _templates: ["processTemplates", "templates", "_project",
                    function(processTemplates, templates, project) {
                        var projectTemplates = processTemplates.templates(project.process_templates, project.id);
                        templates.set(projectTemplates);
                        return projectTemplates;
                    }]
            }
        })
        .state('project.home', {
            url: '/home',
            template: '<mc-project-home></mc-project-home>',
            // hack to update project view
            resolve: {
                // Set the current project in the project service so all components
                // will resolve without having to worry if a promise has resolved.
                // The resolved object is ignored.
                _project: ["$stateParams", "projectsService", "project",
                    // Inject projects so that it resolves before looking up the project.
                    function($stateParams, projectsService, project) {
                        return projectsService.getProject($stateParams.project_id)
                            .then(function(proj) {
                                project.set(proj);
                                return proj;
                            });
                    }]
            }
        })
        .state('project.search', {
            url: '/search/:query',
            template: '<mc-project-search></mc-project-search>'
        })
        .state('project.create', {
            url: '/create',
            abstract: true,
            template: '<ui-view flex layout="column"></ui-view>'
        })
        .state('project.experiment', {
            url: '/experiment/:experiment_id',
            template: '<mc-experiment></mc-experiment>'
        })
        .state('project.create.process', {
            url: '/process/:template_id/:process_id',
            template: '<mc-process-create></mc-process-create>',
            resolve: {
                _template: ['templates', 'template', '$stateParams', 'projectsService',
                    function(templates, template, $stateParams, projectsService) {
                        if ($stateParams.process_id) {
                            return projectsService.getProjectProcess($stateParams.project_id, $stateParams.process_id)
                                .then(function(process) {
                                    var t = templates.loadTemplateFromProcess($stateParams.template_id, process);
                                    template.set(t);
                                    return t;
                                });
                        } else {
                            var t = templates.getTemplate($stateParams.template_id);
                            template.set(t);
                            return t;
                        }
                    }]
            }
        })
        .state('project.experiments', {
            url: '/experiments',
            template: '<mc-project-experiments experiments="ctrl.experiments"></mc-project-experiments>',
            controllerAs: 'ctrl',
            controller: ['$stateParams', 'experimentsService', 'toastr', function($stateParams, experimentsService, toastr) {
                let ctrl = this;
                ctrl.experiments = [];
                experimentsService.getAllForProject($stateParams.project_id).then(
                    (experiments) => {
                        ctrl.experiments = experiments;
                    },
                    () => toastr.error('Unable to retrieve experiments for project', 'Error', {closeButton: true})
                );
            }]
        })
        .state('project.processes', {
            url: '/processes',
            template: '<mc-project-processes processes="ctrl.processes"></mc-project-processes>',
            controllerAs: 'ctrl',
            controller: ['projectsService', '$stateParams', 'toastr',
                function(projectsService, $stateParams, toastr) {
                    var ctrl = this;
                    ctrl.processes = [];
                    projectsService.getProjectProcesses($stateParams.project_id).then(
                        (processes) => {
                            ctrl.processes = processes;
                        },
                        () => toastr.error('Unable to retrieve project processes', 'Error', {closeButton: true})
                    )
                }]
        })
        .state('project.processes.process', {
            url: '/process/:process_id',
            template: '<mc-process></mc-process>',
            resolve: {
                _process: ['process', 'projectsService', '$stateParams',
                    function(process, projectsService, $stateParams) {
                        return projectsService.getProjectProcess($stateParams.project_id, $stateParams.process_id)
                            .then(function(p) {
                                process.set(p);
                                return p;
                            });
                    }]
            }
        })
        .state('project.processes.edit', {
            url: '/edit/:process_id',
            template: '<mc-process-edit></mc-process-edit>',
            resolve: {
                _process: ['process', 'projectsService', '$stateParams', 'processEdit', 'templates',
                    function(process, projectsService, $stateParams, processEdit, templates) {
                        return projectsService.getProjectProcess($stateParams.project_id, $stateParams.process_id)
                            .then(function(proc) {
                                var t = templates.getTemplate(proc.process_name);
                                var p = processEdit.fillProcess(t, proc);
                                process.set(p);
                                return p;
                            });
                    }]
            }
        })
        .state('project.samples', {
            url: '/samples',
            template: '<mc-project-samples samples="ctrl.samples"></mc-project-samples>',
            controllerAs: 'ctrl',
            controller: ['samplesService', '$stateParams', 'toastr',
                function(samplesService, $stateParams, toastr) {
                    var ctrl = this;
                    ctrl.samples = [];
                    samplesService.getProjectSamples($stateParams.project_id).then(
                        (samples) => {
                            //console.dir(samples);
                            ctrl.samples = samples;
                        },
                        () => toastr.error('Error retrieving samples for project', 'Error', {closeButton: true})
                    );
                }]
        })
        .state('project.samples.sample', {
            url: '/sample/:sample_id',
            template: '<mc-sample></mc-sample>'
        })
        .state('project.files', {
            url: '/files',
            template: '<mc-file-tree flex layout-fill></mc-file-tree>'
        })
        .state('project.files.uploads', {
            url: '/uploads',
            template: '<mc-file-uploads></mc-file-uploads>'
        })
        .state('project.files.file', {
            url: '/file/:file_id',
            template: '<mc-file></mc-file>'
        })
        .state('project.files.dir', {
            url: '/dir/:dir_id',
            template: '<mc-dir></mc-dir>'
        })
        .state('project.settings', {
            url: '/settings',
            template: '<mc-project-settings></mc-project-settings>'
        });

    $urlRouterProvider.otherwise('/login');
}
<|endoftext|>


<commit_before>const jetpack = require('fs-jetpack')
const print = require('../utils/print')
const {
  identity,
  replace,
  prop,
  pipe,
  filter,
  propEq,
  any,
  forEach,
  cond,
  always,
  equals,
  sortBy,
  concat
} = require('ramda')

/**
 * Does this have a loadState error?
 */
const hasLoadStateError = propEq('loadState', 'error')

/**
 * Does this plugin have any problems?
 *
 * @param  {Plugin} plugin The plugin to check
 * @return {bool}          `true` if problems otherwise `false`
 */
const hasProblem = plugin =>
  hasLoadStateError(plugin) ||
  any(hasLoadStateError, plugin.commands) ||
  any(hasLoadStateError, plugin.extensions)

/**
 * Provides a human explanation of the plugin error.
 *
 * @param  {string} errorState The error state
 * @return {string}
 */
const humanizePluginError = cond([
  [equals('ok'), identity],
  [equals('missingdir'), always('Missing Directory')],
  [equals('badname'), always('Invalid Name')],
  [always, concat('Unknown Error - ')]
])

/**
 * Provides a human explanation of the command error.
 *
 * @param  {string} errorState The error state
 * @return {string}
 */
const humanizeCommandError = cond([
  [equals('ok'), identity],
  [equals('missingdir'), always('Missing Directory')],
  [equals('badfunction'), always('Problem with function')],
  [equals('badfile'), always('Problem parsing file')],
  [always, concat('Unknown Error - ')]
])

/**
 * Prints debug information about the runtime.
 */
module.exports = function (runtime) {
  print.newline()

  const cwdslash = jetpack.cwd() + '/'

  // grab the printable errors
  const printable = pipe(
    filter(hasProblem),
    sortBy(prop('name'))
  )(runtime.plugins)

  // and print!
  forEach(plugin => {
    // find the relative directory
    const pluginRelativeDir = replace(cwdslash, '', plugin.directory)

    // start with a divider to see between plugins
    print.divider()

    // print some information about the plugin
    const pluginWriter = hasProblem(plugin) ? print.colors.error : print.colors.success
    const problemDescription = plugin.errorState !== 'none' &&
      print.colors.error(`-- ${humanizePluginError(plugin.errorState)}`)
    print.fancy(print.colors.muted('plugin ') + pluginWriter(`${plugin.name} ${problemDescription}`))
    print.info('  ' + pluginRelativeDir)
    print.newline()

    // print the extensions
    forEach(extension => {
      // print the name (with optional error message)
      const colorWriter = hasLoadStateError(extension) ? print.colors.error : print.colors.success
      const commandErrorDescription = extension.errorState !== 'none' &&
        print.colors.error(`-- ${humanizeCommandError(extension.errorState)}`)
      print.fancy(print.colors.muted('extension ') + colorWriter(`${extension.name} ${commandErrorDescription}`))

      // the directory
      print.info('  ' + pluginRelativeDir + '/' + replace(plugin.directory + '/', '', extension.file))

      // print the exception if we have one
      if (extension.exception) {
        print.newline()
        console.dir(extension.exception)
      }

      print.newline()
    }, filter(hasLoadStateError, plugin.extensions))

    // print the commands
    forEach(command => {
      // print the name (with optional error message)
      const colorWriter = hasLoadStateError(command) ? print.colors.error : print.colors.success
      const commandErrorDescription = command.errorState !== 'none' &&
        print.colors.error(`-- ${humanizeCommandError(command.errorState)}`)
      print.fancy(print.colors.muted('command ') + colorWriter(`${command.name} ${commandErrorDescription}`))

      // the description if we have one
      if (command.description) {
        print.info(`  ${print.colors.muted(command.description)}`)
      }
      // the directory
      print.info('  ' + pluginRelativeDir + '/' + replace(plugin.directory + '/', '', command.file))

      // the exception if any
      if (command.exception) {
        print.newline()
        console.dir(command.exception)
      }

      print.newline()
    }, filter(hasLoadStateError, plugin.commands))
  }, printable)
}
<commit_msg>Cleans up the printWtf logging.<commit_after>const jetpack = require('fs-jetpack')
const print = require('../utils/print')
const {
  identity,
  replace,
  prop,
  pipe,
  filter,
  propEq,
  any,
  forEach,
  cond,
  always,
  equals,
  sortBy,
  concat
} = require('ramda')

/**
 * Does this have a loadState error?
 */
const hasLoadStateError = propEq('loadState', 'error')

/**
 * Does this plugin have any problems?
 *
 * @param  {Plugin} plugin The plugin to check
 * @return {bool}          `true` if problems otherwise `false`
 */
const hasProblem = plugin =>
  hasLoadStateError(plugin) ||
  any(hasLoadStateError, plugin.commands) ||
  any(hasLoadStateError, plugin.extensions)

/**
 * Provides a human explanation of the plugin error.
 *
 * @param  {string} errorState The error state
 * @return {string}
 */
const humanizePluginError = cond([
  [equals('ok'), identity],
  [equals('missingdir'), always('Missing Directory')],
  [equals('badname'), always('Invalid Name')],
  [always, concat('Unknown Error - ')]
])

/**
 * Provides a human explanation of the command error.
 *
 * @param  {string} errorState The error state
 * @return {string}
 */
const humanizeCommandError = cond([
  [equals('ok'), identity],
  [equals('missingdir'), always('Missing Directory')],
  [equals('badfunction'), always('Problem with function')],
  [equals('badfile'), always('Problem parsing file')],
  [always, concat('Unknown Error - ')]
])

/**
 * Prints debug information about the runtime.
 */
module.exports = function (runtime) {
  print.newline()

  const cwdslash = jetpack.cwd() + '/'

  // grab the printable errors
  const printable = pipe(
    filter(hasProblem),
    sortBy(prop('name'))
  )(runtime.plugins)

  // and print!
  forEach(plugin => {
    // find the relative directory
    const pluginRelativeDir = replace(cwdslash, '', plugin.directory)

    // start with a divider to see between plugins
    print.divider()

    // print some information about the plugin
    const pluginWriter = hasProblem(plugin) ? print.colors.error : print.colors.success
    const problemDescription = plugin.errorState !== 'none'
      ? print.colors.error(`-- ${humanizePluginError(plugin.errorState)}`)
      : ''
    print.fancy(print.colors.muted('plugin ') + pluginWriter(`${plugin.name} ${problemDescription}`))
    print.info('  ' + pluginRelativeDir)
    print.newline()

    // print the extensions
    forEach(extension => {
      // print the name (with optional error message)
      const colorWriter = hasLoadStateError(extension) ? print.colors.error : print.colors.success
      const commandErrorDescription = extension.errorState !== 'none'
        ? print.colors.error(`-- ${humanizeCommandError(extension.errorState)}`)
        : ''
      print.fancy(print.colors.muted('extension ') + colorWriter(`${extension.name} ${commandErrorDescription}`))

      // the directory
      print.info('  ' + pluginRelativeDir + '/' + replace(plugin.directory + '/', '', extension.file))

      // print the exception if we have one
      if (extension.exception) {
        print.newline()
        console.dir(extension.exception)
      }

      print.newline()
    }, filter(hasLoadStateError, plugin.extensions))

    // print the commands
    forEach(command => {
      // print the name (with optional error message)
      const colorWriter = hasLoadStateError(command) ? print.colors.error : print.colors.success
      const commandErrorDescription = command.errorState !== 'none'
        ? print.colors.error(`-- ${humanizeCommandError(command.errorState)}`)
        : ''
      print.fancy(print.colors.muted('command ') + colorWriter(`${command.name} ${commandErrorDescription}`))

      // the description if we have one
      if (command.description) {
        print.info(`  ${print.colors.muted(command.description)}`)
      }
      // the directory
      print.info('  ' + pluginRelativeDir + '/' + replace(plugin.directory + '/', '', command.file))

      // the exception if any
      if (command.exception) {
        print.newline()
        console.dir(command.exception)
      }

      print.newline()
    }, filter(hasLoadStateError, plugin.commands))
  }, printable)
}
<|endoftext|>


<commit_before>const {resolve, join} = require('path');
const webpack = require('webpack');

const rootDir = join(__dirname, '..');
const libSources = join(rootDir, 'modules');
const packageVersion = require('../lerna.json').version;

const ALIASES = require('ocular-dev-tools/config/ocular.config')({
  aliasMode: 'src',
  root: resolve(__dirname, '..')
}).aliases;

// Otherwise modules imported from outside this directory does not compile
// Seems to be a Babel bug
// https://github.com/babel/babel-loader/issues/149#issuecomment-191991686
const BABEL_CONFIG = {
  // https://babeljs.io/docs/en/babel-polyfill#size
  presets: [['@babel/preset-env', {useBuiltIns: 'usage'}], '@babel/preset-react'],
  plugins: [
    ['@babel/plugin-proposal-decorators', {legacy: true}],
    ['@babel/plugin-proposal-class-properties', {loose: true}]
  ]
};

const COMMON_CONFIG = {
  entry: ['./src/main'],

  devServer: {
    contentBase: [resolve(__dirname, './src/static')]
  },

  output: {
    path: resolve(__dirname, './dist'),
    filename: 'bundle.js'
  },

  externals: {
    'highlight.js': 'hljs'
  },

  module: {
    rules: [
      {
        // Compile ES2015 using bable
        test: /\.js$/,
        loader: 'babel-loader',
        options: BABEL_CONFIG,
        include: [resolve('..'), libSources],
        exclude: [/node_modules/]
      },
      {
        test: /\.scss$/,
        use: [
          // style-loader
          {loader: 'style-loader'},
          // css-loader
          {
            loader: 'css-loader',
            options: {
              url: false
            }
          },
          // sass-loader
          {loader: 'sass-loader'}
        ]
      }
    ],

    // Uglify seems to be incompatible with mapbox
    // https://github.com/mapbox/mapbox-gl-js/issues/4359#issuecomment-288001933
    noParse: /(mapbox-gl)\.js$/
  },

  resolve: {
    // Prefer local dependencies over root
    modules: [resolve('./node_modules'), resolve('../node_modules')],
    alias: Object.assign({}, ALIASES, {
      'website-examples': resolve('../examples/website'),
      'viewport-mercator-project': resolve('../node_modules/viewport-mercator-project')
    })
  },

  node: {
    fs: 'empty'
  },

  plugins: [
    // Uncomment to analyze bundle size
    // new (require('webpack-bundle-analyzer').BundleAnalyzerPlugin)(),
    new webpack.EnvironmentPlugin(['MapboxAccessToken'])
  ]
};

const addDevConfig = config => {
  config.module.rules.push({
    // Unfortunately, webpack doesn't import library sourcemaps on its own...
    test: /\.js$/,
    use: ['source-map-loader'],
    enforce: 'pre'
  });

  config.devServer.contentBase.push(resolve(__dirname, '../'));

  return Object.assign(config, {
    mode: 'development',
    devtool: 'source-maps',

    plugins: config.plugins.concat([
      // new webpack.HotModuleReplacementPlugin(),
      new webpack.NoEmitOnErrorsPlugin(),
      new webpack.DefinePlugin({
        USE_LOCAL_PAGES: true // eslint-disable-line
      }),
      new webpack.DefinePlugin({
        DOCS_DIR: JSON.stringify('.')
      })
    ])
  });
};

const addProdConfig = config => {
  config.plugins = config.plugins.concat(
    new webpack.DefinePlugin({
      __VERSION__: JSON.stringify(packageVersion),
      DOCS_DIR: JSON.stringify('https://raw.githubusercontent.com/uber/deck.gl/master')
    })
  );

  return Object.assign(config, {
    mode: 'production'
  });
};

module.exports = env => {
  env = env || {};

  let config = COMMON_CONFIG;

  if (env.local) {
    config = addDevConfig(config);
  }

  if (env.prod) {
    config = addProdConfig(config);
  }

  // Enable to debug config
  // console.warn(JSON.stringify(config, null, 2));

  return config;
};
<commit_msg>Website reference ES5 transpiled version of supercluster depend… (#3427)<commit_after>const {resolve, join} = require('path');
const webpack = require('webpack');

const rootDir = join(__dirname, '..');
const libSources = join(rootDir, 'modules');
const packageVersion = require('../lerna.json').version;

const ALIASES = require('ocular-dev-tools/config/ocular.config')({
  aliasMode: 'src',
  root: resolve(__dirname, '..')
}).aliases;

// Otherwise modules imported from outside this directory does not compile
// Seems to be a Babel bug
// https://github.com/babel/babel-loader/issues/149#issuecomment-191991686
const BABEL_CONFIG = {
  // https://babeljs.io/docs/en/babel-polyfill#size
  presets: [['@babel/preset-env', {useBuiltIns: 'usage'}], '@babel/preset-react'],
  plugins: [
    ['@babel/plugin-proposal-decorators', {legacy: true}],
    ['@babel/plugin-proposal-class-properties', {loose: true}]
  ]
};

const COMMON_CONFIG = {
  entry: ['./src/main'],

  devServer: {
    contentBase: [resolve(__dirname, './src/static')]
  },

  output: {
    path: resolve(__dirname, './dist'),
    filename: 'bundle.js'
  },

  externals: {
    'highlight.js': 'hljs'
  },

  module: {
    rules: [
      {
        // Compile ES2015 using bable
        test: /\.js$/,
        loader: 'babel-loader',
        options: BABEL_CONFIG,
        include: [resolve('..'), libSources],
        exclude: [/node_modules/]
      },
      {
        test: /\.scss$/,
        use: [
          // style-loader
          {loader: 'style-loader'},
          // css-loader
          {
            loader: 'css-loader',
            options: {
              url: false
            }
          },
          // sass-loader
          {loader: 'sass-loader'}
        ]
      }
    ],

    // Uglify seems to be incompatible with mapbox
    // https://github.com/mapbox/mapbox-gl-js/issues/4359#issuecomment-288001933
    noParse: /(mapbox-gl)\.js$/
  },

  resolve: {
    // Prefer local dependencies over root
    modules: [resolve('./node_modules'), resolve('../node_modules')],
    alias: Object.assign({}, ALIASES, {
      'website-examples': resolve('../examples/website'),
      'viewport-mercator-project': resolve('../node_modules/viewport-mercator-project'),
      supercluster: resolve('../node_modules/supercluster/dist/supercluster.js')
    })
  },

  node: {
    fs: 'empty'
  },

  plugins: [
    // Uncomment to analyze bundle size
    // new (require('webpack-bundle-analyzer').BundleAnalyzerPlugin)(),
    new webpack.EnvironmentPlugin(['MapboxAccessToken'])
  ]
};

const addDevConfig = config => {
  config.module.rules.push({
    // Unfortunately, webpack doesn't import library sourcemaps on its own...
    test: /\.js$/,
    use: ['source-map-loader'],
    enforce: 'pre'
  });

  config.devServer.contentBase.push(resolve(__dirname, '../'));

  return Object.assign(config, {
    mode: 'development',
    devtool: 'source-maps',

    plugins: config.plugins.concat([
      // new webpack.HotModuleReplacementPlugin(),
      new webpack.NoEmitOnErrorsPlugin(),
      new webpack.DefinePlugin({
        USE_LOCAL_PAGES: true // eslint-disable-line
      }),
      new webpack.DefinePlugin({
        DOCS_DIR: JSON.stringify('.')
      })
    ])
  });
};

const addProdConfig = config => {
  config.plugins = config.plugins.concat(
    new webpack.DefinePlugin({
      __VERSION__: JSON.stringify(packageVersion),
      DOCS_DIR: JSON.stringify('https://raw.githubusercontent.com/uber/deck.gl/master')
    })
  );

  return Object.assign(config, {
    mode: 'production'
  });
};

module.exports = env => {
  env = env || {};

  let config = COMMON_CONFIG;

  if (env.local) {
    config = addDevConfig(config);
  }

  if (env.prod) {
    config = addProdConfig(config);
  }

  // Enable to debug config
  // console.warn(JSON.stringify(config, null, 2));

  return config;
};
<|endoftext|>


<commit_before>// rollup.config.js
export default {
  input: 'index.js',
  output: [
  	  {
	    file: 'dist/helpers-lib-cjs.js',
	    format: 'cjs'
	  },
	  {
	    file: 'dist/helpers-lib-es6.js',
	    format: 'es'
	  },
	  {
	    file: 'dist/helpers-lib-umd.js',
	    name: 'jison-helpers-lib',
	    format: 'umd'
	  }
  ]
};
<commit_msg>make all rollup.config.js files similar, i.e. every rollup process should be the same.<commit_after>// rollup.config.js
import resolve from 'rollup-plugin-node-resolve';

export default {
  input: 'index.js',
  output: [
  	  {
	    file: 'dist/helpers-lib-cjs.js',
	    format: 'cjs'
	  },
	  {
	    file: 'dist/helpers-lib-es6.js',
	    format: 'es'
	  },
	  {
	    file: 'dist/helpers-lib-umd.js',
	    name: 'jison-helpers-lib',
	    format: 'umd'
	  }
  ],
  plugins: [
    resolve({
      // use "module" field for ES6 module if possible
      module: true, // Default: true

      // use "main" field or index.js, even if it's not an ES6 module
      // (needs to be converted from CommonJS to ES6
      //  see https://github.com/rollup/rollup-plugin-commonjs
      main: true,  // Default: true

      // not all files you want to resolve are .js files
      extensions: [ '.js' ],  // Default: ['.js']

      // whether to prefer built-in modules (e.g. `fs`, `path`) or
      // local ones with the same names
      preferBuiltins: true,  // Default: true

      // If true, inspect resolved files to check that they are
      // ES2015 modules
      modulesOnly: true, // Default: false
    })
  ],
  external: [
    '@gerhobbelt/ast-util',
    '@gerhobbelt/json5',
    '@gerhobbelt/nomnom',
    '@gerhobbelt/prettier-miscellaneous',
    '@gerhobbelt/recast',
    '@gerhobbelt/xregexp',
    'assert',
    'fs',
    'path',
    'process',
  ]
};
<|endoftext|>


<commit_before>'use strict';

/**
 * Watch later controller.
 */
angular.module('mytube').controller('WatchLater', function($scope, Firebase) {
  $scope.data = Firebase.getPlaylist('WL');

  $scope.watchlater = function(video) {
    $scope.data.$remove(video);
  };

  $scope.addFromUrl = function() {
    if (!$scope.videoId) {
      return;
    }

    var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/;
    var videoId = null;
    var match = $scope.videoId.match(regExp);
    if (match && match[7].length == 11){
      videoId = match[7];
    } else {
      alert('Not a valid YouTube URL');
      return;
    }

    gapi.client.youtube.videos.list({
      id: videoId,
      part: 'snippet,contentDetails,statistics'
    }).execute(function(response) {
          var video = response.items[0];
          $scope.videoId = '';

          $scope.data.$add({
            id: video.id,
            title: video.snippet.title,
            description: video.snippet.description,
            channel_id: video.snippet.channelId,
            channel_title: video.snippet.channelTitle,
            published_date: Date.parse(video.snippet.publishedAt),
            view_count: video.statistics.viewCount,
            like_count: video.statistics.likeCount,
            dislike_count: video.statistics.dislikeCount,
            duration: video.contentDetails.duration,
            thumbnails: {
              medium: {
                url: video.snippet.thumbnails.medium.url,
                width: video.snippet.thumbnails.medium.width,
                height: video.snippet.thumbnails.medium.height
              },
              high: {
                url: video.snippet.thumbnails.high.url,
                width: video.snippet.thumbnails.high.width,
                height: video.snippet.thumbnails.high.height
              }
            }
          });
        });
  };

  $scope.youtubeDL = function () {
    $scope.youtubeDLoutput = 'youtube-dl -U\n';
    _.each($scope.data, function (video) {
      $scope.youtubeDLoutput += 'youtube-dl -i --write-sub --all-subs --write-thumbnail -w --write-description --write-info-json --write-annotations -f \'bestvideo[height<=1080]+bestaudio/best[height<=1080]\' --merge-output-format mkv  https://www.youtube.com/watch?v=' + video.id + '\n';
    });
    $scope.youtubeDLoutput += '\n';
  };
});<commit_msg>remove dislike count<commit_after>'use strict';

/**
 * Watch later controller.
 */
angular.module('mytube').controller('WatchLater', function($scope, Firebase) {
  $scope.data = Firebase.getPlaylist('WL');

  $scope.watchlater = function(video) {
    $scope.data.$remove(video);
  };

  $scope.addFromUrl = function() {
    if (!$scope.videoId) {
      return;
    }

    var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/;
    var videoId = null;
    var match = $scope.videoId.match(regExp);
    if (match && match[7].length == 11){
      videoId = match[7];
    } else {
      alert('Not a valid YouTube URL');
      return;
    }

    gapi.client.youtube.videos.list({
      id: videoId,
      part: 'snippet,contentDetails,statistics'
    }).execute(function(response) {
          var video = response.items[0];
          $scope.videoId = '';

          $scope.data.$add({
            id: video.id,
            title: video.snippet.title,
            description: video.snippet.description,
            channel_id: video.snippet.channelId,
            channel_title: video.snippet.channelTitle,
            published_date: Date.parse(video.snippet.publishedAt),
            view_count: video.statistics.viewCount,
            like_count: video.statistics.likeCount,
            duration: video.contentDetails.duration,
            thumbnails: {
              medium: {
                url: video.snippet.thumbnails.medium.url,
                width: video.snippet.thumbnails.medium.width,
                height: video.snippet.thumbnails.medium.height
              },
              high: {
                url: video.snippet.thumbnails.high.url,
                width: video.snippet.thumbnails.high.width,
                height: video.snippet.thumbnails.high.height
              }
            }
          });
        });
  };

  $scope.youtubeDL = function () {
    $scope.youtubeDLoutput = 'youtube-dl -U\n';
    _.each($scope.data, function (video) {
      $scope.youtubeDLoutput += 'youtube-dl -i --write-sub --all-subs --write-thumbnail -w --write-description --write-info-json --write-annotations -f \'bestvideo[height<=1080]+bestaudio/best[height<=1080]\' --merge-output-format mkv  https://www.youtube.com/watch?v=' + video.id + '\n';
    });
    $scope.youtubeDLoutput += '\n';
  };
});
<|endoftext|>


<commit_before>/** @jsx createElement */
import { Component, createElement, render } from '../src/index'
import sinon from 'sinon'
import { normalizeHTML } from './util'

describe('patch', () => {
  let scratch

  beforeEach(() => {
    scratch = document.createElement('div')
  })

  it('should not patch when stateless component scu was set false', () => {
    const App = ({ text }) =>
{text}

    render(<App text='test' onShouldComponentUpdate={() => false} />, scratch)
    render(<App text='qweqe' onShouldComponentUpdate={() => false} />, scratch)
    expect(scratch.firstChild.textContent).toBe('test')
  })

  it('should handle float', () => {
    const App = () =>

    render(<App />, scratch)
    expect(scratch.innerHTML).toContain('left')
    // console.log(scratch.innerHTML)
  })

  it('should ignore last style when it does not exist', () => {
    render(
, scratch)
    render(
, scratch)
    render(
, scratch)
    render(
, scratch)
    expect(scratch.innerHTML).toContain('10px')
    // console.log(scratch.innerHTML)
  })

  it('should hanlde style', () => {
    let inst
    class App extends Component {
      constructor () {
        super(...arguments)
        this.state = {
          type: (

                1

a

b

          )
        }
        inst = this
      }

      render () {
        return this.state.type
      }
    }
    render(<App />, scratch)
    inst.setState({
      type: (

            1

a

b

      )
    })
    inst.forceUpdate()
    const style = getComputedStyle(scratch.firstChild.firstChild)
    expect(style.color.indexOf('123')).not.toBe('-1')
  })

  it('should handle classNames', () => {
    const key = Math.random()
    render(
, scratch)
    render(
, scratch)
    expect(scratch.firstChild.className).toBe('')
  })

  it('should handle order', () => {
    let inst
    class App extends Component {
      constructor () {
        super(...arguments)
        this.state = {
          type: (

1

a

b

          )
        }
        inst = this
      }

      render () {
        return this.state.type
      }
    }
    render(<App />, scratch)
    inst.setState({
      type: (

1

b

a

      )
    })
    inst.forceUpdate()
    expect(scratch.innerHTML).toEqual(
      normalizeHTML('

1

b

a

')
    )
  })

  it('unkeyed children diffing error', () => {
    class A extends Component {
      render () {
        return
 this is a component

      }
      componentWillUnmount () {
        // console.log('unmount')
      }
      componentDidMount () {
        // console.log('didMount')
      }
      componentDidUpdate () {
        // console.log('didUpdate')
      }
    }

    const cwu = sinon.spy(A.prototype, 'componentWillUnmount')
    const cdm = sinon.spy(A.prototype, 'componentDidMount')
    const cdu = sinon.spy(A.prototype, 'componentDidUpdate')

    class B extends Component {
      render () {
        const visible = this.props.visible
        return (

            {visible ?
this is a plain div
 : null}

        )
      }
    }

    let inst

    class App extends Component {
      state = { visible: false }

      setVisible (visible) {
        this.setState({
          visible
        })
      }

      constructor () {
        super(...arguments)
        inst = this
      }

      render () {
        return (

        )
      }
    }

    render(<App />, scratch)
    expect(cdm.callCount).toBe(1)
    inst.setVisible(true)
    inst.forceUpdate()
    expect(scratch.innerHTML).toEqual(
      normalizeHTML('

this is a plain div

 this is a component

')
    )
    expect(cwu.called).toBe(false)
    expect(cdm.callCount).toBe(1)
    expect(cdu.callCount).toBe(1)
    inst.setVisible(false)
    inst.forceUpdate()
    expect(scratch.innerHTML).toEqual(
     normalizeHTML('

 this is a component

')
    )
    expect(cwu.called).toBe(false)
    expect(cdm.callCount).toBe(1)
    expect(cdu.callCount).toBe(2)
    inst.setVisible(true)
    inst.forceUpdate()
    expect(scratch.innerHTML).toEqual(
      normalizeHTML('

this is a plain div

 this is a component

')
    )
    expect(cwu.called).toBe(false)
    expect(cdm.callCount).toBe(1)
    expect(cdu.callCount).toBe(3)
  })
})
<commit_msg>fix(test): IE8 ignore empty space<commit_after>/** @jsx createElement */
import { Component, createElement, render } from '../src/index'
import sinon from 'sinon'
import { normalizeHTML } from './util'

describe('patch', () => {
  let scratch

  beforeEach(() => {
    scratch = document.createElement('div')
  })

  it('should not patch when stateless component scu was set false', () => {
    const App = ({ text }) =>
{text}

    render(<App text='test' onShouldComponentUpdate={() => false} />, scratch)
    render(<App text='qweqe' onShouldComponentUpdate={() => false} />, scratch)
    expect(scratch.firstChild.textContent).toBe('test')
  })

  it('should handle float', () => {
    const App = () =>

    render(<App />, scratch)
    expect(scratch.innerHTML).toContain('left')
    // console.log(scratch.innerHTML)
  })

  it('should ignore last style when it does not exist', () => {
    render(
, scratch)
    render(
, scratch)
    render(
, scratch)
    render(
, scratch)
    expect(scratch.innerHTML).toContain('10px')
    // console.log(scratch.innerHTML)
  })

  it('should hanlde style', () => {
    let inst
    class App extends Component {
      constructor () {
        super(...arguments)
        this.state = {
          type: (

                1

a

b

          )
        }
        inst = this
      }

      render () {
        return this.state.type
      }
    }
    render(<App />, scratch)
    inst.setState({
      type: (

            1

a

b

      )
    })
    inst.forceUpdate()
    const style = getComputedStyle(scratch.firstChild.firstChild)
    expect(style.color.indexOf('123')).not.toBe('-1')
  })

  it('should handle classNames', () => {
    const key = Math.random()
    render(
, scratch)
    render(
, scratch)
    expect(scratch.firstChild.className).toBe('')
  })

  it('should handle order', () => {
    let inst
    class App extends Component {
      constructor () {
        super(...arguments)
        this.state = {
          type: (

1

a

b

          )
        }
        inst = this
      }

      render () {
        return this.state.type
      }
    }
    render(<App />, scratch)
    inst.setState({
      type: (

1

b

a

      )
    })
    inst.forceUpdate()
    expect(scratch.innerHTML).toEqual(
      normalizeHTML('

1

b

a

')
    )
  })

  it('unkeyed children diffing error', () => {
    class A extends Component {
      render () {
        return
this is a component

      }
      componentWillUnmount () {
        // console.log('unmount')
      }
      componentDidMount () {
        // console.log('didMount')
      }
      componentDidUpdate () {
        // console.log('didUpdate')
      }
    }

    const cwu = sinon.spy(A.prototype, 'componentWillUnmount')
    const cdm = sinon.spy(A.prototype, 'componentDidMount')
    const cdu = sinon.spy(A.prototype, 'componentDidUpdate')

    class B extends Component {
      render () {
        const visible = this.props.visible
        return (

            {visible ?
this is a plain div
 : null}

        )
      }
    }

    let inst

    class App extends Component {
      state = { visible: false }

      setVisible (visible) {
        this.setState({
          visible
        })
      }

      constructor () {
        super(...arguments)
        inst = this
      }

      render () {
        return (

        )
      }
    }

    render(<App />, scratch)
    expect(cdm.callCount).toBe(1)
    inst.setVisible(true)
    inst.forceUpdate()
    expect(scratch.innerHTML).toEqual(
      normalizeHTML('

this is a plain div

this is a component

')
    )
    expect(cwu.called).toBe(false)
    expect(cdm.callCount).toBe(1)
    expect(cdu.callCount).toBe(1)
    inst.setVisible(false)
    inst.forceUpdate()
    expect(scratch.innerHTML).toEqual(
     normalizeHTML('

this is a component

')
    )
    expect(cwu.called).toBe(false)
    expect(cdm.callCount).toBe(1)
    expect(cdu.callCount).toBe(2)
    inst.setVisible(true)
    inst.forceUpdate()
    expect(scratch.innerHTML).toEqual(
      normalizeHTML('

this is a plain div

this is a component

')
    )
    expect(cwu.called).toBe(false)
    expect(cdm.callCount).toBe(1)
    expect(cdu.callCount).toBe(3)
  })
})
<|endoftext|>


<commit_before>const keyboards = require('./keyboards');
const dbmanager = require('./dbmanager');
const strings = require('./strings');

// Rating

/**
 * Handles case when client clicks rate option after job is finished
 * @param  {Telegram:Bot} bot Bot that should respond
 * @param  {Telegram:Messager} msg Message received
 */
eventEmitter.on(strings.askRateFreelancerInline, ({ msg, bot }) => {
  const jobId = msg.data.split(strings.inlineSeparator)[1];

  dbmanager.findJobById(jobId, 'selectedCandidate client')
    .then(job => {
      const freelancer = job.selectedCandidate;

      let keyboard = keyboards.rateKeyboard(strings.rateClientInline, job._id);
      let send = {
        chat_id: job.current_inline_chat_id,
        message_id: job.current_inline_message_id,
        text: strings.rateClientMessage,
        reply_markup: {
          inline_keyboard: keyboard
        },
        disable_web_page_preview: 'true'
      };
      send.reply_markup = JSON.stringify(send.reply_markup);
      bot.editMessageText(send)
        .catch(err => console.log(err.error.description));
    });
});

/**
 * Handles case when freelancer clicks rate option after job is finished
 * @param  {Telegram:Bot} bot Bot that should respond
 * @param  {Telegram:Messager} msg Message received
 */
eventEmitter.on(strings.askRateClientInline, ({ msg, bot }) => {
  const jobId = msg.data.split(strings.inlineSeparator)[1];

  dbmanager.findJobById(jobId, 'client freelancer_chat_inlines selectedCandidate')
    .then(job => {
        let keyboard = keyboards.rateKeyboard(strings.rateFreelancerInline, job._id);
        const chatInline = dbmanager.chatInline(job, job.selectedCandidate);
        let send = {
          chat_id: chatInline.chat_id,
          message_id: chatInline.message_id,
          text: strings.rateClientMessage,
          reply_markup: {
            inline_keyboard: keyboard
          },
          disable_web_page_preview: 'true'
        };
        send.reply_markup = JSON.stringify(send.reply_markup);
        bot.editMessageText(send)
          .catch(err => console.log(err.error.description));
    });
});

/**
 * Handles case when client rates freelancer after job is done
 * @param  {Telegram:Bot} bot Bot that should respond
 * @param  {Telegram:Messager} msg Message received
 */
eventEmitter.on(strings.rateFreelancerInline, ({ msg, bot }) => {
  const rating = msg.data.split(strings.inlineSeparator)[1];
  const jobId = msg.data.split(strings.inlineSeparator)[2];

  dbmanager.findJobById(jobId, 'client freelancer_chat_inlines')
    .then(job => {
      dbmanager.findUserById(job.selectedCandidate)
        .then(freelancer => {
          writeReview(bot, job, rating, job.client, freelancer, strings.reviewTypes.byFreelancer);
        });
    });
});

/**
 * Handles case when freelancer rates client after job is done
 * @param  {Telegram:Bot} bot Bot that should respond
 * @param  {Telegram:Messager} msg Message received
 */
eventEmitter.on(strings.rateClientInline, ({ msg, bot }) => {
  const rating = msg.data.split(strings.inlineSeparator)[1];
  const jobId = msg.data.split(strings.inlineSeparator)[2];

  dbmanager.findJobById(jobId, 'client freelancer_chat_inlines')
    .then(job => {
      dbmanager.findUserById(job.selectedCandidate)
        .then(freelancer => {
          writeReview(bot, job, rating, job.client, freelancer, strings.reviewTypes.byClient);
        });
    });
});

/**
 * Adds review to client and freelancer user objects; clears message on user that rated
 * @param  {Telegram:Bot} bot        Bot that should respond
 * @param  {Mongoose:Job} job        Job about which the report is made
 * @param  {Number} rating     Rating 1-5 stars
 * @param  {Mongoose:User} client     Relevant client
 * @param  {Mongoose:User} freelancer Relevant freelancer
 * @param  {String} reviewType Type of review (client-freelancer or freelancer-client)
 */
function writeReview(bot, job, rating, client, freelancer, reviewType) {
  const byClient = (reviewType === strings.reviewTypes.byClient);
  const byUser = (byClient) ? client : freelancer;
  const toUser = (byClient) ? freelancer : client;
  const chatInline = dbmanager.chatInline(job, freelancer);
  const chat_id = (byClient) ? job.current_inline_chat_id : chatInline.chat_id;
  const message_id = (byClient) ? job.current_inline_message_id : chatInline.message_id;

  if ((job.reviewByClient && byClient) || (job.reviewByFreelancer && !byClient)) return;

  dbmanager.addReview({
    byUser: byUser,
    toUser: toUser,
    job: job._id,
    rate: rating,
    review: '',
    reviewType: reviewType
  })
    .then(dbReviewObject => {
      dbmanager.findUserById(toUser)
      .then(toUser => {
        toUser.reviews.push(dbReviewObject._id);
        toUser.rate += parseInt(rating);
        toUser.save()
          .then(toUser => {
            let message = {
              chat_id: toUser.id,
              text: `${job.description}\n\n${strings.youWereRated} ${rating}`,
              disable_web_page_preview: 'true'
            };
            bot.sendMessage(message)
              .catch(err => console.log(err.error.description));
          });
      });

      if (byClient) {
        job.reviewByClient = dbReviewObject._id;
      } else {
        job.reviewByFreelancer = dbReviewObject._id;
      }

      if (job.reviewByClient && job.reviewByFreelancer) {
        job.state = strings.jobStates.rated;
      }

      job.save();

      byUser.writeReview.push(dbReviewObject._id);
      byUser.save()
        .then(byUser => {
          let send = {
            chat_id: chat_id,
            message_id: message_id,
            text: `${job.description}\n\n${strings.thanksReviewMessage}`,
            reply_markup: {
              inline_keyboard: []
            },
            disable_web_page_preview: 'true'
          };
          send.reply_markup = JSON.stringify(send.reply_markup);
          bot.editMessageText(send)
            .catch(err => console.log(err.error.description));
        });
    });
}

// Exports
module.exports = {
    writeReview
};<commit_msg>small fix<commit_after>const keyboards = require('./keyboards');
const dbmanager = require('./dbmanager');
const strings = require('./strings');

// Rating

/**
 * Handles case when client clicks rate option after job is finished
 * @param  {Telegram:Bot} bot Bot that should respond
 * @param  {Telegram:Messager} msg Message received
 */
eventEmitter.on(strings.askRateFreelancerInline, ({ msg, bot }) => {
  sendRateKeyboard(msg, bot, strings.rateClientInline);
});

/**
 * Handles case when freelancer clicks rate option after job is finished
 * @param  {Telegram:Bot} bot Bot that should respond
 * @param  {Telegram:Messager} msg Message received
 */
eventEmitter.on(strings.askRateClientInline, ({ msg, bot }) => {
  sendRateKeyboard(msg, bot, strings.rateFreelancerInline);
});

/**
 * Handles case when client rates freelancer after job is done
 * @param  {Telegram:Bot} bot Bot that should respond
 * @param  {Telegram:Messager} msg Message received
 */
eventEmitter.on(strings.rateFreelancerInline, ({ msg, bot }) => {
  const rating = msg.data.split(strings.inlineSeparator)[1];
  const jobId = msg.data.split(strings.inlineSeparator)[2];

  dbmanager.findJobById(jobId, 'client freelancer_chat_inlines')
    .then(job => {
      dbmanager.findUserById(job.selectedCandidate)
        .then(freelancer => {
          writeReview(bot, job, rating, job.client, freelancer, strings.reviewTypes.byFreelancer);
        });
    });
});

/**
 * Handles case when freelancer rates client after job is done
 * @param  {Telegram:Bot} bot Bot that should respond
 * @param  {Telegram:Messager} msg Message received
 */
eventEmitter.on(strings.rateClientInline, ({ msg, bot }) => {
  const rating = msg.data.split(strings.inlineSeparator)[1];
  const jobId = msg.data.split(strings.inlineSeparator)[2];

  dbmanager.findJobById(jobId, 'client freelancer_chat_inlines')
    .then(job => {
      dbmanager.findUserById(job.selectedCandidate)
        .then(freelancer => {
          writeReview(bot, job, rating, job.client, freelancer, strings.reviewTypes.byClient);
        });
    });
});

function sendRateKeyboard(msg, bot, type) {
  const jobId = msg.data.split(strings.inlineSeparator)[1];

  dbmanager.findJobById(jobId)
    .then(job => {
      let keyboard = keyboards.rateKeyboard(type, job._id);
      let send = {
        chat_id: msg.message.chat.id,
        message_id: msg.message.message_id,
        text: strings.rateClientMessage,
        reply_markup: {
          inline_keyboard: keyboard
        },
        disable_web_page_preview: 'true'
      };
      send.reply_markup = JSON.stringify(send.reply_markup);
      bot.editMessageText(send)
        .catch(err => console.log(err.error.description));
    });
}

/**
 * Adds review to client and freelancer user objects; clears message on user that rated
 * @param  {Telegram:Bot} bot        Bot that should respond
 * @param  {Mongoose:Job} job        Job about which the report is made
 * @param  {Number} rating     Rating 1-5 stars
 * @param  {Mongoose:User} client     Relevant client
 * @param  {Mongoose:User} freelancer Relevant freelancer
 * @param  {String} reviewType Type of review (client-freelancer or freelancer-client)
 */
function writeReview(bot, job, rating, client, freelancer, reviewType) {
  const byClient = (reviewType === strings.reviewTypes.byClient);
  const byUser = (byClient) ? client : freelancer;
  const toUser = (byClient) ? freelancer : client;
  const chatInline = dbmanager.chatInline(job, freelancer);
  const chat_id = (byClient) ? job.current_inline_chat_id : chatInline.chat_id;
  const message_id = (byClient) ? job.current_inline_message_id : chatInline.message_id;

  if ((job.reviewByClient && byClient) || (job.reviewByFreelancer && !byClient)) return;

  dbmanager.addReview({
    byUser: byUser,
    toUser: toUser,
    job: job._id,
    rate: rating,
    review: '',
    reviewType: reviewType
  })
    .then(dbReviewObject => {
      dbmanager.findUserById(toUser)
      .then(toUser => {
        toUser.reviews.push(dbReviewObject._id);
        toUser.rate += parseInt(rating);
        toUser.save()
          .then(toUser => {
            let message = {
              chat_id: toUser.id,
              text: `${job.description}\n\n${strings.youWereRated} ${rating}`,
              disable_web_page_preview: 'true'
            };
            bot.sendMessage(message)
              .catch(err => console.log(err.error.description));
          });
      });

      if (byClient) {
        job.reviewByClient = dbReviewObject._id;
      } else {
        job.reviewByFreelancer = dbReviewObject._id;
      }

      if (job.reviewByClient && job.reviewByFreelancer) {
        job.state = strings.jobStates.rated;
      }

      job.save();

      byUser.writeReview.push(dbReviewObject._id);
      byUser.save()
        .then(byUser => {
          let send = {
            chat_id: chat_id,
            message_id: message_id,
            text: `${job.description}\n\n${strings.thanksReviewMessage}`,
            reply_markup: {
              inline_keyboard: []
            },
            disable_web_page_preview: 'true'
          };
          send.reply_markup = JSON.stringify(send.reply_markup);
          bot.editMessageText(send)
            .catch(err => console.log(err.error.description));
        });
    });
}

// Exports
module.exports = {
    writeReview
};<|endoftext|>


<commit_before>'use strict';

var CachingWriter = require('broccoli-caching-writer');
var path = require('path');
var fs = require('fs');
var _ = require('lodash');
var mkdirp = require('mkdirp');
var cheerio = require('cheerio');

function ensurePosix(filePath) {
  if (path.sep !== '/') {
    return filePath.split(path.sep).join('/');
  }
  return filePath;
}

function getHelperKey(filePath) {
  return path.basename(filePath)
    .replace(/\.[^/.]+$/, '')
    .replace(/[\s]/g, '-');
}

function getSVGData(svgContent) {
  var $svg = cheerio.load(svgContent, { xmlMode: true })('svg');
  var viewBox = $svg.attr('viewBox');
  var viewBoxValues = viewBox.split(/\s+/);

  return {
    content: $svg.html(),
    viewBox: viewBox,
    width: $svg.attr('width') || viewBoxValues[2],
    height: $svg.attr('height') || viewBoxValues[3]
  };
}

function filterItemsFor(assets, key) {
  return _
    .chain(assets)
    .map(key)
    .without(undefined)
    .countBy()
    .toPairs()
    .map(function(pair) {
      return { name: pair[0], count: pair[1] };
    })
    .value();
}

function filtersFor(assets, filters) {
  return filters.map(function(filter) {
    return {
      name: filter.name,
      key: filter.key,
      items: filterItemsFor(assets, filter.key)
    };
  });
}

/**
  All options:
  - outputFile,
  - strategy,
  - symbolsPrefix
*/
function DemoBuilder(inputNode, options) {
  if (!options || !options.outputFile) {
    throw new Error('the outputFile option is required');
  }

  CachingWriter.call(this, [inputNode], {
    name: 'DemoBuilder',
    annotation: options.annotation,
  });

  this.options = options;
}

DemoBuilder.prototype = Object.create(CachingWriter.prototype);
DemoBuilder.prototype.constructor = DemoBuilder;

DemoBuilder.prototype.build = function() {
  var demoContent = JSON.stringify(this.getDemoModel());
  var outputFilePath = path.join(this.outputPath, this.options.outputFile);
  mkdirp.sync(path.dirname(outputFilePath));
  fs.writeFileSync(outputFilePath, demoContent);
};

DemoBuilder.prototype.getFilePaths = function() {
  var posixFilePaths = this.listFiles().map(ensurePosix);

  return _.uniq(posixFilePaths).filter(function(filePath) {
    // files returned from this.listFiles are directories if they end in /
    var isDirectory = filePath.charAt(filePath.length - 1) === '/';
    return !isDirectory;
  });
};

DemoBuilder.prototype.getDemoAssetUsage = function(relativePath) {
  var helperKey = getHelperKey(relativePath);

  if (this.options.strategy === 'symbol') {
    helperKey = '#' + this.options.symbolsPrefix + helperKey;
  }

  return '{{svg-jar "' + helperKey + '"}}';
};

DemoBuilder.prototype.getDemoModel = function() {
  var inputPath = this.inputPaths[0];
  var posixInputPath = ensurePosix(inputPath);
  var demoAssets = [];
  var _this = this;

  this.getFilePaths().forEach(function(posixFilePath) {
    var relativePath = posixFilePath.replace(posixInputPath + '/', '');
    var filePath = path.join(inputPath, relativePath);
    var svgConent = fs.readFileSync(filePath, 'UTF-8');
    var fileName = path.basename(relativePath);
    var fileDir = relativePath.replace(fileName, '');
    var svgData = getSVGData(svgConent);

    demoAssets.push({
      svg: svgData,
      copypasta: _this.getDemoAssetUsage(relativePath),
      name: fileName,
      fileDir: fileDir,
      baseSize: svgData.height + 'px'
    });
  });

  return {
    sortBy: [
      { name: 'Asset name', key: 'name' },
      { name: 'Base size', key: 'baseSize' }
    ],

    arrangeBy: [
      { name: 'Directory', key: 'fileDir' },
      { name: 'Base size', key: 'baseSize' }
    ],

    filters: filtersFor(demoAssets, [
      { name: 'Directory', key: 'fileDir' },
      { name: 'Base size', key: 'baseSize' }
    ]),

    assets: demoAssets
  };
};

module.exports = DemoBuilder;
<commit_msg>Sort sidebar filters by name<commit_after>'use strict';

var CachingWriter = require('broccoli-caching-writer');
var path = require('path');
var fs = require('fs');
var _ = require('lodash');
var mkdirp = require('mkdirp');
var cheerio = require('cheerio');

function ensurePosix(filePath) {
  if (path.sep !== '/') {
    return filePath.split(path.sep).join('/');
  }
  return filePath;
}

function getHelperKey(filePath) {
  return path.basename(filePath)
    .replace(/\.[^/.]+$/, '')
    .replace(/[\s]/g, '-');
}

function getSVGData(svgContent) {
  var $svg = cheerio.load(svgContent, { xmlMode: true })('svg');
  var viewBox = $svg.attr('viewBox');
  var viewBoxValues = viewBox.split(/\s+/);

  return {
    content: $svg.html(),
    viewBox: viewBox,
    width: $svg.attr('width') || viewBoxValues[2],
    height: $svg.attr('height') || viewBoxValues[3]
  };
}

function filterItemsFor(assets, key) {
  return _
    .chain(assets)
    .map(key)
    .without(undefined)
    .countBy()
    .toPairs()
    .map(function(pair) {
      return { name: pair[0], count: pair[1] };
    })
    .sortBy('name')
    .value();
}

function filtersFor(assets, filters) {
  return filters.map(function(filter) {
    return {
      name: filter.name,
      key: filter.key,
      items: filterItemsFor(assets, filter.key)
    };
  });
}

/**
  All options:
  - outputFile,
  - strategy,
  - symbolsPrefix
*/
function DemoBuilder(inputNode, options) {
  if (!options || !options.outputFile) {
    throw new Error('the outputFile option is required');
  }

  CachingWriter.call(this, [inputNode], {
    name: 'DemoBuilder',
    annotation: options.annotation,
  });

  this.options = options;
}

DemoBuilder.prototype = Object.create(CachingWriter.prototype);
DemoBuilder.prototype.constructor = DemoBuilder;

DemoBuilder.prototype.build = function() {
  var demoContent = JSON.stringify(this.getDemoModel());
  var outputFilePath = path.join(this.outputPath, this.options.outputFile);
  mkdirp.sync(path.dirname(outputFilePath));
  fs.writeFileSync(outputFilePath, demoContent);
};

DemoBuilder.prototype.getFilePaths = function() {
  var posixFilePaths = this.listFiles().map(ensurePosix);

  return _.uniq(posixFilePaths).filter(function(filePath) {
    // files returned from this.listFiles are directories if they end in /
    var isDirectory = filePath.charAt(filePath.length - 1) === '/';
    return !isDirectory;
  });
};

DemoBuilder.prototype.getDemoAssetUsage = function(relativePath) {
  var helperKey = getHelperKey(relativePath);

  if (this.options.strategy === 'symbol') {
    helperKey = '#' + this.options.symbolsPrefix + helperKey;
  }

  return '{{svg-jar "' + helperKey + '"}}';
};

DemoBuilder.prototype.getDemoModel = function() {
  var inputPath = this.inputPaths[0];
  var posixInputPath = ensurePosix(inputPath);
  var demoAssets = [];
  var _this = this;

  this.getFilePaths().forEach(function(posixFilePath) {
    var relativePath = posixFilePath.replace(posixInputPath + '/', '');
    var filePath = path.join(inputPath, relativePath);
    var svgConent = fs.readFileSync(filePath, 'UTF-8');
    var fileName = path.basename(relativePath);
    var fileDir = relativePath.replace(fileName, '');
    var svgData = getSVGData(svgConent);

    demoAssets.push({
      svg: svgData,
      copypasta: _this.getDemoAssetUsage(relativePath),
      name: fileName,
      fileDir: fileDir,
      baseSize: svgData.height + 'px'
    });
  });

  return {
    sortBy: [
      { name: 'Asset name', key: 'name' },
      { name: 'Base size', key: 'baseSize' }
    ],

    arrangeBy: [
      { name: 'Directory', key: 'fileDir' },
      { name: 'Base size', key: 'baseSize' }
    ],

    filters: filtersFor(demoAssets, [
      { name: 'Directory', key: 'fileDir' },
      { name: 'Base size', key: 'baseSize' }
    ]),

    assets: demoAssets
  };
};

module.exports = DemoBuilder;
<|endoftext|>


<commit_before>/*
MIT License

Copyright (c) 2017 Grall Arnaud

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
'use strict';

const Q = require('q');
const Immutable = require('immutable');
const ldf = require('ldf-client');
const StatusQueue = require('./status-queue.js');
const DelegationProtocol = require('./delegation-protocol.js');
const NDPMessage = require('./ndp-message.js');
const uuidV4 = require('uuid/v4');

// LDF LOG Disabling
ldf.Logger.setLevel('EMERGENCY');
// ldf.Logger.setLevel('DEBUG');
// status
const STATUS_DELEGATED = 'status_delegated';

// utility to format dates in hh:mm:ss:ms
const formatTime = time => {
	const hours = time.getHours().toString(),
		min = time.getMinutes().toString(),
		sec = time.getSeconds().toString();
	let mil = time.getMilliseconds().toString();
	if(mil.length === 2) {
		mil = `0${mil}`;
	}
	return `${hours}:${min}:${sec}:${mil}`;
};

/**
 * Ladda delegation protocol
 * @extends DelegationProtocol
 * @author Arnaud Grall (Folkvir), Thomas Minier
 */
class LaddaProtocol extends DelegationProtocol {
	/**
	 * Constructor
	 * @param {int|undefined} nbDestinations - (optional) The number of destinations for delegation (default to 2, as in Ladda paper)
	 * @param {int|undefined} timeout - (optional) The timeout used by the protocol. Disable by default unless it is set.
	 */
	constructor (nbDestinations, timeout) {
		super('ladda');
		// this.queryQueue = Immutable.Map();
		this.queryQueue = new StatusQueue();
		this.busyPeers = Immutable.Set();
		this.isFree = true;
		this.nbDestinations = nbDestinations || 2;
		this.timeout = timeout || -1; // disable dy default
	}

	/**
	 * Set the foglet used by the protocol and configure how to handle incoming messages
	 * @param {NDP} foglet - The foglet used by the delegation protocol
	 * @return {void}
	 * @override
	 */
	use (foglet) {
		super.use(foglet);
		const self = this;
		this.foglet.onUnicast((id, message) => {
			const receiveMessageTime = formatTime(new Date());
			switch (message.type) {
			case 'request': {
				self.foglet._flog('@LADDA - Peer @' + self.foglet.id + ' received a query to execute from : @' + id);
				if(self.isFree && !self.queryQueue.hasWaitingQueries()) {
					self.isFree = false;
					const query = message.payload;
					const startExecutionTime = formatTime(new Date());
					self.execute(query, message.endpoint).then(result => {
						const endExecutionTime = formatTime(new Date());
						self.isFree = true;
						const msg = new NDPMessage({
							type: 'answer',
							id: this.foglet.id,
							schedulerId: message.id,
							payload: result,
							query: query,
							qId: message.qId,
							endpoint: message.endpoint,
							startTime: message.startTime,
							sendQueryTime: message.sendQueryTime,
							receiveQueryTime: receiveMessageTime,
							startExecutionTime,
							endExecutionTime
						});
						self.foglet._flog(msg);
						msg.sendResultsTime = formatTime(new Date());
						self.foglet.sendUnicast(msg, id);
					}).catch(error => {
						self.foglet._flog('**********************ERROR****************************');
						self.isFree = true;
						console.log(error);
						self.foglet._flog('*******************************************************');
					});
				} else {
					self.foglet._flog('@LADDA - Peer @' + self.foglet.id + ' is busy, cannot execute query ' + message.payload + ' from ' + id);
					const msg = new NDPMessage({
						type: 'failed',
						id,
						payload: message.payload,
						endpoint: message.endpoint,
						qId: message.qId,
						receiveQueryTime: receiveMessageTime
					});
					self.foglet._flog(msg);
					self.foglet.sendUnicast(msg, id);
				}
				break;
			}
			case 'answer': {
				try {
					self.foglet._flog('@LADDA : Received an answer from @' + message.id);
					self.queryQueue.setDone(message.qId);
					self.busyPeers = this.busyPeers.delete(id);
					message.receiveResultsTime = receiveMessageTime;
					self.foglet.events.emit('ndp-answer', message);
					// retry delegation if there's queries in the queue
					if(self.queryQueue.hasWaitingQueries()) self.delegateQueries(message.endpoint);
				} catch (e) {
					self.foglet._flog('**********************ERROR****************************');
					self.foglet._flog('@NDP : error ' + e);
					self.foglet._flog('*******************************************************');
				}
				break;
			}
			case 'failed': {
				self.foglet._flog('@LADDA : failed query from @' + message.id);
				self.queryQueue.setWaiting(message.qId);
				self.busyPeers = self.busyPeers.delete(id);
				if(self.isFree) self.delegateQueries(message.endpoint);
				break;
			}
			default:
				break;
			}
		});
	}

	/**
	 * Send queries to neighbours and emit results on ndp-answer
	 * @param {array} data array of element to send (query)
	 * @param {string} endpoint - Endpoint to send queries
	 * @return {promise} A Q promise
	 */
	send (data, endpoint) {
		// clear queue before anything
		this.queryQueue.clear();
		data.forEach(query => this.queryQueue.push(this._getNewUid(), query));
		console.log('===> Queue:');
		console.log(this.queryQueue.queries.toJS());
		return this.delegateQueries(endpoint);
	}

	/**
	 * Generate and return  a v4 UUID (random) based on uuid npm package
	 * @return {string} uuidv4
	 */
	_getNewUid () {
		return uuidV4();
	}

	// /**
	//  * Return true if the queue has queries to delegate
	//  * @return {boolean} True or false
	//  */
	// queueIsNotEmpty () {
	// 	return this.queryQueue.filter(x => x === STATUS_WAITING).count() > 0;
	// }

	/**
	 * Perform delegation using Ladda algorithm
	 * @param {string} endpoint - The LDF-server on which queries will be evaluated
	 * @return {Q.Promise} A Q Promise fullfilled when delegation is complete
	 */
	delegateQueries (endpoint) {
		this.foglet._flog('@LADDA - beginning delegation');
		const self = this;
		return Q.Promise((resolve, reject) => {
			try {
				if (self.queryQueue.hasWaitingQueries()) {
					self.foglet._flog('@LADDA - queue not empty, try to delegate to me first');
					if (self.isFree) {
						console.log(self.queryQueue.queries.toJS());
						self.foglet._flog('@LADDA - Peer @' + self.foglet.id + ' (client) will execute one query');
						const query = self.queryQueue.first();
						self.isFree = false;
						self.foglet._flog('@LADDA - Selected query:' + query.query);
						self.queryQueue.setDelegated(query.id);
						const startExecutionTime = formatTime(new Date());
						self.execute(query.query, endpoint).then(result => {
							self.queryQueue.setDone(query.id);
							const endExecutionTime = formatTime(new Date());
							self.isFree = true;
							const msg = new NDPMessage({
								type: 'answer',
								id: 'me',
								schedulerId: 'me',
								payload: result,
								query: query.query,
								qId: query.id,
								endpoint,
								sendQueryTime: startExecutionTime,
								receiveQueryTime: startExecutionTime,
								startExecutionTime,
								endExecutionTime,
								sendResultsTime: endExecutionTime,
								receiveResultsTime: endExecutionTime
							});
							self.foglet._flog('@LADDA - client finished query');
							self.emit('ndp-answer', msg);
							// retry delegation if there's queries in the queue
							if(self.queryQueue.hasWaitingQueries()) self.delegateQueries(endpoint);
						}).catch(error => {
							self.foglet._flog('**********************ERROR****************************');
							self.isFree = true;
							self.foglet._flog('@LADDA - Error : ' + error);
							self.foglet._flog('*******************************************************');
						});
					}
					self.foglet._flog('@LADDA - trying to delegate to peers');
					if (self.queryQueue.hasWaitingQueries()) {
						// delegate queries to peers
						const peers = self._choosePeers();
						self.foglet._flog('@LADDA - chosen peers: ' + peers);
						peers.forEach(peer => {
							if (self.queryQueue.hasWaitingQueries()) {
								const query = self.queryQueue.first();
								console.log(query);
								self.foglet._flog('@LADDA - delegate ' + query.query + ' to peer @' + peer);
								self.queryQueue.setDelegated(query.id);
								// mark the peer as 'busy'
								self.busyPeers = self.busyPeers.add(peer);
								const sendQueryTime = formatTime(new Date());
								self.foglet.sendUnicast(new NDPMessage({
									type: 'request',
									id: self.foglet.id,
									payload: query.query,
									qId: query.id,
									endpoint,
									sendQueryTime
								}), peer);
								// set timeout if necessary
								if (self.timeout > 0) {
									setTimeout(() => {
										if(self.queryQueue.getStatus(query.id) === STATUS_DELEGATED) {
											self.queryQueue.setWaiting(query.id);
											self.busyPeers = self.busyPeers.delete(peer);
										}
									}, self.timeout);
								}
							}
						});
					}
				}
				resolve('delegation done');
			} catch (e) {
				reject(e);
			}
		});
	}

	/**
	 * Execute one query on an endpoint using ldf-client
	 * @param {string} query - The query to execute
	 * @param {string} endpoint - Endpoint to process queries
	 * @return {Promise} A Promise with results as reponse
	 */
	execute (query, endpoint) {
		this.foglet._flog(' Execution of : ' + query + ' on ' + endpoint);
		console.log(query);
		let delegationResults = Immutable.List();
		const self = this;
		return Q.Promise( (resolve, reject) => {
			try {
				let fragmentsClient = new ldf.FragmentsClient(endpoint);
				let queryResults = new ldf.SparqlIterator(query, {fragmentsClient});
				queryResults.on('data', ldfResult => {
					delegationResults = delegationResults.push(ldfResult);
				});
				// resolve when all results are arrived
				queryResults.on('end', () => {
					self.isFree = true;
					resolve(delegationResults.toJS());
				});/* SEE WITH LDF-CLIENT BECAUSE THIS IS A BUG ! .catch((error) => reject(error) */
			} catch (error) {
				self.foglet._flog('**********************ERROR****************************');
				console.log(error);
				self.foglet._flog('*******************************************************');
				reject(error);
			}
		});
	}

	/**
	 * Choose non-busy peers fro query delegation
	 * @return {Immutable.Set} A set of peers selected for delegation
	 */
	_choosePeers () {
		let chosenPeers = Immutable.Set();
		let _peers = Immutable.Set();
		// gather non-busy peers
		_peers = _peers.union(this.foglet.getNeighbours());
		_peers = _peers.subtract(this.busyPeers).toList();
		let index = 0;
		// random selection beytween non-busy peers (as in LADDA algorithm)
		while( (chosenPeers.count() < this.nbDestinations) && (_peers.count() > 0)) {
			index = this._randomInt(0, _peers.count());
			chosenPeers = chosenPeers.add(_peers.get(index));
			_peers = _peers.remove(index);
		}
		return chosenPeers;
	}

	/**
	 * Pick a random int between two values
	 * @param {int} min - The lower bound
	 * @param {int} max - The upper bound (excluded)
	 * @return {int} A random int between min and max (excluded)
	 */
	_randomInt (min, max) {
		min = Math.ceil(min);
		max = Math.floor(max);
		return Math.floor(Math.random() * (max - min)) + min;
	}
}

module.exports = LaddaProtocol;
<commit_msg>fix another bug<commit_after>/*
MIT License

Copyright (c) 2017 Grall Arnaud

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
'use strict';

const Q = require('q');
const Immutable = require('immutable');
const ldf = require('ldf-client');
const StatusQueue = require('./status-queue.js');
const DelegationProtocol = require('./delegation-protocol.js');
const NDPMessage = require('./ndp-message.js');
const uuidV4 = require('uuid/v4');

// LDF LOG Disabling
ldf.Logger.setLevel('EMERGENCY');
// ldf.Logger.setLevel('DEBUG');
// status
const STATUS_DELEGATED = 'status_delegated';

// utility to format dates in hh:mm:ss:ms
const formatTime = time => {
	const hours = time.getHours().toString(),
		min = time.getMinutes().toString(),
		sec = time.getSeconds().toString();
	let mil = time.getMilliseconds().toString();
	if(mil.length === 1) {
		mil = `00${mil}`;
	}else if (mil.length === 2) {
		mil = `0${mil}`;
	}
	return `${hours}:${min}:${sec}:${mil}`;
};

/**
 * Ladda delegation protocol
 * @extends DelegationProtocol
 * @author Arnaud Grall (Folkvir), Thomas Minier
 */
class LaddaProtocol extends DelegationProtocol {
	/**
	 * Constructor
	 * @param {int|undefined} nbDestinations - (optional) The number of destinations for delegation (default to 2, as in Ladda paper)
	 * @param {int|undefined} timeout - (optional) The timeout used by the protocol. Disable by default unless it is set.
	 */
	constructor (nbDestinations, timeout) {
		super('ladda');
		// this.queryQueue = Immutable.Map();
		this.queryQueue = new StatusQueue();
		this.busyPeers = Immutable.Set();
		this.isFree = true;
		this.nbDestinations = nbDestinations || 2;
		this.timeout = timeout || -1; // disable dy default
	}

	/**
	 * Set the foglet used by the protocol and configure how to handle incoming messages
	 * @param {NDP} foglet - The foglet used by the delegation protocol
	 * @return {void}
	 * @override
	 */
	use (foglet) {
		super.use(foglet);
		const self = this;
		this.foglet.onUnicast((id, message) => {
			const receiveMessageTime = formatTime(new Date());
			switch (message.type) {
			case 'request': {
				self.foglet._flog('@LADDA - Peer @' + self.foglet.id + ' received a query to execute from : @' + id);
				if(self.isFree && !self.queryQueue.hasWaitingQueries()) {
					self.isFree = false;
					const query = message.payload;
					const startExecutionTime = formatTime(new Date());
					self.execute(query, message.endpoint).then(result => {
						const endExecutionTime = formatTime(new Date());
						self.isFree = true;
						const msg = new NDPMessage({
							type: 'answer',
							id: this.foglet.id,
							schedulerId: message.id,
							payload: result,
							query: query,
							qId: message.qId,
							endpoint: message.endpoint,
							startTime: message.startTime,
							sendQueryTime: message.sendQueryTime,
							receiveQueryTime: receiveMessageTime,
							startExecutionTime,
							endExecutionTime
						});
						self.foglet._flog(msg);
						msg.sendResultsTime = formatTime(new Date());
						self.foglet.sendUnicast(msg, id);
					}).catch(error => {
						self.foglet._flog('**********************ERROR****************************');
						self.isFree = true;
						console.log(error);
						self.foglet._flog('*******************************************************');
					});
				} else {
					self.foglet._flog('@LADDA - Peer @' + self.foglet.id + ' is busy, cannot execute query ' + message.payload + ' from ' + id);
					const msg = new NDPMessage({
						type: 'failed',
						id,
						payload: message.payload,
						endpoint: message.endpoint,
						qId: message.qId,
						receiveQueryTime: receiveMessageTime
					});
					self.foglet._flog(msg);
					self.foglet.sendUnicast(msg, id);
				}
				break;
			}
			case 'answer': {
				try {
					self.foglet._flog('@LADDA : Received an answer from @' + message.id);
					self.queryQueue.setDone(message.qId);
					self.busyPeers = this.busyPeers.delete(id);
					message.receiveResultsTime = receiveMessageTime;
					self.foglet.events.emit('ndp-answer', message);
					// retry delegation if there's queries in the queue
					if(self.queryQueue.hasWaitingQueries()) self.delegateQueries(message.endpoint);
				} catch (e) {
					self.foglet._flog('**********************ERROR****************************');
					self.foglet._flog('@NDP : error ' + e);
					self.foglet._flog('*******************************************************');
				}
				break;
			}
			case 'failed': {
				self.foglet._flog('@LADDA : failed query from @' + message.id);
				self.queryQueue.setWaiting(message.qId);
				self.busyPeers = self.busyPeers.delete(id);
				if(self.isFree) self.delegateQueries(message.endpoint);
				break;
			}
			default:
				break;
			}
		});
	}

	/**
	 * Send queries to neighbours and emit results on ndp-answer
	 * @param {array} data array of element to send (query)
	 * @param {string} endpoint - Endpoint to send queries
	 * @return {promise} A Q promise
	 */
	send (data, endpoint) {
		// clear queue before anything
		this.queryQueue.clear();
		data.forEach(query => this.queryQueue.push(this._getNewUid(), query));
		console.log('===> Queue:');
		console.log(this.queryQueue.queries.toJS());
		return this.delegateQueries(endpoint);
	}

	/**
	 * Generate and return  a v4 UUID (random) based on uuid npm package
	 * @return {string} uuidv4
	 */
	_getNewUid () {
		return uuidV4();
	}

	// /**
	//  * Return true if the queue has queries to delegate
	//  * @return {boolean} True or false
	//  */
	// queueIsNotEmpty () {
	// 	return this.queryQueue.filter(x => x === STATUS_WAITING).count() > 0;
	// }

	/**
	 * Perform delegation using Ladda algorithm
	 * @param {string} endpoint - The LDF-server on which queries will be evaluated
	 * @return {Q.Promise} A Q Promise fullfilled when delegation is complete
	 */
	delegateQueries (endpoint) {
		this.foglet._flog('@LADDA - beginning delegation');
		const self = this;
		return Q.Promise((resolve, reject) => {
			try {
				if (self.queryQueue.hasWaitingQueries()) {
					self.foglet._flog('@LADDA - queue not empty, try to delegate to me first');
					if (self.isFree) {
						console.log(self.queryQueue.queries.toJS());
						self.foglet._flog('@LADDA - Peer @' + self.foglet.id + ' (client) will execute one query');
						const query = self.queryQueue.first();
						self.isFree = false;
						self.foglet._flog('@LADDA - Selected query:' + query.query);
						self.queryQueue.setDelegated(query.id);
						const startExecutionTime = formatTime(new Date());
						self.execute(query.query, endpoint).then(result => {
							self.queryQueue.setDone(query.id);
							const endExecutionTime = formatTime(new Date());
							self.isFree = true;
							const msg = new NDPMessage({
								type: 'answer',
								id: 'me',
								schedulerId: 'me',
								payload: result,
								query: query.query,
								qId: query.id,
								endpoint,
								sendQueryTime: startExecutionTime,
								receiveQueryTime: startExecutionTime,
								startExecutionTime,
								endExecutionTime,
								sendResultsTime: endExecutionTime,
								receiveResultsTime: endExecutionTime
							});
							self.foglet._flog('@LADDA - client finished query');
							self.emit('ndp-answer', msg);
							// retry delegation if there's queries in the queue
							if(self.queryQueue.hasWaitingQueries()) self.delegateQueries(endpoint);
						}).catch(error => {
							self.foglet._flog('**********************ERROR****************************');
							self.isFree = true;
							self.foglet._flog('@LADDA - Error : ' + error);
							self.foglet._flog('*******************************************************');
						});
					}
					self.foglet._flog('@LADDA - trying to delegate to peers');
					if (self.queryQueue.hasWaitingQueries()) {
						// delegate queries to peers
						const peers = self._choosePeers();
						self.foglet._flog('@LADDA - chosen peers: ' + peers);
						peers.forEach(peer => {
							if (self.queryQueue.hasWaitingQueries()) {
								const query = self.queryQueue.first();
								console.log(query);
								self.foglet._flog('@LADDA - delegate ' + query.query + ' to peer @' + peer);
								self.queryQueue.setDelegated(query.id);
								// mark the peer as 'busy'
								self.busyPeers = self.busyPeers.add(peer);
								const sendQueryTime = formatTime(new Date());
								self.foglet.sendUnicast(new NDPMessage({
									type: 'request',
									id: self.foglet.id,
									payload: query.query,
									qId: query.id,
									endpoint,
									sendQueryTime
								}), peer);
								// set timeout if necessary
								if (self.timeout > 0) {
									setTimeout(() => {
										if(self.queryQueue.getStatus(query.id) === STATUS_DELEGATED) {
											self.queryQueue.setWaiting(query.id);
											self.busyPeers = self.busyPeers.delete(peer);
										}
									}, self.timeout);
								}
							}
						});
					}
				}
				resolve('delegation done');
			} catch (e) {
				reject(e);
			}
		});
	}

	/**
	 * Execute one query on an endpoint using ldf-client
	 * @param {string} query - The query to execute
	 * @param {string} endpoint - Endpoint to process queries
	 * @return {Promise} A Promise with results as reponse
	 */
	execute (query, endpoint) {
		this.foglet._flog(' Execution of : ' + query + ' on ' + endpoint);
		console.log(query);
		let delegationResults = Immutable.List();
		const self = this;
		return Q.Promise( (resolve, reject) => {
			try {
				let fragmentsClient = new ldf.FragmentsClient(endpoint);
				let queryResults = new ldf.SparqlIterator(query, {fragmentsClient});
				queryResults.on('data', ldfResult => {
					delegationResults = delegationResults.push(ldfResult);
				});
				// resolve when all results are arrived
				queryResults.on('end', () => {
					self.isFree = true;
					resolve(delegationResults.toJS());
				});/* SEE WITH LDF-CLIENT BECAUSE THIS IS A BUG ! .catch((error) => reject(error) */
			} catch (error) {
				self.foglet._flog('**********************ERROR****************************');
				console.log(error);
				self.foglet._flog('*******************************************************');
				reject(error);
			}
		});
	}

	/**
	 * Choose non-busy peers fro query delegation
	 * @return {Immutable.Set} A set of peers selected for delegation
	 */
	_choosePeers () {
		let chosenPeers = Immutable.Set();
		let _peers = Immutable.Set();
		// gather non-busy peers
		_peers = _peers.union(this.foglet.getNeighbours());
		_peers = _peers.subtract(this.busyPeers).toList();
		let index = 0;
		// random selection beytween non-busy peers (as in LADDA algorithm)
		while( (chosenPeers.count() < this.nbDestinations) && (_peers.count() > 0)) {
			index = this._randomInt(0, _peers.count());
			chosenPeers = chosenPeers.add(_peers.get(index));
			_peers = _peers.remove(index);
		}
		return chosenPeers;
	}

	/**
	 * Pick a random int between two values
	 * @param {int} min - The lower bound
	 * @param {int} max - The upper bound (excluded)
	 * @return {int} A random int between min and max (excluded)
	 */
	_randomInt (min, max) {
		min = Math.ceil(min);
		max = Math.floor(max);
		return Math.floor(Math.random() * (max - min)) + min;
	}
}

module.exports = LaddaProtocol;
<|endoftext|>


<commit_before>var request = require('request');
var fs = require('fs');
var path = require('path');

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

function get_leader_url(callback) {
    // attempts to get the marathon leader url, note if
    // the url is configured to be localhost, that url
    // is returned
    if(config.marathon_url.indexOf('localhost') != -1) {
        callback(config.marathon_url);
    } else {
        request(config.marathon_url + '/leader', function (error, response, body) {
            if (!error && response.statusCode == 200) {
                var info = JSON.parse(body);
                callback('http://' + info.leader + '/v2');
            } else {
                if(error) {
                    throw(error);
                } else {
                    throw new Error('Request for leader failed.  Status: ' + response.statusCode);
                }
            }
        });
    }
};

function update_app(app, callback) {
    var file = 'marker_' + app + '_marathon.json';
    var json = fs.readFileSync(path.join(__dirname, 'config', file), 'utf8');
    var now = Math.floor(Date.now() / 1000);

    // add deployment time to json
    json = json.replace("##TIME##", now.toString());

    // retrieve the URL for the Marathon leader
    get_leader_url(function(url) {
        // does the app exist?
        request(url + '/apps/' + app, function(error, response, body) {
            if(!error) {
                var method = response.statusCode == 200 ? "PUT" : "POST";

                // need to preserve number of instances
                var info = JSON.parse(body);
                var instances = info['app']['instances'];
                json = json.replace("##INSTANCES##", instances);

                request({
                        url: url + '/apps' + (method == 'PUT' ? '/' + app : ''),
                        method: method,
                        json: JSON.parse(json),
                    },
                    function(error, response, body) {
                        if(error) {
                            throw(error);
                        } else if(Math.floor(response.statusCode / 100) != 2) {
                            throw new Error('Request to marathon for process failed.  Process: ' + app + ', Status: ' + response.statusCode)
                        } else {
                            callback(body);
                        }
                    }
                );
            } else {
                console.log('Error retrieving app information: ' + error);
                throw(error);
            }
        });
    });
}

var hook_processor = {
    handle: function(app, callback) {
        var res = null;
        if((app == 'fetch') || (app == 'mapper')) {
            update_app(app, function(res) {
                callback(res);
            });
        } else {
            callback(null);
        }
    }
};

module.exports = hook_processor;<commit_msg>check around instance count<commit_after>var request = require('request');
var fs = require('fs');
var path = require('path');

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

function get_leader_url(callback) {
    // attempts to get the marathon leader url, note if
    // the url is configured to be localhost, that url
    // is returned
    if(config.marathon_url.indexOf('localhost') != -1) {
        callback(config.marathon_url);
    } else {
        request(config.marathon_url + '/leader', function (error, response, body) {
            if (!error && response.statusCode == 200) {
                var info = JSON.parse(body);
                callback('http://' + info.leader + '/v2');
            } else {
                if(error) {
                    throw(error);
                } else {
                    throw new Error('Request for leader failed.  Status: ' + response.statusCode);
                }
            }
        });
    }
};

function update_app(app, callback) {
    var file = 'marker_' + app + '_marathon.json';
    var json = fs.readFileSync(path.join(__dirname, 'config', file), 'utf8');
    var now = Math.floor(Date.now() / 1000);

    // add deployment time to json
    json = json.replace("##TIME##", now.toString());

    // retrieve the URL for the Marathon leader
    get_leader_url(function(url) {
        // does the app exist?
        request(url + '/apps/' + app, function(error, response, body) {
            if(!error) {
                var method = response.statusCode == 200 ? "PUT" : "POST";

                // need to preserve number of instances
                var info = JSON.parse(body);
                var instances = 1;
                if(info && info['app'] && info['app']['instances']) {
                    instances = info['app']['instances'];
                }
                json = json.replace("##INSTANCES##", instances);
                request({
                        url: url + '/apps' + (method == 'PUT' ? '/' + app : ''),
                        method: method,
                        json: JSON.parse(json),
                    },
                    function(error, response, body) {
                        if(error) {
                            throw(error);
                        } else if(Math.floor(response.statusCode / 100) != 2) {
                            throw new Error('Request to marathon for process failed.  Process: ' + app + ', Status: ' + response.statusCode)
                        } else {
                            callback(body);
                        }
                    }
                );
            } else {
                console.log('Error retrieving app information: ' + error);
                throw(error);
            }
        });
    });
}

var hook_processor = {
    handle: function(app, callback) {
        var res = null;
        if((app == 'fetch') || (app == 'mapper')) {
            update_app(app, function(res) {
                callback(res);
            });
        } else {
            callback(null);
        }
    }
};

module.exports = hook_processor;<|endoftext|>