<commit_before>const os = require('os')
const path = require('path')
const fs = require('fs-extra')
const resolveFrom = require('resolve-from')
const cac = require('cac')
const chalk = require('chalk')
const merge = require('lodash.merge')
const logger = require('@poi/logger')
const Hooks = require('./Hooks')
const WebpackUtils = require('./WebpackUtils')
const createConfigLoader = require('./utils/createConfigLoader')
const loadEnvs = require('./utils/loadEnvs')
const parseArgs = require('./utils/parseArgs')
const PoiError = require('./utils/PoiError')
const spinner = require('./utils/spinner')
const validateConfig = require('./utils/validateConfig')
const { normalizePlugins, mergePlugins } = require('./utils/plugins')

module.exports = class PoiCore {
  constructor(
    rawArgs = process.argv,
    {
      defaultConfigFiles = [
        'poi.config.js',
        'package.json',
        '.poirc',
        '.poirc.json',
        '.poirc.js'
      ],
      extendConfigLoader,
      config: externalConfig
    } = {}
  ) {
    this.rawArgs = rawArgs
    this.logger = logger
    this.spinner = spinner
    this.PoiError = PoiError
    // For plugins, it's only used in plugin.cli export
    this.args = parseArgs(rawArgs)
    this.hooks = new Hooks()
    this.testRunners = new Map()

    if (this.args.has('debug')) {
      logger.setOptions({ debug: true })
    }

    this.mode = this.args.get('mode')
    if (!this.mode) {
      this.mode = 'development'
    }

    if (this.args.has('prod') || this.args.has('production')) {
      this.mode = 'production'
    }

    if (this.args.has('test')) {
      this.mode = 'test'
    }

    if (this.args.args[0] && /^test(:|$)/.test(this.args.args[0])) {
      this.mode = 'test'
    }

    logger.debug(`Running in ${this.mode} mode`)

    this.cwd = this.args.get('cwd')
    if (!this.cwd) {
      this.cwd = process.cwd()
    }

    this.configLoader = createConfigLoader(this.cwd)

    // For other tools that use Poi under the hood
    if (extendConfigLoader) {
      extendConfigLoader(this.configLoader)
    }

    // Load .env files
    loadEnvs(this.mode, this.resolveCwd('.env'))

    if (!process.env.NODE_ENV) {
      process.env.NODE_ENV = this.mode
    }

    this.webpackUtils = new WebpackUtils(this)

    // Try to load config file
    if (externalConfig || this.args.get('config') === false) {
      logger.debug('Poi config file was disabled')
      this.config = externalConfig || {}
    } else {
      const configFiles =
        typeof this.args.get('config') === 'string'
          ? [this.args.get('config')]
          : defaultConfigFiles
      const { path: configPath, data: configFn } = this.configLoader.load({
        files: configFiles,
        packageKey: 'poi'
      })
      if (configPath) {
        logger.debug(`Using Poi config file:`, configPath)
      } else {
        logger.debug(`Not using any Poi config file`)
      }
      this.configPath = configPath
      this.config =
        typeof configFn === 'function' ? configFn(this.args.options) : configFn
      this.config = this.config || {}
    }

    this.pkg = this.configLoader.load({
      files: ['package.json']
    })
    this.pkg.data = this.pkg.data || {}

    // Initialize plugins
    this.initPlugins()
    // Init CLI instance, call plugin.cli, parse CLI args
    this.initCLI()
    // Merge cli config with config file
    this.mergeConfig()
    // Call plugin.apply
    this.applyPlugins()
    this.hooks.invoke('createConfig', this.config)
  }

  get isProd() {
    return this.mode === 'production'
  }

  initCLI() {
    const cli = (this.cli = cac())
    this.command = cli
      .command('[...entries]', 'Entry files to start bundling', {
        ignoreOptionDefaultValue: true
      })
      .usage('[...entries] [options]')
      .action(async () => {
        logger.debug(`Using default handler`)
        const chain = this.createWebpackChain()
        const compiler = this.createWebpackCompiler(chain.toConfig())
        await this.runCompiler(compiler)
      })

    this.extendCLI()

    // Global options
    cli
      .option('--mode <mode>', 'Set mode', 'development')
      .option('--prod, --production', 'Alias for --mode production')
      .option('--test', 'Alias for --mode test')
      .option('--no-config', 'Disable config file')
      .option('--config <path>', 'Set the path to config file')
      .option(
        '--plugin, --plugins <plugin>',
        'Add a plugin (can be used for multiple times)'
      )
      .option('--debug', 'Show debug logs')
      .option('--inspect-webpack', 'Inspect webpack config in your editor')
      .version(require('../package').version)
      .help(sections => {
        for (const section of sections) {
          if (section.title && section.title.includes('For more info')) {
            const body = section.body.split('\n')
            body.shift()
            body.unshift(
              `  $ ${cli.name} --help`,
              `  $ ${cli.name} --serve --help`,
              `  $ ${cli.name} --prod --help`
            )
            section.body = body.join('\n')
          }
        }
      })

    this.cli.parse(this.rawArgs, { run: false })

    logger.debug('Command args', this.cli.args)
    logger.debug('Command options', this.cli.options)
  }

  hasDependency(name) {
    return [
      ...Object.keys(this.pkg.data.dependencies || {}),
      ...Object.keys(this.pkg.data.devDependencies || {})
    ].includes(name)
  }

  /**
   * @private
   * @returns {void}
   */
  initPlugins() {
    const cwd = this.resolveCwd()
    const cliPlugins = normalizePlugins(
      this.args.get('plugin') || this.args.get('plugins'),
      cwd
    )
    const configPlugins = normalizePlugins(this.config.plugins, cwd)

    this.plugins = [
      { resolve: require.resolve('./plugins/command-options') },
      { resolve: require.resolve('./plugins/config-babel') },
      { resolve: require.resolve('./plugins/config-vue') },
      { resolve: require.resolve('./plugins/config-css') },
      { resolve: require.resolve('./plugins/config-font') },
      { resolve: require.resolve('./plugins/config-image') },
      { resolve: require.resolve('./plugins/config-eval') },
      { resolve: require.resolve('./plugins/config-html') },
      { resolve: require.resolve('./plugins/config-electron') },
      { resolve: require.resolve('./plugins/config-misc-loaders') },
      { resolve: require.resolve('./plugins/config-reason') },
      { resolve: require.resolve('./plugins/config-yarn-pnp') },
      { resolve: require.resolve('./plugins/watch') },
      { resolve: require.resolve('./plugins/serve') },
      { resolve: require.resolve('./plugins/eject-html') },
      { resolve: require.resolve('@poi/plugin-html-entry') }
    ]
      .concat(mergePlugins(configPlugins, cliPlugins))
      .map(plugin => {
        if (typeof plugin.resolve === 'string') {
          plugin._resolve = plugin.resolve
          plugin.resolve = require(plugin.resolve)
        }
        return plugin
      })
  }

  extendCLI() {
    for (const plugin of this.plugins) {
      if (plugin.resolve.cli) {
        plugin.resolve.cli(this, plugin.options)
      }
    }
  }

  /**
   * @private
   * @returns {void}
   */
  applyPlugins() {
    let plugins = this.plugins.filter(plugin => {
      return !plugin.resolve.when || plugin.resolve.when(this)
    })

    // Run plugin's `filterPlugins` method
    for (const plugin of plugins) {
      if (plugin.resolve.filterPlugins) {
        plugins = plugin.resolve.filterPlugins(this.plugins, plugin.options)
      }
    }

    // Run plugin's `apply` method
    for (const plugin of plugins) {
      if (plugin.resolve.apply) {
        logger.debug(`Apply plugin: \`${chalk.bold(plugin.resolve.name)}\``)
        if (plugin._resolve) {
          logger.debug(`location: ${plugin._resolve}`)
        }
        plugin.resolve.apply(this, plugin.options)
      }
    }
  }

  hasPlugin(name) {
    return (
      this.plugins &&
      this.plugins.find(plugin => {
        return plugin.resolve.name === name
      })
    )
  }

  mergeConfig() {
    const cliConfig = this.createConfigFromCLIOptions()
    logger.debug(`Config from command options`, cliConfig)

    this.config = validateConfig(this, merge({}, this.config, cliConfig))
  }

  hook(name, fn) {
    this.hooks.add(name, fn)
    return this
  }

  registerTestRunner(name, runner) {
    if (this.testRunners.has(name)) {
      throw new PoiError({
        message: `Test runner "${name}" has already been registered!`
      })
    }
    this.testRunners.set(name, runner)
    return this
  }

  resolveCwd(...args) {
    return path.resolve(this.cwd, ...args)
  }

  resolveOutDir(...args) {
    return this.resolveCwd(this.config.output.dir, ...args)
  }

  async run() {
    await this.hooks.invokePromise('beforeRun')

    await this.cli.runMatchedCommand()

    await this.hooks.invokePromise('afterRun')
  }

  createConfigFromCLIOptions() {
    const {
      minimize,
      sourceMap,
      format,
      moduleName,
      outDir,
      publicUrl,
      target,
      clean,
      parallel,
      cache,
      jsx,
      extractCss,
      hot,
      host,
      port,
      open,
      proxy,
      fileNames,
      html,
      publicFolder
    } = this.cli.options
    return {
      entry: this.cli.args.length > 0 ? this.cli.args : undefined,
      output: {
        minimize,
        sourceMap,
        format,
        moduleName,
        dir: outDir,
        publicUrl,
        target,
        clean,
        fileNames,
        html
      },
      parallel,
      cache,
      publicFolder,
      babel: {
        jsx
      },
      css: {
        extract: extractCss
      },
      devServer: {
        hot,
        host,
        port,
        open,
        proxy
      }
    }
  }

  createWebpackChain(opts) {
    const WebpackChain = require('./utils/WebpackChain')

    opts = Object.assign({ type: 'client', mode: this.mode }, opts)

    const config = new WebpackChain({
      configureWebpack: this.config.configureWebpack,
      opts
    })

    require('./webpack/webpack.config')(config, this)

    this.hooks.invoke('createWebpackChain', config, opts)

    if (this.config.chainWebpack) {
      this.config.chainWebpack(config, opts)
    }

    if (this.cli.options.inspectWebpack) {
      const inspect = () => {
        const id = Math.random()
          .toString(36)
          .substring(7)
        const outFile = path.join(
          os.tmpdir(),
          `poi-inspect-webpack-config-${id}.js`
        )
        const configString = `// ${JSON.stringify(
          opts
        )}\nvar config = ${config.toString()}\n\n`
        fs.writeFileSync(outFile, configString, 'utf8')
        require('@poi/dev-utils/open')(outFile, {
          wait: false
        })
      }

      config.plugin('inspect-webpack').use(
        class InspectWebpack {
          apply(compiler) {
            compiler.hooks.afterEnvironment.tap('inspect-webpack', inspect)
          }
        }
      )
    }

    return config
  }

  runCompiler(compiler, watch) {
    return new Promise((resolve, reject) => {
      if (watch) {
        compiler.watch({}, err => {
          if (err) return reject(err)
          resolve()
        })
      } else {
        compiler.run((err, stats) => {
          if (err) return reject(err)
          resolve(stats)
        })
      }
    })
  }

  createWebpackCompiler(config) {
    const compiler = require('webpack')(config)

    // Override the .watch method so we can handle error here instead of letting WDM handle it
    // And in fact we disabled WDM logger so errors will never show displayed there
    const originalWatch = compiler.watch.bind(compiler)
    compiler.watch = (options, cb) => {
      return originalWatch(options, (err, stats) => {
        if (err) {
          throw err
        }
        cb(null, stats)
      })
    }

    return compiler
  }

  getCacheConfig(dir, keys, files) {
    let content = ''
    if (files) {
      const file = this.configLoader.resolve({ files: [].concat(files) })
      if (file) {
        content = fs.readFileSync(file, 'utf8')
      }
    }

    return {
      cacheDirectory: this.resolveCwd('node_modules/.cache', dir),
      cacheIdentifier: `${JSON.stringify(keys)}::${content}`
    }
  }

  localResolve(name, cwd = this.cwd) {
    return resolveFrom.silent(cwd, name)
  }

  localRequire(name, cwd) {
    const resolved = this.localResolve(name, cwd)
    return resolved ? require(resolved) : null
  }
}
<commit_msg>fix: plugins should be resolved from config dir<commit_after>const os = require('os')
const path = require('path')
const fs = require('fs-extra')
const resolveFrom = require('resolve-from')
const cac = require('cac')
const chalk = require('chalk')
const merge = require('lodash.merge')
const logger = require('@poi/logger')
const Hooks = require('./Hooks')
const WebpackUtils = require('./WebpackUtils')
const createConfigLoader = require('./utils/createConfigLoader')
const loadEnvs = require('./utils/loadEnvs')
const parseArgs = require('./utils/parseArgs')
const PoiError = require('./utils/PoiError')
const spinner = require('./utils/spinner')
const validateConfig = require('./utils/validateConfig')
const { normalizePlugins, mergePlugins } = require('./utils/plugins')

