<commit_before>const path = require('path')
const fs = require('fs')
const webpack = require('webpack')
const react = require('@neutrinojs/react')
const copy = require('@neutrinojs/copy')
const jest = require('@neutrinojs/jest')
const wext = require('neutrino-webextension')
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
const MomentLocalesPlugin = require('moment-locales-webpack-plugin')
const dotenv = require('dotenv')
const argv = require('yargs').argv
const AfterBuildPlugin = require('./scripts/after-build')
const svgToMiniDataURI = require('mini-svg-data-uri')
const isAnalyze = argv.analyze || argv.analyse

module.exports = {
  options: {
    mains: {
      content: {
        entry: 'content',
        webext: {
          type: 'content_scripts',
          manifest: {
            css: ['assets/content.css'],
            matches: ['<all_urls>']
          },
          setup: 'content/__fake__/env.ts'
        }
      },

      selection: {
        entry: 'selection',
        webext: {
          type: 'content_scripts',
          manifest: {
            match_about_blank: true,
            all_frames: true,
            matches: ['<all_urls>']
          }
        }
      },

      popup: {
        entry: 'popup',
        webext: {
          type: 'browser_action',
          manifest: {
            default_icon: {
              '16': 'assets/icon-16.png',
              '19': 'assets/icon-19.png',
              '24': 'assets/icon-24.png',
              '38': 'assets/icon-38.png',
              '48': 'assets/icon-48.png',
              '128': 'assets/icon-128.png'
            }
          },
          setup: 'popup/__fake__/env.ts'
        }
      },

      options: {
        entry: 'options',
        webext: {
          type: 'options_ui',
          manifest: {
            open_in_tab: true
          },
          setup: 'options/__fake__/env.ts'
        }
      },

      background: {
        entry: 'background',
        webext: {
          type: 'background',
          setup: 'background/__fake__/env.ts'
        }
      },

      notebook: {
        entry: 'notebook'
      },

      history: {
        entry: 'history'
      },

      'quick-search': {
        entry: 'quick-search'
      },

      'word-editor': {
        entry: 'word-editor'
      },

      'audio-control': {
        entry: 'audio-control'
      }
    }
  },
  use: [
    react({
      html: {
        title: 'Saladict'
      },
      image: false,
      style: {
        test: /\.(css|scss)$/,
        modulesTest: /\.module\.(css|scss)$/,
        loaders: [
          // Define loaders as objects. Note: loaders must be specified in reverse order.
          // ie: for the loaders below the actual execution order would be:
          // input file -> sass-loader -> postcss-loader -> css-loader -> style-loader/mini-css-extract-plugin
          {
            loader: 'postcss-loader',
            options: {
              plugins: [require('autoprefixer')]
            },
            useId: 'postcss'
          },
          {
            loader: 'sass-loader',
            useId: 'scss'
          },
          {
            loader: 'sass-resources-loader',
            useId: 'sass-resources',
            options: {
              sourceMap: process.env.NODE_ENV !== 'production',
              resources: fs
                .readdirSync(path.join(__dirname, 'src/_sass_shared/_global/'))
                .map(filename =>
                  path.join(__dirname, 'src/_sass_shared/_global/', filename)
                )
            }
          }
        ]
      },
      babel: {
        presets: [
          [
            '@babel/preset-env',
            {
              /* remove targets set by neutrino web preset preferring browserslistrc */
            }
          ],
          [
            '@babel/preset-typescript',
            {
              isTSX: true,
              allExtensions: true
            }
          ]
        ],
        plugins: [
          [
            'import',
            {
              libraryName: 'antd'
            },
            'antd'
          ],
          [
            'import',
            {
              libraryName: '@ant-design/icons',
              libraryDirectory: '',
              camel2DashComponentName: false,
              style: false
            },
            '@ant-design/icons'
          ]
        ]
      }
    }),
    copy({
      patterns: [
        { context: 'assets', from: '**/*', to: 'assets/', toType: 'dir' },
        {
          context: 'src/_locales/manifest',
          from: '**/*',
          to: '_locales/',
          toType: 'dir'
        },
        {
          context: 'node_modules/antd/dist/',
          from: '+(antd|antd.dark).min.css',
          to: 'assets/',
          toType: 'dir'
        }
      ]
    }),
    neutrino => {
      /* eslint-disable indent */

      // images
      neutrino.config.module.rules
        .delete('image')
        .end()
        .rule('svg')
        .test(/\.(svg)(\?v=\d+\.\d+\.\d+)?$/)
        .use('svg-url')
        .loader(require.resolve('url-loader'))
        .options({
          limit: 8192,
          // remove `default` when `require` image
          // due to legacy code
          esModule: false,
          generator: content => svgToMiniDataURI(content.toString())
        })
        .end()
        .end()
        .rule('pixel')
        .test(/\.(ico|png|jpg|jpeg|gif|webp)(\?v=\d+\.\d+\.\d+)?$/)
        .use('img-url')
        .loader(require.resolve('file-loader'))
        .options({
          // dev-server image name collision
          name: resourcePath => {
            if (process.env.NODE_ENV === 'development') {
              return '[path]/[name].[ext]'
            }

            const dictMatch = /\/dictionaries\/([^/]+)\/favicon.png/.exec(
              resourcePath
            )
            if (dictMatch) {
              return `assets/favicon-${dictMatch[1]}.[contenthash:8].[ext]`
            }

            return 'assets/[name].[contenthash:8].[ext]'
          },
          limit: 0,
          esModule: false
        })

      // avoid collision
      neutrino.config.output.jsonpFunction('saladictEntry')

      // transform *.shadow.(css|scss) to string
      // this will be injected into shadow-dom style tag
      // prettier-ignore
      const shadowStyleRules = neutrino.config.module
        .rule('style')
          .oneOf('shadow')
            .before('normal')
            .test(/\.shadow\.(css|scss)$/)
              .use('tostring')
                .loader('to-string-loader')
                .end()
              .use('minify')
              .after('css')
                .loader('clean-css-loader')
                .options({
                  level: 1,
                })
                .end()
      // copy loaders from normal to shadow
      // prettier-ignore
      neutrino.config.module
        .rule('style')
          .oneOf('normal')
            .uses.values()
              .filter(rule => !/^(extract|style)$/.test(rule.name))
              .forEach(rule => {
                shadowStyleRules
                  .use(rule.name)
                    .loader(rule.get('loader'))
                    .options(rule.get('options'))
              })

      // prettier-ignore
      neutrino.config
        .module
          .rule('compile') // add ts extensions for babel ect
            .test(/\.(mjs|jsx|js|ts|tsx)$/)
            .end()
          .end()
        .resolve
          .extensions // typescript extensions
            .add('.ts')
            .add('.tsx')
            .end()
          .alias // '@' src alias
            .set('@', path.join(__dirname, 'src'))
            .end()
          .end()

      // prettier-ignore
      neutrino.config
        .plugin('process.env')
          .use(webpack.DefinePlugin, [{
            'process.env': JSON.stringify(Object.assign(
                { DEBUG: !!argv.debug },
                dotenv.config().parsed
              ))
          }])
      /* eslint-enable indent */

      if (argv.mode === 'production') {
        // prettier-ignore
        neutrino.config
          .performance
            .hints(false)
            .end()
          .plugin('momentjs')
            .use(MomentLocalesPlugin, [{ localesToKeep: ['zh-cn', 'zh-tw'] }])
            .end()
          .optimization
            .merge({
              splitChunks: {
                cacheGroups: {
                  react: {
                    test: /[\\/]node_modules[\\/](react|react-dom|i18next)[\\/]/,
                    name: 'view-vendor',
                    chunks: 'all',
                    priority: 100
                  },
                  franc: {
                    test: /[\\/]node_modules[\\/]franc/,
                    name: 'franc',
                    chunks: 'all',
                    priority: 100
                  },
                  dexie: {
                    test: /[\\/]node_modules[\\/]dexie/,
                    name: 'dexie',
                    chunks: 'all',
                    priority: 100
                  },
                  wordpage: {
                    test: (module, chunks) => module.resource &&
                      module.resource.includes(`${path.sep}src${path.sep}`) &&
                      !module.resource.includes(`${path.sep}node_modules${path.sep}`),
                    name: 'wordpage',
                    chunks: ({ name }) => /^(notebook|history)$/.test(name),
                  },
                  antd: {
                    test: /[\\/]node_modules[\\/]/,
                    name: 'antd',
                    chunks: ({ name }) => /^(options|notebook|history)$/.test(name),
                  }
                }
              },
            })
      }

      if (argv.debug) {
        // prettier-ignore
        neutrino.config
          .devtool('inline-source-map')
          .optimization
            .minimize(false)
      }

      if (isAnalyze) {
        // prettier-ignore
        neutrino.config
          .plugin('bundle-analyze')
          .use(BundleAnalyzerPlugin);
      }
    },
    jest({
      testRegex: ['test/specs/.*\\.spec\\.(ts|tsx|js|jsx)'],
      setupFilesAfterEnv: ['<rootDir>/config/jest/setupTests.js'],
      moduleNameMapper: {
        '^@/(.*)$': '<rootDir>/src/$1'
      },
      transform: {
        '\\.(mjs|jsx|js|ts|tsx)$': require.resolve(
          '@neutrinojs/jest/src/transformer'
        )
      },
      testTimeout: 20000
    }),
    wext({
      polyfill: true
    }),
    neutrino => {
      // prettier-ignore
      neutrino.config
        .plugin('after-build')
        .use(AfterBuildPlugin);
    }
  ]
}
<commit_msg>build: always strip momentjs locales<commit_after>const path = require('path')
const fs = require('fs')
const webpack = require('webpack')
const react = require('@neutrinojs/react')
const copy = require('@neutrinojs/copy')
const jest = require('@neutrinojs/jest')
const wext = require('neutrino-webextension')
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
const MomentLocalesPlugin = require('moment-locales-webpack-plugin')
const dotenv = require('dotenv')
const argv = require('yargs').argv
const AfterBuildPlugin = require('./scripts/after-build')
const svgToMiniDataURI = require('mini-svg-data-uri')
const isAnalyze = argv.analyze || argv.analyse

