<commit_before>const fs = require('fs')
const path = require('path')
const webpack = require('webpack')
const WebpackChain = require('webpack-chain')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const WebpackProgress = require('./plugin.progress')
const BootDefaultExport = require('./plugin.boot-default-export')

const appPaths = require('../app-paths')
const injectStyleRules = require('./inject.style-rules')

module.exports = function (cfg, configName) {
  const chain = new WebpackChain()

  const needsHash = !cfg.ctx.dev && !['electron', 'cordova', 'capacitor'].includes(cfg.ctx.modeName)
  const fileHash = needsHash ? '.[hash:8]' : ''
  const chunkHash = needsHash ? '.[contenthash:8]' : ''
  const resolveModules = [
    'node_modules',
    appPaths.resolve.app('node_modules'),
    appPaths.resolve.cli('node_modules')
  ]

  if (configName === 'Capacitor') {
    // need to also look into /src-capacitor
    // for deps like @capacitor/core
    resolveModules.push(
      appPaths.resolve.capacitor('node_modules')
    )
  }

  chain.entry('app').add(appPaths.resolve.app('.quasar/client-entry.js'))
  chain.mode(cfg.ctx.dev ? 'development' : 'production')
  chain.devtool(cfg.build.sourceMap ? cfg.build.devtool : false)

  if (cfg.ctx.prod || cfg.ctx.mode.ssr) {
    chain.output
      .path(
        cfg.ctx.mode.ssr
          ? path.join(cfg.build.distDir, 'www')
          : cfg.build.distDir
      )
      .publicPath(cfg.build.publicPath)
      .filename(`js/[name]${fileHash}.js`)
      .chunkFilename(`js/[name]${chunkHash}.js`)
  }

  chain.resolve.symlinks(false)

  chain.resolve.extensions
    .merge([ '.js', '.vue', '.json' ])

  chain.resolve.modules
    .merge(resolveModules)

  chain.resolve.alias
    .merge({
      src: appPaths.srcDir,
      app: appPaths.appDir,
      components: appPaths.resolve.src(`components`),
      layouts: appPaths.resolve.src(`layouts`),
      pages: appPaths.resolve.src(`pages`),
      assets: appPaths.resolve.src(`assets`),
      boot: appPaths.resolve.src(`boot`)
    })

  if (cfg.framework.all === true) {
    chain.resolve.alias.set('quasar$', 'quasar/dist/quasar.esm.js')
  }
  if (cfg.build.vueCompiler) {
    chain.resolve.alias.set('vue$', 'vue/dist/vue.esm.js')
  }

  chain.resolveLoader.modules
    .merge(resolveModules)

  chain.module.noParse(
    cfg.framework.all === true
      ? /^(vue|vue-router|vuex|vuex-router-sync|@quasar[\\/]extras|quasar)$/
      : /^(vue|vue-router|vuex|vuex-router-sync|@quasar[\\/]extras)$/
  )

  const vueRule = chain.module.rule('vue')
    .test(/\.vue$/)

  if (cfg.framework.all === 'auto') {
    vueRule.use('quasar-auto-import')
      .loader(path.join(__dirname, 'loader.auto-import.js'))
      .options(cfg.framework.autoImportComponentCase)
  }

  vueRule.use('vue-loader')
    .loader('vue-loader')
    .options({
      productionMode: cfg.ctx.prod,
      compilerOptions: {
        preserveWhitespace: false
      },
      transformAssetUrls: cfg.build.transformAssetUrls
    })

  chain.module.rule('babel')
    .test(/\.jsx?$/)
    .exclude
      .add(filepath => {
        // always transpile js(x) in Vue files
        if (/\.vue\.jsx?$/.test(filepath)) {
          return false
        }

        if (filepath.match(/[\\/]node_modules[\\/]quasar[\\/]/)) {
          if (configName === 'Server') {
            // transpile only if not from 'quasar/dist' folder
            if (!filepath.match(/[\\/]node_modules[\\/]quasar[\\/]dist/)) {
              return false
            }
          }
          else {
            // always transpile Quasar
            return false
          }
        }

        if (cfg.build.transpileDependencies.some(dep => filepath.match(dep))) {
          return false
        }

        // Don't transpile anything else in node_modules
        return /[\\/]node_modules[\\/]/.test(filepath)
      })
      .end()
    .use('babel-loader')
      .loader('babel-loader')
        .options({
          compact: false,
          extends: appPaths.resolve.app('babel.config.js'),
          plugins: cfg.framework.all !== true && configName !== 'Server' ? [
            [
              'transform-imports', {
                quasar: {
                  transform: `quasar/dist/babel-transforms/imports.js`,
                  preventFullImport: true
                }
              }
            ]
          ] : []
        })

  chain.module.rule('images')
    .test(/\.(png|jpe?g|gif|svg)(\?.*)?$/)
    .use('url-loader')
      .loader('url-loader')
      .options({
        esModule: false,
        limit: 10000,
        name: `img/[name]${fileHash}.[ext]`
      })

  chain.module.rule('fonts')
    .test(/\.(woff2?|eot|ttf|otf)(\?.*)?$/)
    .use('url-loader')
      .loader('url-loader')
      .options({
        esModule: false,
        limit: 10000,
        name: `fonts/[name]${fileHash}.[ext]`
      })

  chain.module.rule('media')
    .test(/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/)
    .use('url-loader')
      .loader('url-loader')
      .options({
        esModule: false,
        limit: 10000,
        name: `media/[name]${fileHash}.[ext]`
      })

  injectStyleRules(chain, {
    rtl: cfg.build.rtl,
    sourceMap: cfg.build.sourceMap,
    extract: cfg.build.extractCSS,
    serverExtract: configName === 'Server' && cfg.build.extractCSS,
    minify: cfg.build.minify,
    stylusLoaderOptions: cfg.build.stylusLoaderOptions,
    sassLoaderOptions: cfg.build.sassLoaderOptions,
    scssLoaderOptions: cfg.build.scssLoaderOptions,
    lessLoaderOptions: cfg.build.lessLoaderOptions
  })

  chain.plugin('vue-loader')
    .use(VueLoaderPlugin)

  chain.plugin('define')
    .use(webpack.DefinePlugin, [ cfg.build.env ])

  if (cfg.build.showProgress) {
    chain.plugin('progress')
      .use(WebpackProgress, [{ name: configName }])
  }

  chain.plugin('boot-default-export')
    .use(BootDefaultExport)

  chain.performance
    .hints(false)
    .maxAssetSize(500000)

  if (configName !== 'Server' && cfg.vendor.disable !== true) {
    const { add, remove } = cfg.vendor
    const regex = /[\\/]node_modules[\\/]/

    chain.optimization
      .splitChunks({
        cacheGroups: {
          vendors: {
            name: 'vendor',
            chunks: 'all',
            priority: -10,
            // a module is extracted into the vendor chunk if...
            test: add !== void 0 || remove !== void 0
              ? module => {
                if (module.resource) {
                  if (add !== void 0 && add.test(module.resource)) { return true }
                  if (remove !== void 0 && remove.test(module.resource)) { return false }
                }
                return regex.test(module.resource)
              }
              : module => regex.test(module.resource)
          },
          common: {
            name: `chunk-common`,
            minChunks: 2,
            priority: -20,
            chunks: 'all',
            reuseExistingChunk: true
          }
        }
      })

    // extract webpack runtime and module manifest to its own file in order to
    // prevent vendor hash from being updated whenever app bundle is updated
    if (cfg.build.webpackManifest) {
      chain.optimization.runtimeChunk('single')
    }
  }

  // DEVELOPMENT build
  if (cfg.ctx.dev) {
    const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
    const { devCompilationSuccess } = require('../helpers/banner')

    chain.optimization
      .noEmitOnErrors(true)

    chain.plugin('friendly-errors')
      .use(FriendlyErrorsPlugin, [{
        clearConsole: true,
        compilationSuccessInfo: ['spa', 'pwa', 'ssr'].includes(cfg.ctx.modeName)
          ? { notes: [ devCompilationSuccess(cfg.ctx, cfg.build.APP_URL, appPaths.appDir) ] }
          : undefined
      }])
  }
  // PRODUCTION build
  else {
    // keep module.id stable when vendor modules does not change
    chain.plugin('hashed-module-ids')
      .use(webpack.HashedModuleIdsPlugin, [{
        hashDigest: 'hex'
      }])

    if (configName !== 'Server') {
      // copy statics to dist folder
      const CopyWebpackPlugin = require('copy-webpack-plugin')

      const copyArray = []
      const staticsFolder = appPaths.resolve.src('statics')

      if (fs.existsSync(staticsFolder)) {
        copyArray.push({
          from: staticsFolder,
          to: 'statics',
          ignore: ['.*'].concat(
            // avoid useless files to be copied
            ['electron', 'cordova', 'capacitor'].includes(cfg.ctx.modeName)
              ? [ 'icons/*', 'app-logo-128x128.png' ]
              : []
          )
        })
      }

      chain.plugin('copy-webpack')
        .use(CopyWebpackPlugin, [ copyArray ])
    }

    // Scope hoisting ala Rollupjs
    if (cfg.build.scopeHoisting) {
      chain.optimization
        .concatenateModules(true)
    }

    if (cfg.ctx.debug) {
      // reset default webpack 4 minimizer
      chain.optimization.minimizers.delete('js')
      // also:
      chain.optimization.minimize(false)
    }
    else if (cfg.build.minify) {
      const TerserPlugin = require('terser-webpack-plugin')

      chain.optimization
        .minimizer('js')
        .use(TerserPlugin, [{
          terserOptions: cfg.build.uglifyOptions,
          extractComments: false,
          cache: true,
          parallel: true,
          sourceMap: cfg.build.sourceMap
        }])
    }

    // configure CSS extraction & optimize
    if (configName !== 'Server' && cfg.build.extractCSS) {
      const MiniCssExtractPlugin = require('mini-css-extract-plugin')

      // extract css into its own file
      chain.plugin('mini-css-extract')
        .use(MiniCssExtractPlugin, [{
          filename: 'css/[name].[contenthash:8].css'
        }])

      // dedupe & minify CSS (only if extracted)
      if (cfg.build.minify) {
        const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')

        const cssProcessorOptions = {
          parser: require('postcss-safe-parser'),
          autoprefixer: { disable: true }
        }
        if (cfg.build.sourceMap) {
          cssProcessorOptions.map = { inline: false }
        }

        // We are using this plugin so that possible
        // duplicated CSS = require(different components) can be deduped.
        chain.plugin('optimize-css')
          .use(OptimizeCSSPlugin, [{
            canPrint: false,
            cssProcessor: require('cssnano'),
            cssProcessorOptions,
            cssProcessorPluginOptions: {
              preset: ['default', {
                mergeLonghand: false,
                convertValues: false,
                cssDeclarationSorter: false,
                reduceTransforms: false
              }]
            }
          }])
      }
    }

    if (configName !== 'Server') {
      // also produce a gzipped version
      if (cfg.build.gzip) {
        const CompressionWebpackPlugin = require('compression-webpack-plugin')
        chain.plugin('compress-webpack')
          .use(CompressionWebpackPlugin, [ cfg.build.gzip ])
      }

      if (cfg.build.analyze) {
        const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
        chain.plugin('bundle-analyzer')
          .use(BundleAnalyzerPlugin, [ Object.assign({}, cfg.build.analyze) ])
      }
    }
  }

  return chain
}
<commit_msg>fix(app): hash name computation algorithm for generated build files #6096<commit_after>const fs = require('fs')
const path = require('path')
const webpack = require('webpack')
const WebpackChain = require('webpack-chain')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const WebpackProgress = require('./plugin.progress')
const BootDefaultExport = require('./plugin.boot-default-export')