module.exports = class PoiCore {
  constructor(
    rawArgs = process.argv,
    {
      defaultConfigFiles = [
        'poi.config.js',
        'package.json',
        '.poirc',
        '.poirc.json',
        '.poirc.js'
      ],
      extendConfigLoader,
      config: externalConfig
    } = {}
  ) {
    this.rawArgs = rawArgs
    this.logger = logger
    this.spinner = spinner
    this.PoiError = PoiError
    // For plugins, it's only used in plugin.cli export
    this.args = parseArgs(rawArgs)
    this.hooks = new Hooks()
    this.testRunners = new Map()

    if (this.args.has('debug')) {
      logger.setOptions({ debug: true })
    }

    this.mode = this.args.get('mode')
    if (!this.mode) {
      this.mode = 'development'
    }

    if (this.args.has('prod') || this.args.has('production')) {
      this.mode = 'production'
    }

    if (this.args.has('test')) {
      this.mode = 'test'
    }

    if (this.args.args[0] && /^test(:|$)/.test(this.args.args[0])) {
      this.mode = 'test'
    }

    logger.debug(`Running in ${this.mode} mode`)

    this.cwd = this.args.get('cwd')
    if (!this.cwd) {
      this.cwd = process.cwd()
    }

    this.configLoader = createConfigLoader(this.cwd)

    // For other tools that use Poi under the hood
    if (extendConfigLoader) {
      extendConfigLoader(this.configLoader)
    }

    // Load .env files
    loadEnvs(this.mode, this.resolveCwd('.env'))

    if (!process.env.NODE_ENV) {
      process.env.NODE_ENV = this.mode
    }

    this.webpackUtils = new WebpackUtils(this)

    // Try to load config file
    if (externalConfig || this.args.get('config') === false) {
      logger.debug('Poi config file was disabled')
      this.config = externalConfig || {}
    } else {
      const configFiles =
        typeof this.args.get('config') === 'string'
          ? [this.args.get('config')]
          : defaultConfigFiles
      const { path: configPath, data: configFn } = this.configLoader.load({
        files: configFiles,
        packageKey: 'poi'
      })
      if (configPath) {
        logger.debug(`Using Poi config file:`, configPath)
      } else {
        logger.debug(`Not using any Poi config file`)
      }
      this.configPath = configPath
      this.config =
        typeof configFn === 'function' ? configFn(this.args.options) : configFn
      this.config = this.config || {}
    }

    this.pkg = this.configLoader.load({
      files: ['package.json']
    })
    this.pkg.data = this.pkg.data || {}

    // Initialize plugins
    this.initPlugins()
    // Init CLI instance, call plugin.cli, parse CLI args
    this.initCLI()
    // Merge cli config with config file
    this.mergeConfig()
    // Call plugin.apply
    this.applyPlugins()
    this.hooks.invoke('createConfig', this.config)
  }

  get isProd() {
    return this.mode === 'production'
  }

  initCLI() {
    const cli = (this.cli = cac())
    this.command = cli
      .command('[...entries]', 'Entry files to start bundling', {
        ignoreOptionDefaultValue: true
      })
      .usage('[...entries] [options]')
      .action(async () => {
        logger.debug(`Using default handler`)
        const chain = this.createWebpackChain()
        const compiler = this.createWebpackCompiler(chain.toConfig())
        await this.runCompiler(compiler)
      })

    this.extendCLI()

    // Global options
    cli
      .option('--mode <mode>', 'Set mode', 'development')
      .option('--prod, --production', 'Alias for --mode production')
      .option('--test', 'Alias for --mode test')
      .option('--no-config', 'Disable config file')
      .option('--config <path>', 'Set the path to config file')
      .option(
        '--plugin, --plugins <plugin>',
        'Add a plugin (can be used for multiple times)'
      )
      .option('--debug', 'Show debug logs')
      .option('--inspect-webpack', 'Inspect webpack config in your editor')
      .version(require('../package').version)
      .help(sections => {
        for (const section of sections) {
          if (section.title && section.title.includes('For more info')) {
            const body = section.body.split('\n')
            body.shift()
            body.unshift(
              `  $ ${cli.name} --help`,
              `  $ ${cli.name} --serve --help`,
              `  $ ${cli.name} --prod --help`
            )
            section.body = body.join('\n')
          }
        }
      })

    this.cli.parse(this.rawArgs, { run: false })

    logger.debug('Command args', this.cli.args)
    logger.debug('Command options', this.cli.options)
  }

  hasDependency(name) {
    return [
      ...Object.keys(this.pkg.data.dependencies || {}),
      ...Object.keys(this.pkg.data.devDependencies || {})
    ].includes(name)
  }

  /**
   * @private
   * @returns {void}
   */
  initPlugins() {
    const cwd = this.configPath
      ? path.dirname(this.configPath)
      : this.resolveCwd()
    const cliPlugins = normalizePlugins(
      this.args.get('plugin') || this.args.get('plugins'),
      cwd
    )
    const configPlugins = normalizePlugins(this.config.plugins, cwd)

    this.plugins = [
      { resolve: require.resolve('./plugins/command-options') },
      { resolve: require.resolve('./plugins/config-babel') },
      { resolve: require.resolve('./plugins/config-vue') },
      { resolve: require.resolve('./plugins/config-css') },
      { resolve: require.resolve('./plugins/config-font') },
      { resolve: require.resolve('./plugins/config-image') },
      { resolve: require.resolve('./plugins/config-eval') },
      { resolve: require.resolve('./plugins/config-html') },
      { resolve: require.resolve('./plugins/config-electron') },
      { resolve: require.resolve('./plugins/config-misc-loaders') },
      { resolve: require.resolve('./plugins/config-reason') },
      { resolve: require.resolve('./plugins/config-yarn-pnp') },
      { resolve: require.resolve('./plugins/watch') },
      { resolve: require.resolve('./plugins/serve') },
      { resolve: require.resolve('./plugins/eject-html') },
      { resolve: require.resolve('@poi/plugin-html-entry') }
    ]
      .concat(mergePlugins(configPlugins, cliPlugins))
      .map(plugin => {
        if (typeof plugin.resolve === 'string') {
          plugin._resolve = plugin.resolve
          plugin.resolve = require(plugin.resolve)
        }
        return plugin
      })
  }

  extendCLI() {
    for (const plugin of this.plugins) {
      if (plugin.resolve.cli) {
        plugin.resolve.cli(this, plugin.options)
      }
    }
  }

  /**
   * @private
   * @returns {void}
   */
  applyPlugins() {
    let plugins = this.plugins.filter(plugin => {
      return !plugin.resolve.when || plugin.resolve.when(this)
    })

    // Run plugin's `filterPlugins` method
    for (const plugin of plugins) {
      if (plugin.resolve.filterPlugins) {
        plugins = plugin.resolve.filterPlugins(this.plugins, plugin.options)
      }
    }

    // Run plugin's `apply` method
    for (const plugin of plugins) {
      if (plugin.resolve.apply) {
        logger.debug(`Apply plugin: \`${chalk.bold(plugin.resolve.name)}\``)
        if (plugin._resolve) {
          logger.debug(`location: ${plugin._resolve}`)
        }
        plugin.resolve.apply(this, plugin.options)
      }
    }
  }

  hasPlugin(name) {
    return (
      this.plugins &&
      this.plugins.find(plugin => {
        return plugin.resolve.name === name
      })
    )
  }

  mergeConfig() {
    const cliConfig = this.createConfigFromCLIOptions()
    logger.debug(`Config from command options`, cliConfig)

    this.config = validateConfig(this, merge({}, this.config, cliConfig))
  }

  hook(name, fn) {
    this.hooks.add(name, fn)
    return this
  }

  registerTestRunner(name, runner) {
    if (this.testRunners.has(name)) {
      throw new PoiError({
        message: `Test runner "${name}" has already been registered!`
      })
    }
    this.testRunners.set(name, runner)
    return this
  }

  resolveCwd(...args) {
    return path.resolve(this.cwd, ...args)
  }

  resolveOutDir(...args) {
    return this.resolveCwd(this.config.output.dir, ...args)
  }

  async run() {
    await this.hooks.invokePromise('beforeRun')

    await this.cli.runMatchedCommand()

    await this.hooks.invokePromise('afterRun')
  }

  createConfigFromCLIOptions() {
    const {
      minimize,
      sourceMap,
      format,
      moduleName,
      outDir,
      publicUrl,
      target,
      clean,
      parallel,
      cache,
      jsx,
      extractCss,
      hot,
      host,
      port,
      open,
      proxy,
      fileNames,
      html,
      publicFolder
    } = this.cli.options
    return {
      entry: this.cli.args.length > 0 ? this.cli.args : undefined,
      output: {
        minimize,
        sourceMap,
        format,
        moduleName,
        dir: outDir,
        publicUrl,
        target,
        clean,
        fileNames,
        html
      },
      parallel,
      cache,
      publicFolder,
      babel: {
        jsx
      },
      css: {
        extract: extractCss
      },
      devServer: {
        hot,
        host,
        port,
        open,
        proxy
      }
    }
  }

  createWebpackChain(opts) {
    const WebpackChain = require('./utils/WebpackChain')

    opts = Object.assign({ type: 'client', mode: this.mode }, opts)

    const config = new WebpackChain({
      configureWebpack: this.config.configureWebpack,
      opts
    })

    require('./webpack/webpack.config')(config, this)

    this.hooks.invoke('createWebpackChain', config, opts)

    if (this.config.chainWebpack) {
      this.config.chainWebpack(config, opts)
    }

    if (this.cli.options.inspectWebpack) {
      const inspect = () => {
        const id = Math.random()
          .toString(36)
          .substring(7)
        const outFile = path.join(
          os.tmpdir(),
          `poi-inspect-webpack-config-${id}.js`
        )
        const configString = `// ${JSON.stringify(
          opts
        )}\nvar config = ${config.toString()}\n\n`
        fs.writeFileSync(outFile, configString, 'utf8')
        require('@poi/dev-utils/open')(outFile, {
          wait: false
        })
      }

      config.plugin('inspect-webpack').use(
        class InspectWebpack {
          apply(compiler) {
            compiler.hooks.afterEnvironment.tap('inspect-webpack', inspect)
          }
        }
      )
    }

    return config
  }

  runCompiler(compiler, watch) {
    return new Promise((resolve, reject) => {
      if (watch) {
        compiler.watch({}, err => {
          if (err) return reject(err)
          resolve()
        })
      } else {
        compiler.run((err, stats) => {
          if (err) return reject(err)
          resolve(stats)
        })
      }
    })
  }

  createWebpackCompiler(config) {
    const compiler = require('webpack')(config)

    // Override the .watch method so we can handle error here instead of letting WDM handle it
    // And in fact we disabled WDM logger so errors will never show displayed there
    const originalWatch = compiler.watch.bind(compiler)
    compiler.watch = (options, cb) => {
      return originalWatch(options, (err, stats) => {
        if (err) {
          throw err
        }
        cb(null, stats)
      })
    }

    return compiler
  }

  getCacheConfig(dir, keys, files) {
    let content = ''
    if (files) {
      const file = this.configLoader.resolve({ files: [].concat(files) })
      if (file) {
        content = fs.readFileSync(file, 'utf8')
      }
    }

    return {
      cacheDirectory: this.resolveCwd('node_modules/.cache', dir),
      cacheIdentifier: `${JSON.stringify(keys)}::${content}`
    }
  }

  localResolve(name, cwd = this.cwd) {
    return resolveFrom.silent(cwd, name)
  }

  localRequire(name, cwd) {
    const resolved = this.localResolve(name, cwd)
    return resolved ? require(resolved) : null
  }
}
<|endoftext|>