module.exports = {
  options: {
    mains: {
      content: {
        entry: 'content',
        webext: {
          type: 'content_scripts',
          manifest: {
            css: ['assets/content.css'],
            matches: ['<all_urls>']
          },
          setup: 'content/__fake__/env.ts'
        }
      },

      selection: {
        entry: 'selection',
        webext: {
          type: 'content_scripts',
          manifest: {
            match_about_blank: true,
            all_frames: true,
            matches: ['<all_urls>']
          }
        }
      },

      popup: {
        entry: 'popup',
        webext: {
          type: 'browser_action',
          manifest: {
            default_icon: {
              '16': 'assets/icon-16.png',
              '19': 'assets/icon-19.png',
              '24': 'assets/icon-24.png',
              '38': 'assets/icon-38.png',
              '48': 'assets/icon-48.png',
              '128': 'assets/icon-128.png'
            }
          },
          setup: 'popup/__fake__/env.ts'
        }
      },

      options: {
        entry: 'options',
        webext: {
          type: 'options_ui',
          manifest: {
            open_in_tab: true
          },
          setup: 'options/__fake__/env.ts'
        }
      },

      background: {
        entry: 'background',
        webext: {
          type: 'background',
          setup: 'background/__fake__/env.ts'
        }
      },

      notebook: {
        entry: 'notebook'
      },

      history: {
        entry: 'history'
      },

      'quick-search': {
        entry: 'quick-search'
      },

      'word-editor': {
        entry: 'word-editor'
      },

      'audio-control': {
        entry: 'audio-control'
      }
    }
  },
  use: [
    react({
      html: {
        title: 'Saladict'
      },
      image: false,
      style: {
        test: /\.(css|scss)$/,
        modulesTest: /\.module\.(css|scss)$/,
        loaders: [
          // Define loaders as objects. Note: loaders must be specified in reverse order.
          // ie: for the loaders below the actual execution order would be:
          // input file -> sass-loader -> postcss-loader -> css-loader -> style-loader/mini-css-extract-plugin
          {
            loader: 'postcss-loader',
            options: {
              plugins: [require('autoprefixer')]
            },
            useId: 'postcss'
          },
          {
            loader: 'sass-loader',
            useId: 'scss'
          },
          {
            loader: 'sass-resources-loader',
            useId: 'sass-resources',
            options: {
              sourceMap: process.env.NODE_ENV !== 'production',
              resources: fs
                .readdirSync(path.join(__dirname, 'src/_sass_shared/_global/'))
                .map(filename =>
                  path.join(__dirname, 'src/_sass_shared/_global/', filename)
                )
            }
          }
        ]
      },
      babel: {
        presets: [
          [
            '@babel/preset-env',
            {
              /* remove targets set by neutrino web preset preferring browserslistrc */
            }
          ],
          [
            '@babel/preset-typescript',
            {
              isTSX: true,
              allExtensions: true
            }
          ]
        ],
        plugins: [
          [
            'import',
            {
              libraryName: 'antd'
            },
            'antd'
          ],
          [
            'import',
            {
              libraryName: '@ant-design/icons',
              libraryDirectory: '',
              camel2DashComponentName: false,
              style: false
            },
            '@ant-design/icons'
          ]
        ]
      }
    }),
    copy({
      patterns: [
        { context: 'assets', from: '**/*', to: 'assets/', toType: 'dir' },
        {
          context: 'src/_locales/manifest',
          from: '**/*',
          to: '_locales/',
          toType: 'dir'
        },
        {
          context: 'node_modules/antd/dist/',
          from: '+(antd|antd.dark).min.css',
          to: 'assets/',
          toType: 'dir'
        }
      ]
    }),
    neutrino => {
      /* eslint-disable indent */

      // images
      neutrino.config.module.rules
        .delete('image')
        .end()
        .rule('svg')
        .test(/\.(svg)(\?v=\d+\.\d+\.\d+)?$/)
        .use('svg-url')
        .loader(require.resolve('url-loader'))
        .options({
          limit: 8192,
          // remove `default` when `require` image
          // due to legacy code
          esModule: false,
          generator: content => svgToMiniDataURI(content.toString())
        })
        .end()
        .end()
        .rule('pixel')
        .test(/\.(ico|png|jpg|jpeg|gif|webp)(\?v=\d+\.\d+\.\d+)?$/)
        .use('img-url')
        .loader(require.resolve('file-loader'))
        .options({
          // dev-server image name collision
          name: resourcePath => {
            if (process.env.NODE_ENV === 'development') {
              return '[path]/[name].[ext]'
            }

            const dictMatch = /\/dictionaries\/([^/]+)\/favicon.png/.exec(
              resourcePath
            )
            if (dictMatch) {
              return `assets/favicon-${dictMatch[1]}.[contenthash:8].[ext]`
            }

            return 'assets/[name].[contenthash:8].[ext]'
          },
          limit: 0,
          esModule: false
        })

      // avoid collision
      neutrino.config.output.jsonpFunction('saladictEntry')

      // transform *.shadow.(css|scss) to string
      // this will be injected into shadow-dom style tag
      // prettier-ignore
      const shadowStyleRules = neutrino.config.module
        .rule('style')
          .oneOf('shadow')
            .before('normal')
            .test(/\.shadow\.(css|scss)$/)
              .use('tostring')
                .loader('to-string-loader')
                .end()
              .use('minify')
              .after('css')
                .loader('clean-css-loader')
                .options({
                  level: 1,
                })
                .end()
      // copy loaders from normal to shadow
      // prettier-ignore
      neutrino.config.module
        .rule('style')
          .oneOf('normal')
            .uses.values()
              .filter(rule => !/^(extract|style)$/.test(rule.name))
              .forEach(rule => {
                shadowStyleRules
                  .use(rule.name)
                    .loader(rule.get('loader'))
                    .options(rule.get('options'))
              })

      // prettier-ignore
      neutrino.config
        .module
          .rule('compile') // add ts extensions for babel ect
            .test(/\.(mjs|jsx|js|ts|tsx)$/)
            .end()
          .end()
        .resolve
          .extensions // typescript extensions
            .add('.ts')
            .add('.tsx')
            .end()
          .alias // '@' src alias
            .set('@', path.join(__dirname, 'src'))
            .end()
          .end()

      // remove locales
      neutrino.config
        .plugin('momentjs')
          .use(MomentLocalesPlugin, [{ localesToKeep: ['zh-cn', 'zh-tw'] }])
          .end()

      // prettier-ignore
      neutrino.config
        .plugin('process.env')
          .use(webpack.DefinePlugin, [{
            'process.env': JSON.stringify(Object.assign(
                { DEBUG: !!argv.debug },
                dotenv.config().parsed
              ))
          }])
      /* eslint-enable indent */

      if (argv.mode === 'production') {
        // prettier-ignore
        neutrino.config
          .performance
            .hints(false)
            .end()
          .optimization
            .merge({
              splitChunks: {
                cacheGroups: {
                  react: {
                    test: /[\\/]node_modules[\\/](react|react-dom|i18next)[\\/]/,
                    name: 'view-vendor',
                    chunks: 'all',
                    priority: 100
                  },
                  franc: {
                    test: /[\\/]node_modules[\\/]franc/,
                    name: 'franc',
                    chunks: 'all',
                    priority: 100
                  },
                  dexie: {
                    test: /[\\/]node_modules[\\/]dexie/,
                    name: 'dexie',
                    chunks: 'all',
                    priority: 100
                  },
                  wordpage: {
                    test: (module, chunks) => module.resource &&
                      module.resource.includes(`${path.sep}src${path.sep}`) &&
                      !module.resource.includes(`${path.sep}node_modules${path.sep}`),
                    name: 'wordpage',
                    chunks: ({ name }) => /^(notebook|history)$/.test(name),
                  },
                  antd: {
                    test: /[\\/]node_modules[\\/]/,
                    name: 'antd',
                    chunks: ({ name }) => /^(options|notebook|history)$/.test(name),
                  }
                }
              },
            })
      }

      if (argv.debug) {
        // prettier-ignore
        neutrino.config
          .devtool('inline-source-map')
          .optimization
            .minimize(false)
      }

      if (isAnalyze) {
        // prettier-ignore
        neutrino.config
          .plugin('bundle-analyze')
          .use(BundleAnalyzerPlugin);
      }
    },
    jest({
      testRegex: ['test/specs/.*\\.spec\\.(ts|tsx|js|jsx)'],
      setupFilesAfterEnv: ['<rootDir>/config/jest/setupTests.js'],
      moduleNameMapper: {
        '^@/(.*)$': '<rootDir>/src/$1'
      },
      transform: {
        '\\.(mjs|jsx|js|ts|tsx)$': require.resolve(
          '@neutrinojs/jest/src/transformer'
        )
      },
      testTimeout: 20000
    }),
    wext({
      polyfill: true
    }),
    neutrino => {
      // prettier-ignore
      neutrino.config
        .plugin('after-build')
        .use(AfterBuildPlugin);
    }
  ]
}
<|endoftext|>


<commit_before>//
// HTTP Server
//
// HTTP server.
// Version: 0.2
// Author: Mark W. B. Ashcroft (mark [at] kurunt [dot] com)
// License: MIT or Apache 2.0.
//
// Copyright (c) 2013 Mark W. B. Ashcroft.
// Copyright (c) 2013 Kurunt.
//

var config			= require("./config.json");								// your config settings.
var gconfig			= require("../../.././config.json");			// your global config settings.
var http 				= require('http');												// Load the http Library.
var util 				= require('util');
var url 				= require("url");
var path 				= require("path");
var querystring = require('querystring');

var log 				= function(txt) { if ( config['debug'] === 'benchmarking' || config['debug'] === 'debug' ) { console.log(txt); } };

//var streams = {};		// get dynamically set/unset by index.js through web admin.
//exports.streams = streams;

var uidNumberBands 	= require('uid-number-bands');
uidNumberBands.init(gconfig['band'], gconfig['bands'], true);		// [band, bands, start id at 1 = true else 0 = false].

var server			= undefined;

var toobusy = undefined;
try {
	toobusy = require('toobusy');
	var TOOBUSY_PAUSE = 200;		// set in miliseconds to pause incomming stream.
} catch(e) {
	console.log('http@inputs> To use toobusy, you need to install >npm install toobusy -g');
}

var streams = {};		// get dynamically set/unset by index.js through web admin.
exports.streams = streams;