const appPaths = require('../app-paths')
const injectStyleRules = require('./inject.style-rules')

module.exports = function (cfg, configName) {
  const chain = new WebpackChain()

  const needsHash = !cfg.ctx.dev && !['electron', 'cordova', 'capacitor'].includes(cfg.ctx.modeName)
  const fileHash = needsHash ? '.[contenthash:8]' : ''
  const chunkHash = needsHash ? '.[chunkhash:8]' : ''
  const resolveModules = [
    'node_modules',
    appPaths.resolve.app('node_modules'),
    appPaths.resolve.cli('node_modules')
  ]

  if (configName === 'Capacitor') {
    // need to also look into /src-capacitor
    // for deps like @capacitor/core
    resolveModules.push(
      appPaths.resolve.capacitor('node_modules')
    )
  }

  chain.entry('app').add(appPaths.resolve.app('.quasar/client-entry.js'))
  chain.mode(cfg.ctx.dev ? 'development' : 'production')
  chain.devtool(cfg.build.sourceMap ? cfg.build.devtool : false)

  if (cfg.ctx.prod || cfg.ctx.mode.ssr) {
    chain.output
      .path(
        cfg.ctx.mode.ssr
          ? path.join(cfg.build.distDir, 'www')
          : cfg.build.distDir
      )
      .publicPath(cfg.build.publicPath)
      .filename(`js/[name]${fileHash}.js`)
      .chunkFilename(`js/[name]${chunkHash}.js`)
  }

  chain.resolve.symlinks(false)

  chain.resolve.extensions
    .merge([ '.js', '.vue', '.json' ])

  chain.resolve.modules
    .merge(resolveModules)

  chain.resolve.alias
    .merge({
      src: appPaths.srcDir,
      app: appPaths.appDir,
      components: appPaths.resolve.src(`components`),
      layouts: appPaths.resolve.src(`layouts`),
      pages: appPaths.resolve.src(`pages`),
      assets: appPaths.resolve.src(`assets`),
      boot: appPaths.resolve.src(`boot`)
    })

  if (cfg.framework.all === true) {
    chain.resolve.alias.set('quasar$', 'quasar/dist/quasar.esm.js')
  }
  if (cfg.build.vueCompiler) {
    chain.resolve.alias.set('vue$', 'vue/dist/vue.esm.js')
  }

  chain.resolveLoader.modules
    .merge(resolveModules)

  chain.module.noParse(
    cfg.framework.all === true
      ? /^(vue|vue-router|vuex|vuex-router-sync|@quasar[\\/]extras|quasar)$/
      : /^(vue|vue-router|vuex|vuex-router-sync|@quasar[\\/]extras)$/
  )

  const vueRule = chain.module.rule('vue')
    .test(/\.vue$/)

  if (cfg.framework.all === 'auto') {
    vueRule.use('quasar-auto-import')
      .loader(path.join(__dirname, 'loader.auto-import.js'))
      .options(cfg.framework.autoImportComponentCase)
  }

  vueRule.use('vue-loader')
    .loader('vue-loader')
    .options({
      productionMode: cfg.ctx.prod,
      compilerOptions: {
        preserveWhitespace: false
      },
      transformAssetUrls: cfg.build.transformAssetUrls
    })

  chain.module.rule('babel')
    .test(/\.jsx?$/)
    .exclude
      .add(filepath => {
        // always transpile js(x) in Vue files
        if (/\.vue\.jsx?$/.test(filepath)) {
          return false
        }

        if (filepath.match(/[\\/]node_modules[\\/]quasar[\\/]/)) {
          if (configName === 'Server') {
            // transpile only if not from 'quasar/dist' folder
            if (!filepath.match(/[\\/]node_modules[\\/]quasar[\\/]dist/)) {
              return false
            }
          }
          else {
            // always transpile Quasar
            return false
          }
        }

        if (cfg.build.transpileDependencies.some(dep => filepath.match(dep))) {
          return false
        }

        // Don't transpile anything else in node_modules
        return /[\\/]node_modules[\\/]/.test(filepath)
      })
      .end()
    .use('babel-loader')
      .loader('babel-loader')
        .options({
          compact: false,
          extends: appPaths.resolve.app('babel.config.js'),
          plugins: cfg.framework.all !== true && configName !== 'Server' ? [
            [
              'transform-imports', {
                quasar: {
                  transform: `quasar/dist/babel-transforms/imports.js`,
                  preventFullImport: true
                }
              }
            ]
          ] : []
        })

  chain.module.rule('images')
    .test(/\.(png|jpe?g|gif|svg)(\?.*)?$/)
    .use('url-loader')
      .loader('url-loader')
      .options({
        esModule: false,
        limit: 10000,
        name: `img/[name]${fileHash}.[ext]`
      })

  chain.module.rule('fonts')
    .test(/\.(woff2?|eot|ttf|otf)(\?.*)?$/)
    .use('url-loader')
      .loader('url-loader')
      .options({
        esModule: false,
        limit: 10000,
        name: `fonts/[name]${fileHash}.[ext]`
      })

  chain.module.rule('media')
    .test(/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/)
    .use('url-loader')
      .loader('url-loader')
      .options({
        esModule: false,
        limit: 10000,
        name: `media/[name]${fileHash}.[ext]`
      })

  injectStyleRules(chain, {
    rtl: cfg.build.rtl,
    sourceMap: cfg.build.sourceMap,
    extract: cfg.build.extractCSS,
    serverExtract: configName === 'Server' && cfg.build.extractCSS,
    minify: cfg.build.minify,
    stylusLoaderOptions: cfg.build.stylusLoaderOptions,
    sassLoaderOptions: cfg.build.sassLoaderOptions,
    scssLoaderOptions: cfg.build.scssLoaderOptions,
    lessLoaderOptions: cfg.build.lessLoaderOptions
  })

  chain.plugin('vue-loader')
    .use(VueLoaderPlugin)

  chain.plugin('define')
    .use(webpack.DefinePlugin, [ cfg.build.env ])

  if (cfg.build.showProgress) {
    chain.plugin('progress')
      .use(WebpackProgress, [{ name: configName }])
  }

  chain.plugin('boot-default-export')
    .use(BootDefaultExport)

  chain.performance
    .hints(false)
    .maxAssetSize(500000)

  if (configName !== 'Server' && cfg.vendor.disable !== true) {
    const { add, remove } = cfg.vendor
    const regex = /[\\/]node_modules[\\/]/

    chain.optimization
      .splitChunks({
        cacheGroups: {
          vendors: {
            name: 'vendor',
            chunks: 'all',
            priority: -10,
            // a module is extracted into the vendor chunk if...
            test: add !== void 0 || remove !== void 0
              ? module => {
                if (module.resource) {
                  if (add !== void 0 && add.test(module.resource)) { return true }
                  if (remove !== void 0 && remove.test(module.resource)) { return false }
                }
                return regex.test(module.resource)
              }
              : module => regex.test(module.resource)
          },
          common: {
            name: `chunk-common`,
            minChunks: 2,
            priority: -20,
            chunks: 'all',
            reuseExistingChunk: true
          }
        }
      })

    // extract webpack runtime and module manifest to its own file in order to
    // prevent vendor hash from being updated whenever app bundle is updated
    if (cfg.build.webpackManifest) {
      chain.optimization.runtimeChunk('single')
    }
  }

  // DEVELOPMENT build
  if (cfg.ctx.dev) {
    const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
    const { devCompilationSuccess } = require('../helpers/banner')

    chain.optimization
      .noEmitOnErrors(true)

    chain.plugin('friendly-errors')
      .use(FriendlyErrorsPlugin, [{
        clearConsole: true,
        compilationSuccessInfo: ['spa', 'pwa', 'ssr'].includes(cfg.ctx.modeName)
          ? { notes: [ devCompilationSuccess(cfg.ctx, cfg.build.APP_URL, appPaths.appDir) ] }
          : undefined
      }])
  }
  // PRODUCTION build
  else {
    // keep module.id stable when vendor modules does not change
    chain.plugin('hashed-module-ids')
      .use(webpack.HashedModuleIdsPlugin, [{
        hashDigest: 'hex'
      }])

    if (configName !== 'Server') {
      // copy statics to dist folder
      const CopyWebpackPlugin = require('copy-webpack-plugin')

      const copyArray = []
      const staticsFolder = appPaths.resolve.src('statics')

      if (fs.existsSync(staticsFolder)) {
        copyArray.push({
          from: staticsFolder,
          to: 'statics',
          ignore: ['.*'].concat(
            // avoid useless files to be copied
            ['electron', 'cordova', 'capacitor'].includes(cfg.ctx.modeName)
              ? [ 'icons/*', 'app-logo-128x128.png' ]
              : []
          )
        })
      }

      chain.plugin('copy-webpack')
        .use(CopyWebpackPlugin, [ copyArray ])
    }

    // Scope hoisting ala Rollupjs
    if (cfg.build.scopeHoisting) {
      chain.optimization
        .concatenateModules(true)
    }

    if (cfg.ctx.debug) {
      // reset default webpack 4 minimizer
      chain.optimization.minimizers.delete('js')
      // also:
      chain.optimization.minimize(false)
    }
    else if (cfg.build.minify) {
      const TerserPlugin = require('terser-webpack-plugin')

      chain.optimization
        .minimizer('js')
        .use(TerserPlugin, [{
          terserOptions: cfg.build.uglifyOptions,
          extractComments: false,
          cache: true,
          parallel: true,
          sourceMap: cfg.build.sourceMap
        }])
    }

    // configure CSS extraction & optimize
    if (configName !== 'Server' && cfg.build.extractCSS) {
      const MiniCssExtractPlugin = require('mini-css-extract-plugin')

      // extract css into its own file
      chain.plugin('mini-css-extract')
        .use(MiniCssExtractPlugin, [{
          filename: 'css/[name].[contenthash:8].css'
        }])

      // dedupe & minify CSS (only if extracted)
      if (cfg.build.minify) {
        const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')

        const cssProcessorOptions = {
          parser: require('postcss-safe-parser'),
          autoprefixer: { disable: true }
        }
        if (cfg.build.sourceMap) {
          cssProcessorOptions.map = { inline: false }
        }

        // We are using this plugin so that possible
        // duplicated CSS = require(different components) can be deduped.
        chain.plugin('optimize-css')
          .use(OptimizeCSSPlugin, [{
            canPrint: false,
            cssProcessor: require('cssnano'),
            cssProcessorOptions,
            cssProcessorPluginOptions: {
              preset: ['default', {
                mergeLonghand: false,
                convertValues: false,
                cssDeclarationSorter: false,
                reduceTransforms: false
              }]
            }
          }])
      }
    }

    if (configName !== 'Server') {
      // also produce a gzipped version
      if (cfg.build.gzip) {
        const CompressionWebpackPlugin = require('compression-webpack-plugin')
        chain.plugin('compress-webpack')
          .use(CompressionWebpackPlugin, [ cfg.build.gzip ])
      }

      if (cfg.build.analyze) {
        const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
        chain.plugin('bundle-analyzer')
          .use(BundleAnalyzerPlugin, [ Object.assign({}, cfg.build.analyze) ])
      }
    }
  }

  return chain
}
<|endoftext|>