<commit_before>import * as ShuffleNetV2_MobileNetV2_Block from "../Layer/ShuffleNetV2_MobileNetV2_Block.js";

export { Base };

/**
 * A neural network composes of multiple blocks.
 *
 * @member {string} name
 *   This neural network's name.
 *
 * @member {number[]} totalChannelExpansionFactor
 *   The final output of this neural network will have ( totalChannelExpansionFactor * sourceChannelCount ) channel count.
 *
 * @member {number[]} sourceImageHeightWidth
 *   The size (i.e. [ height, width ]) of the source image. When apply() is called, the source image will be extracted from the sourceCanvas
 * and be resized to this size. The neural network receives this resized source image.
 */
class Base {

  /**
   * @param {number} depthwiseChannelMultiplierBlock0Step0
   *   The depthwise convolution of the first step (Step 0) of the first block (Block 0) will expand input channel by this factor.
   *
//!!! should use ( strActivationName == "cos" ) and ( bBias == false ) to achieve bias-by-naturally.

   * @param {boolean} bBiasByConstChannel
   *   If true, arrange channel and filter with constant value to achieve bias. This will take more memory (for pre-make filters)
   * but may improve performance (because tf.add() is removed).
   *
   * @param {boolean} bKeepInputTensor
   *   If true, apply_and_destroy_or_keep() will not dispose inputTensor (i.e. keep).
   *
   * @see ShuffleNetV2_MobileNetV2_Block.init
   */
  init(
    sourceHeight, sourceChannelCount,
    stepCountPerBlock,
    bChannelShuffler,
    pointwise1ChannelCountRate,
    strAvgMaxConv, depthwiseFilterHeight, depthwiseChannelMultiplierBlock0Step0, bBias, strActivationName,
    bKeepInputTensor
  ) {

    this.disposeTensors();

    this.sourceChannelCount = sourceChannelCount;
    this.stepCountPerBlock = stepCountPerBlock;
    this.bChannelShuffler = bChannelShuffler;
    this.pointwise1ChannelCountRate = pointwise1ChannelCountRate;
    this.bKeepInputTensor = bKeepInputTensor;

    let targetHeight = 1; // The final output always has ( height x width ) = ( 1 x 1 ), i.e. only one pixel per channel.

    let differenceHeight = sourceHeight - targetHeight;
    let filterWidth = depthwiseFilterHeight;

    this.depthwiseChannelMultiplierBlock0Step0 = depthwiseChannelMultiplierBlock0Step0;
    this.channelCountBlock0 = sourceChannelCount * depthwiseChannelMultiplierBlock0Step0;  // the channel count of the first block (Block 0).

    if ( stepCountPerBlock <= 0 ) { // Not ShuffleNetV2, Not MobileNetV2.

      // The height of processed image will be reduced a little for any depthwise filter larger than 1x1.
      let heightReducedPerBlock = depthwiseFilterHeight - 1;

      // The block count for reducing sourceHeight to targetHeight by tf.depthwiseConv2d( strides = 1, pad = "valid" ).
      this.blockCount = Math.floor( differenceHeight / heightReducedPerBlock );

      // Channel count only be expanded by channel multiplier of depthwise convolution of step 0 of block 0.
      this.totalChannelExpansionFactor = depthwiseChannelMultiplierBlock0Step0;

    } else {  // ShuffleNetV2 or MobileNetV2. Halven per block.

      // The block count for reducing sourceHeight to targetHeight by tf.depthwiseConv2d( strides = 2, pad = "same" ).
//      this.blockCount = Math.floor( Math.log2( sourceHeight ) );
      this.blockCount = Math.ceil( Math.log2( sourceHeight ) );

//!!! wrong
//       // Channel count is expanded both by channel multiplier of depthwise convolution of step 0 of block 0
//       // and by every block (half height x width and double channel count).
//       this.totalChannelExpansionFactor = depthwiseChannelMultiplierBlock0Step0 * Math.pow( 2, this.blockCount );

      // Channel count is expanded by every block (half height x width and double channel count).
      this.totalChannelExpansionFactor = Math.pow( 2, this.blockCount );
    }

    let nextBlockInputChannelCount = sourceChannelCount;
    let nextBlockDepthwiseChannelMultiplier = depthwiseChannelMultiplierBlock0Step0; // Only block 0 can have ( depthwise channel multiplier > 1 ).

    let nextKeepInputTensor = bKeepInputTensor; // Only step 0 may or may not keep the input tensor according to caller's necessary.

    this.blocks = new Array( this.blockCount );
    for ( let i = 0; i < this.blockCount; ++i )
    {
      let block = new ShuffleNetV2_MobileNetV2_Block.Base();
      block.init(
        sourceHeight, nextBlockInputChannelCount,
        stepCountPerBlock,
        bChannelShuffler,
        pointwise1ChannelCountRate,
        strAvgMaxConv, depthwiseFilterHeight, nextBlockDepthwiseChannelMultiplier, bBias, strActivationName,
        nextKeepInputTensor;
      );

      this.blocks[ i ] = block;
      nextBlockInputChannelCount = block.outputChannelCount; // Using previous block's output channel count as next block's input channel count.
      nextBlockDepthwiseChannelMultiplier = 1;               // Except block 0, all other blocks' depthwise channel multiplier should be 1.
      nextKeepInputTensor = false;                           // All blocks (except block 0) should not keep (and should dispose) the input tensor.
    }

    let block0 = this.blocks[ 0 ];

    // e.g. "C24_24__DConv_101x101_DBias_RELU__PConv_PBias_RELU__Block_1__Step_1"
    this.name = `C${sourceChannelCount}_${this.channelCountBlock0}`

      + `${ ( block0.step0.bPointwise1 ) ? "__PConv1(x" + pointwise1ChannelCountRate + ")" : "" }`
      + `${ ( block0.step0.bPointwise1 && block0.step0.bPointwise1Bias ) ? ( "_PBias1" ) : "" }`
      + `${ ( block0.step0.bPointwise1 && block0.step0.pointwise1ActivationFunction ) ? ( "_" + block0.step0.pointwise1ActivationName ) : "" }`

      + `${ ( block0.step0.bDepthwise ) ? `__D${strAvgMaxConv}_${depthwiseFilterHeight}x${depthwiseFilterHeight}` : "" }`
      + `${ ( block0.step0.bDepthwise && block0.step0.bDepthwiseBias ) ? ( "_DBias" ) : "" }`
      + `${ ( block0.step0.bDepthwise && block0.step0.depthwiseActivationFunction ) ? ( "_" + strActivationName ) : "" }`

      + `${ ( block0.step0.bPointwise2 ) ? "__PConv2" : "" }`
      + `${ ( block0.step0.bPointwise2 && block0.step0.bPointwise2Bias ) ? ( "_PBias2" ) : "" }`
      + `${ ( block0.step0.bPointwise2 && block0.step0.pointwise2ActivationFunction ) ? ( "_" + block0.step0.pointwise2ActivationName ) : "" }`

      + `__Block_${this.blockCount}`
      + `__Step_${stepCountPerBlock}`
      + `${ ( bChannelShuffler ) ? "__Shuffle" : ( ( stepCountPerBlock > 0 ) ? "__AddInput" : "" ) }`
      + `${ ( bKeepInputTensor ) ? "__KeepInput" : "" }`
    ;

    this.sourceImageHeightWidth = [ block0.sourceHeight, block0.sourceWidth ];
  }

  disposeTensors() {
    if ( this.blocks ) {
      for ( let i = 0; i < this.blocks.length; ++i ) {
        let block = this.blocks[ i ];
        block.disposeTensors();
      }
      this.blocks = null;
    }
  }

  /**
   *
   * @param {tf.tensor4d} inputTensor
   *   The image which will be processed. This inputTensor may or may not be disposed according to the init()'s bKeepInputTensor.
   *
   * @param {boolean} bReturn
   *   If true, the result tensor will be returned. Otherwise, the result tensor will be disposed.
   *
   * @return {tf.tensor4d}
   *   If ( bReturn == true ), return the result (new) tensor. Otheriwse, the result tensor will be disposed and null will be returned.
   */
  apply_and_destroy_or_keep( inputTensor, bReturn ) {

    let t = inputTensor;

//!!! ...unfinished...
// here should convert sourceImageData to tensor, get typed-array (so that the receiver worker could convert to tensor again without re-construct typed-array),
// transfer it to a web worker. Then, the web worker do the following fromPixels(), ... etc.
//
//     scaledSourceImageTensor.data().then( ( typedArray ) => {
//       let message = [ values: typedArray, shape: scaledSourceImageTensor.shape, dtype: scaledSourceImageTensor ];
//       worker.postMessage( message, [ message.values.data.buffer ] );
//     });

//!!! the following will dispose the scaledSourceImageTensor beffore the above codes get typed-array for another web worker.

    let block;
    for ( let i = 0; i < this.blocks.length; ++i ) {
      block = this.blocks[ i ];
      t = block.apply_and_destroy_or_keep( t );
    }

    if ( bReturn ) {
      return t;
    } else {
      t.dispose();
      return null;
    }
  }

}
<commit_msg>Update NeuralNetwork.js<commit_after>import * as ShuffleNetV2_MobileNetV2_Block from "../Layer/ShuffleNetV2_MobileNetV2_Block.js";

export { Base };

/**
 * A neural network composes of multiple blocks.
 *
 * @member {string} name
 *   This neural network's name.
 *
 * @member {number[]} totalChannelExpansionFactor
 *   The final output of this neural network will have ( totalChannelExpansionFactor * sourceChannelCount ) channel count.
 *
 * @member {number[]} sourceImageHeightWidth
 *   The size (i.e. [ height, width ]) of the source image. When apply() is called, the source image will be extracted from the sourceCanvas
 * and be resized to this size. The neural network receives this resized source image.
 */
class Base {