// Start the HTTP Server.
module.exports.start = function (processID, route, messenger) {
	function onRequest(req, res) {

		// some http clients request favicon, return.
		if (req.url === '/favicon.ico') {
			res.writeHead(200, {'Content-Type': 'image/x-icon'});
			res.end();
			return;
		}

		var uri = url.parse(req.url).pathname;
		//console.log(processID+'@inputs> uri: ' + uri);

		var url_parts = url.parse(req.url, true);
		var query = url_parts.query;

		// apikey.
		var apikey = url_parts.pathname.substring(1, 17);
		console.log('apikey: ' + apikey);

		// lookup apikey with open streams.
		console.log(processID+'@inputs> streams ' + util.inspect(streams, true, 99, true));
		if ( streams[apikey] === undefined ) {
			res.writeHead(403, {'Server': 'Kurunt', 'Content-Type': 'application/json; charset=utf-8', 'Connection': 'closed'});
			res.write( JSON.stringify({"status": "unauthorized request"}) + '\n' );   // return the message id.
			res.end();
			return;
		}
		if ( streams[apikey]['status'] != 'open' ) {
			res.writeHead(403, {'Server': 'Kurunt', 'Content-Type': 'application/json; charset=utf-8', 'Connection': 'closed'});
			res.write( JSON.stringify({"status": "unauthorized request"}) + '\n' );   // return the message id.
			res.end();
			return;
		}

		if ( req.method === 'GET' || req.method === 'PUT' || req.method === 'POST' ) {
			// GET, PUT, POST http verbs are accepted, okay.
		} else {
			res.writeHead(403, {'Server': 'Kurunt', 'Content-Type': 'application/json; charset=utf-8', 'Connection': 'closed'});
			res.write( JSON.stringify({"status": "invalid method request"}) + '\n' );   // return the message id.
			res.end();
			return;
		}

//console.log(processID+'@inputs> url_parts ' + util.inspect(url_parts, true, 99, true));
//console.log(processID+'@inputs> query ' + util.inspect(query, true, 99, true));

		var client_ip = _ipAddress(req);
		//console.log(processID+'@inputs> IP: ' + ip + ' port: ' + req.connection.remotePort);
		if ( client_ip === false || req.headers.host == undefined ) {
			res.writeHead(403, {'Server': 'Kurunt', 'Content-Type': 'application/json; charset=utf-8', 'Connection': 'closed'});
			res.write( JSON.stringify({"status": "invalid request"}) + '\n' );   // return the message id.
			res.end();
			return;
		}

		var mime_type = req.headers['content-type'];
		//console.log('mime_type: ' + mime_type);

		// Handle incoming messages from client.

		var buffer = new Buffer(0);		// concat until message completed.

		// on chunk concate buffer.
		req.on('data', function (chunk) {
			buffer = Buffer.concat([buffer, chunk], buffer.length + chunk.length);

		});

		// on end of data, use concated buffer as message.
		req.on('end', function () {

			if ( req.method === 'GET' ) {
				// form the message from the query and headers.
				var mObj = {};
				mObj.query = query;
				mObj.client_ip = client_ip;
				mObj.client_port = req.connection.remotePort;
				mObj.pathname = url_parts.pathname;
				mObj.language = req.headers['accept-language'];
				mObj.user_agent = req.headers['user-agent'];
				mObj.referer = req.headers.referer;
				mObj.cookie = req.headers.cookie;
				//console.log(processID+'@inputs> GET req.headers ' + util.inspect(req.headers, true, 99, true));
				var message = new Buffer(JSON.stringify(mObj));
			} else {
				var message = buffer;
				console.log(processID+'@inputs> Got end(), buffer : ' + buffer.toString());
			}

			buffer = null;		// reset buffer.

			var id = uidNumberBands.make();		// id is object, eg: id.uid etc.

/*
			if ( toobusy != undefined ) {
				if (toobusy()) {
					//console.log('udp@inputs> Im toobusy.');
					// TODO: udp does not expose socket like tcp! how to pause?
					socket.pause();
					setTimeout(function() {
						socket.resume();
						//console.log('udp@inputs> Im not too busy, resume.');
					}, TOOBUSY_PAUSE);
				}
			}
*/

			// route ...
			route(apikey, config['name'], __remoteAddress(req), message, id, mime_type, messenger, streams, function (validHost) {
				if ( validHost === true ) {
					if ( url_parts.pathname.indexOf('.gif') != -1 && req.method === 'GET' ) {
						// return 1 pixel transparent gif.
						res.writeHead(200, {
							'Server': 'Kurunt',
							'Content-Length': '43',
							'Content-Type': 'image/gif',
							'Expiresponse': 'Mon, 26 Jul 2005 05:00:00 GMT',
							'Cache-Control': 'no-store, no-cache, must-revalidate',
							'Pragma': 'no-cache',
							'Connection': 'close'
						});
				    res.end('\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\xf0\x01\x00\xff\xff\xff\x00\x00\x00\x21\xf9\x04\x01\x0a\x00\x00\x00\x2c\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02\x44\x01\x00\x3b', 'binary');
					} else {
						// return json message with id for this message.
						res.writeHead(200, {'Server': 'Kurunt', 'Content-Type': 'application/json; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive'});
						res.write( JSON.stringify({"uid": id.uid}) + '\n' );   // return the message id.
						res.end();
					}
				} else {
					log(processID+'@inputs> No client host access found for ' + __remoteAddress(req) + ' on apikey: ' + apikey + ' will ignore client.');
					res.writeHead(403, {'Server': 'Kurunt', 'Content-Type': 'application/json; charset=utf-8', 'Connection': 'closed'});
					res.write( JSON.stringify({"status": "unauthorized request"}) + '\n' );   // return the message id.
					res.end();
					return;
				}
			});

		});

		req.connection.addListener('close', function () {
		  console.log('http@inputs> Client closed. Last request for: ' + req.url + ' by ip: ' + client_ip);
		});

	} // end onReceive.
	server = http.createServer(onRequest).listen(config['input_port']);
	log(processID+'@inputs> HTTP (input) Server opened @ http://' + gconfig['host'] + ":" + config['input_port']);
	console.log(processID+'@inputs> streams ' + util.inspect(streams, true, 99, true));
}

function _ipAddress(request) {
	// try request.connection.socket.remoteAddresponses for https, request.socket.remoteAddresponses works for most http but request.connection.remoteAddress seems more reliable.
	var ip = undefined;
	try {
		ip = request.headers['x-forwarded-for'];
		if ( ip === undefined ) {
			ip = __remoteAddress(request);
		}
	} catch ( err ) {
		ip = __remoteAddress(request);
	}
	return ip;
}
function __remoteAddress(request) {
	var ip = undefined;
	ip = request.connection.remoteAddress;
	if ( ip === undefined ) {
		ip = request.socket.remoteAddresponses;
		if (ip === undefined) {
			return false;
		}
	}
	return ip;
}

<commit_msg>http input<commit_after>//
// HTTP Server
//
// HTTP server.
// Version: 0.2
// Author: Mark W. B. Ashcroft (mark [at] kurunt [dot] com)
// License: MIT or Apache 2.0.
//
// Copyright (c) 2013 Mark W. B. Ashcroft.
// Copyright (c) 2013 Kurunt.
//

var config			= require("./config.json");								// your config settings.
var gconfig			= require("../../.././config.json");			// your global config settings.
var http 				= require('http');												// Load the http Library.
var util 				= require('util');
var url 				= require("url");
var path 				= require("path");
var querystring = require('querystring');

var log 				= function(txt) { if ( config['debug'] === 'benchmarking' || config['debug'] === 'debug' ) { console.log(txt); } };

//var streams = {};		// get dynamically set/unset by index.js through web admin.
//exports.streams = streams;

var uidNumberBands 	= require('uid-number-bands');
uidNumberBands.init(gconfig['band'], gconfig['bands'], true);		// [band, bands, start id at 1 = true else 0 = false].

var server			= undefined;

var toobusy = undefined;
try {
	toobusy = require('toobusy');
	var TOOBUSY_PAUSE = 200;		// set in miliseconds to pause incomming stream.
} catch(e) {
	console.log('http@inputs> To use toobusy, you need to install >npm install toobusy -g');
}

var streams = {};		// get dynamically set/unset by index.js through web admin.
exports.streams = streams;