<commit_before>'use strict';

module.exports = function handleQuery () {
    return function handleQueryMiddleware (req, res, next) {
        res.locals.q = (req.body && req.body.q) || (req.query && req.query.q)
        return next();
    };
};
<commit_msg>semicolon<commit_after>'use strict';

module.exports = function handleQuery () {
    return function handleQueryMiddleware (req, res, next) {
        res.locals.q = (req.body && req.body.q) || (req.query && req.query.q);
        return next();
    };
};
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// 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';

var assert = require('assert');
var TypedError = require('error/typed');
var WrappedError = require('error/wrapped');
var timers = require('timers');
var util = require('util');
var EventEmitter = require('events').EventEmitter;

var Reporter = require('../tcollector/reporter.js');
var TChannelJSON = require('../as/json.js');

var AdvertisementTimeoutError = WrappedError({
    type: 'hyperbahn-client.advertisement-timeout',
    message: 'Hyperbahn advertisement timed out after {time} ms!.\n' +
        '{origMessage}.\n'
});

var AlreadyDestroyed = TypedError({
    type: 'hyperbahn-client.already-destroyed',
    message: 'HyperbahnClient was already destroyed.\n' +
        'Cannot invoke {method}.',
    method: null
});

var States = {
    UNADVERTISED: 'UNADVERTISED',
    ADVERTISED: 'ADVERTISED'
};
var DEFAULT_TTL = 60 * 1000;
var ADVERTISEMENT_ERROR_DELAY = 200;

module.exports = HyperbahnClient;

// # HyperbahnClient
// options.
//   * (required) tchannel: tchannel instance
//   * (required) serviceName: string service name
//   * (required) hostPortList: array of initial hyperbahn nodes
//   * callerName: the caller name
//   * logger: logtron instance
//   * reportTracing: Whether to report tracing
//   * hardFail: boolean; default false; whether or not to fail hard when we
//     can't advertise or on unexpected hyperbahn errors
//   * registrationTimeout: deprecated
//   * advertisementTimeout: integer. In hardFail mode we default to 5000. If
//     not in hardFail mode we don't time out advertisements.
function HyperbahnClient(options) {
    /*eslint max-statements: [2, 25] complexity: [2, 20] */
    if (!(this instanceof HyperbahnClient)) {
        return new HyperbahnClient(options);
    }

    var self = this;

    EventEmitter.call(this);

    assert(options && options.tchannel && !options.tchannel.topChannel,
        'Must pass in top level tchannel');
    assert(options.tchannel.tracer, 'Top channel must have trace enabled');
    assert(options.serviceName, 'must pass in serviceName');
    assert(Array.isArray(options.hostPortList),
        'Must pass in hostPortList');

    self.hostPortList = options.hostPortList;
    self.serviceName = options.serviceName;
    self.callerName = options.callerName || options.serviceName;
    self.tchannel = options.tchannel;
    self.reportTracing = 'reportTracing' in options ?
        options.reportTracing : true;
    self.hardFail = !!options.hardFail;

    self.logger = options.logger || self.tchannel.logger;
    self.statsd = options.statsd;

    self.reporter = Reporter({
        channel: self.getClientChannel({
            serviceName: 'tcollector',
            trace: false
        }),
        logger: self.logger,
        callerName: self.callerName
    });
    self.tchannel.tracer.reporter = function report(span) {
        if (self.reportTracing) {
            self.reporter.report(span);
        }
    };

    if (!self.reportTracing) {
        self.logger.warn('HyperbahnClient tcollector tracing is OFF', {
            service: self.serviceName
        });
    }

    self.hyperbahnChannel = self.tchannel.subChannels.hyperbahn ||
        self.tchannel.makeSubChannel({
            serviceName: 'hyperbahn',
            peers: self.hostPortList
        });
    self.tchannelJSON = TChannelJSON();

    self.lastError = null;
    self.latestAdvertisementResult = null;

    self.state = States.UNADVERTISED;
    self._destroyed = false;

    var advertisementTimeout = options.advertisementTimeout ||
        options.registrationTimeout;
    if (self.hardFail) {
        self.advertisementTimeoutTime = advertisementTimeout || 5000;
    } else {
        self.advertisementTimeoutTime = advertisementTimeout;
    }
}

util.inherits(HyperbahnClient, EventEmitter);

HyperbahnClient.prototype.setReportTracing = function setReportTracing(bool) {
    var self = this;

    self.reportTracing = bool;
};

// Gets the subchannel for hitting a particular service.
HyperbahnClient.prototype.getClientChannel =
function getClientChannel(options) {
    var self = this;

    assert(options && options.serviceName, 'must pass serviceName');

    if (self._destroyed) {
        self.emit('error', AlreadyDestroyed({
            method: 'getClientChannel'
        }));
        return null;
    }

    if (self.tchannel.subChannels[options.serviceName]) {
        return self.tchannel.subChannels[options.serviceName];
    }

    var channelOptions = {
        peers: self.hostPortList,
        serviceName: options.serviceName,
        requestDefaults: {
            serviceName: options.serviceName,
            headers: {
                cn: self.callerName
            }
        }
    };
    if ('trace' in options) {
        channelOptions.trace = options.trace;
    }
    if ('timeout' in options) {
        channelOptions.requestDefaults.timeout = options.timeout;
    }
    if ('retryLimit' in options) {
        channelOptions.requestDefaults.retryLimit = options.retryLimit;
    }

    return self.tchannel.makeSubChannel(channelOptions);
};

// ## advertisementTimeout
// Called after a certain amount of time to have a fatal error when reg fails.
// Will not be called if options.advertisementTimeout isn't passed in
HyperbahnClient.prototype.advertisementTimeout =
function advertisementTimeout() {
    var self = this;

    if (self.state === States.UNADVERTISED) {
        var lastError = self.lastError ||
            new Error('advertisement timeout!');
        var err = AdvertisementTimeoutError(lastError, {
            time: self.advertisementTimeoutTime
        });

        self.logger.fatal('HyperbahnClient: advertisement timed out', {
            timeout: self.advertisementTimeout,
            error: err
        });

        self.advertisementFailure(err);
    }
    // TODO else warn
};

HyperbahnClient.prototype.advertisementFailure =
function advertisementFailure(err) {
    var self = this;

    self.destroy();
    self.emit('error', err);

    if (self.statsd) {
        self.statsd.increment(
            'hyperbahn-client.' + self.serviceName + '.advertisement.failure'
        );
    }
};

HyperbahnClient.prototype.sendAdvertiseRequest =
function sendAdvertiseRequest(opts, cb) {
    var self = this;

    var req = self.hyperbahnChannel.request({
        serviceName: 'hyperbahn',
        timeout: (opts && opts.timeout) || 50,
        hasNoParent: true,
        trace: false,
        headers: {
            cn: self.callerName
        }
    });
    self.tchannelJSON.send(req, 'ad', null, {
        services: [{
            cost: 0,
            serviceName: self.serviceName
        }]
    }, cb);
};