  /**
   * @param {number} depthwiseChannelMultiplierBlock0Step0
   *   The depthwise convolution of the first step (Step 0) of the first block (Block 0) will expand input channel by this factor.
   *
//!!! should use ( strActivationName == "cos" ) and ( bBias == false ) to achieve bias-by-naturally.

   * @param {boolean} bBiasByConstChannel
   *   If true, arrange channel and filter with constant value to achieve bias. This will take more memory (for pre-make filters)
   * but may improve performance (because tf.add() is removed).
   *
   * @param {boolean} bKeepInputTensor
   *   If true, apply_and_destroy_or_keep() will not dispose inputTensor (i.e. keep).
   *
   * @see ShuffleNetV2_MobileNetV2_Block.init
   */
  init(
    sourceHeight, sourceChannelCount,
    stepCountPerBlock,
    bChannelShuffler,
    pointwise1ChannelCountRate,
    strAvgMaxConv, depthwiseFilterHeight, depthwiseChannelMultiplierBlock0Step0, bBias, strActivationName,
    bKeepInputTensor
  ) {

    this.disposeTensors();

    this.sourceChannelCount = sourceChannelCount;
    this.stepCountPerBlock = stepCountPerBlock;
    this.bChannelShuffler = bChannelShuffler;
    this.pointwise1ChannelCountRate = pointwise1ChannelCountRate;
    this.bKeepInputTensor = bKeepInputTensor;

    let targetHeight = 1; // The final output always has ( height x width ) = ( 1 x 1 ), i.e. only one pixel per channel.

    let differenceHeight = sourceHeight - targetHeight;
    let filterWidth = depthwiseFilterHeight;

    this.depthwiseChannelMultiplierBlock0Step0 = depthwiseChannelMultiplierBlock0Step0;
    this.channelCountBlock0 = sourceChannelCount * depthwiseChannelMultiplierBlock0Step0;  // the channel count of the first block (Block 0).

    if ( stepCountPerBlock <= 0 ) { // Not ShuffleNetV2, Not MobileNetV2.

      // The height of processed image will be reduced a little for any depthwise filter larger than 1x1.
      let heightReducedPerBlock = depthwiseFilterHeight - 1;

      // The block count for reducing sourceHeight to targetHeight by tf.depthwiseConv2d( strides = 1, pad = "valid" ).
      this.blockCount = Math.floor( differenceHeight / heightReducedPerBlock );

      // Channel count only be expanded by channel multiplier of depthwise convolution of step 0 of block 0.
      this.totalChannelExpansionFactor = depthwiseChannelMultiplierBlock0Step0;

    } else {  // ShuffleNetV2 or MobileNetV2. Halven per block.

      // The block count for reducing sourceHeight to targetHeight by tf.depthwiseConv2d( strides = 2, pad = "same" ).
//      this.blockCount = Math.floor( Math.log2( sourceHeight ) );
      this.blockCount = Math.ceil( Math.log2( sourceHeight ) );

//!!! wrong
//       // Channel count is expanded both by channel multiplier of depthwise convolution of step 0 of block 0
//       // and by every block (half height x width and double channel count).
//       this.totalChannelExpansionFactor = depthwiseChannelMultiplierBlock0Step0 * Math.pow( 2, this.blockCount );

      // Channel count is expanded by every block (half height x width and double channel count).
      this.totalChannelExpansionFactor = Math.pow( 2, this.blockCount );
    }

    let nextBlockInputChannelCount = sourceChannelCount;
    let nextBlockDepthwiseChannelMultiplier = depthwiseChannelMultiplierBlock0Step0; // Only block 0 can have ( depthwise channel multiplier > 1 ).

    let nextKeepInputTensor = bKeepInputTensor; // Only step 0 may or may not keep the input tensor according to caller's necessary.

    this.blocks = new Array( this.blockCount );
    for ( let i = 0; i < this.blockCount; ++i )
    {
      let block = new ShuffleNetV2_MobileNetV2_Block.Base();
      block.init(
        sourceHeight, nextBlockInputChannelCount,
        stepCountPerBlock,
        bChannelShuffler,
        pointwise1ChannelCountRate,
        strAvgMaxConv, depthwiseFilterHeight, nextBlockDepthwiseChannelMultiplier, bBias, strActivationName,
        nextKeepInputTensor;
      );

      this.blocks[ i ] = block;
      nextBlockInputChannelCount = block.outputChannelCount; // Using previous block's output channel count as next block's input channel count.
      nextBlockDepthwiseChannelMultiplier = 1;               // Except block 0, all other blocks' depthwise channel multiplier should be 1.
      nextKeepInputTensor = false;                           // All blocks (except block 0) should not keep (and should dispose) the input tensor.
    }

    let block0 = this.blocks[ 0 ];

    // e.g. "C24_24__DConv_101x101_DBias_RELU__PConv_PBias_RELU__Block_1__Step_1"
    this.name = `C${sourceChannelCount}_${this.channelCountBlock0}`

      + `${ ( block0.step0.bPointwise1 ) ? "__PConv1(x" + pointwise1ChannelCountRate + ")" : "" }`
      + `${ ( block0.step0.bPointwise1 && block0.step0.bPointwise1Bias ) ? ( "_PBias1" ) : "" }`
      + `${ ( block0.step0.bPointwise1 && block0.step0.pointwise1ActivationFunction ) ? ( "_" + block0.step0.pointwise1ActivationName ) : "" }`

      + `${ ( block0.step0.bDepthwise ) ? `__D${strAvgMaxConv}_${depthwiseFilterHeight}x${depthwiseFilterHeight}` : "" }`
      + `${ ( block0.step0.bDepthwise && block0.step0.bDepthwiseBias ) ? ( "_DBias" ) : "" }`
      + `${ ( block0.step0.bDepthwise && block0.step0.depthwiseActivationFunction ) ? ( "_" + strActivationName ) : "" }`

      + `${ ( block0.step0.bPointwise2 ) ? "__PConv2" : "" }`
      + `${ ( block0.step0.bPointwise2 && block0.step0.bPointwise2Bias ) ? ( "_PBias2" ) : "" }`
      + `${ ( block0.step0.bPointwise2 && block0.step0.pointwise2ActivationFunction ) ? ( "_" + block0.step0.pointwise2ActivationName ) : "" }`

      + `__Block_${this.blockCount}`
      + `__Step_${stepCountPerBlock}`
      + `${ ( bChannelShuffler ) ? "__Shuffle" : ( ( stepCountPerBlock > 0 ) ? "__AddInput" : "" ) }`
      + `${ ( bKeepInputTensor ) ? "__KeepInput" : "" }`
    ;

    this.sourceImageHeightWidth = [ block0.sourceHeight, block0.sourceWidth ];
  }

  disposeTensors() {
    if ( this.blocks ) {
      for ( let i = 0; i < this.blocks.length; ++i ) {
        let block = this.blocks[ i ];
        block.disposeTensors();
      }
      this.blocks = null;
    }
  }

  /**
   *
   * @param {tf.tensor4d} inputTensor
   *   The image which will be processed. This inputTensor may or may not be disposed according to the init()'s bKeepInputTensor.
   *
   * @param {boolean} bReturn
   *   If true, the result tensor will be returned. Otherwise, the result tensor will be disposed.
   *
   * @return {tf.tensor4d}
   *   If ( bReturn == true ), return the result (new) tensor. Otheriwse, the result tensor will be disposed and null will be returned.
   */
  apply_and_destroy_or_keep( inputTensor, bReturn ) {
    let t = inputTensor;

    let block;
    for ( let i = 0; i < this.blocks.length; ++i ) {
      block = this.blocks[ i ];
      t = block.apply_and_destroy_or_keep( t );
    }

    if ( bReturn ) {
      return t;
    } else {
      t.dispose();
      return null;
    }
  }

}
<|endoftext|>


<commit_before>// @license Copyright (C) 2015 Erik Ringsmuth - MIT license
// @license Copyright (C) 2015 Neovici AB - Apache 2 License
/*global Cosmoz, Polymer, document, window */