// Start the HTTP Server.
module.exports.start = function (processID, route, messenger) {
	function onRequest(req, res) {

		// some http clients request favicon, return.
		if (req.url === '/favicon.ico') {
			res.writeHead(200, {'Content-Type': 'image/x-icon'});
			res.end();
			return;
		}

		var uri = url.parse(req.url).pathname;
		//console.log(processID+'@inputs> uri: ' + uri);

		var url_parts = url.parse(req.url, true);
		var query = url_parts.query;

		// apikey.
		var apikey = url_parts.pathname.substring(1, 17);
		//console.log('apikey: ' + apikey);

		// lookup apikey with open streams.
		//console.log(processID+'@inputs> streams ' + util.inspect(streams, true, 99, true));
		if ( streams[apikey] === undefined ) {
			res.writeHead(403, {'Server': 'Kurunt', 'Content-Type': 'application/json; charset=utf-8', 'Connection': 'closed'});
			res.write( JSON.stringify({"status": "unauthorized request"}) + '\n' );   // return the message id.
			res.end();
			return;
		}
		if ( streams[apikey]['status'] != 'open' ) {
			res.writeHead(403, {'Server': 'Kurunt', 'Content-Type': 'application/json; charset=utf-8', 'Connection': 'closed'});
			res.write( JSON.stringify({"status": "unauthorized request"}) + '\n' );   // return the message id.
			res.end();
			return;
		}

		if ( req.method === 'GET' || req.method === 'PUT' || req.method === 'POST' ) {
			// GET, PUT, POST http verbs are accepted, okay.
		} else {
			res.writeHead(403, {'Server': 'Kurunt', 'Content-Type': 'application/json; charset=utf-8', 'Connection': 'closed'});
			res.write( JSON.stringify({"status": "invalid method request"}) + '\n' );   // return the message id.
			res.end();
			return;
		}

//console.log(processID+'@inputs> url_parts ' + util.inspect(url_parts, true, 99, true));
//console.log(processID+'@inputs> query ' + util.inspect(query, true, 99, true));

		var client_ip = _ipAddress(req);
		//console.log(processID+'@inputs> IP: ' + ip + ' port: ' + req.connection.remotePort);
		if ( client_ip === false || req.headers.host == undefined ) {
			res.writeHead(403, {'Server': 'Kurunt', 'Content-Type': 'application/json; charset=utf-8', 'Connection': 'closed'});
			res.write( JSON.stringify({"status": "invalid request"}) + '\n' );   // return the message id.
			res.end();
			return;
		}

		var mime_type = req.headers['content-type'];
		//console.log('mime_type: ' + mime_type);

		// Handle incoming messages from client.

		var buffer = new Buffer(0);		// concat until message completed.

		// on chunk concate buffer.
		req.on('data', function (chunk) {
			buffer = Buffer.concat([buffer, chunk], buffer.length + chunk.length);

		});

		// on end of data, use concated buffer as message.
		req.on('end', function () {

			if ( req.method === 'GET' ) {
				// form the message from the query and headers.
				var mObj = {};
				mObj.query = query;
				mObj.client_ip = client_ip;
				mObj.client_port = req.connection.remotePort;
				mObj.pathname = url_parts.pathname;
				mObj.language = req.headers['accept-language'];
				mObj.user_agent = req.headers['user-agent'];
				mObj.referer = req.headers.referer;
				mObj.cookie = req.headers.cookie;
				//console.log(processID+'@inputs> GET req.headers ' + util.inspect(req.headers, true, 99, true));
				var message = new Buffer(JSON.stringify(mObj));
			} else {
				var message = buffer;
				//console.log(processID+'@inputs> Got end(), buffer : ' + buffer.toString());
			}

			buffer = null;		// reset buffer.

			var id = uidNumberBands.make();		// id is object, eg: id.uid etc.

/*
			if ( toobusy != undefined ) {
				if (toobusy()) {
					//console.log('udp@inputs> Im toobusy.');
					// TODO: udp does not expose socket like tcp! how to pause?
					socket.pause();
					setTimeout(function() {
						socket.resume();
						//console.log('udp@inputs> Im not too busy, resume.');
					}, TOOBUSY_PAUSE);
				}
			}
*/

			// route ...
			route(apikey, config['name'], __remoteAddress(req), message, id, mime_type, messenger, streams, function (validHost) {
				if ( validHost === true ) {
					if ( url_parts.pathname.indexOf('.gif') != -1 && req.method === 'GET' ) {
						// return 1 pixel transparent gif.
						res.writeHead(200, {
							'Server': 'Kurunt',
							'Content-Length': '43',
							'Content-Type': 'image/gif',
							'Expiresponse': 'Mon, 26 Jul 2005 05:00:00 GMT',
							'Cache-Control': 'no-store, no-cache, must-revalidate',
							'Pragma': 'no-cache',
							'Connection': 'close'
						});
				    res.end('\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\xf0\x01\x00\xff\xff\xff\x00\x00\x00\x21\xf9\x04\x01\x0a\x00\x00\x00\x2c\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02\x44\x01\x00\x3b', 'binary');
					} else {
						// return json message with id for this message.
						res.writeHead(200, {'Server': 'Kurunt', 'Content-Type': 'application/json; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive'});
						res.write( JSON.stringify({"uid": id.uid}) + '\n' );   // return the message id.
						res.end();
					}
				} else {
					log(processID+'@inputs> No client host access found for ' + __remoteAddress(req) + ' on apikey: ' + apikey + ' will ignore client.');
					res.writeHead(403, {'Server': 'Kurunt', 'Content-Type': 'application/json; charset=utf-8', 'Connection': 'closed'});
					res.write( JSON.stringify({"status": "unauthorized request"}) + '\n' );   // return the message id.
					res.end();
					return;
				}
			});

		});

		req.connection.addListener('close', function () {
		  //console.log('http@inputs> Client closed. Last request for: ' + req.url + ' by ip: ' + client_ip);
		});

	} // end onReceive.
	server = http.createServer(onRequest).listen(config['input_port']);
	log(processID+'@inputs> HTTP (input) Server opened @ http://' + gconfig['host'] + ":" + config['input_port']);
	console.log(processID+'@inputs> streams ' + util.inspect(streams, true, 99, true));
}

function _ipAddress(request) {
	// try request.connection.socket.remoteAddresponses for https, request.socket.remoteAddresponses works for most http but request.connection.remoteAddress seems more reliable.
	var ip = undefined;
	try {
		ip = request.headers['x-forwarded-for'];
		if ( ip === undefined ) {
			ip = __remoteAddress(request);
		}
	} catch ( err ) {
		ip = __remoteAddress(request);
	}
	return ip;
}
function __remoteAddress(request) {
	var ip = undefined;
	ip = request.connection.remoteAddress;
	if ( ip === undefined ) {
		ip = request.socket.remoteAddresponses;
		if (ip === undefined) {
			return false;
		}
	}
	return ip;
}

<|endoftext|>


<commit_before>/* ================================================================================================================
 Start loading added games on page
 =============================================================================================================== */
$(document).ready(function () {
    // show the add button if user is logged in
    if (session.authenticated) {
        $("#addConfirm").css('display',null);
    }
    else {
        $("#addConfirm").css('display',"none");
    }

    loadGames();
});

/* ================================================================================================================
 Local variables
 =============================================================================================================== */
// all the games that user already have (array with game id's)
var alreadyAddedGames = new Array();

// get the id from 1 selected game
var gameId = new Array();

// all the properties from 1 selected game (name, description)
var gameProperties = new Array();

// all errors during add game
var errorArray = new Array();

/* ================================================================================================================
 load all games
 =============================================================================================================== */
var loadGames = function () {
    axios.get("/games").then(function (response) {
        var data = response.data;

        // create html tage with games
        var ul = document.getElementsByClassName('games-list')[0];
        $(ul).empty();

        for (var key in data) {
            if (data.hasOwnProperty(key)) {
                var value = data[key];

                var li = document.createElement("li");
                li.className = "games-list__item";
                li.setAttribute("data-search-term", value.name.toLowerCase());
                li.setAttribute("data-remodal-target", "ShowGameDetailsModal");
                li.setAttribute("onclick", "infoGame(this)");

                var img = document.createElement("img");
                img.className = 'games-list__item--image-small';
                img.setAttribute("src", "img/games/" + value.imageName);
                img.setAttribute("alt", value.id);
                img.setAttribute("title", value.name);

                var p = document.createElement("p");
                p.className = 'games-list__item--text';
                p.innerHTML = value.name;

                var secondP = document.createElement("p");
                secondP.setAttribute("style", "display: none");
                secondP.innerHTML = value.description;

                li.appendChild(img);
                li.appendChild(p);
                li.appendChild(secondP);
                ul.appendChild(li);
            }
        }
    });
}

/******************************************** live search filter *************************************************/
$('#search_box').on('keyup', function () {
    var searchTerm = $(this).val().toLowerCase();

    $('.games-list li').each(function () {
        if ($(this).filter('[data-search-term *= ' + searchTerm + ']').length > 0 || searchTerm.length < 1) {
            $(this).show();
        } else {
            $(this).hide();
        }
    });
});

/* ================================================================================================================
 get already added games from user
 =============================================================================================================== */
axios.get("/users/" + session.id + "/games").then(function (result) {
    var data = result.data;

    for (key in data) {
        if (data.hasOwnProperty(key)) {
            var value = data[key];
            alreadyAddedGames.push(value['game'].id);
        }
    }
})

/* ================================================================================================================
 show info in modal
 =============================================================================================================== */
// give info about the game in the modal
var infoGame = function (e) {
    gameProperties = [];
    gameId = [];
    $("#detailsGames").html("");

    // take game properties out of html
    $(e).children().each(function (i, v) {
        gameProperties[i] = $(this)[0].innerHTML;
    });

    // get id from img alt attribute
    var str = $(e)[0].innerHTML;
    var tmp = document.createElement('div');
    tmp.innerHTML = str;
    gameId[0] = tmp.getElementsByTagName('img')[0].alt;

    // create html tags with info about the game
    var firstH4 = document.createElement("h4");
    firstH4.innerHTML = "Over dit spel";

    var firstP = document.createElement("p");
    firstP.innerHTML = gameId[0];
    firstP.setAttribute('style', 'display: none');

    var secondP = document.createElement("p");
    secondP.innerHTML = gameProperties[2];

    var secondH4 = document.createElement("h4");
    secondH4.innerHTML = "Vrienden";

    var thirdP = document.createElement("p");
    thirdP.innerHTML = "Deze vrienden spelen dit spel ook:";

    var element = document.getElementById('detailsGames');
    element.appendChild(firstH4);
    element.appendChild(firstP);
    element.appendChild(secondP);
    element.appendChild(secondH4);
    element.appendChild(thirdP);

    //get friends who are playing the game
    axios.get("/games/" + gameId[0] + "/users").then(function (response) {
        var data = response.data;

        for (key in data) {
            if (data.hasOwnProperty(key)) {
                var value = data[key];

                var firstImg = document.createElement("img");
                firstImg.setAttribute("src", value["user"].avatar);
                firstImg.setAttribute("alt", "avatar-member");
                firstImg.setAttribute("title", value["user"].username + '\nLevel: ' + value["user"].level);
                firstImg.className += "friendImg";

                element.appendChild(firstImg);
            }
        }
    });
}