// ## advertise
// Advertise with Hyperbahn. If called with a callback, the callback will not be
// called until there has been a successful advertisement. This function
// attempts a advertise and retries until there are no healthy servers left; it
// will then repeatedly choose random servers to try until it finds one that
// works.
// register is **deprecated**
HyperbahnClient.prototype.register =
HyperbahnClient.prototype.advertise =
function advertise(opts) {
    var self = this;
    // Attempt a advertisement. If it succeeds, setTimeout to re-advertise with
    // the same server after the TTL.

    assert(self.tchannel.hostPort,
        'must call tchannel.listen() before advertise()');

    if (self._destroyed) {
        self.emit('error', AlreadyDestroyed({
            method: 'advertise'
        }));
        return;
    }

    if (self.advertisementTimeoutTime) {
        // Start the timeout timer
        self.advertisementTimeoutTimer = timers.setTimeout(
            function advertisementTimeoutTimer() {
                self.advertisementTimeout();
            },
            self.advertisementTimeoutTime
        );
    } else {
        self.logger.info('HyperbahnClient advertisement timeout disabled', {
            service: self.serviceName
        });
    }

    self.sendAdvertiseRequest(opts, advertiseInternalCb);
    self.emit('advertise-attempt');

    function advertiseInternalCb(err, result) {
        /*eslint max-statements: [2, 40] */
        if (err) {
            self.logger[self.hardFail ? 'error' : 'warn'](
                'HyperbahnClient: advertisement failure, ' +
                'marking server as sick', {
                error: err,
                serviceName: self.serviceName,
                hostPort: self.hostPort
            });
            self.lastError = err;

            self.advertiseAgain(ADVERTISEMENT_ERROR_DELAY);
            return;
        }

        if (result.ok === false) {
            err = result.body;
            var errInfo2 = {
                error: err,
                serviceName: self.serviceName,
                hostPort: self.hostPort
            };

            self.logger[self.hardFail ? 'fatal' : 'warn'](
                'HyperbahnClient: unexpected failure (from Hyperbahn)',
                errInfo2
            );

            if (self.hardFail) {
                self.advertisementFailure(err);
            } else {
                self.advertiseAgain(ADVERTISEMENT_ERROR_DELAY);
            }

            return;
        }

        if (self.statsd) {
            self.statsd.increment(
                'hyperbahn-client.' + self.serviceName +
                    '.advertisement.success'
            );
        }

        self.latestAdvertisementResult = result;
        self.state = States.ADVERTISED;
        timers.clearTimeout(self.advertisementTimeoutTimer);

        var ttl = DEFAULT_TTL;

        self.advertiseAgain(ttl);

        // registered event is deprecated
        self.emit('registered');
        self.emit('advertised');
    }
};

HyperbahnClient.prototype.advertiseAgain =
function advertiseAgain(delay) {
    var self = this;

    if (self._destroyed) {
        return;
    }

    self._advertisementTimer = timers.setTimeout(
        function advertiseTimeout() {
            self.advertise();
        },
        delay
    );
};

// ## destroy
HyperbahnClient.prototype.destroy = function destroy() {
    this._destroyed = true;
    timers.clearTimeout(this._advertisementTimer);
    timers.clearTimeout(this.advertisementTimeoutTimer);
};
<commit_msg>hyperbahn: Add timeout fuzz to the re-registration of hyperbahn<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// 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';

var assert = require('assert');
var TypedError = require('error/typed');
var WrappedError = require('error/wrapped');
var timers = require('timers');
var util = require('util');
var EventEmitter = require('events').EventEmitter;

var Reporter = require('../tcollector/reporter.js');
var TChannelJSON = require('../as/json.js');

var AdvertisementTimeoutError = WrappedError({
    type: 'hyperbahn-client.advertisement-timeout',
    message: 'Hyperbahn advertisement timed out after {time} ms!.\n' +
        '{origMessage}.\n'
});

var AlreadyDestroyed = TypedError({
    type: 'hyperbahn-client.already-destroyed',
    message: 'HyperbahnClient was already destroyed.\n' +
        'Cannot invoke {method}.',
    method: null
});

var States = {
    UNADVERTISED: 'UNADVERTISED',
    ADVERTISED: 'ADVERTISED'
};
var DEFAULT_TTL = 60 * 1000;
var ADVERTISEMENT_ERROR_DELAY = 200;

module.exports = HyperbahnClient;

// # HyperbahnClient
// options.
//   * (required) tchannel: tchannel instance
//   * (required) serviceName: string service name
//   * (required) hostPortList: array of initial hyperbahn nodes
//   * callerName: the caller name
//   * logger: logtron instance
//   * reportTracing: Whether to report tracing
//   * hardFail: boolean; default false; whether or not to fail hard when we
//     can't advertise or on unexpected hyperbahn errors
//   * registrationTimeout: deprecated
//   * advertisementTimeout: integer. In hardFail mode we default to 5000. If
//     not in hardFail mode we don't time out advertisements.
function HyperbahnClient(options) {
    /*eslint max-statements: [2, 25] complexity: [2, 20] */
    if (!(this instanceof HyperbahnClient)) {
        return new HyperbahnClient(options);
    }

    var self = this;

    EventEmitter.call(this);

    assert(options && options.tchannel && !options.tchannel.topChannel,
        'Must pass in top level tchannel');
    assert(options.tchannel.tracer, 'Top channel must have trace enabled');
    assert(options.serviceName, 'must pass in serviceName');
    assert(Array.isArray(options.hostPortList),
        'Must pass in hostPortList');

    self.hostPortList = options.hostPortList;
    self.serviceName = options.serviceName;
    self.callerName = options.callerName || options.serviceName;
    self.tchannel = options.tchannel;
    self.reportTracing = 'reportTracing' in options ?
        options.reportTracing : true;
    self.hardFail = !!options.hardFail;
    self.advertiseInterval = options.advertiseInterval || DEFAULT_TTL;
    self.timeoutFuzz = self.advertiseInterval;

    self.logger = options.logger || self.tchannel.logger;
    self.statsd = options.statsd;

    self.reporter = Reporter({
        channel: self.getClientChannel({
            serviceName: 'tcollector',
            trace: false
        }),
        logger: self.logger,
        callerName: self.callerName
    });
    self.tchannel.tracer.reporter = function report(span) {
        if (self.reportTracing) {
            self.reporter.report(span);
        }
    };

    if (!self.reportTracing) {
        self.logger.warn('HyperbahnClient tcollector tracing is OFF', {
            service: self.serviceName
        });
    }

    self.hyperbahnChannel = self.tchannel.subChannels.hyperbahn ||
        self.tchannel.makeSubChannel({
            serviceName: 'hyperbahn',
            peers: self.hostPortList
        });
    self.tchannelJSON = TChannelJSON();

    self.lastError = null;
    self.latestAdvertisementResult = null;

    self.state = States.UNADVERTISED;
    self._destroyed = false;

    var advertisementTimeout = options.advertisementTimeout ||
        options.registrationTimeout;
    if (self.hardFail) {
        self.advertisementTimeoutTime = advertisementTimeout || 5000;
    } else {
        self.advertisementTimeoutTime = advertisementTimeout;
    }
}

util.inherits(HyperbahnClient, EventEmitter);

HyperbahnClient.prototype.setReportTracing = function setReportTracing(bool) {
    var self = this;

    self.reportTracing = bool;
};

// Gets the subchannel for hitting a particular service.
HyperbahnClient.prototype.getClientChannel =
function getClientChannel(options) {
    var self = this;

    assert(options && options.serviceName, 'must pass serviceName');

    if (self._destroyed) {
        self.emit('error', AlreadyDestroyed({
            method: 'getClientChannel'
        }));
        return null;
    }

    if (self.tchannel.subChannels[options.serviceName]) {
        return self.tchannel.subChannels[options.serviceName];
    }

    var channelOptions = {
        peers: self.hostPortList,
        serviceName: options.serviceName,
        requestDefaults: {
            serviceName: options.serviceName,
            headers: {
                cn: self.callerName
            }
        }
    };
    if ('trace' in options) {
        channelOptions.trace = options.trace;
    }
    if ('timeout' in options) {
        channelOptions.requestDefaults.timeout = options.timeout;
    }
    if ('retryLimit' in options) {
        channelOptions.requestDefaults.retryLimit = options.retryLimit;
    }

    return self.tchannel.makeSubChannel(channelOptions);
};

// ## advertisementTimeout
// Called after a certain amount of time to have a fatal error when reg fails.
// Will not be called if options.advertisementTimeout isn't passed in
HyperbahnClient.prototype.advertisementTimeout =
function advertisementTimeout() {
    var self = this;

    if (self.state === States.UNADVERTISED) {
        var lastError = self.lastError ||
            new Error('advertisement timeout!');
        var err = AdvertisementTimeoutError(lastError, {
            time: self.advertisementTimeoutTime
        });

        self.logger.fatal('HyperbahnClient: advertisement timed out', {
            timeout: self.advertisementTimeout,
            error: err
        });

        self.advertisementFailure(err);
    }
    // TODO else warn
};

HyperbahnClient.prototype.advertisementFailure =
function advertisementFailure(err) {
    var self = this;

    self.destroy();
    self.emit('error', err);

    if (self.statsd) {
        self.statsd.increment(
            'hyperbahn-client.' + self.serviceName + '.advertisement.failure'
        );
    }
};

HyperbahnClient.prototype.sendAdvertiseRequest =
function sendAdvertiseRequest(opts, cb) {
    var self = this;

    var req = self.hyperbahnChannel.request({
        serviceName: 'hyperbahn',
        timeout: (opts && opts.timeout) || 50,
        hasNoParent: true,
        trace: false,
        headers: {
            cn: self.callerName
        }
    });
    self.tchannelJSON.send(req, 'ad', null, {
        services: [{
            cost: 0,
            serviceName: self.serviceName
        }]
    }, cb);
};

// ## advertise
// Advertise with Hyperbahn. If called with a callback, the callback will not be
// called until there has been a successful advertisement. This function
// attempts a advertise and retries until there are no healthy servers left; it
// will then repeatedly choose random servers to try until it finds one that
// works.
// register is **deprecated**
HyperbahnClient.prototype.register =
HyperbahnClient.prototype.advertise =
function advertise(opts) {
    var self = this;
    // Attempt a advertisement. If it succeeds, setTimeout to re-advertise with
    // the same server after the TTL.

    assert(self.tchannel.hostPort,
        'must call tchannel.listen() before advertise()');

    if (self._destroyed) {
        self.emit('error', AlreadyDestroyed({
            method: 'advertise'
        }));
        return;
    }

    if (self.advertisementTimeoutTime) {
        // Start the timeout timer
        self.advertisementTimeoutTimer = timers.setTimeout(
            function advertisementTimeoutTimer() {
                self.advertisementTimeout();
            },
            self.advertisementTimeoutTime
        );
    } else {
        self.logger.info('HyperbahnClient advertisement timeout disabled', {
            service: self.serviceName
        });
    }

    self.sendAdvertiseRequest(opts, advertiseInternalCb);
    self.emit('advertise-attempt');

    function advertiseInternalCb(err, result) {
        /*eslint max-statements: [2, 40] */
        if (err) {
            self.logger[self.hardFail ? 'error' : 'warn'](
                'HyperbahnClient: advertisement failure, ' +
                'marking server as sick', {
                error: err,
                serviceName: self.serviceName,
                hostPort: self.hostPort
            });
            self.lastError = err;

            self.advertiseAgain(ADVERTISEMENT_ERROR_DELAY);
            return;
        }

        if (result.ok === false) {
            err = result.body;
            var errInfo2 = {
                error: err,
                serviceName: self.serviceName,
                hostPort: self.hostPort
            };

            self.logger[self.hardFail ? 'fatal' : 'warn'](
                'HyperbahnClient: unexpected failure (from Hyperbahn)',
                errInfo2
            );

            if (self.hardFail) {
                self.advertisementFailure(err);
            } else {
                self.advertiseAgain(ADVERTISEMENT_ERROR_DELAY);
            }

            return;
        }

        if (self.statsd) {
            self.statsd.increment(
                'hyperbahn-client.' + self.serviceName +
                    '.advertisement.success'
            );
        }

        self.latestAdvertisementResult = result;
        self.state = States.ADVERTISED;
        timers.clearTimeout(self.advertisementTimeoutTimer);

        self.advertiseAgain(self.getTimeoutFuzz());

        // registered event is deprecated
        self.emit('registered');
        self.emit('advertised');
    }
};