(function () {
	"use strict";

	// Try to detect importNode bug https://github.com/Polymer/polymer/issues/2157

	var hasImportNodeBug = false,
		testImportLink,
		testTemplate,
		clonedTemplate,
		currentScript,
		currentDocument;

	currentScript = document._currentScript || document.currentScript;
	currentDocument = currentScript.ownerDocument;
	testImportLink = currentDocument.querySelector('link[rel="import"][href="detect-import-node-bug.html"]');
	testTemplate = testImportLink.import.querySelector('template');
	clonedTemplate = document.importNode(testTemplate, true);
	if (!clonedTemplate.content || clonedTemplate.content.childNodes.length === 0) {
		hasImportNodeBug = true;
	}

	// HACK: this is to keep jslint quiet
	var polymer = Polymer;

	polymer({
		is: 'cosmoz-page-router',

		behaviors: [
			Cosmoz.PageRouterUtilitiesBehavior
		],

		properties: {
			fileSuffix: {
				type: String,
				value: '.html'
			},
			mode: {
				type: String,
				value: 'auto'
			},
			manualInit: {
				type: Boolean,
				value: false
			},
			noAdHoc: {
				type: Boolean,
				value: false
			},
			persist: {
				type: Boolean,
				value: false
			},
			typecast: {
				type: String,
				value: 'auto'
			},
			urlPrefix: {
				type: String,
				value: ''
			}
		},
		_currentRoute: null,
		_importedUris: null,
		_initialized: false,
		_previousRoute: null,
		_previousUrl: null,
		_routesInError: null,

		listeners: {
			'neon-animation-finish': '_onNeonAnimationFinish',
			'template-activate': '_stopEventPropagation',
			'template-created': '_stopEventPropagation',
			'template-ready': '_stopEventPropagation'
		},

		/**
		* Utility function that fires an event from a polymer element and return false if preventDefault has been called on the event.
		*/
		_fireEvent: function (type, detail, node, bubbles) {
			return !this.fire(type, detail, {
				bubbles: !!bubbles,
				cancelable: true,
				node: node || this
			}).defaultPrevented;
		},

		initialize: function () {
			if (this._initialized) {
				return;
			}

			var boundStateChangeHandler = this._stateChange.bind(this);
			window.addEventListener('popstate', boundStateChangeHandler);
			boundStateChangeHandler();
			this._initialized = true;
		},

		ready: function () {
			this._importedUris = {};
			this._routesInError = {};
			if (!this.manualInit) {
				this.async(this.initialize);
			}
		},

		go: function (path, options) {
			if (this.mode !== 'pushstate') {
				// mode == auto, hash or hashbang
				if (this.mode === 'hashbang') {
					path = '#!' + path;
				} else {
					path = '#' + path;
				}
			}
			if (options && options.replace === true) {
				window.history.replaceState(null, null, path);
			} else {
				window.history.pushState(null, null, path);
			}

			// dispatch a popstate event
			this.fire('popstate', {
				state: {}
			}, {
				node: window,
				bubbles: false
			});
		},

		// scroll to the element with id="hash" or name="hash"
		_scrollToHash: function (hash) {
			if (!hash) {
				return;
			}

			// wait for the browser's scrolling to finish before we scroll to the hash
			// ex: http://example.com/#/page1#middle
			// the browser will scroll to an element with id or name `/page1#middle` when the page finishes loading. if it doesn't exist
			// it will scroll to the top of the page. let the browser finish the current event loop and scroll to the top of the page
			// before we scroll to the element with id or name `middle`.
			setTimeout(function () {
				var hashElement = document.querySelector('html /deep/ ' + hash) || document.querySelector('html /deep/ [name="' + hash.substring(1) + '"]');
				if (hashElement && hashElement.scrollIntoView) {
					hashElement.scrollIntoView(true);
				}
			}, 0);
		},

		_stateChange: function () {

			var
				url = this.parseUrl(window.location.href, this.mode),
				eventDetail = {
					path: url.path
				},
				errorEvent,
				route;

		    // don't load a new route if only the hash fragment changed
			if (this._previousUrl &&
					url.hash !== this._previousUrl.hash &&
					url.path === this._previousUrl.path &&
					url.search === this._previousUrl.search &&
					url.isHashPath === this._previousUrl.isHashPath) {
				this._scrollToHash(url.hash);
				this._previousUrl = url;
				return;
			}
			this._previousUrl = url;

			// fire a state-change event on the app-router and return early if the user called event.preventDefault()
			if (!this._fireEvent('state-change', eventDetail)) {
				return;
			}

			if (this._routesInError.hasOwnProperty(url.path)) {
				errorEvent = this._routesInError[url.path];
				this._fireEvent('import-error', errorEvent);
				return;
			}

			// find the first matching route
			route = this.$.routes.firstElementChild;
			while (route) {
				if (route.tagName === 'COSMOZ-PAGE-ROUTE' && this.testRoute(route.path, url.path)) {
					this._activateRoute(route, url);
					return;
				}
				route = route.nextSibling;
			}

			eventDetail.url = url;

			if (this.noAdHoc) {
				this._fireEvent('not-found', eventDetail);
				return;
			}

			this._addAdHocRoute(url.path);
		},

		_addAdHocRoute: function (path) {
			var
				importUri = this.urlPrefix + path + this.fileSuffix,
				templateId = path.substring(1).replace(/\//g, '-');

			this._addRouteForCurrentPathAndActivate(importUri, templateId);
		},

		_addRouteForCurrentPathAndActivate: function (importUri, templateId) {
			var
				url = this.parseUrl(window.location.href, this.mode),
				route = this.addRoute({
					import: importUri,
					path: url.path,
					persist: this.persist,
					templateId: templateId
				});

			this._activateRoute(route, url);
		},

		addRoute: function (route) {
			var element = document.createElement("cosmoz-page-route");
			element.setAttribute('path', route.path);
			if (route.persist) {
				element.setAttribute('persist', '');
			}
			element.setAttribute('template-id', route.templateId);
			element.setAttribute('import', route.import);
			return Polymer.dom(this).appendChild(element);
		},

		_activateRoute: function (route, url) {
			if (route.redirect) {
				this.go(route.redirect, {
					replace: true
				});
				return;
			}

			var eventDetail = {
				path: url.path,
				route: route,
				oldRoute: this._activeRoute
			};

			// keep track of the route currently being loaded
			this._loadingRoute = route;

			// if we're on the same route then update the model but don't replace the page content
			if (route === this._activeRoute || (route.imported && route.persist)) {
				this._updateModelAndActivate(route, url, eventDetail);
			} else if (route.import) {
				// import custom element or template
				this._importAndActivate(route, url, eventDetail);
			}
		},

		_updateModelAndActivate: function (route, url, eventDetail) {
			var model = this._createModel(route, url, eventDetail);

			eventDetail.templateInstance = route.templateInstance;
			this._setObjectProperties(route.templateInstance, model);
			this._fireEvent('template-activate', eventDetail, route.templateInstance, true);
		},

		_importAndActivate: function (route, url, eventDetail) {
			var
				router = this,
				importLink,
				importUri = route.import,
				importLoadedCallback = function (e) {
					importLink.loaded = true;
					route.imported = true;
					router._activateImport(route, url, eventDetail, importLink);
				},
				importErrorCallback = function (e) {
					var	importErrorEvent = {
						route: route,
						errorEvent: e
					};

					importLink.notFound = true;
					router._routesInError[importUri] = importErrorEvent;
					router._fireEvent('import-error', importErrorEvent);
				};

			if (this._importedUris === null) {
				this._importedUris = {};
			}

			if (!this._importedUris.hasOwnProperty(route.import)) {
				importLink = document.createElement('link');
				importLink.setAttribute('rel', 'import');
				importLink.setAttribute('href', importUri);
				importLink.setAttribute('async', 'async');
				importLink.addEventListener('load', importLoadedCallback);
				importLink.addEventListener('error', importErrorCallback);
				importLink.loaded = false;
				document.head.appendChild(importLink);
				this._importedUris[importUri] = importLink;

				this._fireEvent('route-loading', eventDetail);

			} else {
				// previously imported. this is an async operation and may not be complete yet.
				importLink = this._importedUris[importUri];
				if (importLink.notFound) {
					importErrorCallback(null, route);
				} else if (!importLink.loaded) {
					importLink.addEventListener('load', importLoadedCallback);
					importLink.addEventListener('error', importErrorCallback);

					this._fireEvent('route-loading', eventDetail);
				} else {
					this._activateImport(route, url, eventDetail, importLink);
				}
			}
		},

		_activateImport: function (route, url, eventDetail, importLink) {
			var template;
			route.importLink = importLink;
			// make sure the user didn't navigate to a different route while it loaded
			if (route === this._loadingRoute) {
				template = importLink.import.getElementById(route.templateId);
				if (!template) {
					this._fireEvent('template-not-found', eventDetail);
					return;
				}
				this._activateTemplate(route, url, eventDetail, template);
			}
		},

		_instantiateTemplate: function (template) {
			if (hasImportNodeBug) {
				return this._fixedImportNode(template);
			}
			return document.importNode(template, true);
		},

		_fixedImportNode: function (node, doc) {
			var clone;
			doc = doc || document;
			clone = doc.importNode(node, false);

			for (var child = node.firstChild; child; child = child.nextSibling) {
				clone.appendChild(this._fixedImportNode(child));
			}

			if (node.nodeName === 'TEMPLATE') {
				// FIX IE bug
				if (!clone.content) {
					clone.content = doc.createDocumentFragment();
				}
				var cloneContent = clone.content;
				for (var child = node.content.firstChild; child; child = child.nextSibling) {
					// FIX: use template's "inert" ownerDocument for cloning template content
					cloneContent.appendChild(this._fixedImportNode(child, node.ownerDocument));
				}
			}

			return clone;
		},

		_activateTemplate: function (route, url, eventDetail, template) {
			var
				templateInstance = this._instantiateTemplate(template),
				templateId = route.templateId,
				templateViewPrototype,
				model;

			eventDetail.templateInstance = templateInstance;
			route.templateInstance = templateInstance;

			templateViewPrototype = Cosmoz.TemplateView[templateId];
			if (templateViewPrototype) {
				Polymer.Base.mixin(templateInstance, templateViewPrototype);
			}

			this._fireEvent('template-created', eventDetail, route, true);

			model = this._createModel(route, url, eventDetail);

			this._setObjectProperties(eventDetail.templateInstance, model);

			this._fireEvent('template-ready', eventDetail, route, true);

			this._activateTemplateInstance(route, url, eventDetail);
		},

		_activateTemplateInstance: function (route, url, eventDetail) {
			var
				router = this,
				templateInstance = eventDetail.templateInstance;

			templateInstance.addEventListener('dom-change', function (e) {
				router._fireEvent('template-activate', eventDetail, templateInstance, true);
			});

			// Make sure _changeRoute is run for both new and persisted routes
			templateInstance.addEventListener('template-activate', function (e) {
				router._changeRoute();
			});

			// add the new content
			Polymer.dom(this._loadingRoute.root).appendChild(templateInstance);
		},

		_changeRoute: function (oldRoute, newRoute) {

			if (oldRoute === undefined) {
				oldRoute = this._activeRoute;
			}

			if (newRoute === undefined) {
				newRoute = this._loadingRoute;
			}

			// update references to the activeRoute, previousRoute, and loadingRoute
			this._previousRoute = oldRoute;
			this._activeRoute = newRoute;
			this._loadingRoute = null;

			if (oldRoute) {
				oldRoute.active = false;
			}

			newRoute.active = true;

			this.$.routes.selected = newRoute.path;
		},

		// Remove the route's content
		_deactivateRoute: function (route) {
			var node, nodeToRemove;
			if (route && !route.persist) {
				// remove the route content
				node = Polymer.dom(route.root).firstChild;
				while (node) {
					nodeToRemove = node;
					node = Polymer.dom(node).nextSibling;
					Polymer.dom(route.root).removeChild(nodeToRemove);
				}
			}
		},

		_createModel: function (route, url, eventDetail) {
			var
				model = {},
				params = this.routeArguments(
					route.path,
					url.path,
					url.search,
					!!route.regex,
					this.typecast === 'auto'
				);

			model.params = params;

			if (!!route.bindRouter || !!this.bindRouter) {
				model.router = this;
			}

			eventDetail.model = model;
			this._fireEvent('before-data-binding', eventDetail);
			this._fireEvent('before-data-binding', eventDetail, route);
			return eventDetail.model;
		},

		_setObjectProperties: function (object, model) {
			var property;
			for (property in model) {
				if (model.hasOwnProperty(property)) {
					object[property] = model[property];
				}
			}
		},

		_onNeonAnimationFinish: function (event) {
			console.log('_onNeonAnimationFinish');
			if (this._previousRoute && !this._previousRoute.active) {
				this._deactivateRoute(this._previousRoute);
			}
		},

		_stopEventPropagation: function (event) {
			event.stopPropagation();
		}
	});
}());<commit_msg>Fix dynamic dom-bind template importing for Safari<commit_after>// @license Copyright (C) 2015 Erik Ringsmuth - MIT license
// @license Copyright (C) 2015 Neovici AB - Apache 2 License
/*global Cosmoz, Polymer, document, window */

(function () {
	"use strict";

	// Try to detect importNode bug https://github.com/Polymer/polymer/issues/2157

	var hasImportNodeBug = false,
		testImportLink,
		testTemplate,
		clonedTemplate,
		currentScript,
		currentDocument;

	currentScript = document._currentScript || document.currentScript;
	currentDocument = currentScript.ownerDocument;
	testImportLink = currentDocument.querySelector('link[rel="import"][href="detect-import-node-bug.html"]');
	testTemplate = testImportLink.import.querySelector('template');
	clonedTemplate = document.importNode(testTemplate, true);
	if (!clonedTemplate.content || clonedTemplate.content.childNodes.length === 0) {
		hasImportNodeBug = true;
	}

	// HACK: this is to keep jslint quiet
	var polymer = Polymer;

	polymer({
		is: 'cosmoz-page-router',

		behaviors: [
			Cosmoz.PageRouterUtilitiesBehavior
		],

		properties: {
			fileSuffix: {
				type: String,
				value: '.html'
			},
			mode: {
				type: String,
				value: 'auto'
			},
			manualInit: {
				type: Boolean,
				value: false
			},
			noAdHoc: {
				type: Boolean,
				value: false
			},
			persist: {
				type: Boolean,
				value: false
			},
			typecast: {
				type: String,
				value: 'auto'
			},
			urlPrefix: {
				type: String,
				value: ''
			}
		},
		_currentRoute: null,
		_importedUris: null,
		_initialized: false,
		_previousRoute: null,
		_previousUrl: null,
		_routesInError: null,

		listeners: {
			'neon-animation-finish': '_onNeonAnimationFinish',
			'template-activate': '_stopEventPropagation',
			'template-created': '_stopEventPropagation',
			'template-ready': '_stopEventPropagation'
		},

		/**
		* Utility function that fires an event from a polymer element and return false if preventDefault has been called on the event.
		*/
		_fireEvent: function (type, detail, node, bubbles) {
			return !this.fire(type, detail, {
				bubbles: !!bubbles,
				cancelable: true,
				node: node || this
			}).defaultPrevented;
		},

		initialize: function () {
			if (this._initialized) {
				return;
			}

			var boundStateChangeHandler = this._stateChange.bind(this);
			window.addEventListener('popstate', boundStateChangeHandler);
			boundStateChangeHandler();
			this._initialized = true;
		},

		ready: function () {
			this._importedUris = {};
			this._routesInError = {};
			if (!this.manualInit) {
				this.async(this.initialize);
			}
		},

		go: function (path, options) {
			if (this.mode !== 'pushstate') {
				// mode == auto, hash or hashbang
				if (this.mode === 'hashbang') {
					path = '#!' + path;
				} else {
					path = '#' + path;
				}
			}
			if (options && options.replace === true) {
				window.history.replaceState(null, null, path);
			} else {
				window.history.pushState(null, null, path);
			}

			// dispatch a popstate event
			this.fire('popstate', {
				state: {}
			}, {
				node: window,
				bubbles: false
			});
		},

		// scroll to the element with id="hash" or name="hash"
		_scrollToHash: function (hash) {
			if (!hash) {
				return;
			}

			// wait for the browser's scrolling to finish before we scroll to the hash
			// ex: http://example.com/#/page1#middle
			// the browser will scroll to an element with id or name `/page1#middle` when the page finishes loading. if it doesn't exist
			// it will scroll to the top of the page. let the browser finish the current event loop and scroll to the top of the page
			// before we scroll to the element with id or name `middle`.
			setTimeout(function () {
				var hashElement = document.querySelector('html /deep/ ' + hash) || document.querySelector('html /deep/ [name="' + hash.substring(1) + '"]');
				if (hashElement && hashElement.scrollIntoView) {
					hashElement.scrollIntoView(true);
				}
			}, 0);
		},

		_stateChange: function () {

			var
				url = this.parseUrl(window.location.href, this.mode),
				eventDetail = {
					path: url.path
				},
				errorEvent,
				route;

		    // don't load a new route if only the hash fragment changed
			if (this._previousUrl &&
					url.hash !== this._previousUrl.hash &&
					url.path === this._previousUrl.path &&
					url.search === this._previousUrl.search &&
					url.isHashPath === this._previousUrl.isHashPath) {
				this._scrollToHash(url.hash);
				this._previousUrl = url;
				return;
			}
			this._previousUrl = url;

			// fire a state-change event on the app-router and return early if the user called event.preventDefault()
			if (!this._fireEvent('state-change', eventDetail)) {
				return;
			}

			if (this._routesInError.hasOwnProperty(url.path)) {
				errorEvent = this._routesInError[url.path];
				this._fireEvent('import-error', errorEvent);
				return;
			}

			// find the first matching route
			route = this.$.routes.firstElementChild;
			while (route) {
				if (route.tagName === 'COSMOZ-PAGE-ROUTE' && this.testRoute(route.path, url.path)) {
					this._activateRoute(route, url);
					return;
				}
				route = route.nextSibling;
			}

			eventDetail.url = url;

			if (this.noAdHoc) {
				this._fireEvent('not-found', eventDetail);
				return;
			}

			this._addAdHocRoute(url.path);
		},

		_addAdHocRoute: function (path) {
			var
				importUri = this.urlPrefix + path + this.fileSuffix,
				templateId = path.substring(1).replace(/\//g, '-');

			this._addRouteForCurrentPathAndActivate(importUri, templateId);
		},

		_addRouteForCurrentPathAndActivate: function (importUri, templateId) {
			var
				url = this.parseUrl(window.location.href, this.mode),
				route = this.addRoute({
					import: importUri,
					path: url.path,
					persist: this.persist,
					templateId: templateId
				});

			this._activateRoute(route, url);
		},

		addRoute: function (route) {
			var element = document.createElement("cosmoz-page-route");
			element.setAttribute('path', route.path);
			if (route.persist) {
				element.setAttribute('persist', '');
			}
			element.setAttribute('template-id', route.templateId);
			element.setAttribute('import', route.import);
			return Polymer.dom(this).appendChild(element);
		},

		_activateRoute: function (route, url) {
			if (route.redirect) {
				this.go(route.redirect, {
					replace: true
				});
				return;
			}

			var eventDetail = {
				path: url.path,
				route: route,
				oldRoute: this._activeRoute
			};

			// keep track of the route currently being loaded
			this._loadingRoute = route;

			// if we're on the same route then update the model but don't replace the page content
			if (route === this._activeRoute || (route.imported && route.persist)) {
				this._updateModelAndActivate(route, url, eventDetail);
			} else if (route.import) {
				// import custom element or template
				this._importAndActivate(route, url, eventDetail);
			}
		},

		_updateModelAndActivate: function (route, url, eventDetail) {
			var model = this._createModel(route, url, eventDetail);

			eventDetail.templateInstance = route.templateInstance;
			this._setObjectProperties(route.templateInstance, model);
			this._fireEvent('template-activate', eventDetail, route.templateInstance, true);
		},

		_importAndActivate: function (route, url, eventDetail) {
			var
				router = this,
				importLink,
				importUri = route.import,
				importLoadedCallback = function (e) {
					importLink.loaded = true;
					route.imported = true;
					router._activateImport(route, url, eventDetail, importLink);
				},
				importErrorCallback = function (e) {
					var	importErrorEvent = {
						route: route,
						errorEvent: e
					};

					importLink.notFound = true;
					router._routesInError[importUri] = importErrorEvent;
					router._fireEvent('import-error', importErrorEvent);
				};

			if (this._importedUris === null) {
				this._importedUris = {};
			}

			if (!this._importedUris.hasOwnProperty(route.import)) {
				importLink = document.createElement('link');
				importLink.setAttribute('rel', 'import');
				importLink.setAttribute('href', importUri);
				importLink.setAttribute('async', 'async');
				importLink.addEventListener('load', importLoadedCallback);
				importLink.addEventListener('error', importErrorCallback);
				importLink.loaded = false;
				document.head.appendChild(importLink);
				this._importedUris[importUri] = importLink;

				this._fireEvent('route-loading', eventDetail);

			} else {
				// previously imported. this is an async operation and may not be complete yet.
				importLink = this._importedUris[importUri];
				if (importLink.notFound) {
					importErrorCallback(null, route);
				} else if (!importLink.loaded) {
					importLink.addEventListener('load', importLoadedCallback);
					importLink.addEventListener('error', importErrorCallback);

					this._fireEvent('route-loading', eventDetail);
				} else {
					this._activateImport(route, url, eventDetail, importLink);
				}
			}
		},

		_activateImport: function (route, url, eventDetail, importLink) {
			var template;
			route.importLink = importLink;
			// make sure the user didn't navigate to a different route while it loaded
			if (route === this._loadingRoute) {
				template = importLink.import.getElementById(route.templateId);
				if (!template) {
					this._fireEvent('template-not-found', eventDetail);
					return;
				}
				this._activateTemplate(route, url, eventDetail, template);
			}
		},

		_instantiateTemplate: function (template) {
			if (hasImportNodeBug) {
				return this._fixedImportNode(template);
			}
			return document.importNode(template, true);
		},

		_fixedImportNode: function (node, doc) {
			var clone = document.importNode(node, false);
			clone.innerHTML = node.innerHTML;
			return clone;
		},

		_activateTemplate: function (route, url, eventDetail, template) {
			var
				templateInstance = this._instantiateTemplate(template),
				templateId = route.templateId,
				templateViewPrototype,
				model;

			eventDetail.templateInstance = templateInstance;
			route.templateInstance = templateInstance;

			templateViewPrototype = Cosmoz.TemplateView[templateId];
			if (templateViewPrototype) {
				Polymer.Base.mixin(templateInstance, templateViewPrototype);
			}

			this._fireEvent('template-created', eventDetail, route, true);

			model = this._createModel(route, url, eventDetail);

			this._setObjectProperties(eventDetail.templateInstance, model);

			this._fireEvent('template-ready', eventDetail, route, true);

			this._activateTemplateInstance(route, url, eventDetail);
		},

		_activateTemplateInstance: function (route, url, eventDetail) {
			var
				router = this,
				templateInstance = eventDetail.templateInstance;

			templateInstance.addEventListener('dom-change', function (e) {
				router._fireEvent('template-activate', eventDetail, templateInstance, true);
			});

			// Make sure _changeRoute is run for both new and persisted routes
			templateInstance.addEventListener('template-activate', function (e) {
				router._changeRoute();
			});

			// add the new content
			Polymer.dom(this._loadingRoute.root).appendChild(templateInstance);
		},

		_changeRoute: function (oldRoute, newRoute) {

			if (oldRoute === undefined) {
				oldRoute = this._activeRoute;
			}

			if (newRoute === undefined) {
				newRoute = this._loadingRoute;
			}

			// update references to the activeRoute, previousRoute, and loadingRoute
			this._previousRoute = oldRoute;
			this._activeRoute = newRoute;
			this._loadingRoute = null;

			if (oldRoute) {
				oldRoute.active = false;
			}

			newRoute.active = true;

			this.$.routes.selected = newRoute.path;
		},

		// Remove the route's content
		_deactivateRoute: function (route) {
			var node, nodeToRemove;
			if (route && !route.persist) {
				// remove the route content
				node = Polymer.dom(route.root).firstChild;
				while (node) {
					nodeToRemove = node;
					node = Polymer.dom(node).nextSibling;
					Polymer.dom(route.root).removeChild(nodeToRemove);
				}
			}
		},

		_createModel: function (route, url, eventDetail) {
			var
				model = {},
				params = this.routeArguments(
					route.path,
					url.path,
					url.search,
					!!route.regex,
					this.typecast === 'auto'
				);

			model.params = params;

			if (!!route.bindRouter || !!this.bindRouter) {
				model.router = this;
			}

			eventDetail.model = model;
			this._fireEvent('before-data-binding', eventDetail);
			this._fireEvent('before-data-binding', eventDetail, route);
			return eventDetail.model;
		},

		_setObjectProperties: function (object, model) {
			var property;
			for (property in model) {
				if (model.hasOwnProperty(property)) {
					object[property] = model[property];
				}
			}
		},

		_onNeonAnimationFinish: function (event) {
			console.log('_onNeonAnimationFinish');
			if (this._previousRoute && !this._previousRoute.active) {
				this._deactivateRoute(this._previousRoute);
			}
		},

		_stopEventPropagation: function (event) {
			event.stopPropagation();
		}
	});
}());<|endoftext|>


<commit_before>routing.$inject = ['$stateProvider', '$locationProvider', '$urlRouterProvider'];

export default function routing($stateProvider, $locationProvider, $urlRouterProvider) {

  $locationProvider.html5Mode(true);
  $urlRouterProvider.otherwise('/');

  $stateProvider
    .state('Home', {
      url: '/',
      views: {
        'lazyLoadView': {
          templateUrl: './templates/home.ejs'
        }
      }
    })
    .state('oke', {
      url: '/oke',
      views: {
        'lazyLoadView': {
          templateUrl: './templates/oke.ejs'
        }
      }
    });

}
<commit_msg>update untuk config routing<commit_after>routing.$inject = ['$stateProvider', '$locationProvider', '$urlRouterProvider'];

export default function routing($stateProvider, $locationProvider, $urlRouterProvider) {

  $locationProvider.html5Mode(true);
  $urlRouterProvider.otherwise('/');

  $stateProvider
    .state('Home', {
      url: '/',
      views: {
        'lazyLoadView@': {
          template: '<ng-home></ng-home>'
        }
      }
    });

}
<|endoftext|>


<commit_before>'use-scrict';

import View from './view';

/**
* The image view class reprensents the image data and its representation in the
* DOM. The image data is taken from a video DOM object when an analysis request
* is made.
*/
export default class ImageView extends View {
	constructor(domId) {
		super(domId);

		this.domElement = document.getElementById(this.domId);
		this.base64Data = '';
	}

	display() {
		this.domElement.parentNode.style.display = 'block';
	}

	hide() {
		this.domElement.parentNode.style.display = 'none';
	}

	setImage(videoElement) {
		// Could get videoWith or height, but as they are never set we
		// rely on the dom's element dimensions
		var width = videoElement.offsetWidth;
		var height = videoElement.offsetHeight;

		this.domElement.width = width;
		this.domElement.height = height;
		this.domElement.getContext('2d').drawImage(videoElement, 0, 0,
			width, height);

		// By default base64, no conversion needed
		this.base64Data = this.domElement.toDataURL('image/png');
	}

	setOverlay(boundaries) {

		var context = this.domElement.getContext('2d');
		var textBoxHeight = 50;

		boundaries.forEach(function(item){
			var x = item.boundaries[0];
			var width = item.boundaries[1] - x;
			var y = item.boundaries[2];
			var height = item.boundaries[3] - y;

			context.beginPath();
			context.lineWidth="2";
			context.globalAlpha = 0.8;

			switch(item.category) {
				case "recyclable":
				context.strokeStyle="yellow";
				context.fillStyle = "yellow";
				break;
				case "metal":
				context.strokeStyle="blue";
				context.fillStyle = "blue";
				break;
				case "composte":
				context.strokeStyle="red";
				context.fillStyle = "red";
				break;
				default:
				context.strokeStyle="gray";
				context.fillStyle = "gray";
			}
			context.rect(x, y -textBoxHeight, width, textBoxHeight);
			context.fillRect(x, y -textBoxHeight, width, textBoxHeight);

			context.font="20px helvetica";
			context.fillStyle = "#fff";
			context.textAlign="center";
			var capitalizeCat = item.category.charAt(0).toUpperCase() + string.slice(1);
			context.fillText(capitalizeCat, x+width /2, y - textBoxHeight/2);

			context.rect(x,y,width,height);
			context.stroke();
		});

	}

	getData() {
		return this.base64Data;
	}

}
<commit_msg>Forgot to change the second 'string'<commit_after>'use-scrict';

import View from './view';

/**
* The image view class reprensents the image data and its representation in the
* DOM. The image data is taken from a video DOM object when an analysis request
* is made.
*/
export default class ImageView extends View {
	constructor(domId) {
		super(domId);

		this.domElement = document.getElementById(this.domId);
		this.base64Data = '';
	}

	display() {
		this.domElement.parentNode.style.display = 'block';
	}

	hide() {
		this.domElement.parentNode.style.display = 'none';
	}

	setImage(videoElement) {
		// Could get videoWith or height, but as they are never set we
		// rely on the dom's element dimensions
		var width = videoElement.offsetWidth;
		var height = videoElement.offsetHeight;

		this.domElement.width = width;
		this.domElement.height = height;
		this.domElement.getContext('2d').drawImage(videoElement, 0, 0,
			width, height);

		// By default base64, no conversion needed
		this.base64Data = this.domElement.toDataURL('image/png');
	}

	setOverlay(boundaries) {

		var context = this.domElement.getContext('2d');
		var textBoxHeight = 50;

		boundaries.forEach(function(item){
			var x = item.boundaries[0];
			var width = item.boundaries[1] - x;
			var y = item.boundaries[2];
			var height = item.boundaries[3] - y;

			context.beginPath();
			context.lineWidth="2";
			context.globalAlpha = 0.8;

			switch(item.category) {
				case "recyclable":
				context.strokeStyle="yellow";
				context.fillStyle = "yellow";
				break;
				case "metal":
				context.strokeStyle="blue";
				context.fillStyle = "blue";
				break;
				case "composte":
				context.strokeStyle="red";
				context.fillStyle = "red";
				break;
				default:
				context.strokeStyle="gray";
				context.fillStyle = "gray";
			}
			context.rect(x, y -textBoxHeight, width, textBoxHeight);
			context.fillRect(x, y -textBoxHeight, width, textBoxHeight);

			context.font="20px helvetica";
			context.fillStyle = "#fff";
			context.textAlign="center";
			var capitalizeCat = item.category.charAt(0).toUpperCase() + item.category.slice(1);
			context.fillText(capitalizeCat, x+width /2, y - textBoxHeight/2);

			context.rect(x,y,width,height);
			context.stroke();
		});

	}

	getData() {
		return this.base64Data;
	}

}
<|endoftext|>


<commit_before>Intranet.controller('ChatController', ['$scope', '$http', '$paginator', function($scope, $http, $paginator){
	container = $('#conversation');
	messageContainer = $('#write-message');

	$scope.paginator = $paginator;
	$scope.postsPerPage = 10;
	$scope.paginator.postsPerPage = $scope.postsPerPage;

	$scope.$watch('paginator.curPageId', function(){
		var offset = $scope.paginator.postsPerPage*($scope.paginator.curPageId - 1);
		var limit = $scope.paginator.postsPerPage;
		getPosts(offset, limit);
		console.log("curPageId: paginator--->", $scope.paginator);
	});

	$scope.pressEnter = function(e)
	{
		if ((e.shiftKey == false) && ( e.keyCode == 13 ))
		{
			e.preventDefault();
			$scope.sendPost();
		}
	}

	$scope.posts = [];
	$scope.members = [];
	$scope.message = '';
	$scope.editingPost = null;
	$scope.lastDate = null;

	$scope.postsGetURL = JSON_URLS.posts;
	$scope.avatarURL = JSON_URLS.avatar;
	$scope.postAddURL = JSON_URLS.post_add;
	$scope.membersURL = JSON_URLS.members;
	$scope.postsNewURL = JSON_URLS.posts_new;
	$scope.postsCountURL = JSON_URLS.post_count;

	$scope.entityid = window.ENTITY.id;
	$scope.userid = window.USER.id;

	function updatePosts(posts)
	{
		var editedMessages = _.filter(posts, function(p){return p.edited;});
		if (editedMessages.length == posts.length)
		{
			_.map(posts, function(post){
				_.map($scope.posts, function(p, i){
					if (p.id == post.id)
						$scope.posts[i] = post;
				});
			});
			return true;
		}

		return false;
	}

	function getPosts(offset, limit)
	{
		$http({
			method: "GET",
			url: $scope.postsGetURL,
			params: {offset: offset, limit: limit}})
		.success(function(response){
			console.log(response.result);
			if (response.result)
			{
				$scope.posts = response.result.reverse();
			}
			if (response.result.length>0)
			{
				$scope.lastDate = (_.last($scope.posts)).posted.date;
			}
			container.animate({ scrollTop: container.height()+1900 },1000);
		})
	}

	function getPostsCount(callback)
	{
		$http({
			method: "GET",
			url: $scope.postsCountURL,
			})
		.success(function(response){
			console.log("posts count: ", response.result);
			if (response.result)
				callback(response.result);
		})
	}

	function getMembers()
	{
		$http({
			method: "GET",
			url: $scope.membersURL,
			})
		.success(function(response){
			console.log("members: ", response.result);
			if (response.result)
				$scope.members = response.result;
		})
	}

	function getNewPosts()
	{
		if ($scope.paginator.curPageId == 1)
		{
			$http({
				method: "GET",
				url: $scope.postsNewURL,
				params: {last_posted: $scope.lastDate}})
			.success(function(response){
				console.log("new posts: ", response.result);
				if ((response.result) && (response.result.length > 0))
				{
					if (updatePosts(response.result) == false)
						getPostsCount(function(postsCount){
							$scope.paginator.init(postsCount, $scope.postsPerPage);
							var offset = $scope.paginator.postsPerPage*($scope.paginator.curPageId - 1);
							var limit = $scope.paginator.postsPerPage;
							getPosts(offset, limit);
							getMembers();
						});
				}
			})
		}
	}

	$scope.editPost = function(post)
	{
		if ((!$scope.isEditable(post)) || ($scope.editingPost != null)) return;
		console.log(post);
		$scope.editingPost = post;
		messageContainer.val(post.message);
	}

	Date.minutesBetween = function( date1, date2 ) {
		  var one_minute=1000*60;
		  var date1_ms = date1.getTime();
		  var date2_ms = date2.getTime();
		  var difference_ms = date2_ms - date1_ms;

		  return Math.ceil(difference_ms/one_minute);
	}

	Date.milisecondsBetween = function( date1, date2 ) {
		  var date1_ms = date1.getTime();
		  var date2_ms = date2.getTime();
		  var difference_ms = date2_ms - date1_ms;

		  return difference_ms;
	}

	Date.inMyString = function(date)
	{
		return date.getFullYear()+"-"+date.getMonth()+1+"-"+date.getDate()+" "+date.getHours()+":"+date.getMinutes()+":"+date.getSeconds();
	}

	$scope.isEditable = function(post)
	{
		var postedTime = new Date(Date.parse(post.posted.date));
		var now = new Date();
		var utc = new Date(now.getTime() + now.getTimezoneOffset() * 60000);

		var minutesAgo = Date.minutesBetween(postedTime, utc);

		return (minutesAgo <= 5 && post.userid == $scope.userid);
	}

	$scope.sendPost = function()
	{
		var post = {
				entityid: $scope.entityid,
				userid: $scope.userid,
				message: $scope.message,
				posted: new Date()
		}

		if ($scope.editingPost)
			post.postid = $scope.editingPost.id;

		$http({
			method: "POST",
			url: $scope.postAddURL,
			data: post })
		.success(function(response){
			console.log("Created post: ", response.result);
			if (response.result)
			{
				// maybe need to request for posts and init paginator!!!
				if ($scope.editingPost == null)
				{
					$scope.posts.push(response.result);
					container.animate({ scrollTop: container.height()+1900 },1000);
				}
				else
				{
					_.map($scope.posts, function(p, i){
						if (p.id == response.result.id)
							$scope.posts[i] = response.result;
					});
				}
			}

			$scope.editingPost = null;
			$scope.message = "";
			messageContainer.val("");
			messageContainer.focus();
			getMembers();
		})
	}

	$scope.changePostsPerPage = function(){
		getPostsCount(function(postsCount){
			$scope.paginator.init(postsCount, $scope.postsPerPage);
			var offset = $scope.paginator.postsPerPage*($scope.paginator.curPageId - 1);
			var limit = $scope.paginator.postsPerPage;
			getPosts(offset, limit);
		});
	}

	function startChat()
	{
		getMembers();
		getPostsCount(function(postsCount){
			$scope.paginator.init(postsCount, $scope.postsPerPage);

		});

		setInterval(getNewPosts, 3000);
	}

	startChat();

}]);<commit_msg>uploaded bug fixed<commit_after>Intranet.controller('ChatController', ['$scope', '$http', '$paginator', function($scope, $http, $paginator){
	container = $('#conversation');
	messageContainer = $('#write-message');

	$scope.paginator = $paginator;
	$scope.postsPerPage = 10;
	$scope.paginator.postsPerPage = $scope.postsPerPage;

	$scope.$watch('paginator.curPageId', function(){
		var offset = $scope.paginator.postsPerPage*($scope.paginator.curPageId - 1);
		var limit = $scope.paginator.postsPerPage;
		getPosts(offset, limit);
		console.log("curPageId: paginator--->", $scope.paginator);
	});

	$scope.pressEnter = function(e)
	{
		if ((e.shiftKey == false) && ( e.keyCode == 13 ))
		{
			e.preventDefault();
			$scope.sendPost();
		}
	}

	$scope.posts = [];
	$scope.members = [];
	$scope.message = '';
	$scope.editingPost = null;
	$scope.lastDate = null;

	$scope.postsGetURL = JSON_URLS.posts;
	$scope.avatarURL = JSON_URLS.avatar;
	$scope.postAddURL = JSON_URLS.post_add;
	$scope.membersURL = JSON_URLS.members;
	$scope.postsNewURL = JSON_URLS.posts_new;
	$scope.postsCountURL = JSON_URLS.post_count;

	$scope.entityid = window.ENTITY.id;
	$scope.userid = window.USER.id;

	function updatePosts(posts)
	{
		var editedMessages = _.filter(posts, function(p){return p.edited;});
		if (editedMessages.length == posts.length)
		{
			_.map(posts, function(post){
				_.map($scope.posts, function(p, i){
					if (p.id == post.id)
						$scope.posts[i] = post;
				});
			});
			return true;
		}

		return false;
	}

	function getPosts(offset, limit)
	{
		$http({
			method: "GET",
			url: $scope.postsGetURL,
			params: {offset: offset, limit: limit}})
		.success(function(response){
			console.log(response.result);
			if (response.result)
			{
				$scope.posts = response.result.reverse();
			}
			if (response.result.length>0)
			{
				$scope.lastDate = (_.last($scope.posts)).posted.date;
			}
			container.animate({ scrollTop: container.height()+1900 },1000);
		})
	}

	function getPostsCount(callback)
	{
		$http({
			method: "GET",
			url: $scope.postsCountURL,
			})
		.success(function(response){
			console.log("posts count: ", response.result);
			if (response.result)
				callback(response.result);
		})
	}

	function getMembers()
	{
		$http({
			method: "GET",
			url: $scope.membersURL,
			})
		.success(function(response){
			console.log("members: ", response.result);
			if (response.result)
				$scope.members = response.result;
		})
	}

	function getNewPosts()
	{
		if ($scope.paginator.curPageId == 1)
		{
			$http({
				method: "GET",
				url: $scope.postsNewURL,
				params: {last_posted: $scope.lastDate}})
			.success(function(response){
				console.log("new posts: ", response.result);
				if ((response.result) && (response.result.length > 0))
				{
					var onlyUpdated = updatePosts(response.result);
					if (onlyUpdated == false)
					{
						getPostsCount(function(postsCount){
							$scope.paginator.init(postsCount, $scope.postsPerPage);
							var offset = $scope.paginator.postsPerPage*($scope.paginator.curPageId - 1);
							var limit = $scope.paginator.postsPerPage;
							getPosts(offset, limit);
							getMembers();
						});
					}

				}
			})
		}
	}

	$scope.editPost = function(post)
	{
		if ((!$scope.isEditable(post)) || ($scope.editingPost != null)) return;
		console.log(post);
		$scope.editingPost = post;
		messageContainer.val(post.message);
	}

	Date.minutesBetween = function( date1, date2 ) {
		  var one_minute=1000*60;
		  var date1_ms = date1.getTime();
		  var date2_ms = date2.getTime();
		  var difference_ms = date2_ms - date1_ms;

		  return Math.ceil(difference_ms/one_minute);
	}

	Date.milisecondsBetween = function( date1, date2 ) {
		  var date1_ms = date1.getTime();
		  var date2_ms = date2.getTime();
		  var difference_ms = date2_ms - date1_ms;

		  return difference_ms;
	}

	Date.inMyString = function(date)
	{
		return date.getFullYear()+"-"+date.getMonth()+1+"-"+date.getDate()+" "+date.getHours()+":"+date.getMinutes()+":"+date.getSeconds();
	}

	$scope.isEditable = function(post)
	{
		var postedTime = new Date(Date.parse(post.posted.date));
		var now = new Date();
		var utc = new Date(now.getTime() + now.getTimezoneOffset() * 60000);

		var minutesAgo = Date.minutesBetween(postedTime, utc);

		return (minutesAgo <= 5 && post.userid == $scope.userid);
	}

	$scope.sendPost = function()
	{
		var post = {
				entityid: $scope.entityid,
				userid: $scope.userid,
				message: $scope.message,
				posted: new Date()
		}

		if ($scope.editingPost)
			post.postid = $scope.editingPost.id;

		$http({
			method: "POST",
			url: $scope.postAddURL,
			data: post })
		.success(function(response){
			console.log("Created post: ", response.result);
			if (response.result)
			{
				// maybe need to request for posts and init paginator!!!
				if ($scope.editingPost == null)
				{
					$scope.posts.push(response.result);
					container.animate({ scrollTop: container.height()+1900 },1000);
				}
				else
				{
					_.map($scope.posts, function(p, i){
						if (p.id == response.result.id)
							$scope.posts[i] = response.result;
					});
				}
			}

			$scope.editingPost = null;
			$scope.message = "";
			messageContainer.val("");
			messageContainer.focus();
			getMembers();
		})
	}

	$scope.changePostsPerPage = function(){
		getPostsCount(function(postsCount){
			$scope.paginator.init(postsCount, $scope.postsPerPage);
			var offset = $scope.paginator.postsPerPage*($scope.paginator.curPageId - 1);
			var limit = $scope.paginator.postsPerPage;
			getPosts(offset, limit);
		});
	}

	function startChat()
	{
		getMembers();
		getPostsCount(function(postsCount){
			$scope.paginator.init(postsCount, $scope.postsPerPage);

		});

		setInterval(getNewPosts, 3000);
	}

	startChat();

}]);<|endoftext|>


<commit_before>/**
 * Created by yutao on 15/10/5.
 */
import './discover.styl';
import DocumentTitle from 'react-document-title';
import Component from 'react-pure-render/component';
import DynamicScripts from '../../server/lib/dynamicscript.js'
import React from 'react';
import {FormattedHTMLMessage} from 'react-intl';
import {Link} from 'react-router';
import Header from '../app/header.react.js';
import Wizard from '../wizard/wizard.react.js';

import Waterfall from '../waterfall/waterfall.react.js'
import DiscoverNav from '../discover/discoverNav.react.js'
import DiscoverFrame from '../discover/discoverFrame.react.js'
import DiscoverPoi from '../discover/discoverPoi.react.js'

import ReactDOM from 'react-dom'
import ReactTabs from '../lib/react-tabs'
let Tab = ReactTabs.Tab;
let Tabs = ReactTabs.Tabs;
let TabList = ReactTabs.TabList;
let TabPanel = ReactTabs.TabPanel;

export default class Discover extends Component {

  static propTypes = {
    actions: React.PropTypes.object.isRequired,
    discover: React.PropTypes.object.isRequired,
    msg: React.PropTypes.object.isRequired
  }

  componentDidMount() {

  }

  handleSelect(index, last) {
    console.log('Selected tab: ' + index + ', Last tab: ' + last);
  }

  render() {
    const {actions, discover: {pois, frames, offset}, msg: {discover: msg}, users: {viewer}} = this.props;
    const scripts = `

    `;

    let data = pois;

    return (
      <DocumentTitle title={msg.title}>
        <DynamicScripts scripts={scripts}>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

            {/*=== End Breadcrumbs ===*/}
            {/*=== Content Part ===*/}

              <Tabs >

                <TabList>
                  <Tab>

                      图片

                  </Tab>
                  <Tab>

                      标记

                  </Tab>
                  <Tab>

                      队列

                  </Tab>
                  <Tab>

                      收藏

                  </Tab>
                </TabList>

                <TabPanel>

                    <DiscoverFrame {...{actions, frames, offset}} />

                </TabPanel>
                <TabPanel>

                    <DiscoverPoi {...{actions, pois, offset}}/>

                </TabPanel>
                <TabPanel>

Hello from Baz

                </TabPanel>
                <TabPanel>

Hello aafrom Baz

                </TabPanel>
              </Tabs>

            <Wizard />

        </DynamicScripts>
      </DocumentTitle>
    );
  }

}
<commit_msg>remove styleSheet<commit_after>/**
 * Created by yutao on 15/10/5.
 */
import './discover.styl';
import DocumentTitle from 'react-document-title';
import Component from 'react-pure-render/component';
import DynamicScripts from '../../server/lib/dynamicscript.js'
import React from 'react';
import {FormattedHTMLMessage} from 'react-intl';
import {Link} from 'react-router';
import Header from '../app/header.react.js';
import Wizard from '../wizard/wizard.react.js';

import Waterfall from '../waterfall/waterfall.react.js'
import DiscoverNav from '../discover/discoverNav.react.js'
import DiscoverFrame from '../discover/discoverFrame.react.js'
import DiscoverPoi from '../discover/discoverPoi.react.js'

import ReactDOM from 'react-dom'
import ReactTabs from '../lib/react-tabs'
let Tab = ReactTabs.Tab;
let Tabs = ReactTabs.Tabs;
let TabList = ReactTabs.TabList;
let TabPanel = ReactTabs.TabPanel;

export default class Discover extends Component {

  static propTypes = {
    actions: React.PropTypes.object.isRequired,
    discover: React.PropTypes.object.isRequired,
    msg: React.PropTypes.object.isRequired
  }

  componentDidMount() {

  }

  handleSelect(index, last) {
    console.log('Selected tab: ' + index + ', Last tab: ' + last);
  }

  render() {
    const {actions, discover: {pois, frames, offset}, msg: {discover: msg}, users: {viewer}} = this.props;
    const scripts = `

    `;

    let data = pois;

    return (
      <DocumentTitle title={msg.title}>
        <DynamicScripts scripts={scripts}>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

            {/*=== End Breadcrumbs ===*/}
            {/*=== Content Part ===*/}

              <Tabs >

                <TabList>
                  <Tab>

                      图片

                  </Tab>
                  <Tab>

                      标记

                  </Tab>
                  <Tab>

                      队列

                  </Tab>
                  <Tab>

                      收藏

                  </Tab>
                </TabList>

                <TabPanel>

                    <DiscoverFrame {...{actions, frames, offset}} />

                </TabPanel>
                <TabPanel>

                    <DiscoverPoi {...{actions, pois, offset}}/>

                </TabPanel>
                <TabPanel>

Hello from Baz

                </TabPanel>
                <TabPanel>

Hello aafrom Baz

                </TabPanel>
              </Tabs>

            <Wizard />

        </DynamicScripts>
      </DocumentTitle>
    );
  }

}
<|endoftext|>


<commit_before>import Reflux from 'reflux'
import api from 'data/api'

const DatapointActions = Reflux.createActions({
  'fetchDatapoints': { children: ['completed', 'failed'], asyncResult: true },
  'clearDatapoints': 'clearDatapoints'
})

// API CALLS
// ---------------------------------------------------------------------------
DatapointActions.fetchDatapoints.listen(params => {
  const query = _prepDatapointsQuery(params)
  DatapointActions.fetchDatapoints.promise(api.datapoints(query))
})

// ACTION HELPERS
// ---------------------------------------------------------------------------
const _prepDatapointsQuery = (params) => {
  let query = {
    indicator__in: params.indicator_ids,
    campaign_start: params.start_date,
    campaign_end: params.end_date,
    chart_type: params.type
  }

  let parent_location_chart_types = ['ChoroplethMap', 'MapChart']
  if (parent_location_chart_types.indexOf(params.type) > 0) {
    query['parent_location_id__in'] = params.location_ids
  } else {
    query['location_id__in'] = params.location_ids
  }
  return query
}

export default DatapointActions
<commit_msg>use || not indexOf to determine datapoitn api location param<commit_after>import Reflux from 'reflux'
import api from 'data/api'

const DatapointActions = Reflux.createActions({
  'fetchDatapoints': { children: ['completed', 'failed'], asyncResult: true },
  'clearDatapoints': 'clearDatapoints'
})

// API CALLS
// ---------------------------------------------------------------------------
DatapointActions.fetchDatapoints.listen(params => {
  const query = _prepDatapointsQuery(params)
  DatapointActions.fetchDatapoints.promise(api.datapoints(query))
})

// ACTION HELPERS
// ---------------------------------------------------------------------------
const _prepDatapointsQuery = (params) => {
  let query = {
    indicator__in: params.indicator_ids,
    campaign_start: params.start_date,
    campaign_end: params.end_date,
    chart_type: params.type
  }

  console.log('params')

  if (params.type === 'ChoroplethMap' || params.type === 'MapChart') {
    query['parent_location_id__in'] = params.location_ids
  } else {
    query['location_id__in'] = params.location_ids
  }
  return query
}

export default DatapointActions
<|endoftext|>


<commit_before>/*global describe, it, browser, require */

describe('tabs', function () {
    'use strict';

    it('should match the baseline tab screenshot', function (done) {
        var common = require('../common');

        browser
            .setupTest('/tabs/fixtures/test.full.html')
            .moveToObject('#screenshot-tab-2')
            .compareScreenshot({
                prefix: common.getPrefix(browser),
                screenshotName: 'tabs',
                selector: '#screenshot-tabs'
            })
            .call(done);
    });
});
<commit_msg>added checkAccessibility<commit_after>/*global describe, it, browser, require */

describe('tabs', function () {
    'use strict';

    it('should match the baseline tab screenshot', function (done) {
        var common = require('../common');

        browser
            .setupTest('/tabs/fixtures/test.full.html')
            .moveToObject('#screenshot-tab-2')
            .compareScreenshot({
                prefix: common.getPrefix(browser),
                screenshotName: 'tabs',
                selector: '#screenshot-tabs',
                checkAccessibility: true
            })
            .call(done);
    });
});
<|endoftext|>