/************************************************ add button ****************************************************/
// by click on the add button
$('#addConfirm').click(function () {
    if (gameId.length == 0) {
        errorArray.push("There are no games selected, try again");
    }
    else {
        // check if user is logged in
        if (session.authenticated) {
            // check if user already have the game
            if (!eleContainsInArray(alreadyAddedGames, gameId[0])) {
                //add game to user
                axios.post("/users/" + session.id + "/games", gameId, {
                }).then(function (data) {
                    loadGames();
                });
            }
            else {
                errorArray.push("Game is already added to your profile")
            }
        }
        else {
            errorArray.push("User must login before adding games");
        }

        // show errors on top page
        $('.error-list').empty();
        $(errorArray).each(function(index, value){ $('.error-list').append('

' + value + '

') });
        $('.error-list').slideDown();

        errorArray = [];
    }
});

/* ================================================================================================================
 Help classes
 =============================================================================================================== */
// check if a element already exists in array
var eleContainsInArray = function(array, element) {
    if (array != null && array.length > 0) {
        for (var i = 0; i < array.length; i++) {
            if (array[i] == element) {
                return true;
            }
        }
    }
    return false;
}
<commit_msg>vrienden de dit spel spelen juist zetten<commit_after>/* ================================================================================================================
 Start loading added games on page
 =============================================================================================================== */
$(document).ready(function () {
    // show the add button if user is logged in
    if (session.authenticated) {
        $("#addConfirm").css('display',null);
    }
    else {
        $("#addConfirm").css('display',"none");
    }

    loadGames();
    getFriends();
});

/* ================================================================================================================
 Local variables
 =============================================================================================================== */
// all the games that user already have (array with game id's)
var alreadyAddedGames = new Array();

// get the id from 1 selected game
var gameId = new Array();

// all the properties from 1 selected game (name, description)
var gameProperties = new Array();

// all errors during add game
var errorArray = new Array();

// all friends logged in user
var friends = new Array();

/* ================================================================================================================
   get all friends
 =============================================================================================================== */
var getFriends = function () {
//get friends logged in user
    axios.get("/users/" + session.id + "/friends").then(function (response) {
        var data = response.data;
        for (var key in data) {
            if (data.hasOwnProperty(key)) {
                var value = data[key];
                friends.push(value)
            }
        }
    });
}

/* ================================================================================================================
 load all games
 =============================================================================================================== */
var loadGames = function () {
    axios.get("/games").then(function (response) {
        var data = response.data;

        // create html tage with games
        var ul = document.getElementsByClassName('games-list')[0];
        $(ul).empty();

        for (var key in data) {
            if (data.hasOwnProperty(key)) {
                var value = data[key];

                var li = document.createElement("li");
                li.className = "games-list__item";
                li.setAttribute("data-search-term", value.name.toLowerCase());
                li.setAttribute("data-remodal-target", "ShowGameDetailsModal");
                li.setAttribute("onclick", "infoGame(this)");

                var img = document.createElement("img");
                img.className = 'games-list__item--image-small';
                img.setAttribute("src", "img/games/" + value.imageName);
                img.setAttribute("alt", value.id);
                img.setAttribute("title", value.name);

                var p = document.createElement("p");
                p.className = 'games-list__item--text';
                p.innerHTML = value.name;

                var secondP = document.createElement("p");
                secondP.setAttribute("style", "display: none");
                secondP.innerHTML = value.description;

                li.appendChild(img);
                li.appendChild(p);
                li.appendChild(secondP);
                ul.appendChild(li);
            }
        }
    });
}

/******************************************** live search filter *************************************************/
$('#search_box').on('keyup', function () {
    var searchTerm = $(this).val().toLowerCase();

    $('.games-list li').each(function () {
        if ($(this).filter('[data-search-term *= ' + searchTerm + ']').length > 0 || searchTerm.length < 1) {
            $(this).show();
        } else {
            $(this).hide();
        }
    });
});

/* ================================================================================================================
 get already added games from user
 =============================================================================================================== */
axios.get("/users/" + session.id + "/games").then(function (result) {
    var data = result.data;

    for (key in data) {
        if (data.hasOwnProperty(key)) {
            var value = data[key];
            alreadyAddedGames.push(value['game'].id);
        }
    }
})

/* ================================================================================================================
 show info in modal
 =============================================================================================================== */
// give info about the game in the modal
var infoGame = function (e) {
    gameProperties = [];
    gameId = [];
    $("#detailsGames").html("");
    // take game properties out of html
    $(e).children().each(function (i, v) {
        gameProperties[i] = $(this)[0].innerHTML;
    });

    // get id from img alt attribute
    var str = $(e)[0].innerHTML;
    var tmp = document.createElement('div');
    tmp.innerHTML = str;
    gameId[0] = tmp.getElementsByTagName('img')[0].alt;

    // create html tags with info about the game
    var firstH4 = document.createElement("h4");
    firstH4.innerHTML = "Over dit spel";

    var firstP = document.createElement("p");
    firstP.innerHTML = gameId[0];
    firstP.setAttribute('style', 'display: none');

    var secondP = document.createElement("p");
    secondP.innerHTML = gameProperties[2];

    if (session.authenticated) {
        var secondH4 = document.createElement("h4");
        secondH4.innerHTML = "Vrienden";

        var thirdP = document.createElement("p");
        thirdP.innerHTML = "Deze vrienden spelen dit spel ook:";
    }

    var element = document.getElementById('detailsGames');
    element.appendChild(firstH4);
    element.appendChild(firstP);
    element.appendChild(secondP);
    element.appendChild(secondH4);
    element.appendChild(thirdP);

    //get users who are playing the game
    axios.get("/games/" + gameId[0] + "/users").then(function (response) {
        var data = response.data;

        for(f in friends){
            for (key in data) {
                if (data.hasOwnProperty(key)) {
                    var value = data[key];
                    if(value['user'].id == friends[f].id){
                        var firstImg = document.createElement("img");
                        firstImg.setAttribute("src", value["user"].avatar);
                        firstImg.setAttribute("alt", "avatar-member");
                        firstImg.setAttribute("title", value["user"].username + '\nLevel: ' + value["user"].level);
                        firstImg.className += "friendImg";

                        element.appendChild(firstImg);
                    }
                }
            }
        }
    });
}

/************************************************ add button ****************************************************/
// by click on the add button
$('#addConfirm').click(function () {
    if (gameId.length == 0) {
        errorArray.push("There are no games selected, try again");
    }
    else {
        // check if user is logged in
        if (session.authenticated) {
            // check if user already have the game
            if (!eleContainsInArray(alreadyAddedGames, gameId[0])) {
                //add game to user
                axios.post("/users/" + session.id + "/games", gameId, {
                }).then(function (data) {
                    loadGames();
                });
            }
            else {
                errorArray.push("Game is already added to your profile")
            }
        }
        else {
            errorArray.push("User must login before adding games");
        }

        // show errors on top page
        $('.error-list').empty();
        $(errorArray).each(function(index, value){ $('.error-list').append('

' + value + '

') });
        $('.error-list').slideDown();

        errorArray = [];
    }
});

/* ================================================================================================================
 Help classes
 =============================================================================================================== */
// check if a element already exists in array
var eleContainsInArray = function(array, element) {
    if (array != null && array.length > 0) {
        for (var i = 0; i < array.length; i++) {
            if (array[i] == element) {
                return true;
            }
        }
    }
    return false;
}
<|endoftext|>


<commit_before>"use strict";

//Load dependencies
var async = require("async");
var applicationStorage = process.require("core/applicationStorage.js");
var rankModel = process.require("ranks/rankModel.js");
var realmModel = process.require("realms/realmModel.js");
var guildModel = process.require("guilds/guildModel.js");
var guildProgressModel = process.require("guildProgress/guildProgressModel.js");

module.exports.getRank = function (req, res, next) {

    var logger = applicationStorage.logger;
    logger.info("%s %s %s %s", req.headers['x-forwarded-for'] || req.connection.remoteAddress, req.method, req.path, JSON.stringify(req.params));

    async.parallel({
        world: function (callback) {
            rankModel.getRank(req.params.tier, req.params.region, req.params.realm, req.params.name, function (error, rank) {
                callback(error, rank)
            });
        },
        region: function (callback) {
            rankModel.getRank(req.params.tier + "_" + req.params.region, req.params.region, req.params.realm, req.params.name, function (error, rank) {
                callback(error, rank)
            });
        },
        realm: function (callback) {
            realmModel.findOne({
                region: req.params.region,
                name: req.params.realm
            }, {connected_realms: 1}, function (error, realm) {
                if (realm) {
                    rankModel.getRank(req.params.tier + "_" + req.params.region + "_" + realm.connected_realms.join('_'), req.params.region, req.params.realm, req.params.name, function (error, rank) {
                        callback(error, rank)
                    });
                } else {
                    logger.warn("Realm %s-%s not found", req.params.region, req.params.realm);
                    callback(error);
                }
            });
        }
    }, function (error, result) {
        if (error) {
            logger.error(error.message);
            res.status(500).send(error.message);
        } else if (result.world !== null && result.region != null) {
            result.world++;
            result.region++;
            if (result.realm != null) {
                result.realm++;
            }
            res.json(result);
        } else {
            next();
        }
    });
};

module.exports.getRanking = function (req, res, next) {

    var logger = applicationStorage.logger;
    var config = applicationStorage.config;

    logger.info("%s %s %s %s", req.headers['x-forwarded-for'] || req.connection.remoteAddress, req.method, req.path, JSON.stringify(req.params));

    var start = 0;
    if (req.query && req.query.start) {
        start = parseInt(req.query.start, 10) > 0 ? parseInt(req.query.start, 10) - 1 : 0
    }

    var end = start + 500;
    if (req.query && req.query.limit) {
        var limit = parseInt(req.query.limit, 10);

        if (limit < 0) {
            limit = 50;
        }

        if (limit > 50) {
            limit = 50;
        }

        end = start + limit;
    }

    async.waterfall([
        function (callback) {
            var key = req.params.tier;
            if (req.params.realm && req.params.region) {
                realmModel.findOne({
                    region: req.params.region,
                    name: req.params.realm
                }, {connected_realms: 1}, function (error, realm) {
                    if (realm) {
                        key = req.params.tier + "_" + req.params.region + "_" + realm.connected_realms.join('_');
                        callback(error, key);
                    } else {
                        callback(new Error("Realm %s-%s not found", req.params.region, req.params.realm));
                    }
                });
            } else if (req.params.region) {
                key = req.params.tier + "_" + req.params.region;
                callback(null, key);
            } else {
                callback(null, key);
            }
        },
        function (key, callback) {
            rankModel.getRanking(key, start, end, function (error, ranking) {
                callback(error, ranking);
            });
        }
    ], function (error, ranking) {
        if (error) {
            logger.error(error.message);
            res.status(500).send(error.message);
        } else if (ranking) {
            var finalRanking = {};
            var counter = 1;
            async.forEachSeries(ranking, function (rank, callback) {
                var rankArray = rank.split('-');

                finalRanking[start + counter] = {region: rankArray[0], realm: rankArray[1], name: rankArray[2]};
                async.parallel([
                    function (callback) {
                        //GET GUILD SIDE and add it
                        guildModel.getGuildInfo(rankArray[0], rankArray[1], rankArray[2], function (error, guild) {
                            if (guild && guild.bnet && guild.bnet.side != null) {
                                finalRanking[start + counter]["side"] = guild.bnet.side;
                            }
                            if (guild && guild.ad && guild.ad.lfg == true) {
                                finalRanking[start + counter]["lfg"] = true;
                            }
                            callback(error);
                        });
                    },
                    function (callback) {
                        //GET GUILD Progress and add it
                        var project = {};
                        config.progress.raids.forEach(function (raid) {
                            if (raid.tier == parseInt(req.params.tier, 10)) {
                                var difficulties = ["normal", "heroic", "mythic"];
                                difficulties.forEach(function (difficulty) {
                                    raid.bosses.forEach(function (boss) {
                                        project["progress.tier_" + req.params.tier + "." + difficulty + "." + boss.name] = {$size: "$progress.tier_" + req.params.tier + "." + difficulty + "." + boss.name + ".timestamps"};
                                    });
                                });
                            }
                        });
                        project["progress.tier_" + req.params.tier + ".normalCount"] = 1;
                        project["progress.tier_" + req.params.tier + ".heroicCount"] = 1;
                        project["progress.tier_" + req.params.tier + ".mythicCount"] = 1;

                        guildProgressModel.aggregate({region:rankArray[0],realm:rankArray[1],name:rankArray[2]},project,function(error,result){

                            if (result && result.length > 0&& result[0]['progress'] && result[0]['progress']["tier_" + req.params.tier]) {

                                finalRanking[start + counter]["progress"] = result[0]["progress"]["tier_" + req.params.tier];
                            }
                            callback(error);
                        });

                    }
                ], function (error) {
                    counter++;
                    callback(error);
                })

            }, function () {
                res.json(finalRanking);
            });
        } else {
            next();
        }
    });

};<commit_msg>Return error on Rank api call when an error occur.<commit_after>"use strict";

//Load dependencies
var async = require("async");
var applicationStorage = process.require("core/applicationStorage.js");
var rankModel = process.require("ranks/rankModel.js");
var realmModel = process.require("realms/realmModel.js");
var guildModel = process.require("guilds/guildModel.js");
var guildProgressModel = process.require("guildProgress/guildProgressModel.js");

module.exports.getRank = function (req, res, next) {

    var logger = applicationStorage.logger;
    logger.info("%s %s %s %s", req.headers['x-forwarded-for'] || req.connection.remoteAddress, req.method, req.path, JSON.stringify(req.params));

    async.parallel({
        world: function (callback) {
            rankModel.getRank(req.params.tier, req.params.region, req.params.realm, req.params.name, function (error, rank) {
                callback(error, rank)
            });
        },
        region: function (callback) {
            rankModel.getRank(req.params.tier + "_" + req.params.region, req.params.region, req.params.realm, req.params.name, function (error, rank) {
                callback(error, rank)
            });
        },
        realm: function (callback) {
            realmModel.findOne({
                region: req.params.region,
                name: req.params.realm
            }, {connected_realms: 1}, function (error, realm) {
                if (realm) {
                    rankModel.getRank(req.params.tier + "_" + req.params.region + "_" + realm.connected_realms.join('_'), req.params.region, req.params.realm, req.params.name, function (error, rank) {
                        callback(error, rank)
                    });
                } else {
                    logger.warn("Realm %s-%s not found", req.params.region, req.params.realm);
                    callback(error);
                }
            });
        }
    }, function (error, result) {
        if (error) {
            logger.error(error.message);
            res.status(500).send(error.message);
        } else if (result.world !== null && result.region != null) {
            result.world++;
            result.region++;
            if (result.realm != null) {
                result.realm++;
            }
            res.json(result);
        } else {
            next();
        }
    });
};

module.exports.getRanking = function (req, res, next) {

    var logger = applicationStorage.logger;
    var config = applicationStorage.config;

    logger.info("%s %s %s %s", req.headers['x-forwarded-for'] || req.connection.remoteAddress, req.method, req.path, JSON.stringify(req.params));

    var start = 0;
    if (req.query && req.query.start) {
        start = parseInt(req.query.start, 10) > 0 ? parseInt(req.query.start, 10) - 1 : 0
    }

    var end = start + 500;
    if (req.query && req.query.limit) {
        var limit = parseInt(req.query.limit, 10);

        if (limit < 0) {
            limit = 50;
        }

        if (limit > 50) {
            limit = 50;
        }

        end = start + limit;
    }

    async.waterfall([
        function (callback) {
            var key = req.params.tier;
            if (req.params.realm && req.params.region) {
                realmModel.findOne({
                    region: req.params.region,
                    name: req.params.realm
                }, {connected_realms: 1}, function (error, realm) {
                    if (realm) {
                        key = req.params.tier + "_" + req.params.region + "_" + realm.connected_realms.join('_');
                        callback(error, key);
                    } else {
                        callback(new Error("Realm %s-%s not found", req.params.region, req.params.realm));
                    }
                });
            } else if (req.params.region) {
                key = req.params.tier + "_" + req.params.region;
                callback(null, key);
            } else {
                callback(null, key);
            }
        },
        function (key, callback) {
            rankModel.getRanking(key, start, end, function (error, ranking) {
                callback(error, ranking);
            });
        }
    ], function (error, ranking) {
        if (error) {
            logger.error(error.message);
            res.status(500).send(error.message);
        } else if (ranking) {
            var finalRanking = {};
            var counter = 1;
            async.forEachSeries(ranking, function (rank, callback) {
                var rankArray = rank.split('-');

                finalRanking[start + counter] = {region: rankArray[0], realm: rankArray[1], name: rankArray[2]};
                async.parallel([
                    function (callback) {
                        //GET GUILD SIDE and add it
                        guildModel.getGuildInfo(rankArray[0], rankArray[1], rankArray[2], function (error, guild) {
                            if (guild && guild.bnet && guild.bnet.side != null) {
                                finalRanking[start + counter]["side"] = guild.bnet.side;
                            }
                            if (guild && guild.ad && guild.ad.lfg == true) {
                                finalRanking[start + counter]["lfg"] = true;
                            }
                            callback(error);
                        });
                    },
                    function (callback) {
                        //GET GUILD Progress and add it
                        var project = {};
                        config.progress.raids.forEach(function (raid) {
                            if (raid.tier == parseInt(req.params.tier, 10)) {
                                var difficulties = ["normal", "heroic", "mythic"];
                                difficulties.forEach(function (difficulty) {
                                    raid.bosses.forEach(function (boss) {
                                        project["progress.tier_" + req.params.tier + "." + difficulty + "." + boss.name] = {$size: "$progress.tier_" + req.params.tier + "." + difficulty + "." + boss.name + ".timestamps"};
                                    });
                                });
                            }
                        });
                        project["progress.tier_" + req.params.tier + ".normalCount"] = 1;
                        project["progress.tier_" + req.params.tier + ".heroicCount"] = 1;
                        project["progress.tier_" + req.params.tier + ".mythicCount"] = 1;

                        guildProgressModel.aggregate({region:rankArray[0],realm:rankArray[1],name:rankArray[2]},project,function(error,result){

                            if (result && result.length > 0&& result[0]['progress'] && result[0]['progress']["tier_" + req.params.tier]) {

                                finalRanking[start + counter]["progress"] = result[0]["progress"]["tier_" + req.params.tier];
                            }
                            callback(error);
                        });

                    }
                ], function (error) {
                    counter++;
                    callback(error);
                })

            }, function (error) {
                if (error) {
                    logger.error(error.message);
                    res.status(500).send(error.message)
                } else {
                    res.json(finalRanking);
                }
            });
        } else {
            next();
        }
    });

};<|endoftext|>


<commit_before>/*
 * Copyright 2016 Teppo Kurki <teppo.kurki@iki.fi>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0

 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

var debug = require('debug')('signalk:interfaces:plugins')
var fs = require('fs')
var path = require('path')
var express = require('express')

module.exports = function(app) {

  return {
    start: function() {
      startPlugins(app)

      ensureExists(path.join(__dirname, "../../plugin-config-data"));

      app.use('/plugins/configure', express.static(path.join(__dirname, '/../../plugin-config/public')));

      router = express.Router();

      app.get('/plugins', function(req, res, next) {
        res.json(app.plugins.map((plugin) => {
          var data = null
          try {
            data = getPluginOptions(plugin.id)
          } catch(e) {
            console.log(e.code + " " + e.path)
          }
          return {
            id: plugin.id,
            name: plugin.name,
            description: plugin.description,
            schema: plugin.schema,
            state: plugin.state,
            data: data
          }
        }))
      });
    }
  }
};

function ensureExists(dir) {
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir);
  }
}

function pathForPluginId(id) {
  return path.join(__dirname, "../../plugin-config-data", id + '.json')
}

function savePluginOptions(pluginId, data, callback) {
  const config = JSON.parse(JSON.stringify(data))
  fs.writeFile(pathForPluginId(pluginId), JSON.stringify(data, null, 2), callback);
}

function getPluginOptions(id) {
  try
  {
    const optionsAsString = fs.readFileSync(pathForPluginId(id), 'utf8');
    try {
      return JSON.parse(optionsAsString)
    } catch (e) {
      console.error("Could not parse JSON options:" + optionsAsString);
      return {}
    }
  } catch (e) {
    debug("Could not find options for plugin " + id + ", returning empty options")
    return {}
  }
  return JSON.parse()
}

function startPlugins(app) {
  app.plugins = []
  fs.readdirSync('./node_modules/').filter(name => name != '.bin').forEach(pluginName => {
    var metadata;
    try {
      metadata = require('../../node_modules/' + pluginName + '/package.json')
    } catch (e) {
      console.log(e)
    }
    if (metadata && metadata.keywords && metadata.keywords.includes('signalk-node-server-plugin')) {
      registerPlugin(app, pluginName)
    }
  })
}

function registerPlugin(app, pluginName) {
  debug('Registering plugin ' + pluginName)
  const plugin = require(pluginName)(app)
  const options = getPluginOptions(plugin.id)
  const restart = (newConfiguration) => {
    const pluginOptions = getPluginOptions(plugin.id)
    pluginOptions.configuration = newConfiguration
    savePluginOptions(plugin.id, pluginOptions, (err) => {
      if(err) {
        console.error(err)
      } else {
        plugin.stop()
        plugin.start(newConfiguration, restart)
      }
    })
  }
  if (options && options.enabled) {
    debug('Starting plugin ' + pluginName)
    plugin.start(getPluginOptions(plugin.id).configuration, restart)
  }
  app.plugins.push(plugin)

  var router = express.Router()
  router.get("/", (req, res) => {
    const options = getPluginOptions(plugin.id)
    res.json({
      enabled: options.enabled,
      id: plugin.id,
      name: plugin.name
    })
  })

  router.post("/config", (req, res) => {
    savePluginOptions(plugin.id, req.body, (err) => {
      if(err) {
        console.log(err)
        res.status(500)
        res.send(err)
        return
      }
      res.send("Saved configuration for plugin " + plugin.id)
      plugin.stop()
      const options = getPluginOptions(plugin.id)
      if(options.enabled) {
        plugin.start(options.configuration, restart)
      }
    })
  })

  if(typeof plugin.registerWithRouter != 'undefined') {
    plugin.registerWithRouter(router)
  }
  app.use("/plugins/" + plugin.id, router)
}
<commit_msg>Reformat<commit_after>/*
 * Copyright 2016 Teppo Kurki <teppo.kurki@iki.fi>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0

 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

var debug = require('debug')('signalk:interfaces:plugins')
var fs = require('fs')
var path = require('path')
var express = require('express')

module.exports = function(app) {

  return {
    start: function() {
      startPlugins(app)

      ensureExists(path.join(__dirname, "../../plugin-config-data"));

      app.use('/plugins/configure', express.static(path.join(__dirname, '/../../plugin-config/public')));

      router = express.Router();

      app.get('/plugins', function(req, res, next) {
        res.json(app.plugins.map((plugin) => {
          var data = null
          try {
            data = getPluginOptions(plugin.id)
          } catch(e) {
            console.log(e.code + " " + e.path)
          }
          return {
            id: plugin.id,
            name: plugin.name,
            description: plugin.description,
            schema: plugin.schema,
            state: plugin.state,
            data: data
          }
        }))
      });
    }
  }
};

function ensureExists(dir) {
  if(!fs.existsSync(dir)) {
    fs.mkdirSync(dir);
  }
}

function pathForPluginId(id) {
  return path.join(__dirname, "../../plugin-config-data", id + '.json')
}

function savePluginOptions(pluginId, data, callback) {
  const config = JSON.parse(JSON.stringify(data))
  fs.writeFile(pathForPluginId(pluginId), JSON.stringify(data, null, 2), callback);
}

function getPluginOptions(id) {
  try
  {
    const optionsAsString = fs.readFileSync(pathForPluginId(id), 'utf8');
    try {
      return JSON.parse(optionsAsString)
    } catch (e) {
      console.error("Could not parse JSON options:" + optionsAsString);
      return {}
    }
  } catch (e) {
    debug("Could not find options for plugin " + id + ", returning empty options")
    return {}
  }
  return JSON.parse()
}

function startPlugins(app) {
  app.plugins = []
  fs.readdirSync('./node_modules/').filter(name => name != '.bin').forEach(pluginName => {
    var metadata;
    try {
      metadata = require('../../node_modules/' + pluginName + '/package.json')
    } catch(e) {
      console.log(e)
    }
    if(metadata && metadata.keywords && metadata.keywords.includes('signalk-node-server-plugin')) {
      registerPlugin(app, pluginName)
    }
  })
}

function registerPlugin(app, pluginName) {
  debug('Registering plugin ' + pluginName)
  const plugin = require(pluginName)(app)
  const options = getPluginOptions(plugin.id)
  const restart = (newConfiguration) => {
    const pluginOptions = getPluginOptions(plugin.id)
    pluginOptions.configuration = newConfiguration
    savePluginOptions(plugin.id, pluginOptions, (err) => {
      if(err) {
        console.error(err)
      } else {
        plugin.stop()
        plugin.start(newConfiguration, restart)
      }
    })
  }
  if(options && options.enabled) {
    debug('Starting plugin ' + pluginName)
    plugin.start(getPluginOptions(plugin.id).configuration, restart)
  }
  app.plugins.push(plugin)

  var router = express.Router()
  router.get("/", (req, res) => {
    const options = getPluginOptions(plugin.id)
    res.json({
      enabled: options.enabled,
      id: plugin.id,
      name: plugin.name
    })
  })

  router.post("/config", (req, res) => {
    savePluginOptions(plugin.id, req.body, (err) => {
      if(err) {
        console.log(err)
        res.status(500)
        res.send(err)
        return
      }
      res.send("Saved configuration for plugin " + plugin.id)
      plugin.stop()
      const options = getPluginOptions(plugin.id)
      if(options.enabled) {
        plugin.start(options.configuration, restart)
      }
    })
  })

  if(typeof plugin.registerWithRouter != 'undefined') {
    plugin.registerWithRouter(router)
  }
  app.use("/plugins/" + plugin.id, router)
}
<|endoftext|>


<commit_before>'use strict'
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const path = require('path')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const portfinder = require('portfinder')
const BundleTracker = require('webpack-bundle-tracker')

const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)

const devWebpackConfig = merge(baseWebpackConfig, {
  entry: {
    // the current module/app that the dev server should serve
    aquifers: './src/aquifers/main.js'
  },
  module: {
    rules: utils.styleLoaders({
      sourceMap: config.dev.cssSourceMap,
      extract: true,
      usePostCSS: true
    })
  },
  // cheap-module-eval-source-map is faster for development
  devtool: config.dev.devtool,

  // these devServer options should be customized in /config/index.js
  devServer: {
    clientLogLevel: 'info',
    historyApiFallback: {
      rewrites: [
        { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') }
      ]
    },
    hot: true,
    contentBase: false, // since we use CopyWebpackPlugin.
    compress: true,
    host: HOST || config.dev.host,
    port: PORT || config.dev.port,
    open: config.dev.autoOpenBrowser,
    overlay: config.dev.errorOverlay
      ? { warnings: false, errors: true }
      : false,
    publicPath: config.dev.assetsPublicPath,
    proxy: config.dev.proxyTable,
    quiet: true, // necessary for FriendlyErrorsPlugin
    watchOptions: {
      poll: config.dev.poll
    },
    headers: {
      'Access-Control-Allow-Origin': '*'
    }
  },

  plugins: [
    new webpack.DefinePlugin({
      'process.env': require('../config/dev.env')
    }),
    // extract css into its own file
    new ExtractTextPlugin({
      filename: utils.assetsPath('css/[name].[contenthash].css'),
      // Setting the following option to `false` will not extract CSS from codesplit chunks.
      // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
      // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,
      // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
      allChunks: true
    }),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
    new webpack.NoEmitOnErrorsPlugin(),
    // https://github.com/ampedandwired/html-webpack-plugin
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'index.html',
      inject: true
    }),
    // split vendor js into its own file
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks (module) {
        return module.context && module.context.includes('node_modules')
      }
    }),
    // extract webpack runtime and module manifest to its own file in order to
    // prevent vendor hash from being updated whenever app bundle is updated
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest',
      minChunks: Infinity
    }),
    // This instance extracts shared chunks from code splitted chunks and bundles them
    // in a separate chunk, similar to the vendor chunk
    // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
    new webpack.optimize.CommonsChunkPlugin({
      names: [
        'header',
        'registry',
        'summary',
        'documents',
        'exports',
        'submissions',
        'footer'
      ],
      async: true,
      children: true,
      minChunks: 3
    }),
    // copy custom static assets
    new CopyWebpackPlugin([
      {
        from: path.resolve(__dirname, '../static'),
        to: config.dev.assetsSubDirectory,
        ignore: ['.*']
      }
    ]),
    new BundleTracker({filename: 'webpack-stats.json'})
  ]
})

module.exports = new Promise((resolve, reject) => {
  portfinder.basePort = process.env.PORT || config.dev.port
  portfinder.getPort((err, port) => {
    if (err) {
      reject(err)
    } else {
      // publish the new Port, necessary for e2e tests
      process.env.PORT = port
      // add port to devServer config
      devWebpackConfig.devServer.port = port

      // Add FriendlyErrorsPlugin
      devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
        compilationSuccessInfo: {
          messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`]
        },
        onErrors: config.dev.notifyOnErrors
          ? utils.createNotifierCallback()
          : undefined
      }))

      resolve(devWebpackConfig)
    }
  })
})
<commit_msg>change app loaded by dev server back to submissions<commit_after>'use strict'
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const path = require('path')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const portfinder = require('portfinder')
const BundleTracker = require('webpack-bundle-tracker')

const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)

const devWebpackConfig = merge(baseWebpackConfig, {
  entry: {
    // the current module/app that the dev server should serve
    submissions: './src/submissions/main.js'
  },
  module: {
    rules: utils.styleLoaders({
      sourceMap: config.dev.cssSourceMap,
      extract: true,
      usePostCSS: true
    })
  },
  // cheap-module-eval-source-map is faster for development
  devtool: config.dev.devtool,

  // these devServer options should be customized in /config/index.js
  devServer: {
    clientLogLevel: 'info',
    historyApiFallback: {
      rewrites: [
        { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') }
      ]
    },
    hot: true,
    contentBase: false, // since we use CopyWebpackPlugin.
    compress: true,
    host: HOST || config.dev.host,
    port: PORT || config.dev.port,
    open: config.dev.autoOpenBrowser,
    overlay: config.dev.errorOverlay
      ? { warnings: false, errors: true }
      : false,
    publicPath: config.dev.assetsPublicPath,
    proxy: config.dev.proxyTable,
    quiet: true, // necessary for FriendlyErrorsPlugin
    watchOptions: {
      poll: config.dev.poll
    },
    headers: {
      'Access-Control-Allow-Origin': '*'
    }
  },

  plugins: [
    new webpack.DefinePlugin({
      'process.env': require('../config/dev.env')
    }),
    // extract css into its own file
    new ExtractTextPlugin({
      filename: utils.assetsPath('css/[name].[contenthash].css'),
      // Setting the following option to `false` will not extract CSS from codesplit chunks.
      // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
      // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,
      // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
      allChunks: true
    }),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
    new webpack.NoEmitOnErrorsPlugin(),
    // https://github.com/ampedandwired/html-webpack-plugin
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'index.html',
      inject: true
    }),
    // split vendor js into its own file
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks (module) {
        return module.context && module.context.includes('node_modules')
      }
    }),
    // extract webpack runtime and module manifest to its own file in order to
    // prevent vendor hash from being updated whenever app bundle is updated
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest',
      minChunks: Infinity
    }),
    // This instance extracts shared chunks from code splitted chunks and bundles them
    // in a separate chunk, similar to the vendor chunk
    // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
    new webpack.optimize.CommonsChunkPlugin({
      names: [
        'header',
        'registry',
        'summary',
        'documents',
        'exports',
        'submissions',
        'footer'
      ],
      async: true,
      children: true,
      minChunks: 3
    }),
    // copy custom static assets
    new CopyWebpackPlugin([
      {
        from: path.resolve(__dirname, '../static'),
        to: config.dev.assetsSubDirectory,
        ignore: ['.*']
      }
    ]),
    new BundleTracker({filename: 'webpack-stats.json'})
  ]
})

module.exports = new Promise((resolve, reject) => {
  portfinder.basePort = process.env.PORT || config.dev.port
  portfinder.getPort((err, port) => {
    if (err) {
      reject(err)
    } else {
      // publish the new Port, necessary for e2e tests
      process.env.PORT = port
      // add port to devServer config
      devWebpackConfig.devServer.port = port

      // Add FriendlyErrorsPlugin
      devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
        compilationSuccessInfo: {
          messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`]
        },
        onErrors: config.dev.notifyOnErrors
          ? utils.createNotifierCallback()
          : undefined
      }))

      resolve(devWebpackConfig)
    }
  })
})
<|endoftext|>


<commit_before>/*global browser:false, element:false, by:false */
'use strict';

var _ = require('lodash');

var AppPage = require('../app-page.js').AppPage;

function Reports(){
    AppPage.call(this);
    this.list = element.all(by.repeater('report in reports'));
    this.deleteBtn = element(by.id('delete-reports'));
    this.createBtn = element(by.id('create-report'));
    this.toggle = element(by.model('toggle'));
    this.checkboxes = element.all(by.model('selectedReports[report._id]'));
}
Reports.prototype = _.create(AppPage.prototype);

Reports.prototype.visitPage = function(){
    return browser.get('/');
};

Reports.prototype.selectTemplate = function(reportId){
    element.all(by.id('template-' + reportId)).click();
};

Reports.prototype.createReport = function(reportName, templateReportId){
    this.createBtn.click();
    var createReportBtn = element(by.id('create-report-btn'));
    var reportNameField = element(by.model('report.name'));
    if(templateReportId !== undefined){
        this.selectTemplate(templateReportId);
    }
    reportNameField.clear();
    reportNameField.sendKeys(reportName);
    createReportBtn.click();
};

Reports.prototype.getLastModified = function(report) {
    return report.element(by.css('td[data-last-modified]')).getAttribute('data-last-modified');
};

Reports.prototype.deleteReport = function(reportName){
    var that = this;
    return this.list.map(function(report){
        return {
            name: report.element(by.binding('report.Label')).getText(),
            checkbox: report.element(by.model('selectedReports[report._id]'))
        };
    })
    .then(function(reports){
        return reports.filter(function(report){
            return report.name === reportName;
        })[0];
    })
    .then(function(report){
        report.checkbox.click();
        that.deleteBtn.click();
        return element(by.id('confirm-delete-reports')).click();
    });
};

module.exports = Reports;
<commit_msg>fixed template test.<commit_after>/*global browser:false, element:false, by:false */
'use strict';

var _ = require('lodash');

var AppPage = require('../app-page.js').AppPage;

function Reports(){
    AppPage.call(this);
    this.list = element.all(by.repeater('report in reports'));
    this.deleteBtn = element(by.id('delete-reports'));
    this.createBtn = element(by.id('create-report'));
    this.toggle = element(by.model('toggle'));
    this.checkboxes = element.all(by.model('selectedReports[report._id]'));
}
Reports.prototype = _.create(AppPage.prototype);

Reports.prototype.visitPage = function(){
    return browser.get('/');
};

Reports.prototype.selectTemplate = function(reportId){
    element(by.id('template-' + reportId)).click();
};

Reports.prototype.createReport = function(reportName, templateReportId){
    this.createBtn.click();
    var createReportBtn = element(by.id('create-report-btn'));
    var reportNameField = element(by.model('report.name'));
    if(templateReportId !== undefined){
        this.selectTemplate(templateReportId);
    }
    reportNameField.clear();
    reportNameField.sendKeys(reportName);
    createReportBtn.click();
};

Reports.prototype.getLastModified = function(report) {
    return report.element(by.css('td[data-last-modified]')).getAttribute('data-last-modified');
};

Reports.prototype.deleteReport = function(reportName){
    var that = this;
    return this.list.map(function(report){
        return {
            name: report.element(by.binding('report.Label')).getText(),
            checkbox: report.element(by.model('selectedReports[report._id]'))
        };
    })
    .then(function(reports){
        return reports.filter(function(report){
            return report.name === reportName;
        })[0];
    })
    .then(function(report){
        report.checkbox.click();
        that.deleteBtn.click();
        return element(by.id('confirm-delete-reports')).click();
    });
};

module.exports = Reports;
<|endoftext|>


<commit_before>describe('rating calculator controller', () => {
  describe('add new game', () => {
    var controllerService;
    var sut;
    var scope;
    var mockChessCalculator;

    beforeEach(module('ratingsApp'));

    beforeEach(inject(function($controller, $rootScope) {
      controllerService = $controller;
      scope = $rootScope.$new();
      mockChessCalculator = jasmine.createSpy('ChessGradeCalculator', 'MyMethod');

      sut = controllerService("RatingCalculator2Controller", {
        '$scope': scope,
        'chessGradeCalculator': mockChessCalculator
      });

    }));

    it('should create one game by default with default values', () => {

      expect(scope.games.length).toEqual(1);
      expect(scope.games[0].result).toBe(1);
      expect(scope.games[0].resultText).toBe('Win');
      expect(scope.games[0].id).toEqual(1);

    });

    it('should create new game with default values', () => {

      scope.addNewGame();
      expect(scope.games.length).toEqual(2);
      expect(scope.games[1].result).toBe(1);
      expect(scope.games[1].resultText).toBe('Win');
      expect(scope.games[1].id).toEqual(2);
    });
  });

  describe('remove game', () => {
    var controllerService;
    var sut;
    var scope;
    var mockChessCalculator;

    beforeEach(module('ratingsApp'));

    beforeEach(inject(function($controller, $rootScope) {
      controllerService = $controller;
      scope = $rootScope.$new();
      mockChessCalculator = jasmine.createSpy('ChessGradeCalculator', 'MyMethod');

      sut = controllerService("RatingCalculator2Controller", {
        '$scope': scope,
        'chessGradeCalculator': mockChessCalculator
      });

    }));

    it('should remove selected game', () => {
      scope.addNewGame();
      scope.addNewGame();

      expect(scope.games.length).toEqual(3);

      scope.removeChoice(2);

      expect(scope.games.length).toEqual(2);

    });
  });

  describe('calculate', () => {
    var controllerService;
    var sut;
    var scope;
    var mockChessCalculator;

    beforeEach(module('ratingsApp'));

    beforeEach(inject(function($controller, $rootScope) {
      controllerService = $controller;
      scope = $rootScope.$new();
      mockChessCalculator = jasmine.createSpy('ChessGradeCalculator', 'MyMethod');

      sut = controllerService("RatingCalculator2Controller", {
        '$scope': scope,
        'chessGradeCalculator': mockChessCalculator
      });

    }));

    it('should call calculator', () => {

    });
  });
});
<commit_msg>added tests for default stat on controller<commit_after>describe('rating calculator controller', () => {
  var controllerService;
  var sut;
  var scope;
  var mockChessCalculator;

  beforeEach(module('ratingsApp'));

  beforeEach(inject(function($controller, $rootScope) {
    controllerService = $controller;
    scope = $rootScope.$new();
    mockChessCalculator = jasmine.createSpy('ChessGradeCalculator', 'MyMethod');

    sut = controllerService("RatingCalculator2Controller", {
      '$scope': scope,
      'chessGradeCalculator': mockChessCalculator
    });

  }));

  it('creates statistics', ()=>{

    expect(scope.scoreCard.playerStats[0].name).toEqual(new PlaceholderStat("Performance").name);
    expect(scope.scoreCard.playerStats[0].value).toEqual("N/A");

    expect(scope.scoreCard.playerStats[1].name).toEqual(new BestWin().name);
    expect(scope.scoreCard.playerStats[1].value).toEqual("N/A");

    expect(scope.scoreCard.playerStats[2].name).toEqual(new WinningStreak().name);
    expect(scope.scoreCard.playerStats[2].value).toEqual("N/A");

    expect(scope.scoreCard.playerStats[3].name).toEqual(new AverageOpponentGrade().name);
    expect(scope.scoreCard.playerStats[3].value).toEqual("N/A");

  });

  describe('add new game', () => {

    it('should create one game by default with default values', () => {

      expect(scope.games.length).toEqual(1);
      expect(scope.games[0].result).toBe(1);
      expect(scope.games[0].resultText).toBe('Win');
      expect(scope.games[0].id).toEqual(1);

    });

    it('should create new game with default values', () => {

      scope.addNewGame();
      expect(scope.games.length).toEqual(2);
      expect(scope.games[1].result).toBe(1);
      expect(scope.games[1].resultText).toBe('Win');
      expect(scope.games[1].id).toEqual(2);
    });
  });

  describe('remove game', () => {

    it('should remove selected game', () => {
      scope.addNewGame();
      scope.addNewGame();

      expect(scope.games.length).toEqual(3);

      scope.removeChoice(2);

      expect(scope.games.length).toEqual(2);

    });
  });

  describe('calculate', () => {

    it('should call calculator', () => {

    });
  });
});
<|endoftext|>