HyperbahnClient.prototype.getTimeoutFuzz = function getTimeoutFuzz() {
    var self = this;

    var fuzz = self.timeoutFuzz;
    var delay = Math.round(Math.floor(Math.random() * fuzz)) - (fuzz / 2);

    return self.advertiseInterval + delay;
};

HyperbahnClient.prototype.advertiseAgain =
function advertiseAgain(delay) {
    var self = this;

    if (self._destroyed) {
        return;
    }

    self._advertisementTimer = timers.setTimeout(
        function advertiseTimeout() {
            self.advertise();
        },
        delay
    );
};

// ## destroy
HyperbahnClient.prototype.destroy = function destroy() {
    this._destroyed = true;
    timers.clearTimeout(this._advertisementTimer);
    timers.clearTimeout(this.advertisementTimeoutTimer);
};
<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();
var StoryBlockModel = require('../models/storyblock');

router.get('/', function (req, res) {
    console.log('router.get');
    StoryBlockModel.find(
        {},
        null,
        {
            sort : 'timePosition'
        },
        function (err, storyBlock) {
            res.json(storyBlock);
        })
});

router.get('/:id', function (req, res, next) {
    console.log('router.get id');
    var id = req.params.id;
    StoryBlockModel.findById(id, function (err, storyBlock) {
        if (err) {
            console.log(err);
        }
        return res.json(storyBlock);
    });
});

router.post('/', function (req, res, next) {
    console.log('router.post');
    var data = JSON.parse(req.body.data);
    console.log(data);
    StoryBlockModel.create(data, function (err, storyBlock) {
        if (err) {
            console.log(err);
        }
        res.json(storyBlock);
    });
});

router.put('/:id', function (req, res, next) {
    console.log('router.put id');
    var id = req.params.id;
    var data = JSON.parse(req.body.data);
    StoryBlockModel.findOneAndUpdate({_id: id}, data, function (err, storyBlock) {
        if (err) {
            console.log(err);
        }
        console.log('Saving');
        return res.json(storyBlock);
    });
});

router.delete('/:id', function (req, res, next) {
    console.log('router.delete id');
    var id = req.params.id;
    console.log(id);
    StoryBlockModel.findOneAndRemove({_id: id}, function (err) {
        if (err) {
            console.log(err);
        }
        console.log('Found');
        return res.json({});
    }).exec(function (err) {
        console.log('Deleting...');
    });
});

module.exports = router;
<commit_msg>Deleting a block now returns the deleted block<commit_after>var express = require('express');
var router = express.Router();
var StoryBlockModel = require('../models/storyblock');

router.get('/', function (req, res) {
    console.log('router.get');
    StoryBlockModel.find(
        {},
        null,
        {
            sort : 'timePosition'
        },
        function (err, storyBlock) {
            res.json(storyBlock);
        })
});

router.get('/:id', function (req, res, next) {
    console.log('router.get id');
    var id = req.params.id;
    StoryBlockModel.findById(id, function (err, storyBlock) {
        if (err) {
            console.log(err);
        }
        return res.json(storyBlock);
    });
});

router.post('/', function (req, res, next) {
    console.log('router.post');
    var data = JSON.parse(req.body.data);
    console.log(data);
    StoryBlockModel.create(data, function (err, storyBlock) {
        if (err) {
            console.log(err);
        }
        res.json(storyBlock);
    });
});

router.put('/:id', function (req, res, next) {
    console.log('router.put id');
    var id = req.params.id;
    var data = JSON.parse(req.body.data);
    StoryBlockModel.findOneAndUpdate({_id: id}, data, function (err) {
        if (err) {
            console.log(err);
        }
        console.log('Saving');
        return res.json(storyBlock);
    });
});

router.delete('/:id', function (req, res, next) {
    console.log('router.delete id');
    var id = req.params.id;
    console.log(id);
    StoryBlockModel.findOneAndRemove({_id: id}, function (err, storyBlock) {
        if (err) {
            console.log(err);
        }
        console.log('Found');
        return res.json(storyBlock);
    }).exec(function (err) {
        console.log('Deleting...');
    });
});

module.exports = router;
<|endoftext|>


<commit_before>require('babel-core/register');

global.expect = require('expect');
<commit_msg>Add babel preset back to tests<commit_after>require('babel-core/register')({
  presets: [
    'es2015',
  ],
});

global.expect = require('expect');
<|endoftext|>


<commit_before>'use strict';

angular.module('desecClientApp').controller('HeroCtrl', function($scope, $timeout) {
	var SLIDE_COUNT = 2;
	var timer;

	$scope.slideIndex = 0;

	function cancelTimer() {
		if (timer)
			$timeout.cancel(timer);
	}

	function nextSlide() {
		cancelTimer();
		$scope.slideIndex = ($scope.slideIndex + 1) % SLIDE_COUNT;
		$timeout(nextSlide, 10000);
	}

	$timeout(nextSlide, 10000);

	$scope.showSlide = function(idx) {
		cancelTimer();
		$scope.slideIndex = idx;
	};

	$scope.$on('$destroy', function() {
		cancelTimer();
	});

});
<commit_msg>fix(hero): disabled automatic switch after user interaction<commit_after>'use strict';

angular.module('desecClientApp').controller('HeroCtrl', function($scope, $timeout) {
	var SLIDE_COUNT = 2;
	var timer;

	$scope.slideIndex = 0;

	function cancelTimer() {
		if (timer)
			$timeout.cancel(timer);
	}

	function setTimer() {
		timer = $timeout(nextSlide, 10000);
	}

	function nextSlide() {
		cancelTimer();
		$scope.slideIndex = ($scope.slideIndex + 1) % SLIDE_COUNT;
		setTimer();
	}

	setTimer();

	$scope.showSlide = function(idx) {
		cancelTimer();
		$scope.slideIndex = idx;
	};

	$scope.$on('$destroy', function() {
		cancelTimer();
	});

});
<|endoftext|>


<commit_before>/**
 * @ngdoc function
 * @name musicPlayerApp.controller:ArtistsCtrl
 * @description
 * # ArtistsCtrl
 * Controller of the musicPlayerApp
 */
  angular.module('musicPlayerApp')
  .controller('HomeCtrl', function ($scope, Spotify) {
  	$scope.query;
  	$scope.artists=[];
  	$scope.albums=[];
  	$scope.songs=[];

  	$scope.searchFor = function(){
  		Spotify.search($scope.query,'artist,album,track', {limit:'5'}).then(function (data) {
  		$scope.artists=[];
  		$scope.albums=[];
  		$scope.songs=[];
  		$scope.artists.push(data.artists.items);
  		$scope.albums.push(data.albums.items);
  		$scope.songs.push(data.tracks.items);
  		console.log($scope.artists);
  		console.log($scope.albums);
  		console.log($scope.songs);
  	});
  	}

});
<commit_msg>changes in search<commit_after>/**
 * @ngdoc function
 * @name musicPlayerApp.controller:ArtistsCtrl
 * @description
 * # ArtistsCtrl
 * Controller of the musicPlayerApp
 */
  angular.module('musicPlayerApp')
  .controller('HomeCtrl', function ($scope, Spotify) {
  	$scope.query;
  	$scope.artists=[];
  	$scope.albums=[];
  	$scope.songs=[];

  	$scope.searchFor = function(){
  		Spotify.search($scope.query,'artist,album,track', {limit:'5'}).then(function (data) {
  		$scope.artists=[];
  		$scope.albums=[];
  		$scope.songs=[];
  		for (var i=0; i<data.artists.items.length; i++){
  			$scope.artists.push(data.artists.items[i]);
  		}
		for (var i=0; i<data.albums.items.length; i++){
  			$scope.albums.push(data.albums.items[i]);
  		}
  		for (var i=0; i<data.tracks.items.length; i++){
  			$scope.songs.push(data.tracks.items[i]);
  		}
  		console.log($scope.artists);
  		console.log($scope.albums);
  		console.log($scope.songs);
  	});
  	}

});
<|endoftext|>


<commit_before>'use strict';

angular.module('sublConfigApp')
  .controller('MainCtrl', ['$scope', '$rootScope', function ($scope, $rootScope) {
      $rootScope.config = {};
      $rootScope.configArray = [
        'font_options',
        'rulers',
        'indent_guide_options',
        'auto_complete_triggers',
        'folder_exclude_patterns',
        'file_exclude_patterns',
        'binary_file_patterns',
        'ignored_packages'
      ];

      $rootScope.setConfig = function(what, arg) {
        if(arg == 'default'){
          $rootScope.removeConfig(what);
        } else {
          $rootScope.config[what] = arg;
        }

        $rootScope.$broadcast('setConfig');
      };

      $rootScope.removeConfig = function(what) {
        delete $rootScope.config[what];
      };

      $rootScope.setArrayOptions = function(what, arg) {
        if ($rootScope.config[what] == undefined) {
            $rootScope.config[what] = [];
        }

        $rootScope.config[what].push(arg);

        $rootScope.$broadcast('setConfig');
      };

      $rootScope.removeArrayOptions = function(what, arg) {
        var index = $rootScope.config[what].indexOf(arg);

        $rootScope.config[what].splice(index, 1);

        if ($rootScope.config[what].length == 0) {
            delete $rootScope.config[what];
        }
      };

      $scope.$on('setConfig', function () {
        var json = JSON.stringify($rootScope.config, null, '\t');

        $rootScope.configJson = json.replace(/\"(\d*.\d+|[\d+]|false|true)\"/g, "$1");
      });

    }]);
<commit_msg>fix a bug with array options<commit_after>'use strict';

angular.module('sublConfigApp')
  .controller('MainCtrl', ['$scope', '$rootScope', function ($scope, $rootScope) {
      $rootScope.config = {};
      $rootScope.configArray = [
        'font_options',
        'rulers',
        'indent_guide_options',
        'auto_complete_triggers',
        'folder_exclude_patterns',
        'file_exclude_patterns',
        'binary_file_patterns',
        'ignored_packages'
      ];

      $rootScope.setConfig = function(what, arg) {
        if(arg == 'default'){
          $rootScope.removeConfig(what);
        } else {
          $rootScope.config[what] = arg;
        }

        $rootScope.$broadcast('setConfig');
      };

      $rootScope.removeConfig = function(what) {
        delete $rootScope.config[what];
      };

      $rootScope.setArrayOptions = function(what, arg) {
        if ($rootScope.config[what] == undefined) {
            $rootScope.config[what] = [];
        }

        //add this to the checkbox: ng-false-value="remove_this"
        if (arg == "remove_this"){
          $rootScope.removeArrayOptions(what, arg);
        } else {
          $rootScope.config[what].push(arg);
        }

        $rootScope.$broadcast('setConfig');
      };

      $rootScope.removeArrayOptions = function(what, arg) {
        var index = $rootScope.config[what].indexOf(arg);

        $rootScope.config[what].splice(index, 1);

        if ($rootScope.config[what].length == 0) {
            delete $rootScope.config[what];
        }
      };

      $scope.$on('setConfig', function () {
        var json = JSON.stringify($rootScope.config, null, '\t');

        $rootScope.configJson = json.replace(/\"(\d*.\d+|[\d+]|false|true)\"/g, "$1");
      });

    }]);
<|endoftext|>


<commit_before>describe('oide.filesystemservice', function(){
  var $filesystemservice;
  var httpBackend;

  var dirs = [{
        "filepath": "/home/saurabh/dir2",
        "filename": "dir2",
        "group": "saurabh",
        "is_accessible": true,
        "perm": "-rw-rw-r--",
        "perm_string": "664",
        "size": "4.0 KiB",
        "type": "dir"
      }, {
        "filepath": "/home/saurabh/dir2",
        "filename": "dir2",
        "group": "root",
        "is_accessible": false,
        "perm": "-rw-r--r--",
        "perm_string": "644",
        "size": "4.0 KiB",
        "type": "dir"
      },
      {
        "filepath": "/home/saurabh/dir3",
        "filename": "dir3",
        "group": "saurabh",
        "is_accessible": true,
        "perm": "-rw-rw-r--",
        "perm_string": "664",
        "size": "4.0 KiB",
        "type": "dir"
      }];

    var files = [{
          "filepath": "/home/saurabh/file1",
          "filename": "file1",
          "group": "saurabh",
          "is_accessible": true,
          "perm": "-rw-rw-r--",
          "perm_string": "664",
          "size": "4.0 KiB",
          "type": "dir"
        }, {
          "filepath": "/home/saurabh/file2",
          "filename": "file2",
          "group": "root",
          "is_accessible": false,
          "perm": "-rw-r--r--",
          "perm_string": "644",
          "size": "4.0 KiB",
          "type": "dir"
        }];

    beforeEach(module('oide'));
    beforeEach(module('oide.editor'));
    beforeEach(module('oide.filesystemservice'));

    beforeEach(inject(function(FilesystemService, $httpBackend){
      $filesystemservice = FilesystemService;

      httpBackend = $httpBackend;
      httpBackend.whenGET('/filebrowser/filetree/a/dir').respond(function(){
        return [200, dirs];
      });
      httpBackend.whenGET(/\/filebrowser\/filetree\/a\/dir\?dirpath=.*&folders=true/).respond(function(){
        return [200, dirs];
      });
      httpBackend.whenGET(/\/filebrowser\/filetree\/a\/dir\?dirpath=.*/).respond(function(){
        return [200, files];
      });
      httpBackend.whenGET(/\/filebrowser\/a\/fileutil\?dirpath=.*&operation=GET_NEXT_UNTITLED_FILE/).respond(function(){
        return [200, {'filepath': '/home/saurabh/Untitled1'}];
      });
      httpBackend.whenPOST(/\/filebrowser\/localfiles.*/).respond(function(){
        return [200, {'filepath': '/home/saurabh/Untitled1'}];
      });
      httpBackend.whenPOST(/\/filebrowser\/localfiles.*/).respond(function(){
        return [200, {'filepath': '/home/saurabh/Untitled1'}];
      });
      httpBackend.whenPOST(/\/filebrowser\/a\/fileutil\?filepath=.*&newFileName=.*&operation=RENAME/).respond(function(){
        return [200, {'filepath': '/home/saurabh/somefile'}];
      });
    }));

    describe('Functionality of FilesystemService', function(){
      it('should be able to get files', function(){
        $filesystemservice.getFiles(dirs[0], function(data){
          expect(data.length).toBe(2);
        });
        httpBackend.flush();
      });
      it('should be able to get folders', function(){
        $filesystemservice.getFolders(dirs[0], function(data){
          expect(data.length).toBe(3);
        });
        httpBackend.flush();
      });
      it('should be able to get the next untitled file', function(){
        $filesystemservice.getNextUntitledFile(dirs[0], function(data){
          expect(data.filepath).toBeDefined();
        });
        httpBackend.flush();
      });
      it('should be able to create a new file', function(){
        $filesystemservice.createNewFile(files[0].filename, function(data){
          expect(data.filepath).toBeDefined();
        });
        httpBackend.flush();
      });
      it('should be able to rename a file', function(){
        $filesystemservice.renameFile("somefile", files[0], function(data){
          expect(data.filepath).toBeDefined();
        });
        httpBackend.flush();
      });
    });
});
<commit_msg>add spec to delete file<commit_after>describe('oide.filesystemservice', function(){
  var $filesystemservice;
  var httpBackend;

  var dirs = [{
        "filepath": "/home/saurabh/dir2",
        "filename": "dir2",
        "group": "saurabh",
        "is_accessible": true,
        "perm": "-rw-rw-r--",
        "perm_string": "664",
        "size": "4.0 KiB",
        "type": "dir"
      }, {
        "filepath": "/home/saurabh/dir2",
        "filename": "dir2",
        "group": "root",
        "is_accessible": false,
        "perm": "-rw-r--r--",
        "perm_string": "644",
        "size": "4.0 KiB",
        "type": "dir"
      },
      {
        "filepath": "/home/saurabh/dir3",
        "filename": "dir3",
        "group": "saurabh",
        "is_accessible": true,
        "perm": "-rw-rw-r--",
        "perm_string": "664",
        "size": "4.0 KiB",
        "type": "dir"
      }];

    var files = [{
          "filepath": "/home/saurabh/file1",
          "filename": "file1",
          "group": "saurabh",
          "is_accessible": true,
          "perm": "-rw-rw-r--",
          "perm_string": "664",
          "size": "4.0 KiB",
          "type": "dir"
        }, {
          "filepath": "/home/saurabh/file2",
          "filename": "file2",
          "group": "root",
          "is_accessible": false,
          "perm": "-rw-r--r--",
          "perm_string": "644",
          "size": "4.0 KiB",
          "type": "dir"
        }];

    beforeEach(module('oide'));
    beforeEach(module('oide.editor'));
    beforeEach(module('oide.filesystemservice'));

    beforeEach(inject(function(FilesystemService, $httpBackend){
      $filesystemservice = FilesystemService;

      httpBackend = $httpBackend;
      httpBackend.whenGET('/filebrowser/filetree/a/dir').respond(function(){
        return [200, dirs];
      });
      httpBackend.whenGET(/\/filebrowser\/filetree\/a\/dir\?dirpath=.*&folders=true/).respond(function(){
        return [200, dirs];
      });
      httpBackend.whenGET(/\/filebrowser\/filetree\/a\/dir\?dirpath=.*/).respond(function(){
        return [200, files];
      });
      httpBackend.whenGET(/\/filebrowser\/a\/fileutil\?dirpath=.*&operation=GET_NEXT_UNTITLED_FILE/).respond(function(){
        return [200, {'filepath': '/home/saurabh/Untitled1'}];
      });
      httpBackend.whenPOST(/\/filebrowser\/localfiles.*/).respond(function(){
        return [200, {'filepath': '/home/saurabh/Untitled1'}];
      });
      httpBackend.whenPOST(/\/filebrowser\/localfiles.*/).respond(function(){
        return [200, {'filepath': '/home/saurabh/Untitled1'}];
      });
      httpBackend.whenPOST(/\/filebrowser\/a\/fileutil\?filepath=.*&newFileName=.*&operation=RENAME/).respond(function(){
        return [200, {'filepath': '/home/saurabh/somefile'}];
      });
      httpBackend.when('DELETE', /\/filebrowser\/localfiles.*/).respond(function(){
        return [200, {'result': 'DELETED file'}];
      });
    }));

    describe('Functionality of FilesystemService', function(){
      it('should be able to get files', function(){
        $filesystemservice.getFiles(dirs[0], function(data){
          expect(data.length).toBe(2);
        });
        httpBackend.flush();
      });
      it('should be able to get folders', function(){
        $filesystemservice.getFolders(dirs[0], function(data){
          expect(data.length).toBe(3);
        });
        httpBackend.flush();
      });
      it('should be able to get the next untitled file', function(){
        $filesystemservice.getNextUntitledFile(dirs[0], function(data){
          expect(data.filepath).toBeDefined();
        });
        httpBackend.flush();
      });
      it('should be able to create a new file', function(){
        $filesystemservice.createNewFile(files[0].filename, function(data){
          expect(data.filepath).toBeDefined();
        });
        httpBackend.flush();
      });
      it('should be able to rename a file', function(){
        $filesystemservice.renameFile("somefile", files[0], function(data){
          expect(data.filepath).toBeDefined();
        });
        httpBackend.flush();
      });
      it('should be able to delete a file', function(){
        $filesystemservice.deleteFile(files[0].filepath, function(data){
          expect(data.result).toBeDefined();
        });
        httpBackend.flush();
      });
    });
});
<|endoftext|>


<commit_before>'use strict';

angular.module('searchApp')
  .controller('MainCtrl', [ '$scope', '$window', '$routeParams', '$location', 'SolrService',
    function ($scope, $window, $routeParams, $location, SolrService) {
      if ($routeParams.site !== undefined) {
          $scope.site = $routeParams.site;
      } else {
          $scope.site = 'ESRC';
      }

      $scope.w = $window.innerWidth;
      $scope.h = $window.innerHeight;
      //console.log($scope.w, $scope.h);

      if ($scope.w < 760) {
          //window.location.replace('/basic-search');
          $scope.t = 152;
      } else {
          $scope.t = 152;
      }

      // left (lpw) and right (rpw) panel widths
      $scope.lpw = Math.floor(($scope.w) * 0.3) - 1;
      $scope.rpw = $scope.w - $scope.lpw - 1;

      /* handle summary / detail view toggle */
      $scope.$on('show-search-results-details', function() {
          $scope.detailsActive = false;
      });
      $scope.$on('hide-search-results-details', function() {
          $scope.detailsActive = true;
      });
      $scope.$on('site-name-retrieved', function() {
          if (SolrService.site === 'ESRC') {
              $scope.site_name = 'Search our data';
              $scope.site_url = $location.absUrl();
              $scope.returnToSiteLink = false;
          } else {
              $scope.site_name = 'Search: ' + SolrService.site_name;
              $scope.site_url = SolrService.site_url;
              $scope.returnToSiteLink = true;
          }
      })

      /* button methods */
      $scope.toggleDetails = function() {
          SolrService.toggleDetails();
      };

  }]);
<commit_msg>handle window resize event<commit_after>'use strict';

angular.module('searchApp')
  .controller('MainCtrl', [ '$scope', '$window', '$routeParams', '$location', 'SolrService',
    function ($scope, $window, $routeParams, $location, SolrService) {
      if ($routeParams.site !== undefined) {
          $scope.site = $routeParams.site;
      } else {
          $scope.site = 'ESRC';
      }

      var w = angular.element($window);
      w.bind('resize', function() {
          $scope.$apply(function() {
            sizeThePanels();
          })
      });

      var sizeThePanels = function() {
          $scope.w = $window.innerWidth;
          $scope.h = $window.innerHeight;
          //console.log($scope.w, $scope.h);

          if ($scope.w < 760) {
              //window.location.replace('/basic-search');
              $scope.t = 152;
          } else {
              $scope.t = 152;
          }

          // left (lpw) and right (rpw) panel widths
          $scope.lpw = Math.floor(($scope.w) * 0.3) - 1;
          $scope.rpw = $scope.w - $scope.lpw - 1;
      }
      sizeThePanels();

      /* handle summary / detail view toggle */
      $scope.$on('show-search-results-details', function() {
          $scope.detailsActive = false;
      });
      $scope.$on('hide-search-results-details', function() {
          $scope.detailsActive = true;
      });
      $scope.$on('site-name-retrieved', function() {
          if (SolrService.site === 'ESRC') {
              $scope.site_name = 'Search our data';
              $scope.site_url = $location.absUrl();
              $scope.returnToSiteLink = false;
          } else {
              $scope.site_name = 'Search: ' + SolrService.site_name;
              $scope.site_url = SolrService.site_url;
              $scope.returnToSiteLink = true;
          }
      })

      /* button methods */
      $scope.toggleDetails = function() {
          SolrService.toggleDetails();
      };

  }]);
<|endoftext|>


<commit_before>'use strict';

function s4() {
  return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
}

function guid() {
  return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
}

angular.module('planningPokerApp')
  .controller('MainCtrl', function ($rootScope, $scope, $cookieStore, $location, $routeParams, angularFire) {

    // Firebase URL
    var URL = 'https://pzfqrq7kjy.firebaseio.com';

    // Load cookies
    $scope.fp = $cookieStore.get('fp');
    if (!$scope.fp) {
      $scope.fp = {};
    }

    // UID
    if (!$scope.fp.user || !$scope.fp.user.id) {
      var uid = guid();
      $scope.fp.user = {id: uid};
      $cookieStore.put('fp', $scope.fp);
    }

    // GID
    if (!$scope.fp.gid) {
      var gid = guid();
      $scope.fp.gid = gid;
      $cookieStore.put('fp', $scope.fp);
    }

    // Initialize Firebase
    var ref = new Firebase(URL);

    // Generate a new game
    if ($location.path() === '/games/new' || $location.path() === '/games/new/') {
      var id = guid();
      $location.path('/games/new/' + id);
    }

    // Redirect to set full name if empty...
    if (
      $routeParams.gid &&
      $location.path() === '/games/' + $routeParams.gid &&
      !$scope.fp.user.fullname
    ) {
      $location.path('/games/join/' + $routeParams.gid);
    }

    // If fullname already set redirect to the game
    if (
      $routeParams.gid &&
      $location.path() === '/games/join/' + $routeParams.gid &&
      $scope.fp.user.fullname
    ) {
      $location.path('/games/' + $routeParams.gid);
    }

    // Load game & register presence
    if ($routeParams.gid && $location.path() === '/games/' + $routeParams.gid) {
      angularFire(ref.child('/games/' + $routeParams.gid), $scope, 'game');
      ref.child('/games/' + $routeParams.gid + '/participants/' + $scope.fp.user.id).set($scope.fp.user);
      var onlineRef = ref.child('/games/' + $routeParams.gid + '/participants/' + $scope.fp.user.id + '/online');
      var connectedRef = ref.child('/.info/connected');
      connectedRef.on('value', function(snap) {
        if (snap.val() === true) {
          // We're connected (or reconnected)!  Set up our presence state and
          // tell the server to set a timestamp when we leave.
          onlineRef.onDisconnect().set(Firebase.ServerValue.TIMESTAMP);
          onlineRef.set(true);
        }
      });
    }

    // Create game
    $scope.createGame = function() {
      var stories = [],
          newGame = angular.copy($scope.newGame);
      if (newGame.stories) {
        angular.forEach(newGame.stories.split('\n'), function(title) {
          var story = {
            title: title,
            status: 'queue'
          };
          stories.push(story);
        });
      }
      newGame.stories = stories;
      newGame.status = 'active';
      newGame.created = new Date().getTime();
      newGame.owner = $scope.fp.user;
      newGame.participants = false;
      newGame.estimate = false;
      ref.child('/games/' + $routeParams.gid).set(newGame);
      $cookieStore.put('fp', $scope.fp);
      $location.path('/games/' + $routeParams.gid);
    };

    // Create story
    $scope.createStory = function(type) {
      if (type === 'structured') {
        var title = 'As a/an ' +
          $scope.newStory.asA +
          ' I would like to ' +
          $scope.newStory.iWouldLikeTo +
          ' so that ' +
          $scope.newStory.soThat;
        $scope.newStory.title = title;
        delete $scope.newStory.asA;
        delete $scope.newStory.iWouldLikeTo;
        delete $scope.newStory.soThat;
      }
      $scope.newStory.results = false;
      $scope.newStory.points = 0;
      $scope.newStory.status = 'queue';
      $scope.newStory.startedAt = false;
      $scope.newStory.endedAt = false;
      if (!$scope.game.stories) {
        $scope.game.stories = [];
      }
      $scope.game.stories.push($scope.newStory);
      $scope.newStory = null;
      // Set this story if there is none active
      // maybe this is good thing todo only if the queue is empty
      if (!$scope.game.estimate) {
        $scope.setStory($scope.game.stories.length - 1);
      }
    };

    // Set story
    $scope.setStory = function(index) {
      $scope.resetRound();
      $scope.game.estimate = $scope.game.stories[index];
      $scope.game.estimate.status = 'active';
      $scope.game.estimate.id = index;
      $scope.game.estimate.startedAt = new Date().getTime();
      $scope.game.estimate.endedAt = false;
    };

    // Estimate story
    $scope.estimate = function(points) {
      if (!$scope.game.estimate.results) {
        $scope.game.estimate.results = [];
      }
      $scope.game.estimate.results.push({points:points, user:$scope.fp.user});
    };

    // Set full name
    $scope.setFullname = function() {
      $cookieStore.put('fp', $scope.fp);
      $location.path('/games/' + $routeParams.gid);
    };

    // Get estimate results average
    $scope.getResultsAverage = function() {
      var avg = 0;
      if ($scope.game.estimate.results) {
        var sum = 0;
        angular.forEach($scope.game.estimate.results, function(result) {
          if (result.points && angular.isNumber(result.points)) {
            sum += +result.points;
          }
        });
        avg = Math.ceil(sum / $scope.game.estimate.results.length);
      }
      return avg;
    };

    // Get total of active participants
    $scope.totalOfOnlineParticipants = function() {
      var totalOfOnlineParticipants = 0;
      if ($scope.game && $scope.game.participants) {
        angular.forEach($scope.game.participants, function(participant) {
          if (participant.online === true) {
            totalOfOnlineParticipants++;
          }
        });
      }
      return totalOfOnlineParticipants;
    };

    // Accept
    $scope.acceptRound = function() {
      $scope.game.estimate.points = $scope.newEstimate.points;
      $scope.game.estimate.endedAt = new Date().getTime();
      $scope.game.estimate.status = 'closed';
      $scope.game.stories[$scope.game.estimate.id] = angular.copy($scope.game.estimate);
      $scope.game.estimate = false;
    };

    // Play again
    $scope.playAgain = function() {
      $scope.game.estimate.results = [];
    };

    // Reset round
    $scope.resetRound = function() {
      if ($scope.game.estimate) {
        var idx = $scope.game.estimate.id;
        $scope.game.stories[idx].startedAt = false;
        $scope.game.stories[idx].endedAt = false;
        $scope.game.stories[idx].status = 'queue';
        $scope.game.estimate = false;
      }
    };

    // Reveal cards
    $scope.revealCards = function() {
      $scope.showCards = true;
    };

    // Card deck options
    $scope.decks = [
      [0, 1, 2, 4, 8, 16, 32, 64, 128, '?'],
      [0, 0.5, 1, 2, 3, 5, 8, 13, 20, 40, 100, '?']
    ];

    // Default card deck
    $scope.newGame = {deck: 0};

    // Update game
    $scope.$watch('game', function(game) {
      // Defaults
      $scope.showCardDeck = true;
      $scope.showSelectEstimate = false;
      $scope.showAddStory = false;
      $scope.showFinishGame = false;
      $scope.isOwner = false;
      $scope.disablePlayAgainButton = false;
      $scope.showCards = false;
      if (!game) {
        return;
      }
      // Is current participant the game owner?
      if (game.owner && game.owner.id && game.owner.id === $scope.fp.user.id) {
        $scope.isOwner = true;
      }
      // Set card deck visibility
      if (game.estimate && game.estimate.results) {
        angular.forEach(game.estimate.results, function(result) {
          if (
            result &&
            result.user &&
            result.user.id &&
            result.user.id === $scope.fp.user.id
          ) {
            $scope.showCardDeck = false;
          }
        });
      }
      // Set estimation form visibility
      if (
        game.estimate &&
        // game.estimate.results &&
        game.owner &&
        game.owner.id === $scope.fp.user.id
      ) {
        $scope.showSelectEstimate = true;
      }
      // Set new estimate average points
      $scope.newEstimate = { points: $scope.getResultsAverage() };
      // Set add story form visibility
      // Set finish game button visibility
      if (game.owner && game.owner.id === $scope.fp.user.id) {
        $scope.showAddStory = true;
        $scope.showFinishGame = true;
      }
      // Disable play again button if results are empty
      if (!game.estimate.results) {
        $scope.disablePlayAgainButton = true;
      }
      // Show cards?
      if (
        game.estimate &&
        game.estimate.results &&
        game.estimate.results.length &&
        game.estimate.results.length === $scope.totalOfOnlineParticipants()
      ) {
        $scope.showCards = true;
      }
    });
  });

<commit_msg>Cleanup<commit_after>'use strict';

function s4() {
  return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
}

function guid() {
  return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
}

angular.module('planningPokerApp')
  .controller('MainCtrl', function ($rootScope, $scope, $cookieStore, $location, $routeParams, angularFire) {

    // Firebase URL
    var URL = 'https://pzfqrq7kjy.firebaseio.com';

    // Load cookies
    $scope.fp = $cookieStore.get('fp');
    if (!$scope.fp) {
      $scope.fp = {};
    }

    // UID
    if (!$scope.fp.user || !$scope.fp.user.id) {
      var uid = guid();
      $scope.fp.user = {id: uid};
      $cookieStore.put('fp', $scope.fp);
    }

    // GID
    if (!$scope.fp.gid) {
      var gid = guid();
      $scope.fp.gid = gid;
      $cookieStore.put('fp', $scope.fp);
    }

    // Initialize Firebase
    var ref = new Firebase(URL);

    // Generate a new game
    if ($location.path() === '/games/new' || $location.path() === '/games/new/') {
      var id = guid();
      $location.path('/games/new/' + id);
    }

    // Redirect to set full name if empty...
    if (
      $routeParams.gid &&
      $location.path() === '/games/' + $routeParams.gid &&
      !$scope.fp.user.fullname
    ) {
      $location.path('/games/join/' + $routeParams.gid);
    }

    // If fullname already set redirect to the game
    if (
      $routeParams.gid &&
      $location.path() === '/games/join/' + $routeParams.gid &&
      $scope.fp.user.fullname
    ) {
      $location.path('/games/' + $routeParams.gid);
    }

    // Load game & register presence
    if ($routeParams.gid && $location.path() === '/games/' + $routeParams.gid) {
      angularFire(ref.child('/games/' + $routeParams.gid), $scope, 'game');
      ref.child('/games/' + $routeParams.gid + '/participants/' + $scope.fp.user.id).set($scope.fp.user);
      var onlineRef = ref.child('/games/' + $routeParams.gid + '/participants/' + $scope.fp.user.id + '/online');
      var connectedRef = ref.child('/.info/connected');
      connectedRef.on('value', function(snap) {
        if (snap.val() === true) {
          // We're connected (or reconnected)!  Set up our presence state and
          // tell the server to set a timestamp when we leave.
          onlineRef.onDisconnect().set(Firebase.ServerValue.TIMESTAMP);
          onlineRef.set(true);
        }
      });
    }

    // Create game
    $scope.createGame = function() {
      var stories = [],
          newGame = angular.copy($scope.newGame);
      if (newGame.stories) {
        angular.forEach(newGame.stories.split('\n'), function(title) {
          var story = {
            title: title,
            status: 'queue'
          };
          stories.push(story);
        });
      }
      newGame.stories = stories;
      newGame.status = 'active';
      newGame.created = new Date().getTime();
      newGame.owner = $scope.fp.user;
      newGame.participants = false;
      newGame.estimate = false;
      ref.child('/games/' + $routeParams.gid).set(newGame);
      $cookieStore.put('fp', $scope.fp);
      $location.path('/games/' + $routeParams.gid);
    };

    // Create story
    $scope.createStory = function(type) {
      if (type === 'structured') {
        var title = 'As a/an ' +
          $scope.newStory.asA +
          ' I would like to ' +
          $scope.newStory.iWouldLikeTo +
          ' so that ' +
          $scope.newStory.soThat;
        $scope.newStory.title = title;
        delete $scope.newStory.asA;
        delete $scope.newStory.iWouldLikeTo;
        delete $scope.newStory.soThat;
      }
      $scope.newStory.results = false;
      $scope.newStory.points = 0;
      $scope.newStory.status = 'queue';
      $scope.newStory.startedAt = false;
      $scope.newStory.endedAt = false;
      if (!$scope.game.stories) {
        $scope.game.stories = [];
      }
      $scope.game.stories.push($scope.newStory);
      $scope.newStory = null;
      // Set this story if there is none active
      // maybe this is good thing todo only if the queue is empty
      if (!$scope.game.estimate) {
        $scope.setStory($scope.game.stories.length - 1);
      }
    };

    // Set story
    $scope.setStory = function(index) {
      $scope.resetRound();
      $scope.game.estimate = $scope.game.stories[index];
      $scope.game.estimate.status = 'active';
      $scope.game.estimate.id = index;
      $scope.game.estimate.startedAt = new Date().getTime();
      $scope.game.estimate.endedAt = false;
    };

    // Estimate story
    $scope.estimate = function(points) {
      if (!$scope.game.estimate.results) {
        $scope.game.estimate.results = [];
      }
      $scope.game.estimate.results.push({points:points, user:$scope.fp.user});
    };

    // Set full name
    $scope.setFullname = function() {
      $cookieStore.put('fp', $scope.fp);
      $location.path('/games/' + $routeParams.gid);
    };

    // Get estimate results average
    $scope.getResultsAverage = function() {
      var avg = 0;
      if ($scope.game.estimate.results) {
        var sum = 0;
        angular.forEach($scope.game.estimate.results, function(result) {
          if (result.points && angular.isNumber(result.points)) {
            sum += +result.points;
          }
        });
        avg = Math.ceil(sum / $scope.game.estimate.results.length);
      }
      return avg;
    };

    // Get total of active participants
    $scope.totalOfOnlineParticipants = function() {
      var totalOfOnlineParticipants = 0;
      if ($scope.game && $scope.game.participants) {
        angular.forEach($scope.game.participants, function(participant) {
          if (participant.online === true) {
            totalOfOnlineParticipants++;
          }
        });
      }
      return totalOfOnlineParticipants;
    };

    // Accept
    $scope.acceptRound = function() {
      $scope.game.estimate.points = $scope.newEstimate.points;
      $scope.game.estimate.endedAt = new Date().getTime();
      $scope.game.estimate.status = 'closed';
      $scope.game.stories[$scope.game.estimate.id] = angular.copy($scope.game.estimate);
      $scope.game.estimate = false;
    };

    // Play again
    $scope.playAgain = function() {
      $scope.game.estimate.results = [];
    };

    // Reset round
    $scope.resetRound = function() {
      if ($scope.game.estimate) {
        var idx = $scope.game.estimate.id;
        $scope.game.stories[idx].startedAt = false;
        $scope.game.stories[idx].endedAt = false;
        $scope.game.stories[idx].status = 'queue';
        $scope.game.estimate = false;
      }
    };

    // Reveal cards
    $scope.revealCards = function() {
      $scope.showCards = true;
    };

    // Card deck options
    $scope.decks = [
      [0, 1, 2, 4, 8, 16, 32, 64, 128, '?'],
      [0, 0.5, 1, 2, 3, 5, 8, 13, 20, 40, 100, '?']
    ];

    // Default card deck
    $scope.newGame = {deck: 0};

    // Update game
    $scope.$watch('game', function(game) {
      // Defaults
      $scope.showCardDeck = true;
      $scope.showSelectEstimate = false;
      $scope.showAddStory = false;
      $scope.isOwner = false;
      $scope.disablePlayAgainButton = false;
      $scope.showCards = false;
      if (!game) {
        return;
      }
      // Is current participant the game owner?
      if (game.owner && game.owner.id && game.owner.id === $scope.fp.user.id) {
        $scope.isOwner = true;
      }
      // Set card deck visibility
      if (game.estimate && game.estimate.results) {
        angular.forEach(game.estimate.results, function(result) {
          if (
            result &&
            result.user &&
            result.user.id &&
            result.user.id === $scope.fp.user.id
          ) {
            $scope.showCardDeck = false;
          }
        });
      }
      // Set estimation form visibility
      if (
        game.estimate &&
        // game.estimate.results &&
        game.owner &&
        game.owner.id === $scope.fp.user.id
      ) {
        $scope.showSelectEstimate = true;
      }
      // Set new estimate average points
      $scope.newEstimate = { points: $scope.getResultsAverage() };
      // Set add story form visibility
      if (game.owner && game.owner.id === $scope.fp.user.id) {
        $scope.showAddStory = true;
      }
      // Disable play again button if results are empty
      if (!game.estimate.results) {
        $scope.disablePlayAgainButton = true;
      }
      // Show cards?
      if (
        game.estimate &&
        game.estimate.results &&
        game.estimate.results.length &&
        game.estimate.results.length === $scope.totalOfOnlineParticipants()
      ) {
        $scope.showCards = true;
      }
    });
  });

<|endoftext|>